Exemple #1
0
        private static ArrayList prove(Hashtable cases, SelectableSource world, Statement[] goal, int maxNumberOfSteps)
        {
            // This is the main routine from euler.js.

            // cases: Resource (predicate) => IList of Sequent

            if (world != null)             // cache our queries to the world, if a world is provided
            {
                world = new SemWeb.Stores.CachedSource(world);
            }

            StatementMap cached_subproofs = new StatementMap();

            // Create the queue and add the first item.
            ArrayList queue = new ArrayList();
            {
                QueueItem start = new QueueItem();
                start.env    = new Hashtable();
                start.rule   = new Sequent(Statement.All, goal, null);
                start.src    = null;
                start.ind    = 0;
                start.parent = null;
                start.ground = new ArrayList();
                queue.Add(start);
                if (Debug)
                {
                    Console.Error.WriteLine("Euler: Queue: " + start);
                }
            }

            // The evidence array holds the results of this proof.
            ArrayList evidence = new ArrayList();

            // Track how many steps we take to not go over the limit.
            int step = 0;

            // Process the queue until it's empty or we reach our step limit.
            while (queue.Count > 0)
            {
                // deal with the QueueItem at the top of the queue
                QueueItem c = (QueueItem)queue[queue.Count - 1];
                queue.RemoveAt(queue.Count - 1);
                ArrayList g = new ArrayList(c.ground);

                // have we done too much?
                step++;
                if (maxNumberOfSteps != -1 && step >= maxNumberOfSteps)
                {
                    if (Debug)
                    {
                        Console.Error.WriteLine("Euler: Maximum number of steps exceeded.  Giving up.");
                    }
                    return(null);
                }

                // if each statement in the body of the sequent has been proved
                if (c.ind == c.rule.body.Length)
                {
                    // if this is the top-level sequent being proved; we've found a complete evidence for the goal
                    if (c.parent == null)
                    {
                        EvidenceItem ev = new EvidenceItem();
                        ev.head = new Statement[c.rule.body.Length];
                        bool canRepresentHead = true;
                        for (int i = 0; i < c.rule.body.Length; i++)
                        {
                            ev.head[i] = evaluate(c.rule.body[i], c.env);
                            if (ev.head[i].AnyNull)                             // can't represent it: literal in subject position, for instance
                            {
                                canRepresentHead = false;
                            }
                        }

                        ev.body = c.ground;
                        ev.env  = c.env;

                        if (Debug)
                        {
                            Console.Error.WriteLine("Euler: Found Evidence: " + ev);
                        }

                        if (!canRepresentHead)
                        {
                            continue;
                        }

                        evidence.Add(ev);

                        // this is a subproof of something; whatever it is a subgroup for can
                        // be incremented
                    }
                    else
                    {
                        // if the rule had no body, it was just an axiom and we represent that with Ground
                        if (c.rule.body.Length != 0)
                        {
                            g.Add(new Ground(c.rule, c.env));
                        }

                        // advance the parent being proved and put the advanced
                        // parent into the queue; unify the parent variable assignments
                        // with this one's
                        QueueItem r = new QueueItem();
                        r.rule   = c.parent.rule;
                        r.src    = c.parent.src;
                        r.ind    = c.parent.ind;
                        r.parent = c.parent.parent;
                        r.env    = (Hashtable)c.parent.env.Clone();
                        r.ground = g;
                        unify(c.rule.head, c.env, r.rule.body[r.ind], r.env, true);
                        r.ind++;
                        queue.Add(r);
                        if (Debug)
                        {
                            Console.Error.WriteLine("Euler: Queue Advancement: " + r);
                        }

                        // The number of live children for this parent is decremented since we are
                        // done with this subproof, but we store the result for later.
                        if (c.parent.solutions == null)
                        {
                            c.parent.solutions = new StatementList();
                        }
                        c.parent.solutions.Add(evaluate(r.rule.body[r.ind - 1], r.env));
                        decrementLife(c.parent, cached_subproofs);
                    }

                    // this sequent still has parts of the body left to be proved; try to
                    // find evidence for the next statement in the body, and if we find
                    // evidence, queue up that evidence
                }
                else
                {
                    // this is the next part of the body that we need to try to prove
                    Statement t = c.rule.body[c.ind];

                    // Try to process this predicate with a user-provided custom
                    // function that resolves things like mathematical relations.
                    // euler.js provides similar functionality, but the system
                    // of user predicates is completely different here.
                    RdfRelation b = FindUserPredicate(t.Predicate);
                    if (b != null)
                    {
                        Resource[] args;
                        Variable[] unifyResult;
                        Resource   value = evaluate(t.Object, c.env);

                        if (!c.rule.callArgs.ContainsKey(t.Subject))
                        {
                            // The array of arguments to this relation is just the subject of the triple itself
                            args        = new Resource[] { evaluate(t.Subject, c.env) };
                            unifyResult = new Variable[1];
                            if (t.Subject is Variable)
                            {
                                unifyResult[0] = (Variable)t.Subject;
                            }
                        }
                        else
                        {
                            // The array of arguments to this relation comes from a pre-grouped arg list.
                            args        = (Resource[])c.rule.callArgs[t.Subject];
                            unifyResult = new Variable[args.Length];

                            for (int i = 0; i < args.Length; i++)
                            {
                                if (args[i] is Variable)
                                {
                                    unifyResult[i] = (Variable)args[i];
                                    args[i]        = evaluate(args[i], c.env);
                                }
                            }
                        }

                        // Run the user relation on the array of arguments (subject) and on the object.
                        if (b.Evaluate(args, ref value))
                        {
                            // If it succeeds, we press on.

                            // The user predicate may update the 'value' variable and the argument
                            // list array, and so we want to unify any variables in the subject
                            // or object of this user predicate with the values given to us
                            // by the user predicate.
                            Hashtable newenv = (Hashtable)c.env.Clone();
                            if (t.Object is Variable)
                            {
                                unify(value, null, t.Object, newenv, true);
                            }
                            for (int i = 0; i < args.Length; i++)
                            {
                                if (unifyResult[i] != null)
                                {
                                    unify(args[i], null, unifyResult[i], newenv, true);
                                }
                            }

                            Statement grnd = evaluate(t, newenv);
                            if (grnd != Statement.All)                             // sometimes not representable, like if literal as subject
                            {
                                g.Add(new Ground(new Sequent(grnd, new Statement[0], null), new Hashtable()));
                            }

                            QueueItem r = new QueueItem();
                            r.rule   = c.rule;
                            r.src    = c.src;
                            r.ind    = c.ind;
                            r.parent = c.parent;
                            r.env    = newenv;
                            r.ground = g;
                            r.ind++;
                            queue.Add(r);

                            // Note: Since we are putting something back in for c, we don't touch the life counter on the parent.
                        }
                        else
                        {
                            // If the predicate fails, decrement the life of the parent.
                            decrementLife(c.parent, cached_subproofs);
                        }
                        continue;
                    }

                    // t can be proved either by the use of a rule
                    // or if t literally exists in the world

                    Statement t_resolved = evaluate(t, c.env);

                    // If resolving this statement requires putting a literal in subject or predicate position, we
                    // can't prove it.
                    if (t_resolved == Statement.All)
                    {
                        decrementLife(c.parent, cached_subproofs);
                        continue;
                    }

                    ArrayList tcases = new ArrayList();

                    // See if we have already tried to prove this.
                    if (cached_subproofs.ContainsKey(t_resolved))
                    {
                        StatementList cached_solutions = (StatementList)cached_subproofs[t_resolved];
                        if (cached_solutions == null)
                        {
                            if (Debug)
                            {
                                Console.Error.WriteLine("Euler: Dropping queue item because we have already failed to prove it: " + t_resolved);
                            }
                        }
                        else
                        {
                            foreach (Statement s in cached_solutions)
                            {
                                if (Debug)
                                {
                                    Console.Error.WriteLine("Euler: Using Cached Axiom:  " + s);
                                }
                                Sequent seq = new Sequent(s);
                                tcases.Add(seq);
                            }
                        }
                    }
                    else
                    {
                        // get all of the rules that apply to the predicate in question
                        if (t_resolved.Predicate != null && cases.ContainsKey(t_resolved.Predicate))
                        {
                            tcases.AddRange((IList)cases[t_resolved.Predicate]);
                        }

                        if (cases.ContainsKey("WILDCARD"))
                        {
                            tcases.AddRange((IList)cases["WILDCARD"]);
                        }

                        // if t has no unbound variables and we've matched something from
                        // the axioms, don't bother looking at the world, and don't bother
                        // proving it any other way than by the axiom.
                        bool lookAtWorld = true;
                        foreach (Sequent seq in tcases)
                        {
                            if (seq.body.Length == 0 && seq.head == t_resolved)
                            {
                                lookAtWorld = false;
                                tcases.Clear();
                                tcases.Add(seq);
                                break;
                            }
                        }

                        // if there is a seprate world, get all of the world
                        // statements that witness t
                        if (world != null && lookAtWorld)
                        {
                            MemoryStore w = new MemoryStore();

                            if (Debug)
                            {
                                Console.Error.WriteLine("Running " + c);
                            }
                            if (Debug)
                            {
                                Console.Error.WriteLine("Euler: Ask World: " + t_resolved);
                            }
                            world.Select(t_resolved, w);
                            foreach (Statement s in w)
                            {
                                if (Debug)
                                {
                                    Console.Error.WriteLine("Euler: World Select Response:  " + s);
                                }
                                Sequent seq = new Sequent(s);
                                tcases.Add(seq);
                            }
                        }
                    }

                    // If there is no evidence or potential evidence (i.e. rules)
                    // for t, then we will dump this QueueItem by not queuing any
                    // subproofs.

                    // Otherwise we try each piece of evidence in turn.
                    foreach (Sequent rl in tcases)
                    {
                        ArrayList g2 = (ArrayList)c.ground.Clone();
                        if (rl.body.Length == 0)
                        {
                            g2.Add(new Ground(rl, new Hashtable()));
                        }

                        QueueItem r = new QueueItem();
                        r.rule   = rl;
                        r.src    = rl;
                        r.ind    = 0;
                        r.parent = c;
                        r.env    = new Hashtable();
                        r.ground = g2;

                        if (unify(t, c.env, rl.head, r.env, true))
                        {
                            QueueItem ep = c;                              // euler path
                            while ((ep = ep.parent) != null)
                            {
                                if (ep.src == c.src && unify(ep.rule.head, ep.env, c.rule.head, c.env, false))
                                {
                                    break;
                                }
                            }
                            if (ep == null)
                            {
                                // It is better for caching subproofs to work an entire proof out before
                                // going on, which means we want to put the new queue item at the
                                // top of the stack.
                                queue.Add(r);
                                c.liveChildren++;
                                if (Debug)
                                {
                                    Console.Error.WriteLine("Euler: Queue from Axiom: " + r);
                                }
                            }
                        }
                    }

                    // If we did not add anything back into the queue for this item, then
                    // we decrement the life of the parent.
                    if (c.liveChildren == 0)
                    {
                        decrementLife(c.parent, cached_subproofs);
                    }
                }
            }

            return(evidence);
        }
