ai.libs.jaicore.search.landscapeanalysis.GenericLandscapeAnalyzer Maven / Gradle / Ivy
package ai.libs.jaicore.search.landscapeanalysis;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.api4.java.ai.graphsearch.problem.IPathSearchWithPathEvaluationsInput;
import org.api4.java.ai.graphsearch.problem.implicit.graphgenerator.IPathGoalTester;
import org.api4.java.ai.graphsearch.problem.pathsearch.pathevaluation.PathEvaluationException;
import org.api4.java.datastructure.graph.ILabeledPath;
import org.api4.java.datastructure.graph.implicit.INewNodeDescription;
import org.api4.java.datastructure.graph.implicit.ISuccessorGenerator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ai.libs.jaicore.search.model.other.SearchGraphPath;
public class GenericLandscapeAnalyzer {
private static Logger logger = LoggerFactory.getLogger("testers");
private final IPathSearchWithPathEvaluationsInput problem;
private final N root;
private final ISuccessorGenerator successorGenerator;
private final IPathGoalTester goalTester;
private double min = Double.MAX_VALUE;
public GenericLandscapeAnalyzer(final IPathSearchWithPathEvaluationsInput problem) {
super();
this.problem = problem;
this.root = problem.getGraphGenerator().getRootGenerator().getRoots().iterator().next();
this.successorGenerator = problem.getGraphGenerator().getSuccessorGenerator();
this.goalTester = problem.getGoalTester();
}
public double[] getValues(final Number probeSize) throws InterruptedException, PathEvaluationException {
return this.getValues(probeSize, LandscapeAnalysisCompletionTechnique.RANDOM);
}
public double[] getValues(final Number probeSize, final LandscapeAnalysisCompletionTechnique technique) throws InterruptedException, PathEvaluationException {
return this.getValues(new SearchGraphPath<>(this.root), probeSize, technique);
}
public double[] getValues(final List decisions, final int probeSize, final LandscapeAnalysisCompletionTechnique technique) throws InterruptedException, PathEvaluationException {
List nodes = new ArrayList<>(decisions.size() + 1);
List arcs = new ArrayList<>(decisions.size());
N current = this.root;
nodes.add(current);
for (int child : decisions) {
INewNodeDescription ned = this.successorGenerator.generateSuccessors(current).get(child);
current = ned.getTo();
nodes.add(current);
arcs.add(ned.getArcLabel());
}
ILabeledPath path = new SearchGraphPath<>(nodes, arcs);
return this.getValues(path, probeSize, technique);
}
public double[] getValues(final ILabeledPath path, final Number probeSize, final LandscapeAnalysisCompletionTechnique technique) throws InterruptedException, PathEvaluationException {
List values = this.probeUnderPath(path, probeSize, technique);
int n = values.size();
double[] valuesAsArray = new double[n];
for (int i = 0; i < n; i++) {
valuesAsArray[i] = values.get(i);
}
return valuesAsArray;
}
private List probeUnderPath(final ILabeledPath path, final Number limit, final LandscapeAnalysisCompletionTechnique technique) throws InterruptedException, PathEvaluationException {
N node = path.getHead();
int cLimit = limit.intValue();
List scoresUnderChildren = new ArrayList<>(cLimit);
if (this.goalTester.isGoal(path)) {
double score = this.problem.getPathEvaluator().evaluate(path);
if (score < this.min) {
this.min = score;
}
scoresUnderChildren.add(score);
return scoresUnderChildren;
}
List> successors = this.successorGenerator.generateSuccessors(node);
int n = successors.size();
/* if we cannot delve into all successors, order them by the defined technique */
if (n > cLimit) {
switch (technique) {
case FIRST:
/* do nothing */
break;
case LAST:
Collections.reverse(successors);
break;
case RANDOM:
Collections.shuffle(successors);
break;
}
}
int limitPerChild = (int)Math.floor(cLimit * 1.0 / n);
int numberOfChildrenWithExtra = cLimit % n;
for (int child = 0; child < n; child++) {
int limitForThisChild = limitPerChild + (child < numberOfChildrenWithExtra ? 1 : 0);
if (limitForThisChild <= 0) {
return scoresUnderChildren;
}
ILabeledPath newPath = new SearchGraphPath<>(path, successors.get(child).getTo(), successors.get(child).getArcLabel());
scoresUnderChildren.addAll(this.probeUnderPath(newPath, limitForThisChild, technique));
}
return scoresUnderChildren;
}
public List> getIterativeProbeValuesAlongRandomPath(final Number probSizePerLevelAndChild) throws PathEvaluationException, InterruptedException {
ILabeledPath currentPath = new SearchGraphPath<>(this.root);
while (!this.goalTester.isGoal(currentPath)) {
List> nedList = this.problem.getGraphGenerator().getSuccessorGenerator().generateSuccessors(currentPath.getHead());
Collections.shuffle(nedList);
currentPath = new SearchGraphPath<>(currentPath, nedList.get(0).getTo(), nedList.get(0).getArcLabel());
}
logger.info("Drew path {}: {}" , currentPath.getArcs(), currentPath.getHead());
return this.getIterativeProbeValues(currentPath, probSizePerLevelAndChild);
}
public List> getIterativeProbeValues(final ILabeledPath path, final Number probSizePerLevelAndChild) throws PathEvaluationException, InterruptedException {
List> iterativeProbes = new ArrayList<>();
for (int depth = 0; depth < path.getNumberOfNodes() - 1; depth++) {
logger.info("Probing on level {}", depth);
/* compute sub-path of the relevant depth */
ILabeledPath subPath = path;
while (subPath.getNumberOfNodes() > depth + 1) {
subPath = subPath.getPathToParentOfHead();
}
/* compute successors in that depth */
List> nedList = this.problem.getGraphGenerator().getSuccessorGenerator().generateSuccessors(subPath.getHead());
/* sample under each of the nodes */
List probesOnLevel = new ArrayList<>(nedList.size());
for (INewNodeDescription ned : nedList) {
ILabeledPath extendedPath = new SearchGraphPath<>(subPath, ned.getTo(), ned.getArcLabel());
double[] landscape = this.getValues(extendedPath, probSizePerLevelAndChild, LandscapeAnalysisCompletionTechnique.RANDOM);
probesOnLevel.add(landscape);
}
iterativeProbes.add(probesOnLevel);
}
return iterativeProbes;
}
}