// try to bind the variable associated with the last of search alternatives // (t1|t2|...|tn) to the target term found matching one of these alternatives bool TryBindingAltListVarToMatch (BaseTerm AltListVar, BaseTerm searchTerm, VarStack varStack) { if (AltListVar == null) return true; return AltListVar.Unify (searchTerm, varStack); }
// try to bind the range specification variable (if present) to the range last. // if the minimun or the maximum range length was a variable, then bind it to the actual length just found bool TryBindingRangeRelatedVars (ListPatternElem g, int rangeLength, ListTerm RangeList, VarStack varStack) { if (g.MinLenTerm.IsVar) g.MinLenTerm.Unify (new DecimalTerm (rangeLength), varStack); if (g.MaxLenTerm.IsVar) g.MaxLenTerm.Unify (new DecimalTerm (rangeLength), varStack); if (g.RangeBindVar != null) { if (RangeList == null) RangeList = ListTerm.EMPTYLIST; if (!g.RangeBindVar.Unify (RangeList, varStack)) return false; // alas, the same range var was apparently used & bound earlier in the pattern } return true; }
// each call processes one element of pattern[] bool UnifyTailEx (int ip, int it, VarStack varStack) { ListPatternElem e = (ListPatternElem)pattern [ip]; Variable rangeSpecVar = (Variable)e.RangeBindVar; NodeIterator subtreeIterator; int k; int marker; ListTerm RangeList = null; BaseTerm tail = null; int minLen; // minimum required range length (number of range elements) int maxLen; // maximum possible ... if (!DoLowerAndUpperboundChecks (ip, it, out minLen, out maxLen)) return false; // scan the minimal number of range elements. Add them to the range last, // i.e. the last variable (if present) preceding the '{ , }' for (int i = 0; i < minLen; i++) { if ((k = it + i) >= target.Count) return false; AppendToRangeList (ref RangeList, rangeSpecVar, target [k], ref tail); } marker = varStack.Count; // register the point to which we must possibly undo unifications if (e.HasSearchTerm) { // scan the elements up to the maximum range length, and the element immediately thereafter for (int i = minLen; i <= maxLen; i++) { BaseTerm t = null; k = it + i; if (k == target.Count) return false; bool negSearchSucceeded = true; // iff none of the alternative term matches the target term for (int j = 4; j < e.Args.Length; j++) // scan all AltSearchTerm alternatives (separated by '|') { BaseTerm searchTerm = e.AltSearchTerms [j]; DownRepFactor downRepFactor = null; // e.downRepFactor [j]; t = target [k]; AltLoopStatus status = AltLoopStatus.TryNextAlt; if (downRepFactor == null) { status = TryOneAlternative (ip, varStack, e, k, marker, RangeList, i, t, ref negSearchSucceeded, searchTerm); if (status == AltLoopStatus.MatchFound) return true; } else // traverse the downRepFactor tree, which in principle may yield more than one match { subtreeIterator = new NodeIterator (t, searchTerm, downRepFactor.minLenTerm, downRepFactor.maxLenTerm, downRepFactor.bindVar, varStack); foreach (BaseTerm match in subtreeIterator) // try -- if necessary -- each tree match with the current search term { status = TryOneAlternative (ip, varStack, e, k, marker, RangeList, i, match, ref negSearchSucceeded, searchTerm); if (status == AltLoopStatus.MatchFound) return true; if (status == AltLoopStatus.Break) break; } } if (status == AltLoopStatus.Break) break; } // at this point sufficient alternatives have been tried if (e.IsNegSearch && negSearchSucceeded) // none of the terms matched => ok if binding succeeds { if (!TryBindingAltListVarToMatch (e.AltListBindVar, t, varStack) || // bind the AltListBindVar to the match !TryBindingRangeRelatedVars (e, i, RangeList, varStack)) // bind the range to the range variables return false; // binding failed if (ip == pattern.Length - 1) // this was the last pattern element { if (k == target.Count - 1) // both pattern and target exhausted return true; } else if (UnifyTailEx (ip + 1, k + 1, varStack)) // now deal with the rest return true; } else if (i < maxLen) // append the rejected term to the range last and go try the next term AppendToRangeList (ref RangeList, rangeSpecVar, t, ref tail); } } else // a range without a subsequent search term (so followed by another range or end of pattern) { for (int i = minLen; i <= maxLen; i++) { k = it + i; if (k == target.Count) // ok, target[k] does not exist, end of target hit return TryBindingRangeRelatedVars (e, i, RangeList, varStack); // i is actual range length // k is ok if (i < maxLen) AppendToRangeList (ref RangeList, rangeSpecVar, target [k], ref tail); // now deal with the rest if (TryBindingRangeRelatedVars (e, i, RangeList, varStack) && UnifyTailEx (ip + 1, k, varStack)) return true; } } // If we arrive here, no matching term was found in or immediately after the permitted range. // Therefore, undo any unifications made locally in this method and return with failure. if (marker != 0) BaseTerm.UnbindToMarker (varStack, marker); return false; }
private AltLoopStatus TryOneAlternative (int ip, VarStack varStack, ListPatternElem e, int k, int marker, ListTerm RangeList, int i, BaseTerm t, ref bool negSearchSucceeded, BaseTerm searchTerm) { bool unified = searchTerm.Unify (t, varStack); if (e.IsNegSearch) // none of the terms in the inner loop may match. ~(a | b | c) = ~a & ~b & ~c { if (unified) // ... no point in investigating the other alternatives if one does { negSearchSucceeded = false; return AltLoopStatus.Break; // don't try the other alternatives } return AltLoopStatus.TryNextDown; // non of the downranges matches may lead to a success } else { if (unified && // we found a match. Unify, and TryBindingAltListVarToMatch (e.AltListBindVar, t, varStack) && // bind the AltListBindVar to the match TryBindingRangeRelatedVars (e, i, RangeList, varStack)) // bind the range to the range variables { if (ip == pattern.Length - 1) // this was the last pattern element { if (k == target.Count - 1) // both pattern and target exhausted return AltLoopStatus.MatchFound; } else if (UnifyTailEx (ip + 1, k + 1, varStack)) // now deal with the rest return AltLoopStatus.MatchFound; } // if we arrive here, it was not possible to ... // (1) ... unify the range's SearchTerm with the target element, or // (2) ... unify the range variable with the range last, or // (3) ... successfully process the rest of the pattern and target // Now unbind and try matching with the next target element BaseTerm.UnbindToMarker (varStack, marker); return AltLoopStatus.TryNextDown; // try the next downrange match } }
public override bool Unify (BaseTerm t, VarStack varStack) { NextUnifyCount (); if (!((t = t.ChainEnd ()) is ListPatternElem)) return false; // should never occur #if old if (isNegSearch != ((ListPatternElem)t).isNegSearch) return false; #endif for (int i = 0; i < arity; i++) if (!((args [i] == null && t.Args [i] == null) || args [i].Unify (t.Args [i], varStack))) return false; return true; }
public override bool Unify (BaseTerm t, VarStack varStack) { if ((t = t.ChainEnd ()) is Variable) // t not unified { ((Variable)t).Bind (this); varStack.Push (t); return true; } if (t is ListPatternTerm && arity == t.Arity) // two ListPatternTerms match if their rangeTerms match { for (int i = 0; i < arity; i++) if (!args [i].Unify (t.Args [i], varStack)) return false; return true; } if (t is ListTerm) { pattern = args; // pattern is searched ... target = ((ListTerm)t).ToList (); // ... in target int ip = 0; int it = 0; return UnifyTailEx (ip, it, varStack); } return false; }
public bool Retract(Term t, VarStack varStack, Term where) { string key = t.KbKey; if (predefineds.Contains(key)) PrologIO.Error("retract of predefined predicate {0} not allowed", key); PredicateDescr pd = this[key]; if (pd == null) return false; #if persistent if (pd is PersistentPredDescr) { ((PersistentPredDescr)pd).Retract (t, varStack, where); return true; } #endif ClauseNode c = pd.GetClauseList(null, null); ClauseNode prevc = null; Term cleanTerm; int top; while (c != null) { cleanTerm = c.Term.CleanCopy(); top = varStack.Count; if (cleanTerm.Unify(t, varStack)) // match found -- remove this term from the chain { if (prevc == null) // remove first clause { if (c.NextClause == null) // we are about to remove the last remaining clause for this predicate { predTable.Remove(key); // ... so remove its PredicateDescr as well #if arg1index pd.CreateFirstArgIndex (); // re-create #endif ResolveIndices(); } else pd.SetClauseListHead(c.NextClause); } else // not the first { prevc.NextClause = c.NextClause; prevc = c; pd.AdjustClauseListEnd(); #if arg1index pd.CreateFirstArgIndex (); // re-create #endif } return true; // possible bindings must stay intact (e.g. if p(a) then retract(p(X)) yields X=a) } Term s; for (int i = varStack.Count - top; i > 0; i--) // unbind all vars that got bound by the above Unification { s = (Term)varStack.Pop(); s.Unbind(); } prevc = c; c = c.NextClause; } ResolveIndices(); return false; }
public bool RetractAll(Term t, VarStack varStack) // should *always* return true ????? { // remark: first-argument indexing is not affected by deleting clauses string key = t.KbKey; if (predefineds.Contains(key)) PrologIO.Error("retract of predefined predicate {0} not allowed", key); PredicateDescr pd = this[key]; if (pd == null) return true; #if persistent if (pd is PersistentPredDescr) { ((PersistentPredDescr)pd).Retract (t, varStack, null); return true; /////////////JPO persistent retract always to succeed ???? } #endif ClauseNode c = pd.GetClauseList(null, null); ClauseNode prevc = null; bool match = false; while (c != null) { Term cleanTerm = c.Term.CleanCopy(); if (cleanTerm.Unifiable(t, varStack)) // match found -- remove this term from the chain { match = true; // to indicate that at least one term was found if (prevc == null) // remove first clause { if (c.NextClause == null) // we are about to remove the last remaining clause for this predicate { predTable.Remove(key); // ... so remove its PredicateDescr as well break; } else pd.SetClauseListHead(c.NextClause); } else // not the first { prevc.NextClause = c.NextClause; prevc = c; } } else prevc = c; c = c.NextClause; } if (match) { #if arg1index pd.DestroyFirstArgIndex (); // rebuild by ResolveIndices() #endif pd.AdjustClauseListEnd(); ResolveIndices(); } return true; }
public override void Retract (Term Term, VarStack stack, Term where) { StringBuilder deleteStat = new StringBuilder ("DELETE FROM " + dbEntity); TableColumnCollection tcc = (TableColumnCollection)MetaDataCollection; ListDictionary varNrs = new ListDictionary (); bool first = true; for (int i = 0; i < Term.Arity; i++) { Term arg = Term.Arg (i); string colName = tcc [i].Name; if (arg.IsAtom || arg.IsString) deleteStat.AppendFormat ("{0} {1}={2}", Conj (ref first), colName, Utils.EnsureQuoted (arg.Functor)); else if (arg.IsNumber) deleteStat.AppendFormat ("{0} {1}={2}", Conj (ref first), colName, arg.Functor); else if (arg.IsVar) { object prevColNo; // check whether value occurred as argument before (anonymous vars always have a unique varNo) if ((prevColNo = varNrs [arg.VarNo]) != null) // ... yes deleteStat.AppendFormat ("{0} {1}={2}", Conj (ref first), tcc [(int)prevColNo].Name, colName); varNrs [arg.VarNo] = i; // save for comparison with next argument(s) } else if (!arg.IsVar) IO.Error ("Illegal argument {0} for retract of persistent clause {1}", arg, Term); } if (where != null) // add the extra where-clause (if any) { // Copy the ref-table of column numers into a ref-table of corresponding column names ListDictionary varNames = new ListDictionary (); // ... in-situ modifications of Collection-values is not possible foreach (DictionaryEntry de in varNrs) varNames [(int)de.Key] = tcc [(int)de.Value].Name; deleteStat.AppendFormat ("{0} {1}", Conj (ref first), where.ToStringSql (varNames)); } if (first) IO.Warning ("Retract -- DELETE without WHERE -- will NOT be executed !!!!!!!!"); else ExecuteSqlCommand (deleteStat.ToString ()); }
public override void Retract (Term Term, VarStack stack, Term where) { IO.Error ("Unable to delete from '{0}' (not a table)", dbEntity); }
public abstract void Retract (Term Term, VarStack stack, Term where);
public void NumberVars(ref int k, VarStack s) { Term t; if (hasValue) { if (isUnified) ULink.NumberVars(ref k, s); else if (arity != 0) // hasValue & not isUnified for (int i = 0; i < arity; i++) args[i].NumberVars(ref k, s); } else // unbound variable { Term a = new Term(k.ToString(), FType.number); k++; t = new Term("'$VAR'", a, OType.noop, 0); this.Unify(t, s); } }
public bool Unifiable(Term t, VarStack varStack) // as Unify, but does not actually bind { int top = varStack.Count; bool result = Unify(t, varStack); for (int i = varStack.Count - top; i > 0; i--) // unbind all varNoSet that got bound by Unify { Term s = (Term)varStack.Pop(); s.Unbind(); } return result; }
public bool Unify(Term t, VarStack varStack, bool occurCheck) { if (isUnified) return ULink.Unify(t, varStack, occurCheck); if (t.isUnified) return Unify(t.ULink, varStack, occurCheck); //Interpreter.UCount++; if (hasValue) { if (t.hasValue) { if (_functor.Equals(t._functor) && arity == t.Arity) // => two cuts will unify as well { for (int i = 0; i < arity; i++) if (!args[i].Unify(t.Arg(i), varStack, occurCheck)) return false; return true; } else return false; } // t is an unbound variable (add occur check here if deemed necessary) t.Bind(this); varStack.Push(t); } else // 'this' is an unbound variable. Add occur check here if deemed necessary { this.Bind(t); varStack.Push(this); } return true; }
// UNIFICATION // The stack is used to store the variables and choice points that are bound by the unification. // This is needed when backtracking. Unify does not do any unbinding in case of failure. This will // be done when backtracking. public bool Unify(Term t, VarStack varStack) { return Unify(t, varStack, false); }