ai.libs.jaicore.search.probleminputs.builders.SearchProblemInputBuilder Maven / Gradle / Ivy
package ai.libs.jaicore.search.probleminputs.builders;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import org.api4.java.ai.graphsearch.problem.IPathSearchInput;
import org.api4.java.ai.graphsearch.problem.implicit.graphgenerator.IPathGoalTester;
import org.api4.java.datastructure.graph.ILabeledPath;
import org.api4.java.datastructure.graph.implicit.IGraphGenerator;
import org.api4.java.datastructure.graph.implicit.INewNodeDescription;
import org.api4.java.datastructure.graph.implicit.IRootGenerator;
import org.api4.java.datastructure.graph.implicit.ISingleRootGenerator;
import org.api4.java.datastructure.graph.implicit.ISuccessorGenerator;
import ai.libs.jaicore.search.model.other.SearchGraphPath;
public abstract class SearchProblemInputBuilder, B extends SearchProblemInputBuilder> {
private IRootGenerator rootGenerator;
private ISuccessorGenerator successorGenerator;
private IPathGoalTester goalTester;
private ILabeledPath prefixPath; // the path from the original root
public B withGraphGenerator(final IGraphGenerator graphGenerator) {
this.rootGenerator = graphGenerator.getRootGenerator();
this.successorGenerator = graphGenerator.getSuccessorGenerator();
return this.self();
}
public IGraphGenerator getGraphGenerator() {
return new IGraphGenerator() {
@Override
public IRootGenerator getRootGenerator() {
return SearchProblemInputBuilder.this.rootGenerator;
}
@Override
public ISuccessorGenerator getSuccessorGenerator() {
return SearchProblemInputBuilder.this.successorGenerator;
}
};
}
public B fromProblem(final IPathSearchInput problem) {
this.withGraphGenerator(problem.getGraphGenerator());
this.withGoalTester(problem.getGoalTester());
return this.self();
}
public B withRoot(final N root) {
this.rootGenerator = () -> Arrays.asList(root);
return this.self();
}
public void withSuccessorGenerator(final ISuccessorGenerator successorGenerator) {
this.successorGenerator = successorGenerator;
}
/**
* Replaces the current root by a new one based on the successor generator
* @throws InterruptedException
**/
public B withOffsetRoot(final List indicesOfSuccessorsFromCurrentRoot) throws InterruptedException {
if (this.rootGenerator == null) {
throw new IllegalStateException("Cannot offset root when currently no root is set.");
}
if (this.successorGenerator == null) {
throw new IllegalStateException("Cannot offset root when currently no successor generator is set.");
}
Collection roots = this.rootGenerator.getRoots();
if (roots.size() > 1) {
throw new IllegalStateException("Root offset is a function that is only reasonably defined for problems with one root!");
}
List prefixNodes = new ArrayList<>();
List prefixArcs = new ArrayList<>();
N current = roots.iterator().next();
prefixNodes.add(current);
for (int child : indicesOfSuccessorsFromCurrentRoot) {
INewNodeDescription ned = this.successorGenerator.generateSuccessors(current).get(child);
current = ned.getTo();
prefixArcs.add(ned.getArcLabel());
prefixNodes.add(current);
}
this.prefixPath = new SearchGraphPath<>(prefixNodes, prefixArcs);
this.rootGenerator = new ISingleRootGenerator() {
@Override
public N getRoot() {
return SearchProblemInputBuilder.this.prefixPath.getHead();
}
};
return this.self();
}
public ILabeledPath getPrefixPath() {
return this.prefixPath;
}
public B withGoalTester(final IPathGoalTester goalTester) {
this.goalTester = goalTester;
return this.self();
}
public IPathGoalTester getGoalTester() {
return this.goalTester;
}
public abstract I build();
protected abstract B self();
}