aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/uk/ac/ox/cs/pagoda/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/uk/ac/ox/cs/pagoda/util')
-rw-r--r--src/main/java/uk/ac/ox/cs/pagoda/util/ConjunctiveQueryHelper.java70
-rw-r--r--src/main/java/uk/ac/ox/cs/pagoda/util/ExponentialInterpolation.java33
-rw-r--r--src/main/java/uk/ac/ox/cs/pagoda/util/Namespace.java34
-rw-r--r--src/main/java/uk/ac/ox/cs/pagoda/util/PagodaProperties.java259
-rw-r--r--src/main/java/uk/ac/ox/cs/pagoda/util/Separator.java11
-rw-r--r--src/main/java/uk/ac/ox/cs/pagoda/util/SimpleProgressBar.java48
-rw-r--r--src/main/java/uk/ac/ox/cs/pagoda/util/SparqlHelper.java282
-rw-r--r--src/main/java/uk/ac/ox/cs/pagoda/util/Timer.java52
-rw-r--r--src/main/java/uk/ac/ox/cs/pagoda/util/TurtleHelper.java56
-rw-r--r--src/main/java/uk/ac/ox/cs/pagoda/util/UFS.java45
-rw-r--r--src/main/java/uk/ac/ox/cs/pagoda/util/Utility.java251
-rw-r--r--src/main/java/uk/ac/ox/cs/pagoda/util/data_structures/Graph.java38
-rw-r--r--src/main/java/uk/ac/ox/cs/pagoda/util/disposable/Disposable.java30
-rw-r--r--src/main/java/uk/ac/ox/cs/pagoda/util/disposable/DisposedException.java12
-rw-r--r--src/main/java/uk/ac/ox/cs/pagoda/util/tuples/Tuple.java54
-rw-r--r--src/main/java/uk/ac/ox/cs/pagoda/util/tuples/TupleBuilder.java38
16 files changed, 1313 insertions, 0 deletions
diff --git a/src/main/java/uk/ac/ox/cs/pagoda/util/ConjunctiveQueryHelper.java b/src/main/java/uk/ac/ox/cs/pagoda/util/ConjunctiveQueryHelper.java
new file mode 100644
index 0000000..937c2c4
--- /dev/null
+++ b/src/main/java/uk/ac/ox/cs/pagoda/util/ConjunctiveQueryHelper.java
@@ -0,0 +1,70 @@
1package uk.ac.ox.cs.pagoda.util;
2
3import java.util.Collection;
4import java.util.HashSet;
5import java.util.LinkedList;
6
7public class ConjunctiveQueryHelper {
8
9 public static String[][] getAnswerVariables(String queryText) {
10 Collection<String> disVars = new LinkedList<String>(), undisVars = new LinkedList<String>();
11 for (String var: getAllVariables(queryText))
12 if (var.startsWith("?")) disVars.add(var.substring(1));
13 else undisVars.add(var.substring(2));
14
15 String[] distinguishedVariables = disVars.toArray(new String[0]);
16 String[] undistinguishedVariables = undisVars.toArray(new String[0]);
17 String[] answerVariables = null;
18
19 String uppercase = queryText.toUpperCase();
20 int selectIndex = uppercase.indexOf("SELECT");
21 int whereIndex = uppercase.indexOf("WHERE");
22 String selectClause = queryText.substring(selectIndex + 6, whereIndex);
23 if (selectClause.contains("*")) answerVariables = distinguishedVariables;
24 else {
25 String[] terms = selectClause.split(" ");
26 int num = 0;
27 for (int i = 0; i < terms.length; ++i)
28 if (terms[i].startsWith("?")) ++num;
29 answerVariables = new String[num];
30 for (int i = 0, j = 0; i < terms.length; ++i)
31 if (terms[i].startsWith("?"))
32 answerVariables[j++] = terms[i].substring(1);
33 }
34
35 if (answerVariables != distinguishedVariables) {
36 int index = 0;
37 for (; index < answerVariables.length; ++index) {
38 distinguishedVariables[index] = answerVariables[index];
39 disVars.remove(answerVariables[index]);
40 }
41 for (String var: disVars)
42 distinguishedVariables[index++] = var;
43 }
44
45 return new String[][] { answerVariables, distinguishedVariables, undistinguishedVariables };
46 }
47
48 private static Collection<String> getAllVariables(String queryText) {
49 Collection<String> vars = new HashSet<String>();
50 int start, end = 0;
51 char ch;
52 while ((start = queryText.indexOf("?", end)) != -1) {
53 end = start + 1;
54 while (end + 1 < queryText.length() && (ch = queryText.charAt(end + 1)) != '\n' && ch != ' ')
55 ++end;
56 vars.add(queryText.substring(start, end + 1));
57 }
58
59 end = 0;
60 while ((start = queryText.indexOf("_:", end)) != -1) {
61 end = start + 1;
62 while (end + 1 < queryText.length() && (ch = queryText.charAt(end + 1)) != '\n' && ch != ' ')
63 ++end;
64 vars.add(queryText.substring(start, end + 1));
65 }
66
67 return vars;
68 }
69
70}
diff --git a/src/main/java/uk/ac/ox/cs/pagoda/util/ExponentialInterpolation.java b/src/main/java/uk/ac/ox/cs/pagoda/util/ExponentialInterpolation.java
new file mode 100644
index 0000000..1d12169
--- /dev/null
+++ b/src/main/java/uk/ac/ox/cs/pagoda/util/ExponentialInterpolation.java
@@ -0,0 +1,33 @@
1package uk.ac.ox.cs.pagoda.util;
2
3/***
4 * Get an exponential function given two points.
5 */
6public class ExponentialInterpolation {
7
8 private final double base;
9 private final double multiplicativeFactor;
10
11 /***
12 * Compute the exponential function passing for the 2 given points.
13 *
14 * @param x1
15 * @param y1
16 * @param x2
17 * @param y2
18 */
19 public ExponentialInterpolation(double x1, double y1, double x2, double y2) {
20 base = Math.pow(y2/y1, 1 / (x2 - x1));
21 multiplicativeFactor = y1 / Math.pow(base, x1);
22 }
23
24 /***
25 * Compute value of the function in x.
26 *
27 * @param x
28 * @return
29 */
30 public double computeValue(double x) {
31 return multiplicativeFactor * Math.pow(base, x);
32 }
33}
diff --git a/src/main/java/uk/ac/ox/cs/pagoda/util/Namespace.java b/src/main/java/uk/ac/ox/cs/pagoda/util/Namespace.java
new file mode 100644
index 0000000..07c8ebd
--- /dev/null
+++ b/src/main/java/uk/ac/ox/cs/pagoda/util/Namespace.java
@@ -0,0 +1,34 @@
1package uk.ac.ox.cs.pagoda.util;
2
3public class Namespace {
4
5 public static final String RDF_NS = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
6 public static final String RDFS_NS = "http://www.w3.org/2000/01/rdf-schema#";
7 public static final String OWL_NS = "http://www.w3.org/2002/07/owl#";
8 public static final String XSD_NS = "http://www.w3.org/2001/XMLSchema#";
9 public static final String SWRL_NS = "http://www.w3.org/2003/11/swrl#";
10 public static final String SWRLB_NS = "http://www.w3.org/2003/11/swrlb#";
11 public static final String SWRLX_NS = "http://www.w3.org/2003/11/swrlx#";
12 public static final String RULEML_NS = "http://www.w3.org/2003/11/ruleml#";
13
14 public static final String RDF_TYPE_QUOTED = "<" + RDF_NS + "type>";
15 public static final String RDF_TYPE = RDF_NS + "type";
16 public static final String RDF_TYPE_ABBR = "rdf:type";
17
18 public static final String EQUALITY = OWL_NS + "sameAs";
19 public static final String EQUALITY_QUOTED = "<" + EQUALITY + ">";
20 public static final String EQUALITY_ABBR = "owl:sameAs";
21
22 public static final String INEQUALITY = OWL_NS + "differentFrom";
23 public static final String INEQUALITY_ABBR = "owl:differentFrom";
24 public static final String INEQUALITY_QUOTED = "<" + INEQUALITY + ">";
25
26 public static final String RDF_PLAIN_LITERAL = RDF_NS + "PlainLiteral";
27 public static final String XSD_STRING = XSD_NS + "string";
28
29 public static final String PAGODA_ANONY = "http://www.cs.ox.ac.uk/PAGOdA/skolemised#";
30 public static final String PAGODA_AUX = "http://www.cs.ox.ac.uk/PAGOdA/auxiliary#";
31 public static final String KARMA_ANONY = "http://www.cs.ox.ac.uk/KARMA/anonymous";
32 public static final String PAGODA_ORIGINAL = PAGODA_AUX + "Original";
33
34}
diff --git a/src/main/java/uk/ac/ox/cs/pagoda/util/PagodaProperties.java b/src/main/java/uk/ac/ox/cs/pagoda/util/PagodaProperties.java
new file mode 100644
index 0000000..2b52a89
--- /dev/null
+++ b/src/main/java/uk/ac/ox/cs/pagoda/util/PagodaProperties.java
@@ -0,0 +1,259 @@
1package uk.ac.ox.cs.pagoda.util;
2
3import org.apache.log4j.Logger;
4
5import java.io.FileInputStream;
6import java.io.IOException;
7import java.io.InputStream;
8import java.nio.file.Path;
9import java.nio.file.Paths;
10import java.util.Properties;
11
12public class PagodaProperties {
13
14 public enum SkolemUpperBoundOptions {DISABLED, BEFORE_SUMMARISATION, AFTER_SUMMARISATION}
15
16 public static final String DEFAULT_CONFIG_FILE = "_default_pagoda.properties";
17 public static final String CONFIG_FILE = "pagoda.properties";
18 public static final boolean DEFAULT_DEBUG = false;
19 private static final boolean DEFAULT_USE_ALWAYS_SIMPLE_UPPER_BOUND;
20 private static final SkolemUpperBoundOptions DEFAULT_SKOLEM_UPPER_BOUND;
21 private static final int DEFAULT_SKOLEM_DEPTH;
22 private static final boolean DEFAULT_TO_CALL_HERMIT;
23 private static final Path DEFAULT_STATISTICS_DIR;
24 private static final long DEFAULT_MAX_TRIPLES_IN_SKOLEM_STORE;
25
26 public static boolean shellModeDefault = false;
27 private static boolean debug = DEFAULT_DEBUG;
28
29 static {
30 Logger logger = Logger.getLogger("PagodaProperties");
31
32 boolean defaultUseAlwaysSimpleUpperBound = false;
33 SkolemUpperBoundOptions defaultSkolemUpperBound = SkolemUpperBoundOptions.DISABLED;
34 int defaultSkolemDepth = 1;
35 boolean toCallHermit = true;
36 Path defaultStatisticsDir = null;
37 long defaultMaxTriplesInSkolemStore = 1000000;
38
39 InputStream configStream = PagodaProperties.class.getClassLoader().getResourceAsStream(CONFIG_FILE);
40
41 if(configStream == null) {
42 logger.info("Unable to find user-defined configuration file (\"" + CONFIG_FILE + "\" in classpath)");
43 logger.info("Using default configuration");
44 configStream = PagodaProperties.class.getClassLoader().getResourceAsStream(DEFAULT_CONFIG_FILE);
45 }
46
47 try {
48 Properties config = new Properties();
49 config.load(configStream);
50 configStream.close();
51
52 if (config.containsKey("debug")) {
53 debug = Boolean.parseBoolean(config.getProperty("debug"));
54 logger.info("Debugging mode is enabled");
55
56 if (config.containsKey("statisticsDir")) {
57 defaultStatisticsDir = Paths.get(config.getProperty("statisticsDir"));
58 logger.info("The directory where statistics are saved is: \"" + defaultStatisticsDir + "\"");
59 }
60 }
61 if (config.containsKey("useAlwaysSimpleUpperBound")) {
62 defaultUseAlwaysSimpleUpperBound =
63 Boolean.parseBoolean(config.getProperty("useAlwaysSimpleUpperBound"));
64 if (defaultUseAlwaysSimpleUpperBound)
65 logger.debug("By default the simple upper bound is always used");
66 }
67 if (config.containsKey("skolemUpperBound")) {
68 defaultSkolemUpperBound = SkolemUpperBoundOptions.valueOf(config.getProperty("skolemUpperBound"));
69 switch (defaultSkolemUpperBound) {
70 case AFTER_SUMMARISATION:
71 logger.debug("By default the Skolem upper bound is applied AFTER Summarisation");
72 break;
73 case BEFORE_SUMMARISATION:
74 logger.debug("By default the Skolem upper bound is applied BEFORE Summarisation");
75 break;
76 default:
77 defaultSkolemUpperBound = SkolemUpperBoundOptions.DISABLED;
78 case DISABLED:
79 logger.debug("By default the Skolem upper bound is disabled");
80 }
81 }
82 if (config.containsKey("toCallHermit")) {
83 toCallHermit = Boolean.parseBoolean(config.getProperty("toCallHermit"));
84 if (toCallHermit)
85 logger.debug("By default Hermit is enabled");
86 else
87 logger.debug("By default Hermit is disabled");
88 }
89 if (config.containsKey("skolemDepth")) {
90 defaultSkolemDepth = Integer.parseInt(config.getProperty("skolemDepth"));
91 logger.debug("By default the max skolemisation depth is " + defaultSkolemDepth);
92 }
93 if (config.containsKey("maxTriplesInSkolemStore")) {
94 defaultMaxTriplesInSkolemStore = Long.parseLong(config.getProperty("maxTriplesInSkolemStore"));
95 logger.debug("By default the maximum number of triples in the Skolem store is " + defaultMaxTriplesInSkolemStore);
96 }
97
98 } catch (IOException e) {
99 e.printStackTrace();
100 }
101 DEFAULT_USE_ALWAYS_SIMPLE_UPPER_BOUND = defaultUseAlwaysSimpleUpperBound;
102 DEFAULT_SKOLEM_UPPER_BOUND = defaultSkolemUpperBound;
103 DEFAULT_TO_CALL_HERMIT = toCallHermit;
104 DEFAULT_STATISTICS_DIR = defaultStatisticsDir;
105 DEFAULT_SKOLEM_DEPTH = defaultSkolemDepth;
106 DEFAULT_MAX_TRIPLES_IN_SKOLEM_STORE = defaultMaxTriplesInSkolemStore;
107 }
108
109 String dataPath = null;
110 String ontologyPath;
111 String queryPath = null;
112 String answerPath = null;
113 boolean toClassify = true;
114 boolean toCallHermiT = DEFAULT_TO_CALL_HERMIT;
115
116 public int getSkolemDepth() {
117 return skolemDepth;
118 }
119
120 public void setSkolemDepth(int skolemDepth) {
121 this.skolemDepth = skolemDepth;
122 }
123
124 int skolemDepth = DEFAULT_SKOLEM_DEPTH;
125 boolean shellMode = shellModeDefault;
126 private boolean useAlwaysSimpleUpperBound = DEFAULT_USE_ALWAYS_SIMPLE_UPPER_BOUND;
127 private SkolemUpperBoundOptions skolemUpperBound = DEFAULT_SKOLEM_UPPER_BOUND;
128 private Path statisticsDir = DEFAULT_STATISTICS_DIR;
129 private long maxTriplesInSkolemStore = DEFAULT_MAX_TRIPLES_IN_SKOLEM_STORE;
130
131 public PagodaProperties(String path) {
132 java.util.Properties m_properties = new java.util.Properties();
133 InputStream inputStream = null;
134 try {
135 inputStream = new FileInputStream(path);
136 m_properties.load(inputStream);
137
138 setOntologyPath(m_properties.getProperty("ONTOLOGY"));
139 setDataPath(m_properties.getProperty("DATA"));
140 setQueryPath(m_properties.getProperty("QUERY"));
141 setAnswerPath(m_properties.getProperty("ANSWER"));
142 setToClassify(Boolean.parseBoolean(m_properties.getProperty("TO_CLASSIFY")));
143 setToCallHermiT(Boolean.parseBoolean(m_properties.getProperty("CALL_HERMIT")));
144
145 } catch (IOException e) {
146 e.printStackTrace();
147 } finally {
148 if (inputStream != null)
149 try {
150 inputStream.close();
151 } catch (IOException e) {
152 e.printStackTrace();
153 }
154 }
155 }
156
157 public PagodaProperties() {
158 }
159
160 public static boolean isDebuggingMode() {
161 return debug;
162 }
163
164 public static boolean getDefaultUseAlwaysSimpleUpperBound() {
165 return DEFAULT_USE_ALWAYS_SIMPLE_UPPER_BOUND;
166 }
167
168 public static Path getDefaultStatisticsDir() {
169 return DEFAULT_STATISTICS_DIR;
170 }
171
172 public static SkolemUpperBoundOptions getDefaultSkolemUpperBound() {
173 return DEFAULT_SKOLEM_UPPER_BOUND;
174 }
175
176 public String getDataPath() {
177 return dataPath;
178 }
179
180 public void setDataPath(String path) {
181 dataPath = path;
182 }
183
184 public String getOntologyPath() {
185 return ontologyPath;
186 }
187
188 public void setOntologyPath(String path) {
189 ontologyPath = path;
190 }
191
192 public String getQueryPath() {
193 return queryPath;
194 }
195
196 public void setQueryPath(String path) {
197 queryPath = path;
198 }
199
200 public String getAnswerPath() {
201 return answerPath;
202 }
203
204 public void setAnswerPath(String path) {
205 answerPath = path;
206 }
207
208 public boolean getToClassify() {
209 return toClassify;
210 }
211
212 public void setToClassify(boolean flag) {
213 toClassify = flag;
214 }
215
216 public boolean getToCallHermiT() {
217 return toCallHermiT;
218 }
219
220 public void setToCallHermiT(boolean flag) {
221 toCallHermiT = flag;
222 }
223
224 public boolean getShellMode() {
225 return shellMode;
226 }
227
228 public void setShellMode(boolean flag) {
229 shellMode = flag;
230 }
231
232 public boolean getUseAlwaysSimpleUpperBound() {
233 return useAlwaysSimpleUpperBound;
234 }
235
236 public void setUseAlwaysSimpleUpperBound(boolean flag) {
237 useAlwaysSimpleUpperBound = flag;
238 }
239
240 public SkolemUpperBoundOptions getSkolemUpperBound() {
241 return skolemUpperBound;
242 }
243
244 public void setSkolemUpperBound(SkolemUpperBoundOptions flag) {
245 skolemUpperBound = flag;
246 }
247
248 public Path getStatisticsDir() {
249 return statisticsDir;
250 }
251
252 public void setStatisticsDir(Path statisticsDir) {
253 this.statisticsDir = statisticsDir;
254 }
255
256 public long getMaxTriplesInSkolemStore() {
257 return maxTriplesInSkolemStore;
258 }
259}
diff --git a/src/main/java/uk/ac/ox/cs/pagoda/util/Separator.java b/src/main/java/uk/ac/ox/cs/pagoda/util/Separator.java
new file mode 100644
index 0000000..1e6ad9c
--- /dev/null
+++ b/src/main/java/uk/ac/ox/cs/pagoda/util/Separator.java
@@ -0,0 +1,11 @@
1package uk.ac.ox.cs.pagoda.util;
2
3public class Separator {
4
5 public static final String FILE = System.getProperty("file.separator");
6 public static final String LINE = System.getProperty("line.separator");
7 public static final String INDIVIDUAL = "\t";
8 public static final String QUERY = "---------------------------------------------";
9
10
11}
diff --git a/src/main/java/uk/ac/ox/cs/pagoda/util/SimpleProgressBar.java b/src/main/java/uk/ac/ox/cs/pagoda/util/SimpleProgressBar.java
new file mode 100644
index 0000000..3c4aad7
--- /dev/null
+++ b/src/main/java/uk/ac/ox/cs/pagoda/util/SimpleProgressBar.java
@@ -0,0 +1,48 @@
1package uk.ac.ox.cs.pagoda.util;
2
3import uk.ac.ox.cs.pagoda.util.disposable.Disposable;
4
5public class SimpleProgressBar extends Disposable {
6
7 private final String name;
8 private int lastPercent;
9 private int maxValue;
10
11 public SimpleProgressBar() {
12 this("");
13 }
14
15 public SimpleProgressBar(String name) {
16 this(name, 100);
17 }
18
19 public SimpleProgressBar(String name, int maxValue) {
20 this.name = name;
21 this.maxValue = maxValue;
22 }
23
24 public void update(int value) {
25 int percent = value * 100 / maxValue;
26 StringBuilder template = new StringBuilder("\r" + name + " [");
27 for (int i = 0; i < 50; i++) {
28 if (i < percent * .5) {
29 template.append("=");
30 } else if (i == percent * .5) {
31 template.append(">");
32 } else {
33 template.append(" ");
34 }
35 }
36 template.append("] %s ");
37 System.out.printf(template.toString(), percent + "%");
38 System.out.flush();
39 lastPercent = percent;
40 }
41
42 @Override
43 public void dispose() {
44 super.dispose();
45
46 System.out.println();
47 }
48}
diff --git a/src/main/java/uk/ac/ox/cs/pagoda/util/SparqlHelper.java b/src/main/java/uk/ac/ox/cs/pagoda/util/SparqlHelper.java
new file mode 100644
index 0000000..1e53b9c
--- /dev/null
+++ b/src/main/java/uk/ac/ox/cs/pagoda/util/SparqlHelper.java
@@ -0,0 +1,282 @@
1package uk.ac.ox.cs.pagoda.util;
2
3import com.hp.hpl.jena.graph.Node;
4import com.hp.hpl.jena.query.Query;
5import com.hp.hpl.jena.query.QueryFactory;
6import com.hp.hpl.jena.sparql.core.TriplePath;
7import com.hp.hpl.jena.sparql.core.Var;
8import com.hp.hpl.jena.sparql.syntax.*;
9import org.semanticweb.HermiT.model.*;
10import uk.ac.ox.cs.pagoda.MyPrefixes;
11import uk.ac.ox.cs.pagoda.hermit.RuleHelper;
12
13import java.util.Collection;
14import java.util.HashSet;
15import java.util.Set;
16
17public class SparqlHelper {
18
19 public static String getSPARQLQuery(Atom[] atoms, String... vars) {
20 Set<Variable> undistinguishedVars = new HashSet<Variable>();
21 for (int i = 0; i < atoms.length; ++i) {
22 atoms[i].getVariables(undistinguishedVars);
23 }
24 int xIndex = 1;
25 while (undistinguishedVars.contains(Variable.create("X" + xIndex))) ++xIndex;
26
27 for (String var: vars)
28 if (var != null && !var.isEmpty())
29 undistinguishedVars.remove(Variable.create(var));
30
31 StringBuffer buffer = new StringBuffer();
32 if (vars.length > 0)
33 buffer.append("SELECT DISTINCT ");
34 else
35 buffer.append("SELECT *");
36 for (int i = 0; i < vars.length; ++i) {
37 if (vars[i] != null && !vars[i].isEmpty())
38 buffer.append("?").append(vars[i]).append(" ");
39 }
40 buffer.append( " WHERE {");
41 for (Atom atom: atoms)
42 if (atom.getDLPredicate() instanceof AtLeastConcept) {
43 AtLeastConcept atLeast = (AtLeastConcept) atom.getDLPredicate();
44 int number = atLeast.getNumber();
45 for (int i = 0; i < number; ++i) {
46 Variable newVar = Variable.create("X" + (xIndex + i));
47
48 Atom tAtom;
49 if (atLeast.getOnRole() instanceof AtomicRole)
50 tAtom = Atom.create(
51 (AtomicRole) atLeast.getOnRole(),
52 atom.getArgument(0),
53 newVar);
54 else
55 tAtom = Atom.create(
56 (AtomicRole) atLeast.getOnRole().getInverse(),
57 newVar,
58 atom.getArgument(0));
59 buffer.append(" ");
60 buffer.append(toSPARQLClause(tAtom, undistinguishedVars));
61 buffer.append(" .");
62
63 if (!atLeast.getToConcept().equals(AtomicConcept.THING)) {
64 if (atLeast.getToConcept() instanceof AtomicConcept);
65
66 tAtom = Atom.create((AtomicConcept) atLeast.getToConcept(), newVar);
67 buffer.append(" ");
68 buffer.append(toSPARQLClause(tAtom, undistinguishedVars));
69 buffer.append(" .");
70 }
71 }
72
73 for (int i = 0; i < number; ++i)
74 for (int j = i + 1; j < number; ++j) {
75 Atom tAtom = Atom.create(Inequality.INSTANCE, Variable.create("X" + (xIndex + i)), Variable.create("X" + (xIndex + j)));
76 buffer.append(" ");
77 buffer.append(toSPARQLClause(tAtom, undistinguishedVars));
78 buffer.append(" .");
79 }
80
81 xIndex += number;
82 }
83 else {
84 buffer.append(" ");
85 buffer.append(toSPARQLClause(atom, undistinguishedVars));
86 buffer.append(" .");
87 }
88 buffer.append(" ").append("}");
89 return buffer.toString();
90 }
91
92 private static String toSPARQLClause(Atom atom, Set<Variable> undisVars ) {
93 DLPredicate predicate = atom.getDLPredicate();
94 String r, a, b;
95
96 if (predicate instanceof Equality || predicate instanceof AnnotatedEquality)
97 atom = Atom.create(predicate = AtomicRole.create(Namespace.EQUALITY), atom.getArgument(0), atom.getArgument(1));
98 else if (predicate instanceof Inequality)
99 atom = Atom.create(predicate = AtomicRole.create(Namespace.INEQUALITY), atom.getArgument(0), atom.getArgument(1));
100
101 if (predicate instanceof AtomicConcept) {
102 r = Namespace.RDF_TYPE_QUOTED;
103 a = MyPrefixes.PAGOdAPrefixes.getQuotedIRI(getName(atom.getArgument(0), undisVars));
104 b = MyPrefixes.PAGOdAPrefixes.getQuotedIRI(RuleHelper.getText(predicate));
105 }
106 else if (predicate instanceof AtomicRole) {
107 r = MyPrefixes.PAGOdAPrefixes.getQuotedIRI(RuleHelper.getText(predicate));
108 a = MyPrefixes.PAGOdAPrefixes.getQuotedIRI(getName(atom.getArgument(0), undisVars));
109 b = MyPrefixes.PAGOdAPrefixes.getQuotedIRI(getName(atom.getArgument(1), undisVars));
110 }
111 else if (predicate instanceof AtomicDataRange) {
112 r = Namespace.RDF_TYPE_QUOTED;
113 a = MyPrefixes.PAGOdAPrefixes.getQuotedIRI(getName(atom.getArgument(0), undisVars));
114 b = MyPrefixes.PAGOdAPrefixes.getQuotedIRI(RuleHelper.getText(predicate));
115 }
116 else {
117 Utility.logError("error!!!!!!!!!!!");
118 return null;
119 }
120
121 return a + " " + r + " " + b;
122 }
123
124 private static String getName(Term t, Set<Variable> undisVars) {
125 if (t instanceof Variable)
126 if (undisVars.contains(t))
127 return "_:" + ((Variable) t).getName();
128 else return "?" + ((Variable) t).getName();
129 return MyPrefixes.PAGOdAPrefixes.abbreviateIRI(t.toString());
130 }
131
132 public static Query parse(String text, Collection<String> vars, Collection<Atom> atoms) {
133 Query query = QueryFactory.create(text);
134 if (vars != null) {
135 vars.clear();
136 for (Var var: query.getProjectVars())
137 vars.add(var.getName());
138 }
139 ElementVisitor visitor = new MySparqlElementVisitor(atoms);
140 query.getQueryPattern().visit(visitor);
141 return query;
142 }
143
144}
145
146class MySparqlElementVisitor implements ElementVisitor {
147
148 Collection<Atom> atoms;
149
150 public MySparqlElementVisitor(Collection<Atom> atoms) {
151 this.atoms = atoms;
152 }
153
154 @Override
155 public void visit(ElementSubQuery el) {
156 Utility.logError("ElmentSubQuery: " + el);
157 }
158
159 @Override
160 public void visit(ElementService el) {
161 // TODO Auto-generated method stub
162 Utility.logError("ElementService: " + el);
163 }
164
165 @Override
166 public void visit(ElementMinus el) {
167 // TODO Auto-generated method stub
168 Utility.logError("ElementMinus: " + el);
169 }
170
171 @Override
172 public void visit(ElementNotExists el) {
173 // TODO Auto-generated method stub
174 Utility.logError("ElementNotExists: " + el);
175 }
176
177 @Override
178 public void visit(ElementExists el) {
179 // TODO Auto-generated method stub
180 Utility.logError("ElementExists: " + el);
181 }
182
183 @Override
184 public void visit(ElementNamedGraph el) {
185 // TODO Auto-generated method stub
186 Utility.logError("ElementNamedGraph: " + el);
187 }
188
189 @Override
190 public void visit(ElementDataset el) {
191 // TODO Auto-generated method stub
192 Utility.logError("ElementDataset: " + el);
193 }
194
195 @Override
196 public void visit(ElementGroup el) {
197 // TODO Auto-generated method stub
198 for (Element e: el.getElements())
199 e.visit(this);
200 }
201
202 @Override
203 public void visit(ElementOptional el) {
204 // TODO Auto-generated method stub
205 Utility.logError("ElementOptional: " + el);
206 }
207
208 @Override
209 public void visit(ElementUnion el) {
210 // TODO Auto-generated method stub
211 Utility.logError("ElementUnion: " + el);
212 }
213
214 @Override
215 public void visit(ElementBind el) {
216 // TODO Auto-generated method stub
217 Utility.logError("ElementBind: " + el);
218 }
219
220 @Override
221 public void visit(ElementAssign el) {
222 // TODO Auto-generated method stub
223 Utility.logError("ElementAssign: " + el);
224 }
225
226 @Override
227 public void visit(ElementFilter el) {
228 // TODO Auto-generated method stub
229 Utility.logError("ElementFilter: " + el);
230 }
231
232 @Override
233 public void visit(ElementPathBlock el) {
234 // TODO Auto-generated method stub
235 for (TriplePath p: el.getPattern().getList()) {
236 if (p.getPredicate().isVariable()) {
237 AtomicRole r = AtomicRole.create("?" + p.getPredicate().getName());
238 Term a = getTerm(p.getSubject()), b = getTerm(p.getObject());
239 atoms.add(Atom.create(r, a, b));
240 }
241 else if (p.getPredicate().getURI().equals(Namespace.RDF_TYPE) && !p.getObject().isVariable()) {
242 AtomicConcept A = AtomicConcept.create(p.getObject().getURI());
243 Term c = getTerm(p.getSubject());
244 atoms.add(Atom.create(A, c));
245 }
246 else {
247 AtomicRole r = AtomicRole.create(p.getPredicate().getURI());
248 Term a = getTerm(p.getSubject()), b = getTerm(p.getObject());
249 atoms.add(Atom.create(r, a, b));
250 }
251 }
252 }
253
254 private Term getTerm(Node node) {
255 if (node.isVariable())
256 return Variable.create(node.getName());
257 if (node.isLiteral())
258 if (node.getLiteralDatatypeURI() == null)
259 return Constant.create(node.getLiteralLexicalForm(), Namespace.XSD_STRING);
260 else
261 return Constant.create(node.getLiteralLexicalForm(), node.getLiteralDatatypeURI());
262
263
264 if (node.isURI())
265 return Individual.create(node.getURI());
266 Utility.logError("unknown node: " + node);
267 return null;
268 }
269
270 @Override
271 public void visit(ElementTriplesBlock el) {
272 // TODO Auto-generated method stub
273
274 Utility.logError("ElementTriplesBlock: " + el);
275 }
276
277 @Override
278 public void visit(ElementData el) {
279 // TODO Auto-generated method stub
280
281 }
282} \ No newline at end of file
diff --git a/src/main/java/uk/ac/ox/cs/pagoda/util/Timer.java b/src/main/java/uk/ac/ox/cs/pagoda/util/Timer.java
new file mode 100644
index 0000000..d1814a4
--- /dev/null
+++ b/src/main/java/uk/ac/ox/cs/pagoda/util/Timer.java
@@ -0,0 +1,52 @@
1package uk.ac.ox.cs.pagoda.util;
2
3public class Timer {
4
5 double pastTime = 0;
6 boolean active = false;
7
8 long startTime;
9
10 public Timer() {
11 resume();
12 }
13
14 public void resume() {
15 if (active) return;
16 startTime = System.currentTimeMillis();;
17 active = true;
18 }
19
20 public double duration() {
21 double time = pastTime;
22 if (active)
23 time += (System.currentTimeMillis() - startTime) / 1000.;
24 return time;
25 }
26
27 public void pause() {
28 if (!active) return ;
29 pastTime = duration();
30 active = false;
31 }
32
33 public double reset() {
34 double ret = duration();
35 pastTime = 0;
36 active = false;
37 resume();
38 return ret;
39 }
40
41 double timeout = -1;
42
43 public boolean timeOut() {
44 if (timeout < 0) return false;
45 return duration() > timeout;
46 }
47
48 public void setTimeout(double timeout) {
49 this.timeout = timeout;
50 }
51
52}
diff --git a/src/main/java/uk/ac/ox/cs/pagoda/util/TurtleHelper.java b/src/main/java/uk/ac/ox/cs/pagoda/util/TurtleHelper.java
new file mode 100644
index 0000000..6887b9f
--- /dev/null
+++ b/src/main/java/uk/ac/ox/cs/pagoda/util/TurtleHelper.java
@@ -0,0 +1,56 @@
1package uk.ac.ox.cs.pagoda.util;
2
3import java.io.*;
4
5public class TurtleHelper {
6
7 public static void simplify(String tempFile, String outputPath) throws IOException {
8 BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(tempFile)));
9 BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outputPath)));
10
11 String line, sub = null, pred = null, obj = null;
12 char lastSymbol = '.', symbol;
13 String[] seg;
14 while ((line = reader.readLine()) != null) {
15 if (line.trim().isEmpty() || line.startsWith("#") || line.startsWith("@base"))
16 continue;
17
18 if (line.startsWith("@")) {
19 writer.write(line);
20 writer.newLine();
21 continue;
22 }
23
24
25 symbol = line.charAt(line.length() - 1);
26
27 if (lastSymbol == '.') {
28 seg = line.split(" ");
29 sub = seg[0];
30 pred = seg[1];
31 obj = seg[2];
32 }
33 else if (lastSymbol == ';') {
34 line = line.substring(sub.length() + 1);
35 seg = line.split(" ");
36 pred = seg[0];
37 obj = seg[1];
38 }
39 else if (lastSymbol == ',') {
40 line = line.substring(sub.length() + pred.length() + 2);
41 obj = line.substring(0, line.lastIndexOf(' '));
42 }
43 else Utility.logError("ERROR");
44
45 lastSymbol = symbol;
46 if (pred.equals("rdf:type") && obj.startsWith("owl:"))
47 continue;
48
49 writer.write(sub + " " + pred + " " + obj + " .\n");
50 }
51
52 reader.close();
53 writer.close();
54 }
55
56}
diff --git a/src/main/java/uk/ac/ox/cs/pagoda/util/UFS.java b/src/main/java/uk/ac/ox/cs/pagoda/util/UFS.java
new file mode 100644
index 0000000..0869fb7
--- /dev/null
+++ b/src/main/java/uk/ac/ox/cs/pagoda/util/UFS.java
@@ -0,0 +1,45 @@
1package uk.ac.ox.cs.pagoda.util;
2
3import java.util.HashMap;
4import java.util.Map;
5import java.util.Set;
6
7public class UFS<T> {
8
9 private Map<T, T> groups = new HashMap<T, T>();
10
11 public boolean merge(T t1, T t2) {
12 t1 = find(t1); t2 = find(t2);
13 if (t1.equals(t2)) return false;
14 if (t2.toString().contains("cs.ox.ac.uk"))
15 groups.put(t2, t1);
16 else
17 groups.put(t1, t2);
18 return true;
19 }
20
21 public Set<T> keySet() {
22 return groups.keySet();
23 }
24
25 public T find(T u) {
26 T v, w = u;
27 while ((v = groups.get(u)) != null)
28 u = v;
29
30 while ((v = groups.get(w)) != null) {
31 groups.put(w, u);
32 w = v;
33 }
34
35 return u;
36 }
37
38 public void clear() {
39 groups.clear();
40 }
41
42 public boolean isEmpty() {
43 return groups.isEmpty();
44 }
45}
diff --git a/src/main/java/uk/ac/ox/cs/pagoda/util/Utility.java b/src/main/java/uk/ac/ox/cs/pagoda/util/Utility.java
new file mode 100644
index 0000000..cef4abd
--- /dev/null
+++ b/src/main/java/uk/ac/ox/cs/pagoda/util/Utility.java
@@ -0,0 +1,251 @@
1package uk.ac.ox.cs.pagoda.util;
2
3import org.apache.log4j.Level;
4import org.apache.log4j.Logger;
5import org.semanticweb.HermiT.model.Atom;
6
7import java.io.*;
8import java.nio.file.Files;
9import java.nio.file.Path;
10import java.text.SimpleDateFormat;
11import java.util.*;
12
13public class Utility {
14
15 public static final String JAVA_FILE_SEPARATOR = "/";
16 public static final String FILE_SEPARATOR = System.getProperty("file.separator");
17 public static final String LINE_SEPARATOR = System.getProperty("line.separator");
18 public static final int TEST = -1;
19 public static final int FLY = 0;
20 public static final int UOBM = 1;
21 public static final int LUBM = 2;
22 public static final int AEO = 3;
23 public static final int WINE = 4;
24 private static final String TEMP_DIR_PATH = "pagoda_tmp";
25 static Stack<PrintStream> outs = new Stack<PrintStream>();
26 private static Logger LOGS;
27 private static String tempDir;
28 private static int asciiX = (int) 'X';
29 private static StringBuilder logMessage = new StringBuilder();
30
31 static {
32 LOGS = Logger.getLogger("Pagoda");
33 LOGS.setLevel(Level.DEBUG);
34 }
35
36 static {
37 outs.push(System.out);
38 }
39
40 static {
41
42 }
43
44 public static String getGlobalTempDirAbsolutePath() {
45 if(tempDir == null) {
46 try {
47 Path path = Files.createTempDirectory(TEMP_DIR_PATH);
48 tempDir = path.toString();
49 new File(tempDir).deleteOnExit();
50 } catch(IOException e) {
51 e.printStackTrace();
52 System.exit(1);
53 }
54 }
55 return tempDir;
56 }
57
58 public static Set<Atom> toSet(Atom[] data) {
59 HashSet<Atom> ret = new HashSet<Atom>();
60 for(Atom element : data)
61 ret.add(element);
62 return ret;
63 }
64
65 public static boolean redirectSystemOut()
66 {
67 String stamp = new SimpleDateFormat( "HH:mm:ss").format(new Date());
68 return redirectCurrentOut("./console" + stamp + ".txt");
69 }
70
71 public static boolean redirectCurrentOut(String fileName)
72 {
73 File file = new File(fileName);
74 PrintStream out;
75 try {
76 out = new PrintStream(new FileOutputStream(file));
77 } catch (FileNotFoundException e) {
78 e.printStackTrace();
79 return false;
80 }
81 outs.push(out);
82 System.setOut(out);
83 return true;
84 }
85
86 public static void closeCurrentOut() {
87 if (!outs.isEmpty())
88 outs.pop().close();
89
90 if(!outs.isEmpty())
91 System.setOut(outs.peek());
92 }
93
94 public static void sparql2expression(String input, String output) throws IOException {
95 BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(input)));
96 BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(output)));
97 boolean first;
98 String line, query;
99 while ((line = reader.readLine()) != null) {
100 if (line.startsWith("^")) {
101 for (int i = 0; i < 4; ++i)
102 line = reader.readLine();
103 first = true;
104 query = "";
105 while ((line = reader.readLine()) != null && !line.startsWith("}"))
106 if (first) {
107 first = false;
108 query = expression(line.trim());
109 }
110 else query += ", " + expression(line.trim());
111 writer.write(query);
112 writer.newLine();
113 }
114 }
115 reader.close();
116 writer.close();
117 }
118
119 private static String expression(String line) {
120 String[] parts = line.split(" ");
121 if (parts[1].equals("rdf:type")) {
122 return parts[2] + "(?" + variableIndex(parts[0]) + ")";
123 }
124 else return parts[1] + "(?" + variableIndex(parts[0]) + ",?" + variableIndex(parts[2]) + ")";
125 }
126
127 private static int variableIndex(String exp) {
128 char var = exp.charAt(1);
129 return (int)var - asciiX;
130 }
131
132 public static String readLine(BufferedReader reader) throws IOException {
133 String line = reader.readLine();
134 if (line == null)
135 return null;
136 return line.trim();
137 }
138
139 public static String getTextfromFile(String fileName) throws FileNotFoundException {
140 Scanner scanner = new Scanner(new File(fileName));
141 String program = scanner.useDelimiter("\\Z").next();
142 scanner.close();
143 return program;
144 }
145
146 public static String[] getPattern(BufferedReader answerReader) throws IOException {
147 String lastLine = readLine(answerReader), line;
148 while ((line = readLine(answerReader)) != null && !line.startsWith("---------"))
149 lastLine = line;
150 return lastLine.split(" ");
151 }
152
153 public static void removeRecursively(File file) {
154 if (!file.exists()) return;
155
156 if (file.isDirectory())
157 for (File tFile: file.listFiles())
158 removeRecursively(tFile);
159 file.delete();
160 }
161
162 public static void removeRecursively(String fileName) {
163 removeRecursively(new File(fileName));
164 }
165
166 public static Collection<String> getQueryTexts(String fileName) throws IOException {
167 BufferedReader queryReader = new BufferedReader(new InputStreamReader(new FileInputStream(fileName)));
168 String line;
169 Collection<String> queryTexts = new LinkedList<String>();
170 while (true) {
171 while((line = queryReader.readLine()) != null && ((line = line.trim()).isEmpty() || line.startsWith("#"))) ;
172 if (line == null) {
173 queryReader.close();
174 return queryTexts;
175 }
176
177 StringBuffer query = new StringBuffer();
178 if (!line.startsWith("^["))
179 query.append(line).append(LINE_SEPARATOR);
180
181 while((line = queryReader.readLine()) != null && !line.trim().endsWith("}"))
182 query.append(line).append(LINE_SEPARATOR);
183 query.append(line);
184 queryTexts.add(query.toString());
185 }
186 }
187
188 /**
189 *
190 * @param answerReader
191 * @return all lines before the next empty line
192 * @throws IOException
193 */
194 public static Collection<String> getLines(BufferedReader answerReader) throws IOException {
195 Collection<String> answerTuples = new LinkedList<String>();
196 String line;
197 while ((line = answerReader.readLine()) != null) {
198 line = line.trim();
199 if (line.isEmpty())
200 break;
201 answerTuples.add(line);
202 }
203 return answerTuples;
204 }
205
206 private static String getLogMessage(Object[] messages) {
207 if (messages.length == 1) return messages[0].toString();
208 else {
209 logMessage.setLength(0);
210 for (int i = 0; i < messages.length; ++i) {
211 if (logMessage.length() != 0)
212 logMessage.append(LINE_SEPARATOR);
213 logMessage.append(messages[i]);
214 }
215 return logMessage.toString();
216 }
217
218 }
219
220 public static void setLogLevel(Level level) {
221 LOGS.setLevel(level);
222 }
223
224 public static void logInfo(Object... messages) {
225 if (LOGS != null)
226 LOGS.info(getLogMessage(messages));
227 }
228
229 public static void logTrace(Object... messages) {
230 if (LOGS != null)
231 LOGS.trace(getLogMessage(messages));
232 }
233
234 public static void logDebug(Object... messages) {
235 if (LOGS != null)
236 LOGS.debug(getLogMessage(messages));
237 }
238
239 public static void logError(Object... messages) {
240 if (LOGS != null)
241 LOGS.error(getLogMessage(messages));
242 }
243
244 public static String toFileIRI(String path) {
245 String iri;
246 if (path.startsWith(FILE_SEPARATOR)) iri = "file:" + path;
247 else iri = "file:\\\\\\" + path;
248 return iri.replace(FILE_SEPARATOR, JAVA_FILE_SEPARATOR).replace(" ", "%20");
249 }
250
251}
diff --git a/src/main/java/uk/ac/ox/cs/pagoda/util/data_structures/Graph.java b/src/main/java/uk/ac/ox/cs/pagoda/util/data_structures/Graph.java
new file mode 100644
index 0000000..4f454df
--- /dev/null
+++ b/src/main/java/uk/ac/ox/cs/pagoda/util/data_structures/Graph.java
@@ -0,0 +1,38 @@
1package uk.ac.ox.cs.pagoda.util.data_structures;
2
3import java.util.*;
4
5public class Graph<V> {
6
7 private final boolean isDirected;
8
9 private Map<V, Set<V>> outEdgesOf = new HashMap<>();
10 public Graph(boolean isDirected) {
11 this.isDirected = isDirected;
12 }
13
14 public Graph() {
15 this(false);
16 }
17 public void addNode(V v) {
18 if(!outEdgesOf.containsKey(v))
19 outEdgesOf.put(v, new HashSet<V>());
20 }
21
22 public void addEdge(V v, V u) {
23 addNode(v);
24 addNode(u);
25 outEdgesOf.get(v).add(u);
26
27 if(isDirected)
28 outEdgesOf.get(u).add(v);
29 }
30
31 public Iterator<V> getOutNeighbors(V v) {
32 return outEdgesOf.get(v).iterator();
33 }
34
35 public boolean isDirected() {
36 return isDirected;
37 }
38}
diff --git a/src/main/java/uk/ac/ox/cs/pagoda/util/disposable/Disposable.java b/src/main/java/uk/ac/ox/cs/pagoda/util/disposable/Disposable.java
new file mode 100644
index 0000000..4015b66
--- /dev/null
+++ b/src/main/java/uk/ac/ox/cs/pagoda/util/disposable/Disposable.java
@@ -0,0 +1,30 @@
1package uk.ac.ox.cs.pagoda.util.disposable;
2
3
4/**
5 * Every public method of a subclass of this class,
6 * as first instruction, should check if the object has already been disposed
7 * and, if so, should throw a <tt>DisposedException</tt>.
8 */
9public abstract class Disposable {
10
11 private boolean disposed = false;
12
13 /**
14 * This method must be called after the use of the object.
15 * <p>
16 * Every overriding method must call <tt>super.dispose()</tt> as first instruction.
17 */
18 public void dispose() {
19 if(isDisposed()) throw new AlreadyDisposedException();
20 disposed = true;
21 }
22
23 public final boolean isDisposed() {
24 return disposed;
25 }
26
27 private class AlreadyDisposedException extends RuntimeException {
28 }
29
30}
diff --git a/src/main/java/uk/ac/ox/cs/pagoda/util/disposable/DisposedException.java b/src/main/java/uk/ac/ox/cs/pagoda/util/disposable/DisposedException.java
new file mode 100644
index 0000000..eb8c039
--- /dev/null
+++ b/src/main/java/uk/ac/ox/cs/pagoda/util/disposable/DisposedException.java
@@ -0,0 +1,12 @@
1package uk.ac.ox.cs.pagoda.util.disposable;
2
3public class DisposedException extends RuntimeException {
4
5 public DisposedException() {
6 super();
7 }
8
9 public DisposedException(String msg) {
10 super(msg);
11 }
12}
diff --git a/src/main/java/uk/ac/ox/cs/pagoda/util/tuples/Tuple.java b/src/main/java/uk/ac/ox/cs/pagoda/util/tuples/Tuple.java
new file mode 100644
index 0000000..0a5983c
--- /dev/null
+++ b/src/main/java/uk/ac/ox/cs/pagoda/util/tuples/Tuple.java
@@ -0,0 +1,54 @@
1package uk.ac.ox.cs.pagoda.util.tuples;
2
3import java.util.ArrayList;
4import java.util.Collections;
5import java.util.Iterator;
6import java.util.Spliterator;
7import java.util.function.Consumer;
8
9public class Tuple<T> implements Iterable<T> {
10
11 final ArrayList<T> elements = new ArrayList<>();
12
13 Tuple() { }
14
15 @SafeVarargs
16 public Tuple(T... elements) {
17 Collections.addAll(this.elements, elements);
18 }
19
20 public Tuple(Iterable<T> iterable) {
21 for (T t : iterable) {
22 this.elements.add(t);
23 }
24 }
25
26 public T get(int i) {
27 return elements.get(i);
28 }
29
30 @Override
31 public Iterator<T> iterator() {
32 return elements.iterator();
33 }
34
35 @Override
36 public void forEach(Consumer<? super T> action) {
37 elements.forEach(action);
38 }
39
40 @Override
41 public Spliterator<T> spliterator() {
42 return elements.spliterator();
43 }
44
45 @Override
46 public int hashCode() {
47 return elements.hashCode() + getClass().hashCode();
48 }
49
50 @Override
51 public String toString() {
52 return elements.toString();
53 }
54}
diff --git a/src/main/java/uk/ac/ox/cs/pagoda/util/tuples/TupleBuilder.java b/src/main/java/uk/ac/ox/cs/pagoda/util/tuples/TupleBuilder.java
new file mode 100644
index 0000000..172e249
--- /dev/null
+++ b/src/main/java/uk/ac/ox/cs/pagoda/util/tuples/TupleBuilder.java
@@ -0,0 +1,38 @@
1package uk.ac.ox.cs.pagoda.util.tuples;
2
3import java.util.Collections;
4
5/**
6 * Allows to create an immutable <tt>Tuple</tt> in a non-atomic way.
7 * It can create only one <tt>Tuple</tt>.
8 * */
9public class TupleBuilder<T> {
10
11 private Tuple<T> tuple = new Tuple<T>();
12
13 private boolean building = true;
14
15 public TupleBuilder<T> append(T t) {
16 if(building) {
17 tuple.elements.add(t);
18 return this;
19 }
20 return null;
21 }
22
23 public TupleBuilder<T> append(T[] t) {
24 if(building) {
25 Collections.addAll(tuple.elements, t);
26 return this;
27 }
28 return null;
29 }
30
31 public Tuple<T> build() {
32 if(building) {
33 building = false;
34 return tuple;
35 }
36 return null;
37 }
38}