JTrologQuery.java
/*
* #%L
* prolobjectlink-jpi-jtrolog
* %%
* Copyright (C) 2019 Prolobjectlink Project
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 2.1 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/lgpl-2.1.html>.
* #L%
*/
package io.github.prolobjectlink.prolog.jtrolog;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import io.github.prolobjectlink.prolog.AbstractEngine;
import io.github.prolobjectlink.prolog.AbstractQuery;
import io.github.prolobjectlink.prolog.PrologLogger;
import io.github.prolobjectlink.prolog.PrologQuery;
import io.github.prolobjectlink.prolog.PrologTerm;
import jTrolog.engine.Prolog;
import jTrolog.engine.Solution;
import jTrolog.parser.Parser;
import jTrolog.terms.Struct;
import jTrolog.terms.Term;
import jTrolog.terms.Var;
/**
*
* @author Jose Zalacain
* @since 1.0
*/
final class JTrologQuery extends AbstractQuery implements PrologQuery {
private Solution solution;
private Prolog jtrolog;
private List<String> variables = new ArrayList<String>();
private void enumerateVariables(List<String> vector, Term term) {
if (!(term instanceof Var)) {
if (term instanceof Struct) {
Struct struct = (Struct) term;
Var[] vars = struct.getVarList();
for (Var var : vars) {
enumerateVariables(variables, var);
}
}
} else if (!vector.contains(term.toString())) {
vector.add(term.toString());
}
}
JTrologQuery(AbstractEngine engine, String query) {
super(engine);
jtrolog = ((JTrologEngine) engine).engine;
enumerateVariables(variables, new Parser(query).nextTerm(false));
try {
this.solution = jtrolog.solve("" + query + ".");
} catch (Throwable e) {
// do nothing
}
}
JTrologQuery(AbstractEngine engine, PrologTerm term) {
super(engine);
String str = "" + term + "";
jtrolog = ((JTrologEngine) engine).engine;
enumerateVariables(variables, fromTerm(term, Term.class));
try {
this.solution = jtrolog.solve(str + '.');
} catch (Throwable e) {
// do nothing
}
}
JTrologQuery(AbstractEngine engine, PrologTerm[] terms) {
super(engine);
jtrolog = ((JTrologEngine) engine).engine;
if (terms != null && terms.length > 0) {
enumerateVariables(variables, fromTerm(terms[terms.length - 1], Term.class));
for (int i = terms.length; i > 1; i--) {
enumerateVariables(variables, fromTerm(terms[i - 2], Term.class));
}
String str = Arrays.toString(terms).substring(1);
str = str.substring(0, str.length() - 1) + '.';
try {
this.solution = jtrolog.solve(str);
} catch (Throwable e) {
// do nothing
}
}
}
JTrologQuery(AbstractEngine engine, PrologTerm term, PrologTerm[] terms) {
super(engine);
String str = "" + term + "";
jtrolog = ((JTrologEngine) engine).engine;
enumerateVariables(variables, fromTerm(term, Term.class));
if (terms != null && terms.length > 0) {
enumerateVariables(variables, fromTerm(terms[terms.length - 1], Term.class));
for (int i = terms.length; i > 1; i--) {
enumerateVariables(variables, fromTerm(terms[i - 2], Term.class));
}
str = str + ", " + Arrays.toString(terms).substring(1);
str = str.substring(0, str.length() - 1);
}
try {
this.solution = jtrolog.solve(str + '.');
} catch (Throwable e) {
// do nothing
}
}
public boolean hasSolution() {
return solution != null && solution.success();
}
public boolean hasMoreSolutions() {
try {
return jtrolog.hasOpenAlternatives();
} catch (Throwable e) {
// do nothing
}
return false;
}
public PrologTerm[] oneSolution() {
int index = 0;
Map<String, PrologTerm> solutionMap = oneVariablesSolution();
PrologTerm[] array = new PrologTerm[solutionMap.size()];
if (array.length > 0) {
for (Iterator<String> i = variables.iterator(); i.hasNext();) {
array[index++] = solutionMap.get(i.next());
}
}
return array;
}
public Map<String, PrologTerm> oneVariablesSolution() {
Map<String, PrologTerm> map = new HashMap<String, PrologTerm>();
for (String vName : variables) {
if (solution != null) {
Term vtTerm = solution.getBinding(vName);
if (vtTerm != null) {
PrologTerm pTerm = toTerm(vtTerm, PrologTerm.class);
map.put(vName, pTerm);
}
}
}
return map;
}
public PrologTerm[] nextSolution() {
PrologTerm[] array = oneSolution();
try {
if (hasMoreSolutions()) {
solution = jtrolog.solveNext();
return array;
}
} catch (Throwable e) {
getLogger().error(getClass(), PrologLogger.NON_SOLUTION, e);
}
return array;
}
public Map<String, PrologTerm> nextVariablesSolution() {
Map<String, PrologTerm> map = oneVariablesSolution();
try {
if (hasMoreSolutions()) {
solution = jtrolog.solveNext();
}
return map;
} catch (Throwable e) {
getLogger().error(getClass(), PrologLogger.NON_SOLUTION, e);
}
return new HashMap<String, PrologTerm>(0);
}
public PrologTerm[][] nSolutions(int n) {
if (n > 0) {
// m:solutionSize
int m = 0;
int index = 0;
List<PrologTerm[]> all = new ArrayList<PrologTerm[]>();
PrologTerm[] array = oneSolution();
m = array.length > m ? array.length : m;
index++;
all.add(array);
while (hasMoreSolutions() && index < n) {
try {
solution = jtrolog.solveNext();
array = oneSolution();
if (array.length > 0 && !contains(all, array)) {
m = array.length > m ? array.length : m;
index++;
all.add(array);
}
} catch (Throwable e) {
getLogger().error(getClass(), PrologLogger.NON_SOLUTION, e);
}
}
PrologTerm[][] allSolutions = new PrologTerm[n][m];
for (int i = 0; i < n; i++) {
array = all.get(i);
System.arraycopy(array, 0, allSolutions[i], 0, m);
}
return allSolutions;
}
return new PrologTerm[0][0];
}
public Map<String, PrologTerm>[] nVariablesSolutions(int n) {
if (n > 0) {
int index = 0;
Map<String, PrologTerm>[] solutionMaps = new HashMap[n];
Map<String, PrologTerm> solutionMap = oneVariablesSolution();
solutionMaps[index++] = solutionMap;
while (hasMoreSolutions() && index < n) {
try {
solution = jtrolog.solveNext();
solutionMap = oneVariablesSolution();
solutionMaps[index++] = solutionMap;
} catch (Throwable e) {
getLogger().error(getClass(), PrologLogger.NON_SOLUTION, e);
}
}
return solutionMaps;
}
return new HashMap[0];
}
public PrologTerm[][] allSolutions() {
// n:solutionCount, m:solutionSize
int n = 0;
int m = 0;
List<PrologTerm[]> all = new ArrayList<PrologTerm[]>();
PrologTerm[] array = oneSolution();
if (array.length > 0) {
m = array.length > m ? array.length : m;
n++;
all.add(array);
}
while (hasMoreSolutions()) {
try {
solution = jtrolog.solveNext();
array = oneSolution();
if (array.length > 0 && !contains(all, array)) {
m = array.length > m ? array.length : m;
n++;
all.add(array);
}
} catch (Throwable e) {
getLogger().error(getClass(), PrologLogger.NON_SOLUTION, e);
}
}
PrologTerm[][] allSolutions = new PrologTerm[n][m];
for (int i = 0; i < n; i++) {
array = all.get(i);
System.arraycopy(array, 0, allSolutions[i], 0, m);
}
return allSolutions;
}
public Map<String, PrologTerm>[] allVariablesSolutions() {
List<Map<String, PrologTerm>> allVariables = new ArrayList<Map<String, PrologTerm>>();
Map<String, PrologTerm> varMap = oneVariablesSolution();
if (!varMap.isEmpty()) {
allVariables.add(varMap);
}
while (hasMoreSolutions()) {
try {
solution = jtrolog.solveNext();
varMap = oneVariablesSolution();
if (!varMap.isEmpty() && !contains(allVariables, varMap)) {
allVariables.add(varMap);
}
} catch (Throwable e) {
getLogger().error(getClass(), PrologLogger.NON_SOLUTION, e);
}
}
int lenght = allVariables.size();
Map<String, PrologTerm>[] allVariablesSolution = new HashMap[lenght];
for (int i = 0; i < lenght; i++) {
allVariablesSolution[i] = allVariables.get(i);
}
return allVariablesSolution;
}
public List<Map<String, PrologTerm>> all() {
List<Map<String, PrologTerm>> all = new ArrayList<Map<String, PrologTerm>>();
Map<String, PrologTerm> varMap = oneVariablesSolution();
if (!varMap.isEmpty()) {
all.add(varMap);
}
while (hasMoreSolutions()) {
try {
solution = jtrolog.solveNext();
varMap = oneVariablesSolution();
if (!varMap.isEmpty() && !contains(all, varMap)) {
all.add(varMap);
}
} catch (Throwable e) {
getLogger().error(getClass(), PrologLogger.NON_SOLUTION, e);
}
}
return all;
}
@Override
public String toString() {
return "" + solution + "";
}
public void dispose() {
solution = null;
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + solution.hashCode();
result = prime * result + variables.hashCode();
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!super.equals(obj))
return false;
if (getClass() != obj.getClass())
return false;
JTrologQuery other = (JTrologQuery) obj;
if (!Prolog.match(solution.getSolution(), other.solution.getSolution()))
return false;
return variables.equals(other.variables);
}
}