TuPrologQuery.java
/*
* #%L
* prolobjectlink-jpi-tuprolog
* %%
* 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.tuprolog;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import alice.tuprolog.MalformedGoalException;
import alice.tuprolog.NoMoreSolutionException;
import alice.tuprolog.NoSolutionException;
import alice.tuprolog.Prolog;
import alice.tuprolog.SolveInfo;
import alice.tuprolog.Struct;
import alice.tuprolog.Term;
import alice.tuprolog.Var;
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;
/**
*
* @author Jose Zalacain
* @since 1.0
*/
final class TuPrologQuery extends AbstractQuery implements PrologQuery {
private Prolog tuProlog;
private SolveInfo solution;
TuPrologQuery(AbstractEngine engine, String query) {
super(engine);
tuProlog = ((TuPrologEngine) engine).engine;
try {
solution = tuProlog.solve("" + query + ".");
} catch (MalformedGoalException e) {
getLogger().error(getClass(), PrologLogger.SYNTAX_ERROR, e);
}
}
TuPrologQuery(AbstractEngine engine, PrologTerm term) {
super(engine);
Term query = fromTerm(term, Term.class);
tuProlog = ((TuPrologEngine) engine).engine;
solution = tuProlog.solve(query);
}
TuPrologQuery(AbstractEngine engine, PrologTerm[] terms) {
super(engine);
if (terms != null && terms.length > 0) {
Term term = fromTerm(terms[terms.length - 1], Term.class);
for (int i = terms.length; i > 1; i--) {
term = new Struct(",", fromTerm(terms[i - 2], Term.class), term);
}
tuProlog = ((TuPrologEngine) engine).engine;
solution = tuProlog.solve(term);
}
}
TuPrologQuery(AbstractEngine engine, PrologTerm term, PrologTerm[] terms) {
super(engine);
Term query = fromTerm(term, Term.class);
if (terms != null && terms.length > 0) {
query = fromTerm(terms[terms.length - 1], Term.class);
for (int i = terms.length; i > 1; i--) {
query = new Struct(",", fromTerm(terms[i - 2], Term.class), query);
}
query = new Struct(",", fromTerm(term, Term.class), query);
}
tuProlog = ((TuPrologEngine) engine).engine;
solution = tuProlog.solve(query);
}
public boolean hasSolution() {
return solution != null && solution.isSuccess();
}
public boolean hasMoreSolutions() {
return tuProlog != null && tuProlog.hasOpenAlternatives();
}
public PrologTerm[] oneSolution() {
if (solution != null && solution.isSuccess()) {
try {
List<Var> vars = solution.getBindingVars();
PrologTerm[] array = new PrologTerm[vars.size()];
for (int i = 0; i < array.length; i++) {
array[i] = toTerm(vars.get(i).getTerm(), PrologTerm.class);
}
return array;
} catch (NoSolutionException e) {
// do nothing
}
}
return new PrologTerm[0];
}
public Map<String, PrologTerm> oneVariablesSolution() {
if (solution != null && solution.isSuccess()) {
try {
List<Var> vars = solution.getBindingVars();
Map<String, PrologTerm> map = new HashMap<String, PrologTerm>(vars.size());
for (Var var : vars) {
map.put(var.getName(), toTerm(var.getTerm(), PrologTerm.class));
}
return map;
} catch (NoSolutionException e) {
// do nothing
}
}
return new HashMap<String, PrologTerm>(0);
}
public PrologTerm[] nextSolution() {
try {
PrologTerm[] array = oneSolution();
if (hasMoreSolutions()) {
solution = tuProlog.solveNext();
}
return array;
} catch (NoMoreSolutionException e) {
// do nothing
}
return new PrologTerm[0];
}
public Map<String, PrologTerm> nextVariablesSolution() {
try {
Map<String, PrologTerm> map = oneVariablesSolution();
if (hasMoreSolutions()) {
solution = tuProlog.solveNext();
}
return map;
} catch (NoMoreSolutionException e) {
// do nothing
}
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;
all.add(array);
index++;
while (hasMoreSolutions() && index < n) {
try {
solution = tuProlog.solveNext();
array = oneSolution();
if (array.length > 0 && !contains(all, array)) {
m = array.length > m ? array.length : m;
all.add(array);
index++;
}
} catch (NoMoreSolutionException e) {
// do nothing
}
}
PrologTerm[][] allSolutions = new PrologTerm[n][m];
for (int i = 0; i < n; i++) {
array = all.get(i);
for (int j = 0; j < m; j++) {
allSolutions[i][j] = array[j];
}
}
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 {
TuPrologEngine pe = (TuPrologEngine) engine;
solution = pe.engine.solveNext();
solutionMap = oneVariablesSolution();
solutionMaps[index++] = solutionMap;
} catch (NoMoreSolutionException e) {
// do nothing
}
}
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 = tuProlog.solveNext();
array = oneSolution();
if (array.length > 0 && !contains(all, array)) {
m = array.length > m ? array.length : m;
n++;
all.add(array);
}
} catch (NoMoreSolutionException e) {
// do nothing
}
}
PrologTerm[][] allSolutions = new PrologTerm[n][m];
for (int i = 0; i < n; i++) {
array = all.get(i);
for (int j = 0; j < m; j++) {
allSolutions[i][j] = array[j];
}
}
return allSolutions;
}
public Map<String, PrologTerm>[] allVariablesSolutions() {
return all().toArray(new Map[0]);
}
public List<Map<String, PrologTerm>> all() {
List<Map<String, PrologTerm>> allVariables = new ArrayList<Map<String, PrologTerm>>();
Map<String, PrologTerm> variables = oneVariablesSolution();
if (!variables.isEmpty()) {
allVariables.add(variables);
}
while (hasMoreSolutions()) {
try {
solution = tuProlog.solveNext();
variables = oneVariablesSolution();
if (!variables.isEmpty() && !contains(allVariables, variables)) {
allVariables.add(variables);
}
} catch (NoMoreSolutionException e) {
// do nothing
}
}
return allVariables;
}
@Override
public String toString() {
return "" + solution.getQuery() + "";
}
public void dispose() {
solution = null;
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + ((solution == null) ? 0 : solution.hashCode());
result = prime * result + ((tuProlog == null) ? 0 : tuProlog.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;
TuPrologQuery other = (TuPrologQuery) obj;
if (solution == null) {
if (other.solution != null)
return false;
} else if (!solution.getQuery().equals(other.solution.getQuery())) {
return false;
}
return true;
}
}