finding path using prolog - path

I want to find whether there is a path from one point to another or not.
For example, 2 -> 4 -> 7
1 -> 3 -> 2 -> 9
5 -> 1 -> 6 -> 8
these are the path.
I want to write a predicate path(Start, End), and arcs are represented by a set of arc(From, To) facts.
For example, when path(1, 7) is given this must return true.
when path(6, 1) is given this must return false. because arcs are directed.

If there is an arc between X and Y, then Path=arc(X,Y). That is,
if arc(X,Y) then path(X,Y)). Or, in Prolog this is:
path(X,Y,[arc(X,Y)]) :- arc(X,Y).
Otherwise, if there is an arc between X and some other node Z, and there is
a path from Z to Y, then there is a path from X to Y too. That is,
if arc(X,Z) and path(Z,Y) then path(X,Y). In Prolog this is:
path(X,Y,[arc(X,Z)|P]) :- arc(X,Z),path(Z,Y,P).
Taken from this site.
You could also bundle this into one predicate that simply takes a list of arcs and recursively searches for a path

Try to answer splitting the problem in elementary problems.
path(From, To) :-
arc(From, Intermediate),
path(Intermediate, To).
But, do you see where path should stop? And if there are cycles, what happens?
What's miss it's the trivial case, stating that path(X, X) it's always true. Add to above rule:
path(To, To).
Maybe it's clearer if we write a single rule, using If Then Else
path(From, To) :-
( From \= To
-> arc(From, Intermediate),
path(Intermediate, To)
; true
).

Related

Generating a random rule for property based test

I am using Triq (erlang quickcheck) and I am having trouble generating a set of nice rules for my program.
What I want to generate are things that looks like this:
A -> B
where I would like to provide A and the size of B, with latter not having any dupicates.
For example, if I say generate me rules with L.H.S. of [a] and R.H.S. of size 4 (ie. A = [a] and size(B) = 4) I would like to get something like this:
{rule, [a], [1,2,4,5]}
{rule, [a], [a,d,c,e]}
{rule, [a], [q,d,3,4]}
Note, I don't want any dupicates in B (this is the part I'm having trouble with). Also, it doesn't really matter what B is made up of - it can be anything as long as it is distinct and without dupicates.
My spec is far too messy to show here, so I'd rather not.
I am not familiar with Triq, but in PropEr and Quviq's Qickcheck you can use ?SUCHTHAT conditions that filter 'bad' instances.
If a generated instance does not satisfy a ?SUCHTHAT constraint it is discarded and not counted as a valid test. You could use this mechanism to generate lists of the specified size (i.e. what PropEr calls 'vectors') and then discard those that have duplicates, but I think that too many instances would then be discarded (see also the link).
It is usually more efficient to tinker with the generator so that all instances are valid, in your case by e.g. generating (3) X-times as many elements, removing duplicates and keeping as many as you need. This can still fail, and it will fail, so you need to guard against it.
Here is a generator for your case, in PropEr, together with a dummy property:
-module(dummy).
-export([rule_prop/0]).
-include_lib("proper/include/proper.hrl").
-define(X, 5).
rule_prop() ->
?FORALL(_, rule_gen(integer(), 4, integer()), true).
rule_gen(A, SizeB, TypeB) ->
?LET(
EnoughB,
?SUCHTHAT(
NoDupB,
?LET(
ManyB,
vector(?X * SizeB, TypeB),
no_dups(ManyB)
),
length(NoDupB) >= SizeB
),
begin
B = lists:sublist(EnoughB, SizeB),
{rule, A, B}
end).
no_dups([]) ->
[];
no_dups([A|B]) ->
[A | no_dups([X || X <- B, X =/= A])].

this clause cannot match because of different types/sizes

i tried to implement binary_search in erlang :
binary_search(X , List) ->
case {is_number(x) , is_list(List)} of
{false , false} -> {error};
{false , true} -> {error} ;
{true , false} -> {error} ;
{true , true} ->
Length = length(List) ,
case Length of
0 -> {false};
1 -> case lists:member(X , List) of
true -> {true};
false -> {false}
end ;
_ ->
Middle = (Length + 1) div 2 ,
case X >= Middle of
true -> binary_search(X , lists:sublist(List , Middle , Length));
false -> binary_search(X , lists:sublist(List , 1 , Middle))
end
end
end .
However when i try to compile it , i get the following error : "this clause cannot match because of different types/sizes" in the two lines :
{true , false} -> {error} ;
{true , true} ->
is_number(x) will always return false since you made a typo: x instead of X, an atom instead of a variable.
BTW, I don't know what you are experiencing, but the whole code can be written as:
binary_search(X , [_|_] = List) when is_number(X) ->
{lists:member(X,List)};
binary_search(_,_) -> {error}.
Context: The OP's post appears to be a learning example -- an attempt to understand binary search in Erlang -- and is treated as one below (hence the calls to io:format/2 each iteration of the inner function). In production lists:member/2 should be used as noted by Steve Vinoski in a comment below, or lists:member/2 guarded by a function head as in Pascal's answer. What follows is a manual implementation of binary search.
Pascal is correct about the typo, but this code has more fundamental problems. Instead of just finding the typo let's see if we can obviate the need for this nested case checking entirely.
(The code as written above won't work anyway because X should not represent the value of an index, but rather the value that is held at that index, so Middle will likely never match X. Also, there is another issue: you don't cover all the base cases (cases in which you should stop recursing). So the inner function below covers them all up front as matches within the function head, so it is more obvious how the search works. Note the Middle + 1 when X > Value, by the way; contemplate why this is necessary.)
Two main notes on Erlang style
First: If you receive the wrong sort of data, just crash, don't return an error. With that in mind, consider using a guard.
Second: If you find yourself doing lots of cases, you can usually simplify your life by making them named functions. This gives you two advantages:
A much better crash report than you will get within nested case expressions.
A named, pure function can be tested and even formally verified rather easily if it is small enough -- which is also pretty cool. (As a side note, the religion of testing tests my patience and sanity at times, but when you have pure functions you actually can test at least those parts of your program -- so distilling out as much of this sort of thing as possible is a big win.)
Below I do both, and this should obviate the issue you ran into as well as make things a bit easier to read/sort through mentally:
%% Don't return errors, just crash.
%% Only check the data on entry.
%% Guarantee the data is sorted, as this is fundamental to binary search.
binary_search(X, List)
when is_number(X),
is_list(List) ->
bs(X, lists:sort(List)).
%% Get all of our obvious base cases out of the way as matches.
%% Note the lack of type checking; its already been done.
bs(_, []) -> false;
bs(X, [X]) -> true;
bs(X, [_]) -> false;
bs(X, List) ->
ok = io:format("bs(~p, ~p)~n", [X, List]),
Length = length(List),
Middle = (Length + 1) div 2,
Value = lists:nth(Middle, List),
% This is one of those rare times I find an 'if' to be more
% clear in meaning than a 'case'.
if
X == Value -> true;
X > Value -> bs(X, lists:sublist(List, Middle + 1, Length));
X < Value -> bs(X, lists:sublist(List, 1, Middle))
end.

Pathfinding in Prolog

I'm trying to teach myself Prolog. Below, I've written some code that I think should return all paths between nodes in an undirected graph... but it doesn't. I'm trying to understand why this particular code doesn't work (which I think differentiates this question from similar Prolog pathfinding posts). I'm running this in SWI-Prolog. Any clues?
% Define a directed graph (nodes may or may not be "room"s; edges are encoded by "leads_to" predicates).
room(kitchen).
room(living_room).
room(den).
room(stairs).
room(hall).
room(bathroom).
room(bedroom1).
room(bedroom2).
room(bedroom3).
room(studio).
leads_to(kitchen, living_room).
leads_to(living_room, stairs).
leads_to(living_room, den).
leads_to(stairs, hall).
leads_to(hall, bedroom1).
leads_to(hall, bedroom2).
leads_to(hall, bedroom3).
leads_to(hall, studio).
leads_to(living_room, outside). % Note "outside" is the only node that is not a "room"
leads_to(kitchen, outside).
% Define the indirection of the graph. This is what we'll work with.
neighbor(A,B) :- leads_to(A, B).
neighbor(A,B) :- leads_to(B, A).
Iff A --> B --> C --> D is a loop-free path, then
path(A, D, [B, C])
should be true. I.e., the third argument contains the intermediate nodes.
% Base Rule (R0)
path(X,Y,[]) :- neighbor(X,Y).
% Inductive Rule (R1)
path(X,Y,[Z|P]) :- not(X == Y), neighbor(X,Z), not(member(Z, P)), path(Z,Y,P).
Yet,
?- path(bedroom1, stairs, P).
is false. Why? Shouldn't we get a match to R1 with
X = bedroom1
Y = stairs
Z = hall
P = []
since,
?- neighbor(bedroom1, hall).
true.
?- not(member(hall, [])).
true.
?- path(hall, stairs, []).
true .
?
In fact, if I evaluate
?- path(A, B, P).
I get only the length-1 solutions.
Welcome to Prolog! The problem, essentially, is that when you get to not(member(Z, P)) in R1, P is still a pure variable, because the evaluation hasn't gotten to path(Z, Y, P) to define it yet. One of the surprising yet inspiring things about Prolog is that member(Ground, Var) will generate lists that contain Ground and unify them with Var:
?- member(a, X).
X = [a|_G890] ;
X = [_G889, a|_G893] ;
X = [_G889, _G892, a|_G896] .
This has the confusing side-effect that checking for a value in an uninstantiated list will always succeed, which is why not(member(Z, P)) will always fail, causing R1 to always fail. The fact that you get all the R0 solutions and none of the R1 solutions is a clue that something in R1 is causing it to always fail. After all, we know R0 works.
If you swap these two goals, you'll get the first result you want:
path(X,Y,[Z|P]) :- not(X == Y), neighbor(X,Z), path(Z,Y,P), not(member(Z, P)).
?- path(bedroom1, stairs, P).
P = [hall]
If you ask for another solution, you'll get a stack overflow. This is because after the change we're happily generating solutions with cycles as quickly as possible with path(Z,Y,P), only to discard them post-facto with not(member(Z, P)). (Incidentally, for a slight efficiency gain we can switch to memberchk/2 instead of member/2. Of course doing the wrong thing faster isn't much help. :)
I'd be inclined to convert this to a breadth-first search, which in Prolog would imply adding an "open set" argument to contain solutions you haven't tried yet, and at each node first trying something in the open set and then adding that node's possibilities to the end of the open set. When the open set is extinguished, you've tried every node you could get to. For some path finding problems it's a better solution than depth first search anyway. Another thing you could try is separating the path into a visited and future component, and only checking the visited component. As long as you aren't generating a cycle in the current step, you can be assured you aren't generating one at all, there's no need to worry about future steps.
The way you worded the question leads me to believe you don't want a complete solution, just a hint, so I think this is all you need. Let me know if that's not right.

BST printing without mutating?

So i basically want to printbst's .. here is a little more detail
Provide a function (printbst t) that prints a BST constructed from BST as provided by bst.rkt in the following format:
-Each node in the BST should be printed on a separate line;
-the left subtree should be printed after the root;
-The right subtree should be printed before the root;
-The key value should be indented by 2d spaces where d is its depth, or distance from the root. That is, the root should not be indented, the keys in its subtrees should be intended 2 spaces, the keys in their subtrees 4 spaces, and so on.
For example, the complete tree containing {1,2,3,4,5,6} would be printed like this:
6
5
4
3
2
1
Observe that if you rotate the output clockwise and connect each node to its subtrees, you arrive at the conventional graphical representation of the tree. Do not use mutation.
Here is what i have so far:
#lang racket
;;Note: struct-out exports all functions associated with the structure
(provide (struct-out BST))
(define-struct BST (key left right) #:transparent)
(define (depth key bst)
(cond
[(or (empty? bst) (= key (BST-key bst))) 0]
[else (+ 1 (depth key (BST-right bst)) (depth key (BST-left bst)))]))
(define (indent int)
(cond
[(= int 0) ""]
[else " " (indent (sub1 int))]))
(define (printbst t)
(cond
[(empty? t) (newline)]
[(and (empty? (BST-right t)) (empty? (BST-left t)))
(printf "~a~a" (indent (depth (BST-key t) t)) (BST-key t))]))
My printbst only prints a tree with one node thou .... i have an idea but it involves mutation, which i can't use :( ..... Any suggestions ? Should i change my approach to the problem all together?
Short answer: yes, you're going to want to restructure this more or less completely.
On the bright side, I like your indent function :)
The easiest way to write this problem involves making recursive calls on the subtrees. I hope I'm not giving away too much when I tell you that in order to print a subtree, there's one extra piece of information that you need.
...
Based on our discussion below, I'm going to first suggest that you develop the closely related recursive program that prints out the desired numbers with no indentation. So then the correct output would be:
6
5
4
3
2
1
Updating that program to the one that handles indentation is just a question of passing along a single extra piece of information.
P.S.: questions like this that produce output are almost impossible to write good test cases for, and consequently not great for homework. I hope for your sake that you have lots of other problems that don't involve output....

Find all possible pairs between the subsets of N sets with Erlang

I have a set S. It contains N subsets (which in turn contain some sub-subsets of various lengths):
1. [[a,b],[c,d],[*]]
2. [[c],[d],[e,f],[*]]
3. [[d,e],[f],[f,*]]
N. ...
I also have a list L of 'unique' elements that are contained in the set S:
a, b, c, d, e, f, *
I need to find all possible combinations between each sub-subset from each subset so, that each resulting combination has exactly one element from the list L, but any number of occurrences of the element [*] (it is a wildcard element).
So, the result of the needed function working with the above mentioned set S should be (not 100% accurate):
- [a,b],[c],[d,e],[f];
- [a,b],[c],[*],[d,e],[f];
- [a,b],[c],[d,e],[f],[*];
- [a,b],[c],[d,e],[f,*],[*];
So, basically I need an algorithm that does the following:
take a sub-subset from the subset 1,
add one more sub-subset from the subset 2 maintaining the list of 'unique' elements acquired so far (the check on the 'unique' list is skipped if the sub-subset contains the * element);
Repeat 2 until N is reached.
In other words, I need to generate all possible 'chains' (it is pairs, if N == 2, and triples if N==3), but each 'chain' should contain exactly one element from the list L except the wildcard element * that can occur many times in each generated chain.
I know how to do this with N == 2 (it is a simple pair generation), but I do not know how to enhance the algorithm to work with arbitrary values for N.
Maybe Stirling numbers of the second kind could help here, but I do not know how to apply them to get the desired result.
Note: The type of data structure to be used here is not important for me.
Note: This question has grown out from my previous similar question.
These are some pointers (not a complete code) that can take you to right direction probably:
I don't think you will need some advanced data structures here (make use of erlang list comprehensions). You must also explore erlang sets and lists module. Since you are dealing with sets and list of sub-sets, they seems like an ideal fit.
Here is how things with list comprehensions will get solved easily for you: [{X,Y} || X <- [[c],[d],[e,f]], Y <- [[a,b],[c,d]]]. Here i am simply generating a list of {X,Y} 2-tuples but for your use case you will have to put real logic here (including your star case)
Further note that with list comprehensions, you can use output of one generator as input of a later generator e.g. [{X,Y} || X1 <- [[c],[d],[e,f]], X <- X1, Y1 <- [[a,b],[c,d]], Y <- Y1].
Also for removing duplicates from a list of things L = ["a", "b", "a"]., you can anytime simply do sets:to_list(sets:from_list(L)).
With above tools you can easily generate all possible chains and also enforce your logic as these chains get generated.

Resources