/// <summary> /// Ask the knowledge base if a given statement about the model is true, given what it knows. /// </summary> /// <param name="query"></param> /// <returns>True if the statement is known to be true, false if it is known to be false or cannot be determined.</returns> public bool Ask(Expression <Predicate <TModel> > query) { // NB: Very raw implementation - there are a number of possible performance improvements that could be made here // Will return to give them a go at some point.. var queryAsCnf = new CNFExpression <TModel>(query); var clauses = sentences.Append(queryAsCnf).SelectMany(s => s.Clauses).ToList(); List <CNFClause <TModel> > newClauses = new List <CNFClause <TModel> >(); while (true) { // TODO-PERFORMANCE: While this is how the source book writes the algorithm, its very inefficient - // we'll end up resolving the same clauses again and again. Need to improve this (and move this // implementation to the benchmarks project as a baseline). foreach (var ci in clauses) { foreach (var cj in clauses) { var resolvents = CNFClause <TModel> .Resolve(ci, cj); if (resolvents.IsEmpty) { return(true); } newClauses.Add(resolvents); } } // if new ⊆ clauses then return false // need clause equality.. clauses.AddRange(newClauses); } return(false); }
public void NeedsNormalisation() { var e = new CNFExpression <MyModel>(PLExpression <MyModel> .Iff(m => m.L, m => m.R1 || m.R2)); e.ShouldHaveState(clauseCount: 3); e.Clauses.ElementAt(0).ShouldHaveState( isDefiniteClause: false, isGoalClause: false, isHornClause: false, isUnitClause: false, literalCount: 3); e.Clauses.ElementAt(0).Literals.ElementAt(0).ShouldHaveState( atomicSentenceSymbol: "m.L", isNegated: true); e.Clauses.ElementAt(0).Literals.ElementAt(1).ShouldHaveState( atomicSentenceSymbol: "m.R1", isNegated: false); e.Clauses.ElementAt(0).Literals.ElementAt(2).ShouldHaveState( atomicSentenceSymbol: "m.R2", isNegated: false); e.Clauses.ElementAt(1).ShouldHaveState( isDefiniteClause: true, isGoalClause: false, isHornClause: true, isUnitClause: false, literalCount: 2); e.Clauses.ElementAt(1).Literals.ElementAt(0).ShouldHaveState( atomicSentenceSymbol: "m.R1", isNegated: true); e.Clauses.ElementAt(1).Literals.ElementAt(1).ShouldHaveState( atomicSentenceSymbol: "m.L", isNegated: false); e.Clauses.ElementAt(2).ShouldHaveState( isDefiniteClause: true, isGoalClause: false, isHornClause: true, isUnitClause: false, literalCount: 2); e.Clauses.ElementAt(2).Literals.ElementAt(0).ShouldHaveState( atomicSentenceSymbol: "m.R2", isNegated: true); e.Clauses.ElementAt(2).Literals.ElementAt(1).ShouldHaveState( atomicSentenceSymbol: "m.L", isNegated: false); }
public void UnitClause() { var e = new CNFExpression <MyModel>(m => m.L); e.ShouldHaveState(clauseCount: 1); e.Clauses.Single().ShouldHaveState( isDefiniteClause: true, isGoalClause: false, isHornClause: true, isUnitClause: true, literalCount: 1); e.Clauses.Single().Literals.Single().ShouldHaveState( atomicSentenceSymbol: "m.L", isNegated: false); }
public static void ShouldHaveState( this CNFExpression <MyModel> expression, int clauseCount) { Assert.Equal(clauseCount, expression.Clauses.Count); }