\cleardoublepage

\chapter{A Functional API for OWL}\label{chap:fowl}


\section{Motivation}
The semantic web community has widely adopted the OWL API \cite{10.5555/2890046.2890052} for ontology creation and development. Many researchers and programmers find this software very useful and enjoy its Object-Oriented style. Other APIs for OWL have also been written in imperative languages like Owlready \cite{lamy2017owlready} in Python. However, some developers prefer to program in functional languages and find that the imperative style APIs are more of a hindrance than a help when dealing with ontologies. There has been work towards providing functional style programming for OWL, like Tawny-OWL \cite{DBLP:conf/owled/Lord13}, but this is fundamentally dependent on the OWL API so it is cosmetically functional but not obviously compatible with many of the unique features and optimizations of the functional style. In order to support other styles of programming for ontologies we have developed \fowl, a functional perspective on ontology development.

\section{\fowl}
As an original standalone piece of software, \fowl\ is not a wrapper for the OWL API. It starts again at the beginning and is truly functional from the ground up. \fowl\ was written with Clojure because it is a functional language that compiles with the Java Virtual Machine, and thus will have a broad compatibility with any machine that can run Java. Clojure has the added benefit of intuitive native laziness, so writing efficient programs to create and manipulate ontologies is not a challenge. To ensure that the semantics are correct, \fowl\ directly implements the grammar of the OWL 2 Structural Specification \cite{Parsia:12:OWO}. And because it is entirely original, \fowl\ is divorced from any historical dependencies and commitments that clutter other software.

\fowl\ includes many novel optimizations that streamline ontology development. True to the functional paradigm \fowl\ uses functions and shuns classes. Indeed all OWL ontology objects can be created directly with \fowl\ functions. And since these functions are not bound up in an arbitrary class hierarchy, they can operate on independent data structures that are internally typed to represent OWL semantics. A \fowl\ ontology itself is simply another data structure made of collections of smaller similar structures. This means that in most cases an expression, an axiom, even an ontology can be traversed recursively as-is without writing more functions. \fowl\ also simplifies many of the unhelpful, highly verbose Java-style function names that occur in other programs and instead adopts a concise functional naming scheme.

