public SimpleSingleClauseSolver(IClause clause, ISolver subclauseSolver) { if (clause == null) { throw new ArgumentNullException("clause"); } if (subclauseSolver == null) { throw new ArgumentNullException("subclauseSolver"); } _clause = clause; _subclauseSolver = subclauseSolver; // Compile each part of the clause to its subclauses _clauseAssignments = new[] { clause.Implies }.Concat(clause.If) .Select(predicate => { var assignments = PredicateAssignmentList.FromPredicate(predicate); return(new AssignmentData { PredicateName = predicate.UnificationKey, NumArguments = assignments.CountArguments(), Assignments = assignments.Assignments.ToArray() }); }) .ToList(); }
/// <summary> /// Retrieves an object representing the assignments for a particular literal when used as a predicate /// </summary> public static PredicateAssignmentList FromPredicate(ILiteral predicate) { var result = new PredicateAssignmentList(); if (predicate.UnificationKey != null) { foreach (var argument in predicate.Dependencies) { result.AddArgument(argument); } } return(result); }
/// <summary> /// Retrieves an object representing the assignments for a particular literal when used as a predicate /// </summary> public static PredicateAssignmentList FromPredicate(ILiteral predicate) { var result = new PredicateAssignmentList(); if (predicate.UnificationKey != null) { foreach (var argument in predicate.Dependencies) { result.AddArgument(argument); } } return result; }
/// <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> /// Compiles a clause to a bytecode program /// </summary> public static void Compile(this IClause clause, ByteCodeProgram program) { var unifier = new ByteCodeUnifier(program); // Take each part of the clause and retrieve the assignments for it, with the 'implies' set at the start var allPredicates = new[] { clause.Implies }.Concat(clause.If).ToArray(); var assignmentList = allPredicates .Select(predicate => new { Assignments = PredicateAssignmentList.FromPredicate(predicate), UnificationKey = predicate.UnificationKey }) .ToArray(); // Allocate space for the arguments and any permanent variables var permanentVariables = PermanentVariableAssignments.PermanentVariables(assignmentList.Select(assign => assign.Assignments)); var numArguments = assignmentList[0].Assignments.CountArguments(); if (permanentVariables.Count > 0 || allPredicates.Length > 1) { program.Write(Operation.Allocate, permanentVariables.Count, numArguments); } // Unify with the predicate first unifier.ProgramUnifier.Bind(assignmentList[0].Assignments.Assignments, permanentVariables); unifier.ProgramUnifier.Compile(assignmentList[0].Assignments.Assignments); // Call the clauses foreach (var assignment in assignmentList.Skip(1)) { unifier.QueryUnifier.Bind(assignment.Assignments.Assignments, permanentVariables); unifier.QueryUnifier.Compile(assignment.Assignments.Assignments); program.Write(Operation.Call, assignment.UnificationKey, assignment.UnificationKey.Dependencies.Count()); } // Deallocate any permanent variables that we might have found if (permanentVariables.Count > 0 || allPredicates.Length > 1) { program.Write(Operation.Deallocate); } }