aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/uk/ac/ox/cs/acqua
diff options
context:
space:
mode:
authorFederico Igne <federico.igne@cs.ox.ac.uk>2022-05-11 12:35:56 +0100
committerFederico Igne <federico.igne@cs.ox.ac.uk>2022-05-11 12:35:56 +0100
commit32fe8f94255b913c570275043a3c056eaa4ec07b (patch)
tree2a370c3998db1eab758f214f16f2cebc3fd2ef34 /src/main/scala/uk/ac/ox/cs/acqua
parenteaa8ed73aec7ca0ba02eb3e1c954388b8dbfc2cd (diff)
downloadACQuA-32fe8f94255b913c570275043a3c056eaa4ec07b.tar.gz
ACQuA-32fe8f94255b913c570275043a3c056eaa4ec07b.zip
Implement stub for query answering procedure
Diffstat (limited to 'src/main/scala/uk/ac/ox/cs/acqua')
-rw-r--r--src/main/scala/uk/ac/ox/cs/acqua/Main.scala82
-rw-r--r--src/main/scala/uk/ac/ox/cs/acqua/implicits/PagodaConverters.scala31
-rw-r--r--src/main/scala/uk/ac/ox/cs/acqua/reasoner/RSAQueryReasoner.scala78
-rw-r--r--src/main/scala/uk/ac/ox/cs/acqua/util/AcquaConfig.scala211
4 files changed, 383 insertions, 19 deletions
diff --git a/src/main/scala/uk/ac/ox/cs/acqua/Main.scala b/src/main/scala/uk/ac/ox/cs/acqua/Main.scala
index 749a492..e8cfeb7 100644
--- a/src/main/scala/uk/ac/ox/cs/acqua/Main.scala
+++ b/src/main/scala/uk/ac/ox/cs/acqua/Main.scala
@@ -1,16 +1,41 @@
1/*
2 * Copyright 2021,2022 KRR Oxford
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
1package uk.ac.ox.cs.acqua 17package uk.ac.ox.cs.acqua
2 18
19import uk.ac.ox.cs.rsacomb.converter.Normalizer
3import uk.ac.ox.cs.rsacomb.ontology.Ontology 20import uk.ac.ox.cs.rsacomb.ontology.Ontology
21import uk.ac.ox.cs.rsacomb.util.{RDFoxUtil,RSA}
4 22
5import uk.ac.ox.cs.pagoda.owl.OWLHelper 23import uk.ac.ox.cs.pagoda.owl.OWLHelper
6import uk.ac.ox.cs.pagoda.reasoner.{ELHOQueryReasoner,QueryReasoner,RLQueryReasoner} 24import uk.ac.ox.cs.pagoda.reasoner.{ELHOQueryReasoner,MyQueryReasoner,QueryReasoner,RLQueryReasoner}
7// import uk.ac.ox.cs.pagoda.Pagoda 25import uk.ac.ox.cs.pagoda.util.PagodaProperties;
8// import uk.ac.ox.cs.pagoda.util.PagodaProperties; 26import uk.ac.ox.cs.pagoda.util.Utility;
27
28import uk.ac.ox.cs.acqua.reasoner.RSAQueryReasoner
29import uk.ac.ox.cs.acqua.util.AcquaConfig
9 30
10object Acqua extends App { 31object Acqua extends App {
32 val config = AcquaConfig.parse(args.toList)
33 AcquaConfig describe config
11 34
12 val ontopath = os.Path("tests/lubm/univ-bench.owl", base = os.pwd) 35 val ontopath = os.Path("tests/lubm/univ-bench.owl", base = os.pwd)
13 val ontology = Ontology(ontopath, List.empty) 36 val ontology = Ontology(ontopath, List.empty).normalize(new Normalizer)
37
38 val properties = new PagodaProperties()
14 39
15 val performMultiStages = true 40 val performMultiStages = true
16 val considerEqualities = true 41 val considerEqualities = true
@@ -20,22 +45,41 @@ object Acqua extends App {
20 } else if (OWLHelper.isInELHO(ontology.origin)) { 45 } else if (OWLHelper.isInELHO(ontology.origin)) {
21 new ELHOQueryReasoner(); 46 new ELHOQueryReasoner();
22 } else if (ontology.isRSA) { 47 } else if (ontology.isRSA) {
23 // Use combined approach for RSA 48 new RSAQueryReasoner(ontology)
24 ???
25 } else { 49 } else {
26 new MyQueryReasoner(performMultiStages, considerEqualities); 50 // Return ACQuA reasoner
51 // new MyQueryReasoner(performMultiStages, considerEqualities);
52 ???
53 }
54
55 /* Preprocessing */
56 reasoner.setProperties(properties)
57 reasoner.loadOntology(ontology.origin)
58 reasoner.importData(properties.getDataPath())
59 if (reasoner.preprocess()) {
60 Utility.logInfo("The ontology is consistent!");
61 }
62 else {
63 Utility.logInfo("The ontology is inconsistent!");
64 reasoner.dispose();
27 } 65 }
28 // else
29 // switch(type) {
30 // case RLU:
31 // reasoner = new RLUQueryReasoner(performMultiStages, considerEqualities);
32 // break;
33 // case ELHOU:
34 // reasoner = new ELHOUQueryReasoner(performMultiStages, considerEqualities);
35 // break;
36 // default:
37 // reasoner = new MyQueryReasoner(performMultiStages, considerEqualities);
38 // }
39 // return reasoner;
40 66
67 if (config contains 'queries) {
68 val queries =
69 RDFoxUtil.loadQueriesFromFiles(
70 config('queries).get[List[os.Path]],
71 RSA.Prefixes
72 )
73 // for(String queryFile : properties.getQueryPath().split(";")) {
74 // Collection<QueryRecord> queryRecords = pagoda.getQueryManager().collectQueryRecords(queryFile);
75 // pagoda.evaluate(queryRecords);
76 }
41} 77}
78
79
80 // /* Perform query answering */
81 // val answers = rsa ask queries
82
83 // /* Perform logging */
84 // Logger write answers
85 // Logger.generateSimulationScripts(datapath, queries)
diff --git a/src/main/scala/uk/ac/ox/cs/acqua/implicits/PagodaConverters.scala b/src/main/scala/uk/ac/ox/cs/acqua/implicits/PagodaConverters.scala
new file mode 100644
index 0000000..c7c582d
--- /dev/null
+++ b/src/main/scala/uk/ac/ox/cs/acqua/implicits/PagodaConverters.scala
@@ -0,0 +1,31 @@
1/*
2 * Copyright 2021,2022 KRR Oxford
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package uk.ac.ox.cs.acqua.implicits
18
19import uk.ac.ox.cs.rsacomb.sparql.ConjunctiveQuery
20import uk.ac.ox.cs.pagoda.query.QueryRecord
21
22object PagodaConverters {
23
24 implicit def queryRecord2conjuctiveQuery(q: QueryRecord): ConjunctiveQuery = ???
25
26 implicit def conjunctiveQuery2queryRecord(q: ConjunctiveQuery): QueryRecord = ???
27
28}
29
30
31
diff --git a/src/main/scala/uk/ac/ox/cs/acqua/reasoner/RSAQueryReasoner.scala b/src/main/scala/uk/ac/ox/cs/acqua/reasoner/RSAQueryReasoner.scala
new file mode 100644
index 0000000..6b98d79
--- /dev/null
+++ b/src/main/scala/uk/ac/ox/cs/acqua/reasoner/RSAQueryReasoner.scala
@@ -0,0 +1,78 @@
1/*
2 * Copyright 2021,2022 KRR Oxford
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package uk.ac.ox.cs.acqua.reasoner
18
19import org.semanticweb.owlapi.model.OWLOntology
20import uk.ac.ox.cs.rsacomb.RSAOntology
21import uk.ac.ox.cs.rsacomb.approximation.{Approximation,Lowerbound}
22import uk.ac.ox.cs.rsacomb.ontology.Ontology
23import uk.ac.ox.cs.pagoda.query.QueryRecord
24import uk.ac.ox.cs.pagoda.reasoner.QueryReasoner
25
26class RSAQueryReasoner(val origin: Ontology) extends QueryReasoner {
27
28 /* Implicit compatibility between PAGOdA and RSAComb types */
29 import uk.ac.ox.cs.acqua.implicits.PagodaConverters._
30
31 /** This class is instantiated when the input ontology is RSA.
32 * Approximation (via any algorithm with RSAOntology as target)
33 * doesn't perform anything, but is useful to turn a generic
34 * [[uk.ac.ox.cs.rsacomb.ontology.Ontology]] into an
35 * [[uk.ac.ox.cs.rsacomb.RSAOntology]].
36 */
37 private val toRSA: Approximation[RSAOntology] = new Lowerbound
38 val rsa: RSAOntology = origin approximate toRSA
39
40 /** Doesn't perform any action.
41 *
42 * @note Implemented for compatibility with other reasoners.
43 */
44 def loadOntology(ontology: OWLOntology): Unit = {
45 /* Nothing to do */
46 }
47
48 /** Check consistency and returns whether the ontology is RSA.
49 *
50 * Preprocessing is performed on instance creation, so no actual work
51 * is being done here.
52 *
53 * @note Implemented for compatibility with other reasoners.
54 */
55 def preprocess(): Boolean = {
56 origin.isRSA
57 }
58
59 /** Check consistency and returns whether the ontology is RSA.
60 *
61 * Preprocessing is performed on instance creation, along with
62 * consistency checking, so no actual work is being done here.
63 *
64 * @note Implemented for compatibility with other reasoners.
65 */
66 def isConsistent(): Boolean = {
67 origin.isRSA
68 }
69
70 // TODO: probably need to override `evaluate` on multiple queries
71 def evaluate(query: QueryRecord): Unit = {
72 rsa ask query
73 }
74
75 def evaluateUpper(record: QueryRecord): Unit= {
76 ???
77 }
78}
diff --git a/src/main/scala/uk/ac/ox/cs/acqua/util/AcquaConfig.scala b/src/main/scala/uk/ac/ox/cs/acqua/util/AcquaConfig.scala
new file mode 100644
index 0000000..675a592
--- /dev/null
+++ b/src/main/scala/uk/ac/ox/cs/acqua/util/AcquaConfig.scala
@@ -0,0 +1,211 @@
1/*
2 * Copyright 2021,2022 KRR Oxford
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package uk.ac.ox.cs.acqua.util
18
19import scala.collection.mutable.Map
20
21//import util.Logger
22
23case class AcquaOption[+T](opt: T) {
24 def get[T]: T = opt.asInstanceOf[T]
25}
26
27object AcquaConfig {
28 type Config = Map[Symbol, AcquaOption[Any]]
29
30 private implicit def toRSAOption[T](opt: T) = AcquaOption[T](opt)
31
32 /** Help message */
33 private val help: String = """
34
35 rsacomb - combined approach for CQ answering for RSA ontologies.
36
37 USAGE
38 rsacomb [OPTIONS] <ontology> [<data> ...]
39
40 -h | -? | --help
41 print this help message
42
43 -l | --logger <level>
44 specify the logger verbosity. Values are: quiet, normal (default),
45 debug, verbose.
46
47 -a | --answers <file>
48 path to the output file for the answers to the query (in JSON
49 format)
50
51 -q | --queries <file>
52 path to a file containing a single SPARQL query. If no query
53 is provided, only the approximation to RSA will be performed.
54
55 -o | --ontology <file>
56 ontology file in OWL format.
57
58 -d | --data <file>
59 data files to be used alongside the ontology file. If a
60 directory is provided, all files in the directory (recursively)
61 will be considered.
62
63 -x | --approximation <string>
64 values available are "lowerupper" or "upperbound" corresponding
65 to the two algorithms for ontology approximation shipping by
66 default with RSAComb. You will need to change the source code to
67 expose custom approximation modules through the CLI.
68
69 -t | --transitive
70 "upperbound" approximation specific option. Include property chain
71 axioms (and hence the more common transitive properties) when
72 computing the canonical model.
73
74 """
75
76 /** Default config values */
77 private val default: Config = Map(
78 'transitive -> false,
79 'data -> List.empty[os.Path],
80 'approximation -> 'lowerbound
81 )
82
83 /** Parse a string into a path.
84 *
85 * @throws an [[IllegalArgumentException]] on malformed path.
86 */
87 private def getPath(str: String): os.Path =
88 try {
89 os.Path(str, base = os.pwd)
90 } catch {
91 case e: IllegalArgumentException =>
92 exit(s"'$str' is not a well formed path.")
93 }
94
95 /** Utility to exit the program with a custom message on stderr.
96 *
97 * The program will exit with error after printing the help message.
98 *
99 * @param msg message printed to stderr.
100 * @param errno error code number (defaults to 1)
101 */
102 private def exit(msg: String, errno: Int = 1): Nothing = {
103 System.err.println(msg)
104 System.err.println(help)
105 sys.exit(errno)
106 }
107
108 /** Parse arguments with default options.
109 *
110 * @param args arguments list
111 * @return map of config options
112 */
113 def parse(args: List[String]): Config = parse(args, default)
114
115 /** Parse arguments.
116 *
117 * @param args arguments list
118 * @param config default configuration
119 * @return map of config options
120 */
121 def parse(args: List[String], config: Config): Config = {
122 args match {
123 case Nil => finalise(config)
124 case flag @ ("-h" | "-?" | "--help") :: _ => {
125 println(help)
126 sys.exit(0)
127 }
128 case flag @ ("-l" | "--logger") :: _level :: tail => {
129 // val level = _level match {
130 // case "quiet" => Logger.QUIET
131 // case "debug" => Logger.DEBUG
132 // case "verbose" => Logger.VERBOSE
133 // case _ => Logger.NORMAL
134 // }
135 parse(tail, config += ('logger -> _level))
136 }
137 case flag @ ("-a" | "--answers") :: answers :: tail =>
138 parse(tail, config += ('answers -> getPath(answers)))
139 case flag @ ("-x" | "--approximation") :: approx :: tail => {
140 parse(tail, config += ('approximation -> Symbol(approx)))
141 }
142 case flag @ ("-t" | "--transitive") :: tail =>
143 parse(tail, config += ('transitive -> true))
144 case flag @ ("-q" | "--queries") :: _query :: tail => {
145 val query = getPath(_query)
146 val files =
147 if (os.isFile(query))
148 List(query)
149 else if (os.isDir(query))
150 os.walk(query).filter(os.isFile).toList
151 else
152 exit(s"'${_query}' is not a valid path.")
153 parse(tail, config += ('queries -> files))
154 }
155 case flag @ ("-o" | "--ontology") :: _ontology :: tail => {
156 val ontology = getPath(_ontology)
157 if (!os.isFile(ontology))
158 exit(s"'${_ontology}' is not a valid filename.")
159 parse(tail, config += ('ontology -> ontology))
160 }
161 case flag @ ("-d" | "--data") :: _data :: tail => {
162 val data = getPath(_data)
163 val files =
164 if (os.isFile(data))
165 List(data)
166 else if (os.isDir(data)) {
167 os.walk(data).filter(os.isFile).toList
168 }else
169 exit(s"'${_data}' is not a valid path.")
170 parse(tail, config += ('data -> files))
171 }
172 case a => exit(s"Invalid sequence of arguments '${a.mkString(" ")}'.")
173 }
174 }
175
176 /** Perform final checks on parsed options.
177 *
178 * @param config a parsed configuration
179 * @returns the input configuration, unchanged
180 */
181 private def finalise(config: Config): Config = {
182 if (!config.contains('ontology))
183 exit("The following flag is mandatory: '-o' or '--ontology'.")
184 config
185 }
186
187 /** Generate summary of a config object suitable for printing
188 *
189 * @param config a parsed configuration
190 * @returns a string describing the configuration
191 */
192 def describe(config: Config): Unit = {
193 // config foreach { case (k,v) => k match {
194 // case 'logger => Logger print s"Logger level: ${v.get[Logger.Level]}"
195 // case 'ontology => Logger print s"Ontology file: ${v.get[os.Path]}"
196 // case 'data => {
197 // val paths = v.get[List[os.Path]]
198 // val ellipsis = if (paths.length > 1) " [...]" else ""
199 // Logger print s"Data files: ${paths.head}$ellipsis"
200 // }
201 // case 'queries => {
202 // val paths = v.get[List[os.Path]]
203 // val ellipsis = if (paths.length > 1) " [...]" else ""
204 // Logger print s"Query files: ${paths.head}$ellipsis"
205 // }
206 // case 'answers => Logger print s"Path to answers: ${v.get[os.Path]}"
207 // case 'approximation => Logger print s"Applied approximation: ${v.get[Symbol].name}"
208 // case 'transitive => Logger print s"Include property chain axioms: ${v.get[Boolean]}"
209 // }}
210 }
211}