aboutsummaryrefslogtreecommitdiff
path: root/src/uk/ac/ox/cs/pagoda/query
diff options
context:
space:
mode:
Diffstat (limited to 'src/uk/ac/ox/cs/pagoda/query')
-rw-r--r--src/uk/ac/ox/cs/pagoda/query/AnswerTuple.java94
-rw-r--r--src/uk/ac/ox/cs/pagoda/query/QueryRecord.java479
2 files changed, 284 insertions, 289 deletions
diff --git a/src/uk/ac/ox/cs/pagoda/query/AnswerTuple.java b/src/uk/ac/ox/cs/pagoda/query/AnswerTuple.java
index cd86282..7220533 100644
--- a/src/uk/ac/ox/cs/pagoda/query/AnswerTuple.java
+++ b/src/uk/ac/ox/cs/pagoda/query/AnswerTuple.java
@@ -22,10 +22,11 @@ import java.util.regex.Pattern;
22public class AnswerTuple { 22public class AnswerTuple {
23 23
24 public static final String SEPARATOR = "\t"; 24 public static final String SEPARATOR = "\t";
25 static final Pattern owlLiteralRegex =
26 Pattern.compile("^\"(?<lexicalForm>[^@]+(@(?<langTag>.+))?)\"(^^<(?<dataType>.+)>)?$");
27 String m_str = null;
28 GroundTerm[] m_tuple;
25 29
26 String m_str = null;
27 GroundTerm[] m_tuple;
28
29 public AnswerTuple(TupleIterator iter, int arity) { 30 public AnswerTuple(TupleIterator iter, int arity) {
30 m_tuple = new GroundTerm[arity]; 31 m_tuple = new GroundTerm[arity];
31 try { 32 try {
@@ -33,24 +34,29 @@ public class AnswerTuple {
33 m_tuple[i] = iter.getGroundTerm(i); 34 m_tuple[i] = iter.getGroundTerm(i);
34 } catch (JRDFStoreException e) { 35 } catch (JRDFStoreException e) {
35 e.printStackTrace(); 36 e.printStackTrace();
36 } 37 }
37 } 38 }
38 39
39 public AnswerTuple(GroundTerm[] terms) { 40 public AnswerTuple(GroundTerm[] terms) {
40 m_tuple = terms; 41 m_tuple = terms;
41 }
42
43 private AnswerTuple(AnswerTuple sup, int arity) {
44 m_tuple = new GroundTerm[arity];
45 for (int i = 0; i < arity; ++i) m_tuple[i] = sup.m_tuple[i];
46 } 42 }
47 43
48// private AnswerTuple(String m_str) { 44// private AnswerTuple(String m_str) {
49// this.m_str = m_str; 45// this.m_str = m_str;
50// } 46// }
47
48 private AnswerTuple(AnswerTuple sup, int arity) {
49 m_tuple = new GroundTerm[arity];
50 for(int i = 0; i < arity; ++i) m_tuple[i] = sup.m_tuple[i];
51 }
52
53 public static AnswerTuple create(AnswerTuple extendedTuple, int length) {
54 if(length == extendedTuple.getArity()) return extendedTuple;
55 else return new AnswerTuple(extendedTuple, length);
56 }
51 57
52 public int getArity() { 58 public int getArity() {
53 return m_tuple.length; 59 return m_tuple.length;
54 } 60 }
55 61
56 public int hashCode() { 62 public int hashCode() {
@@ -60,7 +66,7 @@ public class AnswerTuple {
60 code = code * 1997 + m_tuple[i].hashCode(); 66 code = code * 1997 + m_tuple[i].hashCode();
61 return code; 67 return code;
62 } 68 }
63 69
64 public boolean equals(Object obj) { 70 public boolean equals(Object obj) {
65 if (!(obj instanceof AnswerTuple)) return false; 71 if (!(obj instanceof AnswerTuple)) return false;
66 AnswerTuple that = (AnswerTuple) obj; 72 AnswerTuple that = (AnswerTuple) obj;
@@ -73,8 +79,8 @@ public class AnswerTuple {
73 } 79 }
74 80
75 public String toString() { 81 public String toString() {
76 if (m_str != null) return m_str; 82 if(m_str != null) return m_str;
77 StringBuilder sb = new StringBuilder(); 83 StringBuilder sb = new StringBuilder();
78 for (int i = 0; i < m_tuple.length; ++i) { 84 for (int i = 0; i < m_tuple.length; ++i) {
79 if (sb.length() != 0) sb.append(SEPARATOR); 85 if (sb.length() != 0) sb.append(SEPARATOR);
80 if (m_tuple[i] instanceof uk.ac.ox.cs.JRDFox.model.Individual) 86 if (m_tuple[i] instanceof uk.ac.ox.cs.JRDFox.model.Individual)
@@ -83,64 +89,58 @@ public class AnswerTuple {
83 sb.append(m_tuple[i].toString()); 89 sb.append(m_tuple[i].toString());
84 } 90 }
85 else { 91 else {
86 Literal l = (Literal) m_tuple[i]; 92 Literal l = (Literal) m_tuple[i];
87 sb.append('"').append(l.getLexicalForm()).append("\""); 93 sb.append('"').append(l.getLexicalForm()).append("\"");
88 if (!l.getDatatype().equals(Datatype.XSD_STRING) && !l.getDatatype().equals(Datatype.RDF_PLAIN_LITERAL)) 94 if (!l.getDatatype().equals(Datatype.XSD_STRING) && !l.getDatatype().equals(Datatype.RDF_PLAIN_LITERAL))
89 sb.append("^^<").append(l.getDatatype().getIRI()).append(">"); 95 sb.append("^^<").append(l.getDatatype().getIRI()).append(">");
90 } 96 }
91 } 97 }
92 return m_str = sb.toString(); 98 return m_str = sb.toString();
93 } 99 }
94 100
95 public GroundTerm getGroundTerm(int i) { 101 public GroundTerm getGroundTerm(int i) {
96 return m_tuple[i]; 102 return m_tuple[i];
97 } 103 }
98 104
99 public Map<Variable, Term> getAssignment(String[] vars) { 105 public Map<Variable, Term> getAssignment(String[] vars) {
100 Map<Variable, Term> map = new HashMap<Variable, Term>(); 106 Map<Variable, Term> map = new HashMap<Variable, Term>();
101 int index = 0; 107 int index = 0;
102 Term t; 108 Term t;
103 for (String var: vars) { 109 for (String var: vars) {
104 if (m_tuple[index] instanceof uk.ac.ox.cs.JRDFox.model.Individual) 110 if(m_tuple[index] instanceof uk.ac.ox.cs.JRDFox.model.Individual)
105 t = Individual.create((((uk.ac.ox.cs.JRDFox.model.Individual) m_tuple[index]).getIRI())); 111 t = Individual.create((((uk.ac.ox.cs.JRDFox.model.Individual) m_tuple[index]).getIRI()));
106 else { 112 else {
107 uk.ac.ox.cs.JRDFox.model.Literal l = (uk.ac.ox.cs.JRDFox.model.Literal) m_tuple[index]; 113 uk.ac.ox.cs.JRDFox.model.Literal l = (uk.ac.ox.cs.JRDFox.model.Literal) m_tuple[index];
108 t = Constant.create(l.getLexicalForm(), l.getDatatype().getIRI()); 114 t = Constant.create(l.getLexicalForm(), l.getDatatype().getIRI());
109 } 115 }
110 map.put(Variable.create(var), t); 116 map.put(Variable.create(var), t);
111 ++index; 117 ++index;
112 } 118 }
113 return map; 119 return map;
114 } 120 }
115 121
116 public boolean hasAuxPredicate() { 122 public boolean hasAuxPredicate() {
117 String iri; 123 String iri;
118 for (int i = 0; i < m_tuple.length; ++i) 124 for (int i = 0; i < m_tuple.length; ++i)
119 if ((m_tuple[i] instanceof uk.ac.ox.cs.JRDFox.model.Individual)) { 125 if ((m_tuple[i] instanceof uk.ac.ox.cs.JRDFox.model.Individual)) {
120 iri = ((uk.ac.ox.cs.JRDFox.model.Individual) m_tuple[i]).getIRI(); 126 iri = ((uk.ac.ox.cs.JRDFox.model.Individual) m_tuple[i]).getIRI();
121 if ( iri.startsWith(Namespace.PAGODA_AUX) || iri.contains("_AUX") || iri.contains("_neg") || iri.contains("internal:def")) 127 if(iri.startsWith(Namespace.PAGODA_AUX) || iri.contains("_AUX") || iri.contains("_neg") || iri.contains("internal:def"))
122 return true; 128 return true;
123 } 129 }
124 return false; 130 return false;
125 } 131 }
126 132
127 public boolean hasAnonyIndividual() { 133 public boolean hasAnonymousIndividual() {
128 String iri; 134 String iri;
129 for (int i = 0; i < m_tuple.length; ++i) 135 for(int i = 0; i < m_tuple.length; ++i)
130 if ((m_tuple[i] instanceof uk.ac.ox.cs.JRDFox.model.Individual)) { 136 if((m_tuple[i] instanceof uk.ac.ox.cs.JRDFox.model.Individual)) {
131 iri = ((uk.ac.ox.cs.JRDFox.model.Individual) m_tuple[i]).getIRI(); 137 iri = ((uk.ac.ox.cs.JRDFox.model.Individual) m_tuple[i]).getIRI();
132 if (iri.startsWith(Namespace.PAGODA_ANONY) || iri.startsWith(Namespace.KARMA_ANONY)) 138 if(iri.startsWith(Namespace.PAGODA_ANONY) || iri.startsWith(Namespace.KARMA_ANONY))
133 return true; 139 return true;
134 } 140 }
135 return false; 141 return false;
136 } 142 }
137 143
138 public static AnswerTuple create(AnswerTuple extendedTuple, int length) {
139 if (length == extendedTuple.getArity()) return extendedTuple;
140 else return new AnswerTuple(extendedTuple, length);
141 }
142
143
144 public static class AnswerTupleSerializer implements JsonSerializer<AnswerTuple> { 144 public static class AnswerTupleSerializer implements JsonSerializer<AnswerTuple> {
145 145
146 public JsonElement serialize(AnswerTuple src, Type typeOfSrc, JsonSerializationContext context) { 146 public JsonElement serialize(AnswerTuple src, Type typeOfSrc, JsonSerializationContext context) {
@@ -149,8 +149,6 @@ public class AnswerTuple {
149 149
150 } 150 }
151 151
152 static final Pattern owlLiteralRegex = Pattern.compile("^\"(?<lexicalForm>[^@]+(@(?<langTag>.+))?)\"(^^<(?<dataType>.+)>)?$");
153
154 public static class AnswerTupleDeserializer implements JsonDeserializer<AnswerTuple> { 152 public static class AnswerTupleDeserializer implements JsonDeserializer<AnswerTuple> {
155 public AnswerTuple deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) 153 public AnswerTuple deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
156 throws JsonParseException { 154 throws JsonParseException {
diff --git a/src/uk/ac/ox/cs/pagoda/query/QueryRecord.java b/src/uk/ac/ox/cs/pagoda/query/QueryRecord.java
index 15b2c01..4998a19 100644
--- a/src/uk/ac/ox/cs/pagoda/query/QueryRecord.java
+++ b/src/uk/ac/ox/cs/pagoda/query/QueryRecord.java
@@ -10,6 +10,8 @@ import uk.ac.ox.cs.pagoda.rules.GeneralProgram;
10import uk.ac.ox.cs.pagoda.util.ConjunctiveQueryHelper; 10import uk.ac.ox.cs.pagoda.util.ConjunctiveQueryHelper;
11import uk.ac.ox.cs.pagoda.util.Namespace; 11import uk.ac.ox.cs.pagoda.util.Namespace;
12import uk.ac.ox.cs.pagoda.util.Utility; 12import uk.ac.ox.cs.pagoda.util.Utility;
13import uk.ac.ox.cs.pagoda.util.tuples.Tuple;
14import uk.ac.ox.cs.pagoda.util.tuples.TupleBuilder;
13 15
14import java.io.*; 16import java.io.*;
15import java.lang.reflect.Type; 17import java.lang.reflect.Type;
@@ -18,199 +20,204 @@ import java.util.*;
18public class QueryRecord { 20public class QueryRecord {
19 21
20 public static final String botQueryText = "SELECT ?X WHERE { ?X <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#Nothing> }"; 22 public static final String botQueryText = "SELECT ?X WHERE { ?X <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#Nothing> }";
21 23 public static final String SEPARATOR = "----------------------------------------";
24 boolean processed = false;
25 String stringQueryID = null;
26 OWLOntology relevantOntology = null;
27 Set<DLClause> relevantClauses = new HashSet<DLClause>();
28 double[] timer;
29 int subID;
30 DLClause queryClause = null;
22 private Step difficulty; 31 private Step difficulty;
23 32 private String queryText;
24 private String queryText; 33 private int queryID = -1;
25 private int queryID = -1;
26
27 private String[][] answerVariables = null; 34 private String[][] answerVariables = null;
28 private Set<AnswerTuple> soundAnswerTuples = new HashSet<AnswerTuple>(); 35 private Set<AnswerTuple> soundAnswerTuples = new HashSet<AnswerTuple>();
29 private Set<AnswerTuple> gapAnswerTuples = null; 36 private Set<AnswerTuple> gapAnswerTuples = null;
30
31 private QueryManager m_manager; 37 private QueryManager m_manager;
38
39 private QueryRecord() {
40 }
32 41
33 public QueryRecord(QueryManager manager, String text, int id, int subID) { 42 public QueryRecord(QueryManager manager, String text, int id, int subID) {
34 m_manager =manager; 43 m_manager = manager;
35 resetInfo(text, id, subID); 44 resetInfo(text, id, subID);
36 resetTimer(); 45 resetTimer();
37 } 46 }
38 47
48// private boolean containsAuxPredicate(String str) {
49// return str.contains(Namespace.PAGODA_AUX) || str.contains("_AUX") || str.contains("owl#Nothing") ||
50// str.contains("internal:def");
51// }
52
53 public static Collection<String> collectQueryTexts(Collection<QueryRecord> queryRecords) {
54 Collection<String> texts = new LinkedList<String>();
55 for(QueryRecord record : queryRecords)
56 texts.add(record.queryText);
57 return texts;
58 }
59
39 public void resetInfo(String text, int id, int subid) { 60 public void resetInfo(String text, int id, int subid) {
40 queryID = id; 61 queryID = id;
41 subID = subid; 62 subID = subid;
42 stringQueryID = id + (subID == 0 ? "" : "_" + subID); 63 stringQueryID = id + (subID == 0 ? "" : "_" + subID);
43 m_manager.remove(queryText); 64 m_manager.remove(queryText);
44 m_manager.put(text, this); 65 m_manager.put(text, this);
45 queryClause = null; 66 queryClause = null;
46 answerVariables = ConjunctiveQueryHelper.getAnswerVariables(text); 67 answerVariables = ConjunctiveQueryHelper.getAnswerVariables(text);
47 queryText = text; // .replace("_:", "?"); 68 queryText = text; // .replace("_:", "?");
48 } 69 }
49 70
50 public void resetTimer() { 71 public void resetTimer() {
51 int length = Step.values().length; 72 int length = Step.values().length;
52 timer = new double[length]; 73 timer = new double[length];
53 for (int i = 0; i < length; ++i) timer[i] = 0; 74 for(int i = 0; i < length; ++i) timer[i] = 0;
54 } 75 }
55 76
56 public AnswerTuples getAnswers() { 77 public AnswerTuples getAnswers() {
57 if (processed()) 78 if(processed())
58 return getLowerBoundAnswers(); 79 return getLowerBoundAnswers();
59 80
60 return getUpperBoundAnswers(); 81 return getUpperBoundAnswers();
61 } 82 }
62 83
63 public AnswerTuples getLowerBoundAnswers() { 84 public AnswerTuples getLowerBoundAnswers() {
64 return new AnswerTuplesImp(answerVariables[0], soundAnswerTuples); 85 return new AnswerTuplesImp(answerVariables[0], soundAnswerTuples);
65 } 86 }
66 87
67 public AnswerTuples getUpperBoundAnswers() { 88 public AnswerTuples getUpperBoundAnswers() {
68 return new AnswerTuplesImp(answerVariables[0], soundAnswerTuples, gapAnswerTuples); 89 return new AnswerTuplesImp(answerVariables[0], soundAnswerTuples, gapAnswerTuples);
69 } 90 }
70 91
71 public boolean updateLowerBoundAnswers(AnswerTuples answerTuples) { 92 public boolean updateLowerBoundAnswers(AnswerTuples answerTuples) {
72 if (answerTuples == null) return false; 93 if(answerTuples == null) return false;
73 boolean update = false; 94 boolean update = false;
74 for (AnswerTuple tuple; answerTuples.isValid(); answerTuples.moveNext()) { 95 for(AnswerTuple tuple; answerTuples.isValid(); answerTuples.moveNext()) {
75 tuple = answerTuples.getTuple(); 96 tuple = answerTuples.getTuple();
76 if (!soundAnswerTuples.contains(tuple) && (gapAnswerTuples == null || gapAnswerTuples.contains(tuple))) { 97 if(!soundAnswerTuples.contains(tuple) && (gapAnswerTuples == null || gapAnswerTuples.contains(tuple))) {
77 soundAnswerTuples.add(tuple); 98 soundAnswerTuples.add(tuple);
78 if (gapAnswerTuples != null) 99 if(gapAnswerTuples != null)
79 gapAnswerTuples.remove(tuple); 100 gapAnswerTuples.remove(tuple);
80 update = true; 101 update = true;
81 } 102 }
82 // TODO could be wrong, but if possible add the check
83// else if (! gapAnswerTuples.contains(tuple)) {
84// throw new IllegalArgumentException("The lower bound answers must be contained in the upper ones!");
85// }
86 } 103 }
87 Utility.logInfo("The number of answers in the lower bound: " + soundAnswerTuples.size()); 104 Utility.logInfo("The number of answers in the lower bound: " + soundAnswerTuples.size());
88 105
89 return update; 106 return update;
90 } 107 }
91 108
92 public boolean updateUpperBoundAnswers(AnswerTuples answerTuples) { 109 public boolean updateUpperBoundAnswers(AnswerTuples answerTuples) {
93 return updateUpperBoundAnswers(answerTuples, false); 110 return updateUpperBoundAnswers(answerTuples, false);
94 } 111 }
95 112
96 public boolean updateUpperBoundAnswers(AnswerTuples answerTuples, boolean toCheckAux) { 113 public boolean updateUpperBoundAnswers(AnswerTuples answerTuples, boolean toCheckAux) {
97 RDFoxAnswerTuples rdfAnswerTuples; 114 RDFoxAnswerTuples rdfAnswerTuples;
98 if (answerTuples instanceof RDFoxAnswerTuples) 115 if(answerTuples instanceof RDFoxAnswerTuples)
99 rdfAnswerTuples = (RDFoxAnswerTuples) answerTuples; 116 rdfAnswerTuples = (RDFoxAnswerTuples) answerTuples;
100 else { 117 else {
101 Utility.logError("The upper bound must be computed by RDFox!"); 118 Utility.logError("The upper bound must be computed by RDFox!");
102 return false; 119 return false;
103 } 120 }
104 121
105 if (soundAnswerTuples.size() > 0) { 122 if(soundAnswerTuples.size() > 0) {
106 int number = 0; 123 int number = 0;
107 for (; answerTuples.isValid(); answerTuples.moveNext()) { 124 for(; rdfAnswerTuples.isValid(); rdfAnswerTuples.moveNext()) {
108 ++number; 125 ++number;
109 } 126 }
110 Utility.logInfo("The number of answers returned by an upper bound: " + number); 127 Utility.logInfo("The number of answers returned by an upper bound: " + number);
111 if (number <= soundAnswerTuples.size()) { 128 if(number == soundAnswerTuples.size()) {
112 if (gapAnswerTuples != null) gapAnswerTuples.clear(); 129 if(gapAnswerTuples != null) gapAnswerTuples.clear();
113 else gapAnswerTuples = new HashSet<AnswerTuple>(); 130 else gapAnswerTuples = new HashSet<AnswerTuple>();
114 131
115 Utility.logInfo("The number of upper bound answers: " + (soundAnswerTuples.size() + gapAnswerTuples.size())); 132 Utility.logInfo("The number of upper bound answers: " + (soundAnswerTuples.size() + gapAnswerTuples.size()));
116 return false; 133 return false;
117 } 134 } else if(number < soundAnswerTuples.size())
118 else if (number < soundAnswerTuples.size())
119 throw new IllegalArgumentException("The upper bound answers must contain all the lower bound ones!"); 135 throw new IllegalArgumentException("The upper bound answers must contain all the lower bound ones!");
120 answerTuples.reset(); 136 rdfAnswerTuples.reset();
121 } 137 }
122 138
123 boolean justCheck = (answerTuples.getArity() != answerVariables[1].length); 139 boolean justCheck = (rdfAnswerTuples.getArity() != answerVariables[1].length);
124 140
125 Set<AnswerTuple> tupleSet = new HashSet<AnswerTuple>(); 141 Set<AnswerTuple> tupleSet = new HashSet<AnswerTuple>();
126 AnswerTuple tuple, extendedTuple; 142 AnswerTuple tuple, extendedTuple;
127 for (; answerTuples.isValid(); answerTuples.moveNext()) { 143 for(; rdfAnswerTuples.isValid(); rdfAnswerTuples.moveNext()) {
128 extendedTuple = rdfAnswerTuples.getTuple(); 144 extendedTuple = rdfAnswerTuples.getTuple();
129 if (isBottom() || !extendedTuple.hasAnonyIndividual()) { 145 if(isBottom() || !extendedTuple.hasAnonymousIndividual()) {
130 tuple = AnswerTuple.create(extendedTuple, answerVariables[0].length); 146 tuple = AnswerTuple.create(extendedTuple, answerVariables[0].length);
131 if ((!toCheckAux || !tuple.hasAuxPredicate()) && !soundAnswerTuples.contains(tuple)) { 147 if((!toCheckAux || !tuple.hasAuxPredicate()) && !soundAnswerTuples.contains(tuple)) {
132 if (!toCheckAux && justCheck) return false; 148 if(!toCheckAux && justCheck) return false;
133 tupleSet.add(extendedTuple); 149 // TODO check
150// tupleSet.add(extendedTuple);
151 tupleSet.add(tuple);
134 } 152 }
135 } 153 }
136 } 154 }
137 155
138 if (gapAnswerTuples == null) { 156 if(gapAnswerTuples == null) {
139 gapAnswerTuples = tupleSet; 157 gapAnswerTuples = tupleSet;
140 158
141 Utility.logInfo("The number of answers in the upper bound: " + (soundAnswerTuples.size() + gapAnswerTuples.size())); 159 Utility.logInfo("The number of answers in the upper bound: " + (soundAnswerTuples.size() + gapAnswerTuples.size()));
142 return true; 160 return true;
143 } 161 }
144 162
145 boolean update = false; 163 boolean update = false;
146 for (Iterator<AnswerTuple> iter = gapAnswerTuples.iterator(); iter.hasNext(); ) { 164 for(Iterator<AnswerTuple> iter = gapAnswerTuples.iterator(); iter.hasNext(); ) {
147 tuple = iter.next(); 165 tuple = iter.next();
148 if (!tupleSet.contains(tuple)) { 166 if(!tupleSet.contains(tuple)) {
149 iter.remove(); 167 iter.remove();
150 update = true; 168 update = true;
151 } 169 }
152 } 170 }
153 171
154 Utility.logInfo("The number of answers in the upper bound: " + (soundAnswerTuples.size() + gapAnswerTuples.size())); 172 Utility.logInfo("The number of answers in the upper bound: " + (soundAnswerTuples.size() + gapAnswerTuples.size()));
155 173
156 return update; 174 return update;
157 } 175 }
158 176
159// private boolean containsAuxPredicate(String str) {
160// return str.contains(Namespace.PAGODA_AUX) || str.contains("_AUX") || str.contains("owl#Nothing") ||
161// str.contains("internal:def");
162// }
163
164 boolean processed = false;
165
166 public void markAsProcessed() { 177 public void markAsProcessed() {
167 processed = true; 178 processed = true;
168 } 179 }
169 180
170 public boolean processed() { 181 public boolean processed() {
171 if (gapAnswerTuples != null && gapAnswerTuples.isEmpty()) processed = true; 182 if(gapAnswerTuples != null && gapAnswerTuples.isEmpty()) processed = true;
172 return processed; 183 return processed;
173 } 184 }
174 185
175 public String[] getDistinguishedVariables() { 186 public String[] getDistinguishedVariables() {
176 return answerVariables[1]; 187 return answerVariables[1];
177 } 188 }
178 189
179 public String[] getAnswerVariables() { 190 public String[] getAnswerVariables() {
180 return answerVariables[0]; 191 return answerVariables[0];
181 } 192 }
182 193
183 public String[][] getVariables() { 194 public String[][] getVariables() {
184 return answerVariables; 195 return answerVariables;
185 } 196 }
186 197
187 public String getQueryText() { 198 public String getQueryText() {
188 return queryText; 199 return queryText;
189 } 200 }
190 201
191 String stringQueryID = null;
192
193 public String getQueryID() { 202 public String getQueryID() {
194 return stringQueryID; 203 return stringQueryID;
195 } 204 }
196 205
197 public AnswerTuples getGapAnswers() { 206 public AnswerTuples getGapAnswers() {
198 return new AnswerTuplesImp(answerVariables[0], gapAnswerTuples); 207 return new AnswerTuplesImp(answerVariables[0], gapAnswerTuples);
199 } 208 }
200 209
201 public String toString() { 210 public String toString() {
202 return queryText; 211 return queryText;
203 } 212 }
204
205 public static final String SEPARATOR = "----------------------------------------";
206 213
207 public void outputAnswers(BufferedWriter writer) throws IOException { 214 public void outputAnswers(BufferedWriter writer) throws IOException {
208 215
209 int answerCounter = soundAnswerTuples.size(); 216 int answerCounter = soundAnswerTuples.size();
210 if (!processed()) answerCounter += gapAnswerTuples.size(); 217 if(!processed()) answerCounter += gapAnswerTuples.size();
211 218
212 Utility.logInfo("The number of answer tuples: " + answerCounter); 219 Utility.logInfo("The number of answer tuples: " + answerCounter);
213 220
214 if (writer != null) { 221 if (writer != null) {
215 writer.write("-------------- Query " + queryID + " ---------------------"); 222 writer.write("-------------- Query " + queryID + " ---------------------");
216 writer.newLine(); 223 writer.newLine();
@@ -242,7 +249,7 @@ public class QueryRecord {
242// writer.write(SEPARATOR); 249// writer.write(SEPARATOR);
243 writer.newLine(); 250 writer.newLine();
244 } 251 }
245 252
246 } 253 }
247 254
248 public void outputAnswerStatistics() { 255 public void outputAnswerStatistics() {
@@ -276,51 +283,48 @@ public class QueryRecord {
276// jsonAnswers.put(Integer.toString(queryID), jsonAnswer); 283// jsonAnswers.put(Integer.toString(queryID), jsonAnswer);
277// } 284// }
278 } 285 }
279 286
280 public void outputTimes() { 287 public void outputTimes() {
281 for (Step step: Step.values()) { 288 for (Step step: Step.values()) {
282 Utility.logDebug("time for " + step + ": " + timer[step.ordinal()]); 289 Utility.logDebug("time for " + step + ": " + timer[step.ordinal()]);
283 } 290 }
284 } 291 }
285 292
286 public String outputSoundAnswerTuple() { 293 public String outputSoundAnswerTuple() {
287 StringBuilder builder = new StringBuilder(); 294 StringBuilder builder = new StringBuilder();
288 for (AnswerTuple tuple: soundAnswerTuples) 295 for (AnswerTuple tuple: soundAnswerTuples)
289 builder.append(tuple.toString()).append(Utility.LINE_SEPARATOR); 296 builder.append(tuple.toString()).append(Utility.LINE_SEPARATOR);
290 return builder.toString(); 297 return builder.toString();
291 } 298 }
292 299
293 public String outputGapAnswerTuple() { 300 public String outputGapAnswerTuple() {
294 StringBuilder builder = new StringBuilder(); 301 StringBuilder builder = new StringBuilder();
295 for (AnswerTuple tuple: gapAnswerTuples) 302 for(AnswerTuple tuple : gapAnswerTuples)
296 builder.append(tuple.toString()).append(Utility.LINE_SEPARATOR); 303 builder.append(tuple.toString()).append(Utility.LINE_SEPARATOR);
297 return builder.toString(); 304 return builder.toString();
298 }
299
300 public void setDifficulty(Step step) {
301 this.difficulty = step;
302 } 305 }
303 306
304 public Step getDifficulty() { 307 public Step getDifficulty() {
305 return difficulty; 308 return difficulty;
306 } 309 }
307 310
308 OWLOntology relevantOntology = null; 311 public void setDifficulty(Step step) {
309 Set<DLClause> relevantClauses = new HashSet<DLClause>(); 312 this.difficulty = step;
310
311 public void setRelevantOntology(OWLOntology knowledgebase) {
312 relevantOntology = knowledgebase;
313 } 313 }
314 314
315 public OWLOntology getRelevantOntology() { 315 public OWLOntology getRelevantOntology() {
316 return relevantOntology; 316 return relevantOntology;
317 } 317 }
318 318
319 public void setRelevantOntology(OWLOntology knowledgebase) {
320 relevantOntology = knowledgebase;
321 }
322
319 public void saveRelevantOntology(String filename) { 323 public void saveRelevantOntology(String filename) {
320 if (relevantOntology == null) return ; 324 if(relevantOntology == null) return;
321 OWLOntologyManager manager = relevantOntology.getOWLOntologyManager(); 325 OWLOntologyManager manager = relevantOntology.getOWLOntologyManager();
322 try { 326 try {
323 FileOutputStream outputStream = new FileOutputStream(filename); 327 FileOutputStream outputStream = new FileOutputStream(filename);
324 manager.saveOntology(relevantOntology, outputStream); 328 manager.saveOntology(relevantOntology, outputStream);
325 outputStream.close(); 329 outputStream.close();
326 } catch (OWLOntologyStorageException e) { 330 } catch (OWLOntologyStorageException e) {
@@ -333,12 +337,11 @@ public class QueryRecord {
333 } 337 }
334 338
335 public void saveRelevantClause() { 339 public void saveRelevantClause() {
336 if (relevantClauses == null) return ; 340 if(relevantClauses == null) return;
337 GeneralProgram p = new GeneralProgram(relevantClauses, relevantOntology); 341 GeneralProgram p = new GeneralProgram(relevantClauses, relevantOntology);
338 p.save(); 342 p.save();
339 } 343 }
340 344
341
342 public void removeUpperBoundAnswers(Collection<AnswerTuple> answers) { 345 public void removeUpperBoundAnswers(Collection<AnswerTuple> answers) {
343 for (AnswerTuple answer: answers) { 346 for (AnswerTuple answer: answers) {
344// if (soundAnswerTuples.contains(answer)) 347// if (soundAnswerTuples.contains(answer))
@@ -349,50 +352,37 @@ public class QueryRecord {
349 } 352 }
350 } 353 }
351 354
352
353 public void addLowerBoundAnswers(Collection<AnswerTuple> answers) { 355 public void addLowerBoundAnswers(Collection<AnswerTuple> answers) {
354 for (AnswerTuple answer: answers) { 356 for (AnswerTuple answer: answers) {
355 if (!gapAnswerTuples.contains(answer)) 357 if (!gapAnswerTuples.contains(answer))
356 Utility.logError("The answer (" + answer + ") cannot be added, because it is not in the upper bound."); 358 Utility.logError("The answer (" + answer + ") cannot be added, because it is not in the upper bound.");
357 gapAnswerTuples.remove(answer); 359 gapAnswerTuples.remove(answer);
358 360
359 answer = AnswerTuple.create(answer, answerVariables[0].length); 361 answer = AnswerTuple.create(answer, answerVariables[0].length);
360// if (soundAnswerTuples.contains(answer)) 362// if (soundAnswerTuples.contains(answer))
361// Utility.logError("The answer (" + answer + ") cannot be added, because it is in the lower bound."); 363// Utility.logError("The answer (" + answer + ") cannot be added, because it is in the lower bound.");
362 soundAnswerTuples.add(answer); 364 soundAnswerTuples.add(answer);
363 } 365 }
364 } 366 }
365 367
366 public int getNoOfSoundAnswers() { 368 public int getNoOfSoundAnswers() {
367 return soundAnswerTuples.size(); 369 return soundAnswerTuples.size();
368 } 370 }
369
370 public enum Step {LowerBound, UpperBound, ELLowerBound,
371 Fragment, FragmentRefinement, Summarisation, Dependency, FullReasoning}
372
373 double[] timer;
374 371
375 public void addProcessingTime(Step step, double time) { 372 public void addProcessingTime(Step step, double time) {
376 timer[step.ordinal()] += time; 373 timer[step.ordinal()] += time;
377 } 374 }
378 375
379 public int getArity() { 376 public int getArity() {
380 return answerVariables[0].length; 377 return answerVariables[0].length;
381 } 378 }
382 379
383 public static Collection<String> collectQueryTexts(Collection<QueryRecord> queryRecords) {
384 Collection<String> texts = new LinkedList<String>();
385 for (QueryRecord record: queryRecords)
386 texts.add(record.queryText);
387 return texts;
388 }
389
390 public void addRelevantClauses(DLClause clause) { 380 public void addRelevantClauses(DLClause clause) {
391 relevantClauses.add(clause); 381 relevantClauses.add(clause);
392 } 382 }
393 383
394 public Set<DLClause> getRelevantClauses() { 384 public Set<DLClause> getRelevantClauses() {
395 return relevantClauses; 385 return relevantClauses;
396 } 386 }
397 387
398 public void clearClauses() { 388 public void clearClauses() {
@@ -403,36 +393,40 @@ public class QueryRecord {
403 for (DLClause clause: relevantClauses) 393 for (DLClause clause: relevantClauses)
404 if (clause.getHeadLength() > 1) 394 if (clause.getHeadLength() > 1)
405 return false; 395 return false;
406 return true; 396 return true;
407 } 397 }
408 398
409 public void saveABoxInTurtle(String filename) { 399 public void saveABoxInTurtle(String filename) {
410 try { 400 try {
411 BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(filename))); 401 BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(filename)));
412 OWLIndividual a, b; 402 OWLIndividual a, b;
413 StringBuilder builder = new StringBuilder(); 403 StringBuilder builder = new StringBuilder();
414 for (OWLAxiom axiom: relevantOntology.getABoxAxioms(true)) { 404 for (OWLAxiom axiom: relevantOntology.getABoxAxioms(true)) {
415 if (axiom instanceof OWLClassAssertionAxiom) { 405 if (axiom instanceof OWLClassAssertionAxiom) {
416 OWLClassAssertionAxiom classAssertion = (OWLClassAssertionAxiom) axiom; 406 OWLClassAssertionAxiom classAssertion = (OWLClassAssertionAxiom) axiom;
417 OWLClass c = (OWLClass) classAssertion.getClassExpression(); 407 OWLClass c = (OWLClass) classAssertion.getClassExpression();
418 a = classAssertion.getIndividual(); 408 a = classAssertion.getIndividual();
419 builder.append(a.toString()).append(" <").append(Namespace.RDF_TYPE).append("> ").append(c.toString()); 409 builder.append(a.toString())
410 .append(" <")
411 .append(Namespace.RDF_TYPE)
412 .append("> ")
413 .append(c.toString());
420 } 414 }
421 else if (axiom instanceof OWLObjectPropertyAssertionAxiom) { 415 else if (axiom instanceof OWLObjectPropertyAssertionAxiom) {
422 OWLObjectPropertyAssertionAxiom propertyAssertion = (OWLObjectPropertyAssertionAxiom) axiom; 416 OWLObjectPropertyAssertionAxiom propertyAssertion = (OWLObjectPropertyAssertionAxiom) axiom;
423 OWLObjectProperty p = (OWLObjectProperty) propertyAssertion.getProperty(); 417 OWLObjectProperty p = (OWLObjectProperty) propertyAssertion.getProperty();
424 a = propertyAssertion.getSubject(); 418 a = propertyAssertion.getSubject();
425 b = propertyAssertion.getObject(); 419 b = propertyAssertion.getObject();
426 builder.append(a.toString()).append(" ").append(p.toString()).append(" ").append(b.toString()); 420 builder.append(a.toString()).append(" ").append(p.toString()).append(" ").append(b.toString());
427 } 421 }
428 else if (axiom instanceof OWLDataPropertyAssertionAxiom) { 422 else if (axiom instanceof OWLDataPropertyAssertionAxiom) {
429 OWLDataPropertyAssertionAxiom propertyAssertion = (OWLDataPropertyAssertionAxiom) axiom; 423 OWLDataPropertyAssertionAxiom propertyAssertion = (OWLDataPropertyAssertionAxiom) axiom;
430 OWLDataProperty p = (OWLDataProperty) propertyAssertion.getProperty(); 424 OWLDataProperty p = (OWLDataProperty) propertyAssertion.getProperty();
431 a = propertyAssertion.getSubject(); 425 a = propertyAssertion.getSubject();
432 OWLLiteral l = propertyAssertion.getObject(); 426 OWLLiteral l = propertyAssertion.getObject();
433 builder.append(a.toString()).append(" ").append(p.toString()).append(" ").append(l.toString()); 427 builder.append(a.toString()).append(" ").append(p.toString()).append(" ").append(l.toString());
434 } 428 }
435 429
436 writer.write(builder.toString()); 430 writer.write(builder.toString());
437 writer.write(" ."); 431 writer.write(" .");
438 writer.newLine(); 432 writer.newLine();
@@ -442,23 +436,19 @@ public class QueryRecord {
442 } catch (IOException e) { 436 } catch (IOException e) {
443 e.printStackTrace(); 437 e.printStackTrace();
444 } finally { 438 } finally {
445 439
446 } 440 }
447 } 441 }
448
449 int subID;
450 442
451 public void updateSubID() { 443 public void updateSubID() {
452 ++subID; 444 ++subID;
453 stringQueryID = String.valueOf(queryID) + "_" + subID; 445 stringQueryID = String.valueOf(queryID) + "_" + subID;
454 } 446 }
455 447
456 DLClause queryClause = null;
457
458 public DLClause getClause() { 448 public DLClause getClause() {
459 if (queryClause != null) 449 if (queryClause != null)
460 return queryClause; 450 return queryClause;
461 return queryClause = DLClauseHelper.getQuery(queryText, null); 451 return queryClause = DLClauseHelper.getQuery(queryText, null);
462 } 452 }
463 453
464 public boolean isBottom() { 454 public boolean isBottom() {
@@ -468,19 +458,19 @@ public class QueryRecord {
468 public int getNoOfCompleteAnswers() { 458 public int getNoOfCompleteAnswers() {
469 return soundAnswerTuples.size() + gapAnswerTuples.size(); 459 return soundAnswerTuples.size() + gapAnswerTuples.size();
470 } 460 }
471 461
472 public int getSubID() { 462 public int getSubID() {
473 return subID; 463 return subID;
474 } 464 }
475 465
476 public boolean hasSameGapAnswers(QueryRecord that) { 466 public boolean hasSameGapAnswers(QueryRecord that) {
477 return gapAnswerTuples.containsAll(that.gapAnswerTuples) && that.gapAnswerTuples.containsAll(gapAnswerTuples); 467 return gapAnswerTuples.containsAll(that.gapAnswerTuples) && that.gapAnswerTuples.containsAll(gapAnswerTuples);
478 } 468 }
479 469
480 public void dispose() { 470 public void dispose() {
481 m_manager.remove(queryText); 471 m_manager.remove(queryText);
482 if (gapAnswerTuples != null) gapAnswerTuples = null; 472 if(gapAnswerTuples != null) gapAnswerTuples = null;
483 if (soundAnswerTuples != null) soundAnswerTuples = null; 473 if(soundAnswerTuples != null) soundAnswerTuples = null;
484 if (relevantClauses != null) relevantClauses.clear(); 474 if (relevantClauses != null) relevantClauses.clear();
485 if (relevantOntology != null) 475 if (relevantOntology != null)
486 relevantOntology.getOWLOntologyManager().removeOntology(relevantOntology); 476 relevantOntology.getOWLOntologyManager().removeOntology(relevantOntology);
@@ -488,53 +478,53 @@ public class QueryRecord {
488 } 478 }
489 479
490 public boolean canBeEncodedIntoAtom() { 480 public boolean canBeEncodedIntoAtom() {
491 // FIXME 481 // FIXME
492 return true; 482 return true;
493// return false; 483// return false;
494 } 484 }
495 485
496 public boolean isPredicate(AnswerTuple a, int i) { 486 public boolean isPredicate(AnswerTuple a, int i) {
497 Atom[] atoms = getClause().getBodyAtoms(); 487 Atom[] atoms = getClause().getBodyAtoms();
498 Variable v = Variable.create(answerVariables[1][i]); 488 Variable v = Variable.create(answerVariables[1][i]);
499 String iri; 489 String iri;
500 for (Atom atom: atoms) { 490 for(Atom atom : atoms) {
501 DLPredicate p = atom.getDLPredicate(); 491 DLPredicate p = atom.getDLPredicate();
502 if (p instanceof AtomicConcept) { 492 if (p instanceof AtomicConcept) {
503 if (((AtomicConcept) p).getIRI().equals(v.toString())) return true; 493 if(((AtomicConcept) p).getIRI().equals(v.toString())) return true;
504 } 494 }
505 else if (p instanceof AtomicRole) { 495 else if (p instanceof AtomicRole) {
506 iri = ((AtomicRole) p).getIRI(); 496 iri = ((AtomicRole) p).getIRI();
507 if (iri.equals(v.toString())) return true; 497 if (iri.equals(v.toString())) return true;
508 if (iri.startsWith("?")) 498 if(iri.startsWith("?"))
509 iri = a.getGroundTerm(i).toString(); 499 iri = a.getGroundTerm(i).toString();
510 if (iri.equals(Namespace.RDF_TYPE) && atom.getArgument(1).equals(v)) return true; 500 if(iri.equals(Namespace.RDF_TYPE) && atom.getArgument(1).equals(v)) return true;
511 } 501 }
512 } 502 }
513 return false; 503 return false;
514 } 504 }
515 505
516 public String[] getExtendedQueryText() { 506 public Tuple<String> getExtendedQueryText() {
517 String[] ret = new String[2]; 507// String[] ret = new String[2];
518 int index = queryText.toUpperCase().indexOf(" WHERE"); 508 int index = queryText.toUpperCase().indexOf(" WHERE");
519 String extendedSelect = queryText.substring(0, index); 509 String extendedSelect = queryText.substring(0, index);
520 String extendedWhere= queryText.substring(index + 1), fullyExtendedWhere = queryText.substring(index + 1); 510 String extendedWhere= queryText.substring(index + 1), fullyExtendedWhere = queryText.substring(index + 1);
521 511
522 String sub, obj; 512 String sub, obj;
523 Map<String, Set<String>> links = new HashMap<String, Set<String>>(); 513 Map<String, Set<String>> links = new HashMap<String, Set<String>>();
524 Set<String> list; 514 Set<String> list;
525 for (Atom atom: getClause().getBodyAtoms()) 515 for (Atom atom: getClause().getBodyAtoms())
526 if (atom.getDLPredicate() instanceof AtomicRole && atom.getArgument(0) instanceof Variable && atom.getArgument(1) instanceof Variable) { 516 if (atom.getDLPredicate() instanceof AtomicRole && atom.getArgument(0) instanceof Variable && atom.getArgument(1) instanceof Variable) {
527 sub = atom.getArgumentVariable(0).getName(); 517 sub = atom.getArgumentVariable(0).getName();
528 obj = atom.getArgumentVariable(1).getName(); 518 obj = atom.getArgumentVariable(1).getName();
529 if ((list = links.get(sub)) == null) 519 if((list = links.get(sub)) == null)
530 links.put(sub, list = new HashSet<String>()); 520 links.put(sub, list = new HashSet<String>());
531 list.add(obj); 521 list.add(obj);
532 if ((list = links.get(obj)) == null) 522 if((list = links.get(obj)) == null)
533 links.put(obj, list = new HashSet<String>()); 523 links.put(obj, list = new HashSet<String>());
534 list.add(sub); 524 list.add(sub);
535 } 525 }
536 526
537 StringBuilder extra = new StringBuilder(), fullyExtra = new StringBuilder(); 527 StringBuilder extra = new StringBuilder(), fullyExtra = new StringBuilder();
538// if (answerVariables[0] != answerVariables[1]) { 528// if (answerVariables[0] != answerVariables[1]) {
539 for (int i = answerVariables[0].length; i < answerVariables[1].length; ++i) { 529 for (int i = answerVariables[0].length; i < answerVariables[1].length; ++i) {
540// for (int i = 0; i < answerVariables[1].length; ++i) { 530// for (int i = 0; i < answerVariables[1].length; ++i) {
@@ -542,21 +532,22 @@ public class QueryRecord {
542 if ((list = links.get(answerVariables[1][i])) == null || list.size() < 2) ; 532 if ((list = links.get(answerVariables[1][i])) == null || list.size() < 2) ;
543 else { 533 else {
544 extra.append(" . ?").append(answerVariables[1][i]).append(" a <").append(Namespace.PAGODA_ORIGINAL).append(">"); 534 extra.append(" . ?").append(answerVariables[1][i]).append(" a <").append(Namespace.PAGODA_ORIGINAL).append(">");
545 } 535 }
546 } 536 }
547 537
548 if (extra.length() > 0) { 538 if(extra.length() > 0) {
549 extra.append(" }"); 539 extra.append(" }");
550 extendedWhere = extendedWhere.replace(" }", extendedWhere.contains(". }") ? extra.substring(2) : extra.toString()); 540 extendedWhere = extendedWhere.replace(" }", extendedWhere.contains(". }") ? extra.substring(2) : extra.toString());
551 } 541 }
552 542
553 if (fullyExtra.length() > 0) { 543 if(fullyExtra.length() > 0) {
554 fullyExtra.append(" }"); 544 fullyExtra.append(" }");
555 fullyExtendedWhere = fullyExtendedWhere.replace(" }", fullyExtendedWhere.contains(". }") ? fullyExtra.substring(2) : fullyExtra.toString()); 545 fullyExtendedWhere = fullyExtendedWhere.replace(" }", fullyExtendedWhere.contains(". }") ? fullyExtra.substring(2) : fullyExtra.toString());
556 } 546 }
557// } 547// }
558 548
559 ret[0] = extendedSelect + " " + fullyExtendedWhere; 549 TupleBuilder result = new TupleBuilder();
550 result.append(extendedSelect + " " + fullyExtendedWhere);
560 551
561 extra.setLength(0); 552 extra.setLength(0);
562 if (answerVariables[0] != answerVariables[1]) { 553 if (answerVariables[0] != answerVariables[1]) {
@@ -564,9 +555,9 @@ public class QueryRecord {
564 extra.append(" ?").append(answerVariables[1][i]); 555 extra.append(" ?").append(answerVariables[1][i]);
565 extendedSelect = extendedSelect + extra.toString(); 556 extendedSelect = extendedSelect + extra.toString();
566 } 557 }
567 ret[1] = extendedSelect + " " + extendedWhere; 558 result.append(extendedSelect + " " + extendedWhere);
568 559
569 return ret; 560 return result.build();
570 } 561 }
571 562
572 public boolean hasNonAnsDistinguishedVariables() { 563 public boolean hasNonAnsDistinguishedVariables() {
@@ -574,6 +565,31 @@ public class QueryRecord {
574 } 565 }
575 566
576 /** 567 /**
568 * Two <tt>QueryRecords</tt> are equal iff
569 * they have the same <tt>queryText</tt>,
570 * <tt>soundAnswerTuples</tt>
571 * and <tt>gapAnswerTuples</tt>.
572 */
573 @Override
574 public boolean equals(Object o) {
575 if(!o.getClass().equals(getClass())) return false;
576 QueryRecord that = (QueryRecord) o;
577 return this.queryText.equals(that.queryText)
578 && soundAnswerTuples.equals(that.soundAnswerTuples)
579 && gapAnswerTuples.equals(that.gapAnswerTuples);
580 }
581
582 @Override
583 public int hashCode() {
584 return Objects.hash(queryText, soundAnswerTuples, gapAnswerTuples);
585 }
586
587 public enum Step {
588 LowerBound, UpperBound, ELLowerBound,
589 Fragment, FragmentRefinement, Summarisation, Dependency, FullReasoning
590 }
591
592 /**
577 * A Json serializer, which considers the main attributes. 593 * A Json serializer, which considers the main attributes.
578 */ 594 */
579 public static class QueryRecordSerializer implements JsonSerializer<QueryRecord> { 595 public static class QueryRecordSerializer implements JsonSerializer<QueryRecord> {
@@ -592,8 +608,6 @@ public class QueryRecord {
592 } 608 }
593 } 609 }
594 610
595 private QueryRecord() { }
596
597 /** 611 /**
598 * A Json deserializer, compliant to the output of the serializer defined above. 612 * A Json deserializer, compliant to the output of the serializer defined above.
599 */ 613 */
@@ -628,25 +642,8 @@ public class QueryRecord {
628 } 642 }
629 643
630 /** 644 /**
631 * Two <tt>QueryRecords</tt> are equal iff 645 * Provides an instance (singleton) of Gson, having a specific configuration.
632 * they have the same <tt>queryText</tt>,
633 * <tt>soundAnswerTuples</tt>
634 * and <tt>gapAnswerTuples</tt>.
635 * */ 646 * */
636 @Override
637 public boolean equals(Object o) {
638 if(!o.getClass().equals(getClass())) return false;
639 QueryRecord that = (QueryRecord) o;
640 return this.queryText.equals(that.queryText)
641 && soundAnswerTuples.equals(that.soundAnswerTuples)
642 && gapAnswerTuples.equals(that.gapAnswerTuples);
643 }
644
645 @Override
646 public int hashCode() {
647 return Objects.hash(queryText, soundAnswerTuples, gapAnswerTuples);
648 }
649
650 public static class GsonCreator { 647 public static class GsonCreator {
651 648
652 private static Gson gson; 649 private static Gson gson;