All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ai.libs.jaicore.search.util.GraphSanityChecker Maven / Gradle / Ivy

package ai.libs.jaicore.search.util;

import java.util.List;
import java.util.Stack;

import org.api4.java.ai.graphsearch.problem.IPathSearchInput;
import org.api4.java.ai.graphsearch.problem.implicit.graphgenerator.IPathGoalTester;
import org.api4.java.algorithm.events.IAlgorithmEvent;
import org.api4.java.datastructure.graph.implicit.INewNodeDescription;
import org.api4.java.datastructure.graph.implicit.ISingleRootGenerator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ai.libs.jaicore.graphvisualizer.events.graph.GraphInitializedEvent;
import ai.libs.jaicore.graphvisualizer.events.graph.NodeAddedEvent;
import ai.libs.jaicore.graphvisualizer.events.graph.NodeTypeSwitchEvent;
import ai.libs.jaicore.search.core.interfaces.AOptimalPathInORGraphSearch;
import ai.libs.jaicore.search.model.travesaltree.BackPointerPath;

public class GraphSanityChecker extends AOptimalPathInORGraphSearch, N, A, Double> {

	private Logger logger = LoggerFactory.getLogger(GraphSanityChecker.class);
	private String loggerName;

	private SanityCheckResult sanityCheckResult;
	private final int maxNodesToExpand;
	private boolean detectCycles = true;
	private boolean detectDeadEnds = true;

	public GraphSanityChecker(final IPathSearchInput problem, final int maxNodesToExpand) {
		super(problem);
		this.maxNodesToExpand = maxNodesToExpand;
	}

	@Override
	public IAlgorithmEvent nextWithException() throws InterruptedException {
		switch (this.getState()) {
		case CREATED:
			return this.activate();
		case ACTIVE:
			int expanded = 0;
			Stack> open = new Stack<>();
			N root = ((ISingleRootGenerator) this.getGraphGenerator().getRootGenerator()).getRoot();
			IPathGoalTester goalTester = this.getGoalTester();
			open.push(new BackPointerPath<>(null, root, null));
			this.post(new GraphInitializedEvent(this, root));
			while (!open.isEmpty() && expanded < this.maxNodesToExpand) {
				BackPointerPath node = open.pop();
				if (!node.isGoal()) {
					this.post(new NodeTypeSwitchEvent<>(this, node, "or_closed"));
				}
				expanded++;
				List> successors = this.getGraphGenerator().getSuccessorGenerator().generateSuccessors(node.getHead());
				if (this.detectDeadEnds && successors.isEmpty() && !node.isGoal()) {
					this.sanityCheckResult = new DeadEndDetectedResult(node.getHead());
					break;
				}
				for (INewNodeDescription successor : successors) {
					if (this.detectCycles && node.getNodes().contains(successor.getTo())) {
						List path = node.getNodes();
						path.add(successor.getTo());
						this.sanityCheckResult = new CycleDetectedResult(path, node.getHead());
						break;
					}
					BackPointerPath newNode = new BackPointerPath<>(node, successor.getTo(), successor.getArcLabel());
					newNode.setGoal(goalTester.isGoal(newNode));
					open.add(newNode);
					this.post(new NodeAddedEvent(this, node.getHead(), successor.getTo(), newNode.isGoal() ? "or_solution" : "or_open"));
				}
				if (this.sanityCheckResult != null) {
					break;
				}
				if (expanded % 100 == 0 || expanded == this.maxNodesToExpand) {
					this.logger.debug("Expanded {}/{} nodes.", expanded, this.maxNodesToExpand);
				}
			}
			this.shutdown();
			return this.terminate();

		default:
			throw new IllegalStateException("Cannot do anything in state " + this.getState());
		}
	}

	public SanityCheckResult getSanityCheck() {
		return this.sanityCheckResult != null ? this.sanityCheckResult : new GraphSeemsSaneResult();
	}

	@Override
	public String getLoggerName() {
		return this.loggerName;
	}

	@Override
	public void setLoggerName(final String name) {
		this.logger.info("Switching logger from {} to {}", this.logger.getName(), name);
		this.loggerName = name;
		this.logger = LoggerFactory.getLogger(name);
		this.logger.info("Activated logger {} with name {}", name, this.logger.getName());
		super.setLoggerName(this.loggerName + "._orgraphsearch");
	}

	public boolean isDetectCycles() {
		return this.detectCycles;
	}

	public void setDetectCycles(final boolean detectCycles) {
		this.detectCycles = detectCycles;
	}

	public boolean isDetectDeadEnds() {
		return this.detectDeadEnds;
	}

	public void setDetectDeadEnds(final boolean detectDeadEnds) {
		this.detectDeadEnds = detectDeadEnds;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy