/// <summary> /// Queries a solver for a goal /// </summary> public static IQueryResult Query(this ISolver solver, ILiteral goal) { // Result is false for something without a key if (goal.UnificationKey == null) { return(new BasicQueryResult(false, new EmptyBinding(null))); } // Compile the query var unifier = new SimpleUnifier(); var assignments = new PredicateAssignmentList(); // Assume we have a basic predicate foreach (var arg in goal.Dependencies) { assignments.AddArgument(arg); } // Run through the unifier var freeVariableNames = unifier.QueryUnifier.Bind(assignments.Assignments); var freeVariables = freeVariableNames.Select(variable => unifier.GetVariableLocation(variable).Dereference()); unifier.QueryUnifier.Compile(assignments.Assignments); // Call via the solver var moveNext = solver.Call(goal.UnificationKey, unifier.GetArgumentVariables(assignments.CountArguments())); Func <IQueryResult> nextResult = () => { // Update the variables to the next result var succeeded = moveNext(); // Nothing to do if we didn't succeed if (!succeeded) { return(new BasicQueryResult(false, new EmptyBinding(null))); } // Bind the variables var variableValues = freeVariables .Select(varRef => varRef.Freeze()) .Zip(freeVariableNames, (value, name) => new { Value = value, Name = name }).ToArray(); var binding = new BasicBinding(null, variableValues.ToDictionary(val => val.Name, val => val.Value)); // Return the result return(new BasicQueryResult(true, binding)); }; // Chain to produce the final result return(new ChainedResult(nextResult(), () => Task.FromResult(nextResult()))); }
/// <summary> /// Solves a subclause /// </summary> private Func <bool> SolveSubclause(AssignmentData clause, SimpleUnifier unifier, Func <bool> solvePreviousClause) { // Create a new trail unifier.PushTrail(); Func <bool> nextInThisClause = null; return(() => { if (nextInThisClause == null || !nextInThisClause()) { // Reset the state and get the solution for the previous clause unifier.ResetTrail(); if (!solvePreviousClause()) { return false; } // Push a new trail for this clause unifier.PushTrail(); // Solve this clause unifier.QueryUnifier.Bind(clause.Assignments); if (!unifier.QueryUnifier.Compile(clause.Assignments)) { return false; } // Call the predicate nextInThisClause = _subclauseSolver.Call(clause.PredicateName, unifier.GetArgumentVariables(clause.NumArguments)); // Result depends on the next item in this clause return nextInThisClause(); } else { // nextInThisClause() returned true, so this clause was solved return true; } }); }