Find path between 2 points from given connections - prolog

I want to solve a typical Prolog problem from here in Ocaml
Connections are represented by following data:
arc(1,2).
arc(2,3).
arc(3,4).
arc(3,5).
arc(2,5).
arc(5,6).
arc(2,6).
One has to find a path given start and end points (solution to be stored in P), e.g.:
?- path(1,6,P).
Prolog code for this is as follows:
path(X,Y,[arc(X,Y)]) :- arc(X,Y).
path(X,Y,[arc(X,Z)|P]) :- arc(X,Z),path(Z,Y,P).
Output will be as:
P = [arc(1, 2), arc(2, 6)] .
I see that that there are many pattern matching capabilities in Ocaml. How can above problem be solved in Ocaml?
Edit: I am not insisting on unification method.

OCaml is not a logic programming language. It is a conventional multi-paradigm, functional, imperative, and object-oriented language. So there are no builtin constructs for solving logical problems (beyond type checking) or anything like this.
However, your problem is a typical graph problem, so you can use any graph library available in OCaml, to solve it, here is the solution implemented using Graphlib's shortest path algorithm, which implements the classical Dijkstra's algorithm
open Core_kernel
open Graphlib.Std
module G = Graphlib.Make(Int)(Unit)
let graph = Graphlib.create (module G) () ~edges:[
1,2,();
2,3,();
3,4,();
3,5,();
2,5,();
5,6,();
2,6,();
]
let () =
match Graphlib.shortest_path (module G) graph 1 6 with
| None -> printf "No path\n"
| Some p ->
Path.edges p |> Sequence.iter ~f:(fun e ->
printf "Arc(%d, %d)\n" (G.Edge.src e) (G.Edge.dst e))
You can install graphlib using opam
opam install graphlib
then, if you put your program in a separate folder and name, let's say, check_path.ml, you can built and run it using ocamlbuild, e.g.
$ ocamlbuild -package graphlib check_path.native --
Arc(1, 2)
Arc(2, 6)

Related

Problog mpe with annotated disjunctions

I'm writing a problog program over a set of triples showing the location of some objects. The goal is to find the most probable feasible world that satisfy all the non-probabilistic rules. (I'm using problog-MPE).
When I run the following:
0.4::t(a,right,b);0.6::t(a,left,b).
0.4::t(b,right,a);0.6::t(b,left,a).
0.4::t(c,right,a);0.6::t(c,left,a).
t(Y,left,X) :- t(X,right,Y).
t(Y,right,X) :- t(X,left,Y).
query(t(_,_,_)).
I obtain a solution that is not feasible (since right and left predicate are in the annotated disjunction for pairs a,b and b,a).
t(a,right,b)
t(a,left,b)
t(b,right,a)
t(b,left,a)
\+(c,right,a)
(c,left,a)
(a,right,c)
\+(a,left,c)
% Probability: 0.216
How can I write a program in which I force the XOR disjunction?
I would expect/want either one of these 2 solutions:
t(a,right,b)
t(b,left,a)
\+(c,right,a)
(c,left,a)
(a,right,c)
\+(a,left,c)
or
t(a,left,b)
t(b,right,a)
\+(c,right,a)
(c,left,a)
(a,right,c)
\+(a,left,c)
How can I write a program to obtain this?

Are both of these ways correct to do beta reduction?

First way: (λz.(λx.x) z) -> (x)[x->z] -> (λz.z)
Second way: (λz.(λx.x) z) -> (λx.x)[z->z] -> (λx.x)
Any lambda calculus online calculator I'm using only provides the first way as a solution, whatever strategy I set on it, and I can't seem to figure out why the second way is not correct.

How can I use rules suggested by solve_direct? (by (rule …) doesn't always work)

Sometimes <statement> solve_direct (which I usually invoke via <statement> try) lists a number of library theorems and says “The current goal can be solved directly with: …”.
Let <theorem> be one search result of solve_direct, then in most cases I can prove <statement> by (rule theorem).
Sometimes, however, such a proof is not accepted, resulting in the error message “Failed to apply initial proof method”.
Is there a general, different technique for reusing theorems found by solve_direct?
Or does it depend on the individual situation? I could try to work out a minimal example and attach it to this question.
Personally, I just tend to just use:
apply (metis thm)
which works most of the time without forcing me to think very hard (but will still occasionally fail if tricky resolution is required).
Other methods that will also typically work include:
apply (rule thm) (* If "thm" has no premises. *)
apply (erule thm) (* If "thm" has a single premise. *)
apply (erule thm, assumption+) (* If "thm" has multiple premises. *)
Why is there no one single answer? The answer is a little complex:
Internally, solve_direct calls find_theorems solves, which then performs the following:
fun etacn thm i = Seq.take (! tac_limit) o etac thm i;
(* ... *)
if Thm.no_prems thm then rtac thm 1 goal
else (etacn thm THEN_ALL_NEW (Goal.norm_hhf_tac THEN' Method.assm_tac ctxt)) 1 goal;
This is the ML code for something similar to rule thm if there are no premises on the rule, or:
apply (erule thm, assumption+)
if there are multiple premises on the rule. As commented by Brian on your question, the above might still fail if there are complex meta-logical connectives in the assumptions (which the norm_hhf_tac deals with, but is not directly exposed as an Isabelle method as far as I am aware).
If you wanted, you could write a new method that exposes the tactic used by find_theorems directly, as follows:
ML {*
fun solve_direct_tac thm ctxt goal =
if Thm.no_prems thm then rtac thm 1 goal
else (etac thm THEN_ALL_NEW (Goal.norm_hhf_tac THEN' Method.assm_tac ctxt)) 1 goal;
*}
method_setup solve =
{* Attrib.thm >> (fn thm => fn ctxt =>
SIMPLE_METHOD' (K (solve_direct_tac thm ctxt ))) *}
"directly solve a rule"
This could then be used as follows:
lemma "⟦ a; b ⟧ ⟹ a ∧ b"
by (solve conjI)
which should hopefully solve anything solve_direct throws at you.
I found another way of using solve_direct's suggestions with by rule. When certain very basic rules from the library, such as Hilbert_Choice.someI2, are suggested, it seems that one of the facts in context actually is a rule itself, which may be applicable. The following worked for me at least in two concrete situations (source):
re-examine the “rule-like” fact, the other facts (if any) and the goal
if necessary, reorder the other facts
do the proof using <other_facts> ... by (rule <rule-like-fact>)
You can try fact or rule_tac. If I recall correctly, rule sometimes fails to apply a given rule in the presence of other facts and I am not entirely sure why; that question will have to be answered by someone who is more familiar with the implementation details of these methods than I am.

Infinite recursion in Haskell

This question is essentially a duplicate of Debugging infinite loops in Haskell programs with GHCi. The author there solved it manually, though I'd like to know other solutions.
(my particular problem)
I have an arrow code which contains a recursive invocation,
testAVFunctor = proc x -> do
y <- errorArrow "good error" -< x
z <- isError -< y
(passError ||| testAVFunctor) -< trace "value of z" z
The errorArrow should make the recursive testAVFunctor not execute, since that will cause isError to return a Left (AVError "good error") which should in turn choose the passError route and bypass the recursive call.
The very odd thing is that inserting "trace" calls at popular sites like the function composition results in the program emitting a finite amount of output, then freezing. Not what I'd expect from an infinite term expansion problem. (see edit 1)
I've uploaded my source code here if anyone is so curious.
EDIT 1
I wasn't looking in the right place (if you care to look at the source, apparently avEither was looping). The way I got there was by compiling a binary, and running gdb:
gdb Main
r (runs code)
Ctrl+C (send interrupt). The backtrace will be useless, but what you can do, is hit
s (step). Then, hold down the enter key; you should see a lot of method names fly by. Hopefully one of them will be recognizable.
You can compile with ghc flag -O0 to disable optimization, which can reveal more method names.
EDIT 3
Apparently, the proc x -> do block above was causing the code to generate combinators, which were calling the AVFunctor.arr lifting method to be called -- something in there must be violating laziness. If I rewrite the top level function as
testAVFunctor = errorArrow "good error" >>>
isError >>> (passError ||| testAVFunctor)
then everything works fine. I guess it's time to try learning and using garrows (by a grad student here at Berkeley).
My general takeaway from the experience is that ghci debugging can be frustrating. For example, I managed to make the argument f of AVFunctor.arr show up as a local variable, but I can't get anything terribly informative from it:
> :i f
f :: b -> c -- <no location info>
Revised source code is here
Keep in mind that the meaning of (|||) depends on the arrow, and testAVFunctor is an infinite object of your arrow:
testAVFunctor = proc x -> do
...
(passError ||| proc x -> do
...
(passError ||| proc x -> ...) -< trace "value of z" z)
-< trace "value of z" z
I'm not sure if you were aware of that. Examine the definition of (|||) (or if there isn't one, left) to see if it can handle infinite terms. Also check (>>>) (er, (.) in modern versions I think). Make sure the combinators are not strict, because then an infinite term will diverge. This may involve making patterns lazier with ~ (I have had to do this a lot when working with arrows). The behavior you're seeing might be caused by too much strictness in one of the combinators, so it evaluates "far enough" to give some output but then gets stuck later.
Good luck. You're into the deep subtleness of Haskell.

Typing the Y combinator

http://muaddibspace.blogspot.com/2008/01/type-inference-for-simply-typed-lambda.html is a concise definition of the simply typed lambda calculus in Prolog.
It looks okay, but then he purports to assign a type to the Y combinator... whereas in a very real sense the entire purpose of adding types to lambda calculus is to refuse to assign a type to things like the Y combinator.
Can anyone see exactly where his error or -- more likely -- my misunderstanding is?
The Y combinator in its basic form
Y f = (\x -> f (x x)) (\x -> f (x x))
just cannot be typed using the simple type system proposed in the article.
There are other, much easier but meaningful examples that cannot be typed on that level:
Take e.g.
test f = (f 1, f "Hello")
This obviously works for test (\x -> x) but we cannot give the higher-ranked type that was required here, namely
test :: (∀a . a -> a) -> (Int, String)
But even in more advanced type systems like the GHCI extensions of Haskell which allow the above, Y is still hard to type.
So, given the possibility of recursion, we can just define and work using the fix combinator
fix f = f (fix f)
with fix :: (a -> a) -> a
Typing should disallow self application, it should not be possible to find a type for (t t). If it where possible then t would have a type A -> B, and we would have A = A -> B. Since self application is part of Y combinator, its also not possible to give a type to it.
Unfortunately many Prolog systems allow a solution for A = A -> B. This happens on many grounds, either the Prolog system allows circular terms, then the unification will succeed and the resulting bindings can even further be processed. Or the Prolog system does not allow circular terms, then it depends on whether it implements an occurs check. If the occurs check is on, then unification will not succeed. If the occurs check is off, then the unification might succeed but the resulting bindings can not further be processed, most likely leading to stack overflow in printing or further unifications.
So I guess a circular unification of this type happens in the given code by the used Prolog system and it gets unnoticed.
One way to solve the issue would be to either switch on the occurs check or to replace any of the occuring unifications in the code by an explicit call to unify_with_occurs_check/2.
Best Regards
P.S.: The following Prolog code works better:
/**
* Simple type inference for lambda expression.
*
* Lambda expressions have the following syntax:
* apply(A,B): The application.
* [X]>>A: The abstraction.
* X: A variable.
*
* Type expressions have the following syntax:
* A>B: Function domain
*
* To be on the save side, we use some unify_with_occurs_check/2.
*/
find(X,[Y-S|_],S) :- X==Y, !.
find(X,[_|C],S) :- find(X,C,S).
typed(C,X,T) :- var(X), !, find(X,C,S),
unify_with_occurs_check(S,T).
typed(C,[X]>>A,S>T) :- typed([X-S|C],A,T).
typed(C,apply(A,B),R) :- typed(C,A,S>R), typed(C,B,T),
unify_with_occurs_check(S,T).
Here are some sample runs:
Jekejeke Prolog, Development Environment 0.8.7
(c) 1985-2011, XLOG Technologies GmbH, Switzerland
?- typed([F-A,G-B],apply(F,G),C).
A = B > C
?- typed([F-A],apply(F,F),B).
No
?- typed([],[X]>>([Y]>>apply(Y,X)),T).
T = _T > ((_T > _Q) > _Q)

Resources