/// <summary> /// Returns the possible ways that a query term can unify with a program term /// </summary> public static IBindings Unify(this ILiteral query, ILiteral program, IBindings bindings = null) { var simpleUnifier = new SimpleUnifier(); var freeVariables = new HashSet<ILiteral>(); // Run the unifier var queryFreeVars = simpleUnifier.QueryUnifier.Compile(query, bindings); if (queryFreeVars == null) return null; simpleUnifier.PrepareToRunProgram(); var programFreeVars = simpleUnifier.ProgramUnifier.Compile(program, bindings); if (programFreeVars == null) return null; freeVariables.UnionWith(queryFreeVars); // Retrieve the unified value for the program var result = simpleUnifier.UnifiedValue(query.UnificationKey ?? query); // If the result was valid, return as the one value from this function if (result != null) { var variableBindings = freeVariables.ToDictionary(variable => variable, variable => simpleUnifier.UnifiedValue(variable)); return new BasicBinding(result, variableBindings); } else { return null; } }
public void FindFreeVariableInMoreComplicatedFunctor() { var functor = GetQueryAndProgram1().Item1; var unifier = new SimpleUnifier(); var freeVars = unifier.QueryUnifier.Compile(functor).ToList(); Assert.AreEqual(2, freeVars.Count); }
public void AtomIsNotFreeVariable() { var atom = Literal.NewAtom(); var unifier = new SimpleUnifier(); var freeVars = unifier.QueryUnifier.Compile(atom).ToList(); Assert.AreEqual(0, freeVars.Count); }
public void VariableIsFreeVariable() { var variable = Literal.NewVariable(); var unifier = new SimpleUnifier(); var freeVars = unifier.QueryUnifier.Compile(variable).ToList(); Assert.AreEqual(1, freeVars.Count); Assert.AreEqual(variable, freeVars[0]); }
public void FindFreeVariableInFunctor() { var variable = Literal.NewVariable(); var functor = Literal.NewFunctor(1).With(variable); var unifier = new SimpleUnifier(); var freeVars = unifier.QueryUnifier.Compile(functor).ToList(); Assert.AreEqual(1, freeVars.Count); Assert.AreEqual(variable, freeVars[0]); }
/// <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())); }
public Func<bool> Call(ILiteral predicate, params IReferenceLiteral[] arguments) { // Assume that predicate is correct // Load the arguments into a simple unifier var unifier = new SimpleUnifier(); unifier.LoadArguments(arguments); // Unify using the predicate unifier.ProgramUnifier.Bind(_clauseAssignments[0].Assignments); if (!unifier.ProgramUnifier.Compile(_clauseAssignments[0].Assignments)) { // Fail if we can't unify return () => false; } // Call using the clauses return SolveAllSubclauses(_clauseAssignments.Skip(1), unifier); }
/// <summary> /// Returns a function that solves a list of subclauses /// </summary> private Func<bool> SolveAllSubclauses(IEnumerable<AssignmentData> assignments, SimpleUnifier unifier) { // The first solution is always true once bool solvedOnce = false; Func<bool> solve = () => { if (solvedOnce) { // Reset the unifier to its original state and give up unifier.ResetTrail(); return false; } else { solvedOnce = true; return true; } }; // Chain the solutions for each subclause to generate the final result foreach (var clause in assignments) { solve = SolveSubclause(clause, unifier, solve); } // This generates the result return solve; }
/// <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; } }; }
public void ManualUnification() { var simpleUnifier = new SimpleUnifier(); var unifier = new TraceUnifier(simpleUnifier); var X = new[] { new Variable(), new Variable(), new Variable(), new Variable(), new Variable(), new Variable(), new Variable(), new Variable() }; var h2 = new UnboundFunctor(2); var f1 = new UnboundFunctor(1); var p3 = new UnboundFunctor(3); var a0 = new UnboundFunctor(0); unifier.BindVariable(0, X[1]); unifier.BindVariable(1, X[2]); unifier.BindVariable(2, X[3]); unifier.BindVariable(3, X[4]); unifier.BindVariable(4, X[5]); unifier.BindVariable(5, X[6]); unifier.BindVariable(6, X[7]); unifier.PutStructure(h2, 2, X[3]); unifier.SetVariable(X[2]); unifier.SetVariable(X[5]); unifier.PutStructure(f1, 1, X[4]); unifier.SetValue(X[5]); unifier.PutStructure(p3, 3, X[1]); unifier.SetValue(X[2]); unifier.SetValue(X[3]); unifier.SetValue(X[4]); unifier.GetStructure(p3, 3, X[1]); unifier.UnifyVariable(X[2]); unifier.UnifyVariable(X[3]); unifier.UnifyVariable(X[4]); unifier.GetStructure(f1, 1, X[2]); unifier.UnifyVariable(X[5]); unifier.GetStructure(h2, 2, X[3]); unifier.UnifyValue(X[4]); unifier.UnifyVariable(X[6]); unifier.GetStructure(f1, 1, X[6]); unifier.UnifyVariable(X[7]); unifier.GetStructure(a0, 0, X[7]); var result = simpleUnifier.UnifiedValue(X[1]); Assert.IsNotNull(result); }