View Javadoc

1   /*
2    * #%L
3    * prolobjectlink-jpi-jtrolog
4    * %%
5    * Copyright (C) 2019 Prolobjectlink Project
6    * %%
7    * This program is free software: you can redistribute it and/or modify
8    * it under the terms of the GNU Lesser General Public License as
9    * published by the Free Software Foundation, either version 2.1 of the
10   * License, or (at your option) any later version.
11   * 
12   * This program is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   * GNU General Lesser Public License for more details.
16   * 
17   * You should have received a copy of the GNU General Lesser Public
18   * License along with this program.  If not, see
19   * <http://www.gnu.org/licenses/lgpl-2.1.html>.
20   * #L%
21   */
22  package io.github.prolobjectlink.prolog.jtrolog;
23  
24  import java.util.ArrayList;
25  import java.util.Arrays;
26  import java.util.HashMap;
27  import java.util.Iterator;
28  import java.util.List;
29  import java.util.Map;
30  
31  import io.github.prolobjectlink.prolog.AbstractEngine;
32  import io.github.prolobjectlink.prolog.AbstractQuery;
33  import io.github.prolobjectlink.prolog.PrologLogger;
34  import io.github.prolobjectlink.prolog.PrologQuery;
35  import io.github.prolobjectlink.prolog.PrologTerm;
36  import jTrolog.engine.Prolog;
37  import jTrolog.engine.Solution;
38  import jTrolog.parser.Parser;
39  import jTrolog.terms.Struct;
40  import jTrolog.terms.Term;
41  import jTrolog.terms.Var;
42  
43  /**
44   * 
45   * @author Jose Zalacain
46   * @since 1.0
47   */
48  final class JTrologQuery extends AbstractQuery implements PrologQuery {
49  
50  	private Solution solution;
51  	private Prolog jtrolog;
52  	private List<String> variables = new ArrayList<String>();
53  
54  	private void enumerateVariables(List<String> vector, Term term) {
55  		if (!(term instanceof Var)) {
56  			if (term instanceof Struct) {
57  				Struct struct = (Struct) term;
58  				Var[] vars = struct.getVarList();
59  				for (Var var : vars) {
60  					enumerateVariables(variables, var);
61  				}
62  			}
63  		} else if (!vector.contains(term.toString())) {
64  			vector.add(term.toString());
65  		}
66  	}
67  
68  	JTrologQuery(AbstractEngine engine, String query) {
69  		super(engine);
70  		jtrolog = ((JTrologEngine) engine).engine;
71  		enumerateVariables(variables, new Parser(query).nextTerm(false));
72  		try {
73  			this.solution = jtrolog.solve("" + query + ".");
74  		} catch (Throwable e) {
75  			// do nothing
76  		}
77  	}
78  
79  	JTrologQuery(AbstractEngine engine, PrologTerm term) {
80  		super(engine);
81  		String str = "" + term + "";
82  		jtrolog = ((JTrologEngine) engine).engine;
83  		enumerateVariables(variables, fromTerm(term, Term.class));
84  		try {
85  			this.solution = jtrolog.solve(str + '.');
86  		} catch (Throwable e) {
87  			// do nothing
88  		}
89  	}
90  
91  	JTrologQuery(AbstractEngine engine, PrologTerm[] terms) {
92  		super(engine);
93  		jtrolog = ((JTrologEngine) engine).engine;
94  		if (terms != null && terms.length > 0) {
95  			enumerateVariables(variables, fromTerm(terms[terms.length - 1], Term.class));
96  			for (int i = terms.length; i > 1; i--) {
97  				enumerateVariables(variables, fromTerm(terms[i - 2], Term.class));
98  			}
99  			String str = Arrays.toString(terms).substring(1);
100 			str = str.substring(0, str.length() - 1) + '.';
101 			try {
102 				this.solution = jtrolog.solve(str);
103 			} catch (Throwable e) {
104 				// do nothing
105 			}
106 		}
107 	}
108 
109 	JTrologQuery(AbstractEngine engine, PrologTerm term, PrologTerm[] terms) {
110 		super(engine);
111 		String str = "" + term + "";
112 		jtrolog = ((JTrologEngine) engine).engine;
113 		enumerateVariables(variables, fromTerm(term, Term.class));
114 		if (terms != null && terms.length > 0) {
115 			enumerateVariables(variables, fromTerm(terms[terms.length - 1], Term.class));
116 			for (int i = terms.length; i > 1; i--) {
117 				enumerateVariables(variables, fromTerm(terms[i - 2], Term.class));
118 			}
119 			str = str + ", " + Arrays.toString(terms).substring(1);
120 			str = str.substring(0, str.length() - 1);
121 		}
122 		try {
123 			this.solution = jtrolog.solve(str + '.');
124 		} catch (Throwable e) {
125 			// do nothing
126 		}
127 	}
128 
129 	public boolean hasSolution() {
130 		return solution != null && solution.success();
131 	}
132 
133 	public boolean hasMoreSolutions() {
134 		try {
135 			return jtrolog.hasOpenAlternatives();
136 		} catch (Throwable e) {
137 			// do nothing
138 		}
139 		return false;
140 	}
141 
142 	public PrologTerm[] oneSolution() {
143 		int index = 0;
144 		Map<String, PrologTerm> solutionMap = oneVariablesSolution();
145 		PrologTerm[] array = new PrologTerm[solutionMap.size()];
146 		if (array.length > 0) {
147 			for (Iterator<String> i = variables.iterator(); i.hasNext();) {
148 				array[index++] = solutionMap.get(i.next());
149 			}
150 		}
151 		return array;
152 	}
153 
154 	public Map<String, PrologTerm> oneVariablesSolution() {
155 		Map<String, PrologTerm> map = new HashMap<String, PrologTerm>();
156 		for (String vName : variables) {
157 			if (solution != null) {
158 				Term vtTerm = solution.getBinding(vName);
159 				if (vtTerm != null) {
160 					PrologTerm pTerm = toTerm(vtTerm, PrologTerm.class);
161 					map.put(vName, pTerm);
162 				}
163 			}
164 		}
165 		return map;
166 	}
167 
168 	public PrologTerm[] nextSolution() {
169 		PrologTerm[] array = oneSolution();
170 		try {
171 			if (hasMoreSolutions()) {
172 				solution = jtrolog.solveNext();
173 				return array;
174 			}
175 		} catch (Throwable e) {
176 			getLogger().error(getClass(), PrologLogger.NON_SOLUTION, e);
177 		}
178 		return array;
179 	}
180 
181 	public Map<String, PrologTerm> nextVariablesSolution() {
182 		Map<String, PrologTerm> map = oneVariablesSolution();
183 		try {
184 
185 			if (hasMoreSolutions()) {
186 				solution = jtrolog.solveNext();
187 			}
188 			return map;
189 		} catch (Throwable e) {
190 			getLogger().error(getClass(), PrologLogger.NON_SOLUTION, e);
191 		}
192 		return new HashMap<String, PrologTerm>(0);
193 	}
194 
195 	public PrologTerm[][] nSolutions(int n) {
196 		if (n > 0) {
197 			// m:solutionSize
198 			int m = 0;
199 			int index = 0;
200 			List<PrologTerm[]> all = new ArrayList<PrologTerm[]>();
201 
202 			PrologTerm[] array = oneSolution();
203 			m = array.length > m ? array.length : m;
204 			index++;
205 			all.add(array);
206 
207 			while (hasMoreSolutions() && index < n) {
208 				try {
209 					solution = jtrolog.solveNext();
210 					array = oneSolution();
211 					if (array.length > 0 && !contains(all, array)) {
212 						m = array.length > m ? array.length : m;
213 						index++;
214 						all.add(array);
215 					}
216 				} catch (Throwable e) {
217 					getLogger().error(getClass(), PrologLogger.NON_SOLUTION, e);
218 				}
219 
220 			}
221 
222 			PrologTerm[][] allSolutions = new PrologTerm[n][m];
223 			for (int i = 0; i < n; i++) {
224 				array = all.get(i);
225 				System.arraycopy(array, 0, allSolutions[i], 0, m);
226 			}
227 			return allSolutions;
228 		}
229 		return new PrologTerm[0][0];
230 	}
231 
232 	public Map<String, PrologTerm>[] nVariablesSolutions(int n) {
233 		if (n > 0) {
234 			int index = 0;
235 			Map<String, PrologTerm>[] solutionMaps = new HashMap[n];
236 
237 			Map<String, PrologTerm> solutionMap = oneVariablesSolution();
238 			solutionMaps[index++] = solutionMap;
239 
240 			while (hasMoreSolutions() && index < n) {
241 				try {
242 					solution = jtrolog.solveNext();
243 					solutionMap = oneVariablesSolution();
244 					solutionMaps[index++] = solutionMap;
245 				} catch (Throwable e) {
246 					getLogger().error(getClass(), PrologLogger.NON_SOLUTION, e);
247 				}
248 			}
249 			return solutionMaps;
250 		}
251 		return new HashMap[0];
252 	}
253 
254 	public PrologTerm[][] allSolutions() {
255 		// n:solutionCount, m:solutionSize
256 		int n = 0;
257 		int m = 0;
258 		List<PrologTerm[]> all = new ArrayList<PrologTerm[]>();
259 
260 		PrologTerm[] array = oneSolution();
261 		if (array.length > 0) {
262 			m = array.length > m ? array.length : m;
263 			n++;
264 			all.add(array);
265 		}
266 
267 		while (hasMoreSolutions()) {
268 			try {
269 				solution = jtrolog.solveNext();
270 				array = oneSolution();
271 				if (array.length > 0 && !contains(all, array)) {
272 					m = array.length > m ? array.length : m;
273 					n++;
274 					all.add(array);
275 				}
276 			} catch (Throwable e) {
277 				getLogger().error(getClass(), PrologLogger.NON_SOLUTION, e);
278 			}
279 
280 		}
281 
282 		PrologTerm[][] allSolutions = new PrologTerm[n][m];
283 		for (int i = 0; i < n; i++) {
284 			array = all.get(i);
285 			System.arraycopy(array, 0, allSolutions[i], 0, m);
286 		}
287 		return allSolutions;
288 	}
289 
290 	public Map<String, PrologTerm>[] allVariablesSolutions() {
291 		List<Map<String, PrologTerm>> allVariables = new ArrayList<Map<String, PrologTerm>>();
292 
293 		Map<String, PrologTerm> varMap = oneVariablesSolution();
294 		if (!varMap.isEmpty()) {
295 			allVariables.add(varMap);
296 		}
297 
298 		while (hasMoreSolutions()) {
299 			try {
300 				solution = jtrolog.solveNext();
301 				varMap = oneVariablesSolution();
302 				if (!varMap.isEmpty() && !contains(allVariables, varMap)) {
303 					allVariables.add(varMap);
304 				}
305 			} catch (Throwable e) {
306 				getLogger().error(getClass(), PrologLogger.NON_SOLUTION, e);
307 			}
308 		}
309 
310 		int lenght = allVariables.size();
311 		Map<String, PrologTerm>[] allVariablesSolution = new HashMap[lenght];
312 		for (int i = 0; i < lenght; i++) {
313 			allVariablesSolution[i] = allVariables.get(i);
314 		}
315 		return allVariablesSolution;
316 	}
317 
318 	public List<Map<String, PrologTerm>> all() {
319 		List<Map<String, PrologTerm>> all = new ArrayList<Map<String, PrologTerm>>();
320 
321 		Map<String, PrologTerm> varMap = oneVariablesSolution();
322 		if (!varMap.isEmpty()) {
323 			all.add(varMap);
324 		}
325 
326 		while (hasMoreSolutions()) {
327 			try {
328 				solution = jtrolog.solveNext();
329 				varMap = oneVariablesSolution();
330 				if (!varMap.isEmpty() && !contains(all, varMap)) {
331 					all.add(varMap);
332 				}
333 			} catch (Throwable e) {
334 				getLogger().error(getClass(), PrologLogger.NON_SOLUTION, e);
335 			}
336 		}
337 
338 		return all;
339 	}
340 
341 	@Override
342 	public String toString() {
343 		return "" + solution + "";
344 	}
345 
346 	public void dispose() {
347 		solution = null;
348 	}
349 
350 	@Override
351 	public int hashCode() {
352 		final int prime = 31;
353 		int result = super.hashCode();
354 		result = prime * result + solution.hashCode();
355 		result = prime * result + variables.hashCode();
356 		return result;
357 	}
358 
359 	@Override
360 	public boolean equals(Object obj) {
361 		if (this == obj)
362 			return true;
363 		if (!super.equals(obj))
364 			return false;
365 		if (getClass() != obj.getClass())
366 			return false;
367 		JTrologQuery other = (JTrologQuery) obj;
368 		if (!Prolog.match(solution.getSolution(), other.solution.getSolution()))
369 			return false;
370 		return variables.equals(other.variables);
371 	}
372 
373 }