Exemple #2
0
        private static ArrayList prove(Hashtable cases, SelectableSource world, Statement[] goal, int maxNumberOfSteps)
        {
            // This is the main routine from euler.js.

            // cases: Resource (predicate) => IList of Sequent

            if (world != null) // cache our queries to the world, if a world is provided
                world = new SemWeb.Stores.CachedSource(world);

            StatementMap cached_subproofs = new StatementMap();

            // Create the queue and add the first item.
            ArrayList queue = new ArrayList();
            {
                QueueItem start = new QueueItem();
                start.env = new Hashtable();
                start.rule = new Sequent(Statement.All, goal, null);
                start.src = null;
                start.ind = 0;
                start.parent = null;
                start.ground = new ArrayList();
                queue.Add(start);
                if (Debug) Console.Error.WriteLine("Euler: Queue: " + start);
            }

            // The evidence array holds the results of this proof.
            ArrayList evidence = new ArrayList();

            // Track how many steps we take to not go over the limit.
            int step = 0;

            // Process the queue until it's empty or we reach our step limit.
            while (queue.Count > 0) {
                // deal with the QueueItem at the top of the queue
                QueueItem c = (QueueItem)queue[queue.Count-1];
                queue.RemoveAt(queue.Count-1);
                ArrayList g = new ArrayList(c.ground);

                // have we done too much?
                step++;
                if (maxNumberOfSteps != -1 && step >= maxNumberOfSteps) {
                    if (Debug) Console.Error.WriteLine("Euler: Maximum number of steps exceeded.  Giving up.");
                    return null;
                }

                // if each statement in the body of the sequent has been proved
                if (c.ind == c.rule.body.Length) {
                    // if this is the top-level sequent being proved; we've found a complete evidence for the goal
                    if (c.parent == null) {
                        EvidenceItem ev = new EvidenceItem();
                        ev.head = new Statement[c.rule.body.Length];
                        bool canRepresentHead = true;
                        for (int i = 0; i < c.rule.body.Length; i++) {
                            ev.head[i] = evaluate(c.rule.body[i], c.env);
                            if (ev.head[i].AnyNull) // can't represent it: literal in subject position, for instance
                                canRepresentHead = false;
                        }

                        ev.body = c.ground;
                        ev.env = c.env;

                        if (Debug) Console.Error.WriteLine("Euler: Found Evidence: " + ev);

                        if (!canRepresentHead)
                            continue;

                        evidence.Add(ev);

                    // this is a subproof of something; whatever it is a subgroup for can
                    // be incremented
                    } else {
                        // if the rule had no body, it was just an axiom and we represent that with Ground
                        if (c.rule.body.Length != 0) g.Add(new Ground(c.rule, c.env));

                        // advance the parent being proved and put the advanced
                        // parent into the queue; unify the parent variable assignments
                        // with this one's
                        QueueItem r = new QueueItem();
                        r.rule = c.parent.rule;
                        r.src = c.parent.src;
                        r.ind = c.parent.ind;
                        r.parent = c.parent.parent;
                        r.env = (Hashtable)c.parent.env.Clone();
                        r.ground = g;
                        unify(c.rule.head, c.env, r.rule.body[r.ind], r.env, true);
                        r.ind++;
                        queue.Add(r);
                        if (Debug) Console.Error.WriteLine("Euler: Queue Advancement: " + r);

                        // The number of live children for this parent is decremented since we are
                        // done with this subproof, but we store the result for later.
                        if (c.parent.solutions == null)
                            c.parent.solutions = new StatementList();
                        c.parent.solutions.Add(evaluate(r.rule.body[r.ind-1], r.env));
                        decrementLife(c.parent, cached_subproofs);
                    }

                // this sequent still has parts of the body left to be proved; try to
                // find evidence for the next statement in the body, and if we find
                // evidence, queue up that evidence
                } else {
                    // this is the next part of the body that we need to try to prove
                    Statement t = c.rule.body[c.ind];

                    // Try to process this predicate with a user-provided custom
                    // function that resolves things like mathematical relations.
                    // euler.js provides similar functionality, but the system
                    // of user predicates is completely different here.
                    RdfRelation b = FindUserPredicate(t.Predicate);
                    if (b != null) {
                        Resource[] args;
                        Variable[] unifyResult;
                        Resource value = evaluate(t.Object, c.env);

                        if (!c.rule.callArgs.ContainsKey(t.Subject)) {
                            // The array of arguments to this relation is just the subject of the triple itself
                            args = new Resource[] { evaluate(t.Subject, c.env) };
                            unifyResult = new Variable[1];
                            if (t.Subject is Variable) unifyResult[0] = (Variable)t.Subject;

                        } else {
                            // The array of arguments to this relation comes from a pre-grouped arg list.
                            args = (Resource[])((ICloneable)c.rule.callArgs[t.Subject]).Clone();
                            unifyResult = new Variable[args.Length];

                            for (int i = 0; i < args.Length; i++) {
                                if (args[i] is Variable) {
                                    unifyResult[i] = (Variable)args[i];
                                    args[i] = evaluate(args[i], c.env);
                                }
                            }
                        }

                        // Run the user relation on the array of arguments (subject) and on the object.
                        if (b.Evaluate(args, ref value)) {
                            // If it succeeds, we press on.

                            // The user predicate may update the 'value' variable and the argument
                            // list array, and so we want to unify any variables in the subject
                            // or object of this user predicate with the values given to us
                            // by the user predicate.
                            Hashtable newenv = (Hashtable)c.env.Clone();
                            if (t.Object is Variable) unify(value, null, t.Object, newenv, true);
                            for (int i = 0; i < args.Length; i++)
                                if (unifyResult[i] != null)
                                    unify(args[i], null, unifyResult[i], newenv, true);

                            Statement grnd = evaluate(t, newenv);
                            if (grnd != Statement.All) // sometimes not representable, like if literal as subject
                                g.Add(new Ground(new Sequent(grnd, new Statement[0], null), new Hashtable()));

                            QueueItem r = new QueueItem();
                            r.rule = c.rule;
                            r.src = c.src;
                            r.ind = c.ind;
                            r.parent = c.parent;
                            r.env = newenv;
                            r.ground = g;
                            r.ind++;
                            queue.Add(r);

                            // Note: Since we are putting something back in for c, we don't touch the life counter on the parent.

                        } else {
                            // If the predicate fails, decrement the life of the parent.
                            if (c.parent != null)
                                decrementLife(c.parent, cached_subproofs);
                        }
                        continue;
                    }

                    // t can be proved either by the use of a rule
                    // or if t literally exists in the world

                    Statement t_resolved = evaluate(t, c.env);

                    // If resolving this statement requires putting a literal in subject or predicate position, we
                    // can't prove it.
                    if (t_resolved == Statement.All) {
                        if (c.parent != null)
                            decrementLife(c.parent, cached_subproofs);
                        continue;
                    }

                    ArrayList tcases = new ArrayList();

                    // See if we have already tried to prove this.
                    if (cached_subproofs.ContainsKey(t_resolved)) {
                        StatementList cached_solutions = (StatementList)cached_subproofs[t_resolved];
                        if (cached_solutions == null) {
                            if (Debug) Console.Error.WriteLine("Euler: Dropping queue item because we have already failed to prove it: " + t_resolved);
                        } else {
                            foreach (Statement s in cached_solutions) {
                                if (Debug) Console.Error.WriteLine("Euler: Using Cached Axiom:  " + s);
                                Sequent seq = new Sequent(s);
                                tcases.Add(seq);
                            }
                        }
                    } else {
                        // get all of the rules that apply to the predicate in question
                        if (t_resolved.Predicate != null && cases.ContainsKey(t_resolved.Predicate))
                            tcases.AddRange((IList)cases[t_resolved.Predicate]);

                        if (cases.ContainsKey("WILDCARD"))
                            tcases.AddRange((IList)cases["WILDCARD"]);

                        // if t has no unbound variables and we've matched something from
                        // the axioms, don't bother looking at the world, and don't bother
                        // proving it any other way than by the axiom.
                        bool lookAtWorld = true;
                        foreach (Sequent seq in tcases) {
                            if (seq.body.Length == 0 && seq.head == t_resolved) {
                                lookAtWorld = false;
                                tcases.Clear();
                                tcases.Add(seq);
                                break;
                            }
                        }

                        // if there is a seprate world, get all of the world
                        // statements that witness t
                        if (world != null && lookAtWorld) {
                            MemoryStore w = new MemoryStore();

                            if (Debug) Console.Error.WriteLine("Running " + c);
                            if (Debug) Console.Error.WriteLine("Euler: Ask World: " + t_resolved);
                            world.Select(t_resolved, w);
                            foreach (Statement s in w) {
                                if (Debug) Console.Error.WriteLine("Euler: World Select Response:  " + s);
                                Sequent seq = new Sequent(s);
                                tcases.Add(seq);
                            }
                        }
                    }

                    // If there is no evidence or potential evidence (i.e. rules)
                    // for t, then we will dump this QueueItem by not queuing any
                    // subproofs.

                    // Otherwise we try each piece of evidence in turn.
                    foreach (Sequent rl in tcases) {
                        ArrayList g2 = (ArrayList)c.ground.Clone();
                        if (rl.body.Length == 0) g2.Add(new Ground(rl, new Hashtable()));

                        QueueItem r = new QueueItem();
                        r.rule = rl;
                        r.src = rl;
                        r.ind = 0;
                        r.parent = c;
                        r.env = new Hashtable();
                        r.ground = g2;

                        if (unify(t, c.env, rl.head, r.env, true)) {
                            QueueItem ep = c;  // euler path
                         	while ((ep = ep.parent) != null)
                          		if (ep.src == c.src && unify(ep.rule.head, ep.env, c.rule.head, c.env, false))
                          			break;
                         	if (ep == null) {
                                // It is better for caching subproofs to work an entire proof out before
                                // going on, which means we want to put the new queue item at the
                                // top of the stack.
                         		queue.Add(r);
                                c.liveChildren++;
                         		if (Debug) Console.Error.WriteLine("Euler: Queue from Axiom: " + r);
                         	}
                        }
                    }

                    // If we did not add anything back into the queue for this item, then
                    // we decrement the life of the parent.
                    if (c.liveChildren == 0 && c.parent != null)
                        decrementLife(c.parent, cached_subproofs);
                }
            }

            return evidence;
        }