diff options
author | Federico Igne <federico.igne@cs.ox.ac.uk> | 2022-05-09 12:30:20 +0100 |
---|---|---|
committer | Federico Igne <federico.igne@cs.ox.ac.uk> | 2022-05-09 12:30:20 +0100 |
commit | 98312cd3c355a2b036edf5236dfcba755da9a17a (patch) | |
tree | 02ee6d77e0eec89610d4ad310557bc1bb6c2394f | |
parent | 155f04db8138d62b3abc2eb777b8453560bbb594 (diff) | |
download | RSAComb-98312cd3c355a2b036edf5236dfcba755da9a17a.tar.gz RSAComb-98312cd3c355a2b036edf5236dfcba755da9a17a.zip |
Refactor code
-rw-r--r-- | src/main/scala/uk/ac/ox/cs/rsacomb/Main.scala | 43 | ||||
-rw-r--r-- | src/main/scala/uk/ac/ox/cs/rsacomb/RSAConfig.scala | 98 |
2 files changed, 86 insertions, 55 deletions
diff --git a/src/main/scala/uk/ac/ox/cs/rsacomb/Main.scala b/src/main/scala/uk/ac/ox/cs/rsacomb/Main.scala index 2daa634..21b4cd2 100644 --- a/src/main/scala/uk/ac/ox/cs/rsacomb/Main.scala +++ b/src/main/scala/uk/ac/ox/cs/rsacomb/Main.scala | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright 2020, 2021 KRR Oxford | 2 | * Copyright 2020-2022 KRR Oxford |
3 | * | 3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. | 5 | * you may not use this file except in compliance with the License. |
@@ -16,42 +16,31 @@ | |||
16 | 16 | ||
17 | package uk.ac.ox.cs.rsacomb | 17 | package uk.ac.ox.cs.rsacomb |
18 | 18 | ||
19 | import java.io.{File, PrintWriter} | 19 | import approximation.{Lowerbound,Upperbound} |
20 | import java.nio.file.{Path, Paths, InvalidPathException} | 20 | import converter.Normalizer |
21 | import java.util.HashMap | 21 | import ontology.Ontology |
22 | import scala.collection.JavaConverters._ | ||
23 | import tech.oxfordsemantic.jrdfox.client.UpdateType | ||
24 | import tech.oxfordsemantic.jrdfox.logic.expression.{IRI, Term} | ||
25 | import tech.oxfordsemantic.jrdfox.logic.sparql.statement.SelectQuery | ||
26 | |||
27 | import util.{Logger, RDFoxUtil, RSA} | 22 | import util.{Logger, RDFoxUtil, RSA} |
28 | import sparql.ConjunctiveQuery | ||
29 | |||
30 | import uk.ac.ox.cs.rsacomb.ontology.Ontology | ||
31 | import uk.ac.ox.cs.rsacomb.converter.Normalizer | ||
32 | import uk.ac.ox.cs.rsacomb.approximation.Approximation | ||
33 | 23 | ||
34 | /** Main entry point to the program */ | ||
35 | object RSAComb extends App { | 24 | object RSAComb extends App { |
36 | |||
37 | /* Command-line options */ | ||
38 | val config = RSAConfig.parse(args.toList) | 25 | val config = RSAConfig.parse(args.toList) |
26 | RSAConfig describe config | ||
39 | 27 | ||
40 | /* Set logger level */ | 28 | /* Configure logger */ |
41 | if (config.contains('logger)) | 29 | if (config.contains('logger)) |
42 | Logger.level = config('logger).get[Logger.Level] | 30 | Logger.level = config('logger).get[Logger.Level] |
43 | |||
44 | /* Set answers output file */ | ||
45 | if (config.contains('answers)) | 31 | if (config.contains('answers)) |
46 | Logger.answers = config('answers).get[os.Path] | 32 | Logger.answers = config('answers).get[os.Path] |
47 | 33 | ||
48 | /* Load original ontology and normalize it */ | 34 | /* Load original ontology and normalize it */ |
49 | val ontopath = config('ontology).get[os.Path] | 35 | val ontopath = config('ontology).get[os.Path] |
50 | val data = config('data).get[List[os.Path]] | 36 | val datapath = config('data).get[List[os.Path]] |
51 | val ontology = Ontology(ontopath, data).normalize(new Normalizer) | 37 | val ontology = Ontology(ontopath, datapath).normalize(new Normalizer) |
52 | 38 | ||
53 | /* Approximate the ontology to RSA */ | 39 | /* Approximate the ontology if necessary */ |
54 | val toRSA = config('approximation).get[Approximation[RSAOntology]] | 40 | val toRSA = config('approximation).get[Symbol] match { |
41 | case 'lowerbound => new Lowerbound | ||
42 | case 'upperbound => new Upperbound | ||
43 | } | ||
55 | val rsa = ontology approximate toRSA | 44 | val rsa = ontology approximate toRSA |
56 | 45 | ||
57 | if (config contains 'queries) { | 46 | if (config contains 'queries) { |
@@ -61,11 +50,11 @@ object RSAComb extends App { | |||
61 | RSA.Prefixes | 50 | RSA.Prefixes |
62 | ) | 51 | ) |
63 | 52 | ||
53 | /* Perform query answering */ | ||
64 | val answers = rsa ask queries | 54 | val answers = rsa ask queries |
65 | 55 | ||
66 | /* Write answers to output file */ | 56 | /* Perform logging */ |
67 | Logger write answers | 57 | Logger write answers |
68 | /* Generate simulation script */ | 58 | Logger.generateSimulationScripts(datapath, queries) |
69 | Logger.generateSimulationScripts(data, queries) | ||
70 | } | 59 | } |
71 | } | 60 | } |
diff --git a/src/main/scala/uk/ac/ox/cs/rsacomb/RSAConfig.scala b/src/main/scala/uk/ac/ox/cs/rsacomb/RSAConfig.scala index fe4b5f1..57c4f05 100644 --- a/src/main/scala/uk/ac/ox/cs/rsacomb/RSAConfig.scala +++ b/src/main/scala/uk/ac/ox/cs/rsacomb/RSAConfig.scala | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright 2020, 2021 KRR Oxford | 2 | * Copyright 2020-2022 KRR Oxford |
3 | * | 3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. | 5 | * you may not use this file except in compliance with the License. |
@@ -17,8 +17,8 @@ | |||
17 | package uk.ac.ox.cs.rsacomb | 17 | package uk.ac.ox.cs.rsacomb |
18 | 18 | ||
19 | import scala.collection.mutable.Map | 19 | import scala.collection.mutable.Map |
20 | |||
20 | import util.Logger | 21 | import util.Logger |
21 | import approximation._ | ||
22 | 22 | ||
23 | case class RSAOption[+T](opt: T) { | 23 | case class RSAOption[+T](opt: T) { |
24 | def get[T]: T = opt.asInstanceOf[T] | 24 | def get[T]: T = opt.asInstanceOf[T] |
@@ -31,6 +31,7 @@ object RSAConfig { | |||
31 | 31 | ||
32 | /** Help message */ | 32 | /** Help message */ |
33 | private val help: String = """ | 33 | private val help: String = """ |
34 | |||
34 | rsacomb - combined approach for CQ answering for RSA ontologies. | 35 | rsacomb - combined approach for CQ answering for RSA ontologies. |
35 | 36 | ||
36 | USAGE | 37 | USAGE |
@@ -59,25 +60,30 @@ object RSAConfig { | |||
59 | directory is provided, all files in the directory (recursively) | 60 | directory is provided, all files in the directory (recursively) |
60 | will be considered. | 61 | will be considered. |
61 | 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 | |||
62 | """ | 74 | """ |
63 | 75 | ||
64 | /** Default config values */ | 76 | /** Default config values */ |
65 | private val default: Config = Map.empty | 77 | private val default: Config = Map( |
78 | 'transitive -> false, | ||
79 | 'data -> List.empty[os.Path], | ||
80 | 'approximation -> 'lowerbound | ||
81 | ) | ||
66 | 82 | ||
67 | /** Utility to exit the program with a custom message on stderr. | 83 | /** Parse a string into a path. |
68 | * | ||
69 | * The program will exit with error code 1 after printing the help | ||
70 | * message. | ||
71 | * | 84 | * |
72 | * @param msg message printed to stderr. | 85 | * @throws an [[IllegalArgumentException]] on malformed path. |
73 | */ | 86 | */ |
74 | private def exit(msg: String): Nothing = { | ||
75 | System.err.println(msg) | ||
76 | System.err.println() | ||
77 | System.err.println(help) | ||
78 | sys.exit(1) | ||
79 | } | ||
80 | |||
81 | private def getPath(str: String): os.Path = | 87 | private def getPath(str: String): os.Path = |
82 | try { | 88 | try { |
83 | os.Path(str, base = os.pwd) | 89 | os.Path(str, base = os.pwd) |
@@ -86,14 +92,27 @@ object RSAConfig { | |||
86 | exit(s"'$str' is not a well formed path.") | 92 | exit(s"'$str' is not a well formed path.") |
87 | } | 93 | } |
88 | 94 | ||
89 | /** Parse arguments with default options | 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. | ||
90 | * | 109 | * |
91 | * @param args arguments list | 110 | * @param args arguments list |
92 | * @return map of config options | 111 | * @return map of config options |
93 | */ | 112 | */ |
94 | def parse(args: List[String]): Config = parse(args, default) | 113 | def parse(args: List[String]): Config = parse(args, default) |
95 | 114 | ||
96 | /** Parse arguments | 115 | /** Parse arguments. |
97 | * | 116 | * |
98 | * @param args arguments list | 117 | * @param args arguments list |
99 | * @param config default configuration | 118 | * @param config default configuration |
@@ -117,13 +136,11 @@ object RSAConfig { | |||
117 | } | 136 | } |
118 | case flag @ ("-a" | "--answers") :: answers :: tail => | 137 | case flag @ ("-a" | "--answers") :: answers :: tail => |
119 | parse(tail, config += ('answers -> getPath(answers))) | 138 | parse(tail, config += ('answers -> getPath(answers))) |
120 | case flag @ ("-x" | "--approximation") :: _approx :: tail => { | 139 | case flag @ ("-x" | "--approximation") :: approx :: tail => { |
121 | val approx = _approx match { | 140 | parse(tail, config += ('approximation -> Symbol(approx))) |
122 | case "lowerbound" => new Lowerbound | ||
123 | case "upperbound" => new Upperbound | ||
124 | } | ||
125 | parse(tail, config += ('approximation -> approx)) | ||
126 | } | 141 | } |
142 | case flag @ ("-t" | "--transitive") :: tail => | ||
143 | parse(tail, config += ('transitive -> true)) | ||
127 | case flag @ ("-q" | "--queries") :: _query :: tail => { | 144 | case flag @ ("-q" | "--queries") :: _query :: tail => { |
128 | val query = getPath(_query) | 145 | val query = getPath(_query) |
129 | val files = | 146 | val files = |
@@ -156,14 +173,39 @@ object RSAConfig { | |||
156 | } | 173 | } |
157 | } | 174 | } |
158 | 175 | ||
159 | /** Perform final checks on parsed options */ | 176 | /** Perform final checks on parsed options. |
177 | * | ||
178 | * @param config a parsed configuration | ||
179 | * @returns the input configuration, unchanged | ||
180 | */ | ||
160 | private def finalise(config: Config): Config = { | 181 | private def finalise(config: Config): Config = { |
161 | if (!config.contains('ontology)) | 182 | if (!config.contains('ontology)) |
162 | exit("The following flag is mandatory: '-o' or '--ontology'.") | 183 | exit("The following flag is mandatory: '-o' or '--ontology'.") |
163 | if (!config.contains('data)) | ||
164 | config += ('data -> List.empty[os.Path]) | ||
165 | if (!config.contains('approximation)) | ||
166 | config += ('approximation -> new Lowerbound) | ||
167 | config | 184 | config |
168 | } | 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 | } | ||
169 | } | 211 | } |