\fowl\ is built and tested using Leiningen\footnote{\url{https://leiningen.org/}} and the source code can be found on GitHub.\footnote{\url{https://github.com/aaronEberhart/fOWL}} During testing, it efficiently reads and writes copies of over 260 different functional syntax ontologies from various domains, including the massive Gene ontology \cite{gene}, with no errors being detected. It is available on the Clojars\footnote{\url{https://clojars.org/onto.aaroneberhart/fowl}} repository so that users can easily import it into their own Clojure projects. ClojureDoc\footnote{\url{https://cljdoc.org/d/onto.aaroneberhart/fowl/0.0.1-SNAPSHOT/doc/readme}} for \fowl\ is available, and documentation is also accessible in the read–eval–print loop (REPL) for individual functions while writing programs.

\begin{table}[t]
\begin{center}
\begin{tabular}{ l m{0.25em} l }
    Functional&&Lisp-like syntax\\
    No dependencies && Requires only Clojure\\
    No classes && Objects can be created and manipulated directly\\
    Ontology data structure && Homogeneous and uniform: can be traversed\\
    Lightweight && Supports OWL 2, no unnecessary baggage\\
    Clojure Efficiency&&Lazy functions and optimizable recursion\\
    Concise function names && Avoids verbose unhelpful Java conventions
\end{tabular}
\end{center}
\caption{Features of \fowl}
\end{table}

\subsection{Examples from the REPL}
\begin{itemize}
\item Create an axiom
{\scriptsize
\begin{verbatim}
fowl.core=> (ont/implies (ont/exists "r" "a") "b")

SubClassOf(ObjectSomeValuesFrom(r a) b)
\end{verbatim}
}
\item Show the documentation for a function
{\scriptsize
\begin{verbatim}
fowl.core=> (doc ont/makeOWLFile)

-------------------------
ontology.core/makeOWLFile
([ontology filename & fileType])
  Writes an owl file of the ontology with the supplied file name. 
  Optional argument allows choice of file type. No option defaults to functional syntax. 
  (Currently only functional syntax defined)
\end{verbatim}
}

\item Make an ontology with a Clojure threading expression
{\scriptsize
\begin{verbatim}
fowl.core=> (-> ont/emptyOntologyFile
               (ont/setOntologyIRI "http://www.test.iri")
               (ont/addAnnotations (ont/annotation "annotations" "are fun"))
               (ont/addPrefixes (ont/prefix "" "http://www.test.iri/")
                                (ont/prefix "prefix" "http://www.prefix.iri/")) 
               (ont/addAxioms (ont/implies "a" (ont/IRI "prefix" "b"))
                              (ont/implies (ont/or "d" "g") "a")
                              (ont/implies (ont/inverseRole "r") "s")
                              (ont/fact "a" "i")
                              (ont/fact "r" "j" "i")))
                              
Prefix(rdf:=<http://www.w3.org/1999/02/22-rdf-syntax-ns#>)
Prefix(rdfs:=<http://www.w3.org/2000/01/rdf-schema#>)
Prefix(prefix:=<http://www.prefix.iri/>)
Prefix(:=<http://www.test.iri/>)
Prefix(xsd:=<http://www.w3.org/2001/XMLSchema#>)
Prefix(owl:=<http://www.w3.org/2002/07/owl#>)

Ontology(<http://www.test.iri>

Annotation(:annotations "are fun")

ObjectPropertyAssertion(:r :j :i)
SubObjectPropertyOf(ObjectInverseOf(:r) :s)
SubClassOf(ObjectUnionOf(:d :g) :a)
SubClassOf(:a prefix:b)
ClassAssertion(:a :i)
)
\end{verbatim}
}
\item Add every third axiom from a vector into a set with a tail recursive loop
{\scriptsize
\begin{verbatim}
fowl.core=> (loop [counter 0
                   axiomSet #{}
                   axioms [(ont/implies (ont/exists "r" "a") "b")
                           (ont/implies (ont/or "b" "c") (ont/not (ont/or "d" "e")))
                           (ont/implies (ont/roleChain "r" (ont/inverseRole "s")) "t")
                           (ont/fact (ont/inverseRole "s") "i" "j")
                           (ont/fact "a" "i")
                           (ont/fact "d" "i" (ont/stringLiteral "l"))
                           (ont/implies (ont/roleChain "s" "q") "t")]]
                           
             (if (empty? axioms)                  ; are there no axioms left?
              
              axiomSet                            ; return axiom set
              
              (recur                              ; else recurse with new values
              
               (inc counter)                      ; counter + 1
               
               (if (= 0 (mod counter 3))          ; is counter mod 3 == 0?
                (conj axiomSet (first axioms))    ; add first axiom to set
                axiomSet)                         ; else keep current axiom set
               
               (rest axioms))))                   ; remove first axiom
              
#{ObjectPropertyAssertion(ObjectInverseOf(s) i j) 
  SubClassOf(ObjectSomeValuesFrom(r a) b)
  SubObjectPropertyOf(ObjectPropertyChain(s q) t)}
\end{verbatim}
}
\item Use a partial function and a list comprehension to make axioms for a class
{\scriptsize
\begin{verbatim}
fowl.core=> (let [aImplies (partial ont/implies "a")]
             (for [b ["c" (ont/all "r" "d") (ont/and "e" "f" "g")]] (aImplies b)))
             
(SubClassOf(a c) 
 SubClassOf(a ObjectAllValuesFrom(r d)) 
 SubClassOf(a ObjectIntersectionOf(e f g)))
\end{verbatim}
}
\end{itemize}
More examples are available on the project GitHub page.

% avg axioms 21767.93462

\section{Evaluation}
As a preliminary benchmark, we choose a few operations in \fowl\ that are commonly used and have near equivalent counterparts in the OWL API: read an ontology, write an ontology, get the NNF of all class axioms. Table \ref{tab:raw} shows the average time to complete a task, and Table \ref{tab:scal} shows the average times when they are each scaled by the number of axioms in the ontology. As expected, the performance of \fowl\ with respect to the OWL API closely parallels the difference between native Java and Clojure. Though it is usually faster when reading files, as indicated by the scaled times, \fowl\ is slowed down while reading large files by the need to construct many immutable objects for the ontology, which is typical for Clojure programs.  However, even a large \fowl\ ontology can be accessed and traversed in a very efficient manner. This allows \fowl\ to write files quickly. And it can get the NNF of all class axioms significantly faster than even optimized stream functions.

All testing was done on a computer running Ubuntu 20.04.1 64-bit with an Intel Core i7-9700K CPU@3.60GHz x 8, 47.1 GiB DDR4, and a GeForce GTX 1060 6GB/PCIe/SSE2.

\avgAll
\avgAx
%\goAll
%\goAx

\section{Conclusion}
\fowl\ provides a lightweight functional alternative for OWL ontology development. It has numerous benefits that will doubtless increase as development finalizes and it matures. \fowl\ is highly practical for developers who prefer a functional language, it supports all of OWL 2, and provides unique functional methods for structuring and manipulating ontology data. 

\section{Future Work}
There are two major efforts in progress to improve this project. The first is writing and testing new functions to allow the parsing of XML and RDF OWL files. This capability is integrated into the current project framework but it is incomplete and takes a fair amount of time to test and debug. Additionally, because OWL files are frequently in XML and RDF format we have delayed the implementation of ontology imports until after these file types can be read. Once the imports are implemented \fowl\ should support at least as much semantics for standard OWL ontology development as other APIs. A custom reasoner is also in the early stages of development for \fowl. We hope that this will streamline reasoning over \fowl\ ontologies by running while they are created.