Prolog - Calculate fastest travel between 2 locations given different travel modes - search
I'm trying to figure out how to calculate the fastest journey between two places, given different travel modes. My factbase starts with a predicate route(Src, Dest, Distance, TravelMode) and input is via the predicate journey(Src, Dest, TravelMode) which should output the fastest travel mode to use. (Basically whichever has the shortest time.)
However, it says that TravelMode is a string and if it contains f, it means the path can be traveled on foot, c for car, t for train and p for plane. This has me confused since I don't really understand how to search the String TravelMode and only run the corresponding time functions for the travel modes included.
Below is my code and right now, it's only able to calculate the time between places (time_f, etc), although I believe my time predicate is wrong since I think it's supposed to be just one general function.
I also did try coding the journey predicate however, it only seems to output true / false and no values which probably means my route / speed predicate is wrong.
Am I on the right path? I've been stuck on this and I'd really appreciate any help to steer me in the correct direction / help explain what I have gotten wrong in here.
Not sure if everyone understands but I added the program specs just so that it could be clearer to understand
/* Sample set of facts */
route(dublin, cork, 200, 'fct').
route(cork, dublin, 200, 'fct').
route(cork, corkAirport, 20, 'fc').
route(corkAirport, cork, 25, 'fc').
route(dublin, dublinAirport, 10, 'fc').
route(dublinAirport, dublin, 20, 'fc').
route(dublinAirport, corkAirport, 225, 'p').
route(corkAirport, dublinAirport, 225, 'p').
/* Speed of mode of transport used */
speed(foot, 5).
speed(car, 80).
speed(train, 100).
speed(plane, 500).
/* Time between 2 cities, given specified transportation mode */
time_f(City1, City2, Time) :-
route(City1, City2, Distance, _),
speed(foot, Speed),
Time is (Distance / Speed),
write('Time travelling between '), write(City1), write(' and '), write(City2), write(' via foot is: '), write(Time), nl.
time_c(City1, City2, Time) :-
route(City1, City2, Distance, _),
speed(car, Speed),
Time is (Distance / Speed),
write('Time travelling between '), write(City1), write(' and '), write(City2), write(' via car is: '), write(Time), nl.
time_t(City1, City2, Time) :-
route(City1, City2, Distance, _),
speed(train, Speed),
Time is (Distance / Speed),
write('Time travelling between '), write(City1), write(' and '), write(City2), write(' via train is: '), write(Time), nl.
time_p(City1, City2, Time) :-
route(City1, City2, Distance, _),
speed(plane, Speed),
Time is (Distance / Speed),
write('Time travelling between '), write(City1), write(' and '), write(City2), write(' via plane is: '), write(Time), nl.
/* Solve for fastest journey */
journey(City1, City2, TravelModes) :-
route(City1, City2, Distance, TravelModes),
speed('TravelModes', Speed),
Time is (Distance / Speed),
write('Time travelling between '), write(City1), write(' and '), write(City2), write(' via '), write(TravelModes),
write(' is: '), write(Time), nl.
EDIT:
I tried to implement some changes. Especially that of detecting if mode is part of the string.
/* Sample set of facts */
route(dublin, cork, 200, fct).
route(dublin, dublinAirport, 10, fc).
route(dublinAirport, corkAirport, 225, p).
/* Speed of mode of transport used */
speed(f, 5).
speed(c, 80).
speed(t, 100).
speed(p, 500).
/* Program Flow
1. Input journey(City1, City2, TravelModes).
2. Check if City1 and City2 can be traveled (or path exists between them)
3. Access time function
4. Get travel time between City1 and City2 for TravelModes used
5. Select lowest travel time and output it.
*/
/* Checks if mode is in string */
availableMode(Mode, TravelModes) :- forall(sub_atom(Mode,_,1,_,C), sub_atom(TravelModes,_,1,_,C)).
/* Check mode of transport */
journey(City1, City2, TravelModes) :-
route(City1, City2, Distance, TravelModes),
availableMode(Mode, TravelModes),
speed(Mode, Speed),
Time is (Distance / Speed),
write('Time between '), write(City1), write(' and '), write(City2), write(' via '), write(Mode), write(' is: '),
write(Time), n1.
EDIT 2:
Currently, this is able to check the TravelMode input and calculate the necessary time. However, it doesn't store the output in a list of which the goal is to select the lowest time between routes and output that time.
/* Sample set of facts */
route(dublin, cork, 200, fct).
route(dublin, dublinAirport, 10, fc).
route(dublinAirport, corkAirport, 225, p).
/* Speed of mode of transport used */
speed(f, 5).
speed(c, 80).
speed(t, 100).
speed(p, 500).
/* Checks if mode is in string */
availableMode(Mode, TravelModes) :- sub_atom(TravelModes,_,1,_,Mode).
/* Read journey user input */
journey(City1, City2, TravelModes) :-
route(City1, City2, Distance, TravelModes),
availableMode(Mode, TravelModes),
speed(Mode, Speed),
Time is (Distance / Speed),
write('Time between '), write(City1), write(' and '), write(City2), write(' via '), write(Mode), write(' is: '),
write(Time), nl.
EDIT 3:
Implemented time variable to secondary journey predicate. Tried to implement all(Solutions) and finding the minimum variable, though I believe I am still missing out something since it only outputs true / false.
/* Sample set of facts */
route(dublin, cork, 200, fct).
route(dublinAirport, dublin, 20, fc).
route(dublinAirport, corkAirport, 225, p).
/* Speed of mode of transport used */
speed(f, 5).
speed(c, 80).
speed(t, 100).
speed(p, 500).
/* Checks if mode is in string */
availableMode(Mode, TravelModes) :- sub_atom(TravelModes,_,1,_,Mode).
journey(City1, City2, TravelModes) :-
route(City1, City2, Distance, TravelModes),
availableMode(Mode, TravelModes),
speed(Mode, Speed),
Time is (Distance / Speed),
write('Time between '), write(City1), write(' and '), write(City2), write(' via '), write(Mode), write(' is: '),
write(Time), nl.
/* Keep definition of journey but include a time variable that can be utilized */
journey(City1, City2, TravelModes) :- journey(City1, City2, TravelModes, _Time).
/* journey using time variable */
journey(City1, City2, TravelModes, Time) :-
route(City1, City2, Distance, TravelModes),
availableMode(Mode, TravelModes),
speed(Mode, Speed),
Time is (Distance / Speed).
/* Collecting all solutions */
all(Solutions) :- findall([City1, City2, TravelModes, Time], journey(City1, City2, TravelModes, Time), Solutions).
/* Finding minimum solution */
find_min(S, Solutions) :- all(Solutions).
EDIT 4:
Implemented (solving for the solutions recursively and storing them in a list). Also removed the redundant journey/3. Currently in the process of fixing the code to show just one solution set (aka the final solution with the lowest time).
/* Sample set of facts */
route(dublin, cork, 200, fct).
route(cork, dublin, 200, fct).
route(cork, corkAirport, 20, fc).
route(corkAirport, cork, 25, fc).
route(dublin, dublinAirport, 10, fc).
route(dublinAirport, dublin, 20, fc).
route(dublinAirport, corkAirport, 225, p).
route(corkAirport, dublinAirport, 225, p).
/* Speed of mode of transport used */
speed(f, 5).
speed(c, 80).
speed(t, 100).
speed(p, 500).
/* Checks if mode is in string */
availableMode(Mode, TravelModes) :- sub_atom(TravelModes,_,1,_,Mode).
/* Keep definition of journey but include a time variable that can be utilized */
journey(City1, City2, TravelModes) :- journey(City1, City2, TravelModes, _Time).
/* journey using time variable */
journey(City1, City2, TravelModes, Time) :-
route(City1, City2, Distance, TravelModes),
availableMode(Mode, TravelModes),
speed(Mode, Speed),
Time is (Distance / Speed),
write('Time between '), write(City1), write(' and '), write(City2), write(' via '), write(Mode), write(' is: '),
write(Time), nl.
/* Collecting all solutions */
all(Solutions) :- findall([City1, City2, TravelModes, Time], journey(City1, City2, TravelModes, Time), Solutions).
/* Recursion to find minimum travel time */
% Using the \+ (not provable operator) which discards the unnecessary solution
% Allowing us to retain the solutions with lowest time
% After recursively going thru the list, the accumulator list is set to the final solution list (aka the lowest time)
minimize([],Sol,Sol).
minimize([S|Ss],SolAcc,FinSol) :- S = [Cy1, Cy2, _, _],
\+ member([Cy1, Cy2, _, _], SolAcc),
minimize(Ss,[S|SolAcc],FinSol).
minimize([S|Ss],SolAcc,FinSol) :- S = [Cy1, Cy2, _MyMd, MyTi],
member([Cy1, Cy2, _OtherMd, OtherTi], SolAcc),
OtherTi < MyTi,
minimize(Ss,SolAcc,FinSol).
minimize([S|Ss],SolAcc,FinSol) :- S = [Cy1, Cy2, _MyMd, MyTi],
member([Cy1, Cy2, _OtherMd, OtherTi], SolAcc),
OtherTi >= MyTi,
delete(SolAcc, [Cy1, Cy2,_,_], SolAcc2),
minimize(Ss,[S|SolAcc2],FinSol).
/* Finding minimum solution */
find_min(MinimizedSolutions) :- all(Solutions),minimize(Solutions,[],MinimizedSolutions).
Answer to adding "minimization" predicate which selects those City-City paths that have lowest time. (This predicate is now in "Edit 4" of the question)
The SWI Prolog documentation for findall or bagof is here.
Note that findall belows is given the expression journey(City1, City2, TravelModes, Time) as a term but "elevates" it to a goal (i.e. a callable predicate). This is meta-call functionality and very much beyond first-order logic, similar to building Java code through string appends, compiling it, then running it. Editors should highlight that part in inverse...
/* Collecting all solutions */
all(Solutions) :- findall([City1, City2, TravelModes, Time], journey(City1, City2, TravelModes, Time), Solutions).
minimize([],Sol,Sol).
minimize([S|Ss],SolAcc,FinSol) :- S = [Cy1, Cy2, _, _],
\+ member([Cy1, Cy2, _, _], SolAcc),
minimize(Ss,[S|SolAcc],FinSol).
minimize([S|Ss],SolAcc,FinSol) :- S = [Cy1, Cy2, _MyMd, MyTi],
member([Cy1, Cy2, _OtherMd, OtherTi], SolAcc),
OtherTi < MyTi,
minimize(Ss,SolAcc,FinSol).
minimize([S|Ss],SolAcc,FinSol) :- S = [Cy1, Cy2, _MyMd, MyTi],
member([Cy1, Cy2, _OtherMd, OtherTi], SolAcc),
OtherTi >= MyTi,
delete(SolAcc, [Cy1, Cy2,_,_], SolAcc2),
minimize(Ss,[S|SolAcc2],FinSol).
/* Finding minimum solution */
find_min(MinimizedSolutions) :- all(Solutions),minimize(Solutions,[],MinimizedSolutions).
Clarification to answer question in comments
If you think of the program as defining a flow of data (see lovingly hand-drawn diagram below), then first Solutions is set-to (or "unified-with") a list of all possible solutions for journey(C1,C2,Tm,Ti), each formatted itself as list [C1,C2,Tm,Ti].
The list Solutions flows into a box representing minimize. That box also takes an empty list [] and is meant to unify its third argument with-the-eventual solution MinimizedSolutions. minimize calls itself (creating a new minimize box within itself) and behaves differently in each of the 4 cases of input it can receive as values of Solutions and SolAcc.
The idea is that minimize removes an element from its first input value, (a list) and adds 1 or 0 elements to its second input value, the accumulator (also a list), before calling itself. In that way when the first input value finally turns out to be [], minimize just needs to short-circuit the second value (input) to the third value (output), which then flows outwards through the recursively imbricated boxes towards the top goal.
In fact Prolog allows nasty (but compact) code to be written because it allows the expressions for case distinctions in minimze/3 to be carcrashed into the rule head. To make minimize clearer and show intention, in an imaginary Prolog which only allows variables as predicate arguments in the rule head and has "guard expressions" to perform case testing to the left of an | in the rule body, we would have the following code:
% Hide the fact that we need an accumulator value by
% defining minimize/2 which calls minimize/3
% This is the "public" part of minimize and can also be done in Prolog.
minimize(SolIn,SolOut) :- minimize(SolIn,[],SolOut).
% This is the "private" part of minimize and uses non-Prolog "guard" syntax
minimize(SolIn,SolAcc,SolOut) :- SolIn = [] |
SolOut = SolAcc.
minimize(SolIn,SolAcc,SolOut) :- SolIn = [S|Ss],
S = [Cy1, Cy2, _, _],
\+ member([Cy1, Cy2, _, _], SolAcc) |
minimize(Ss,[S|SolAcc],SolOut).
minimize(SolIn,SolAcc,SolOut) :- SolIn = [S|Ss],
S = [Cy1, Cy2, _MyMd, MyTi],
member([Cy1, Cy2, _OtherMd, OtherTi], SolAcc),
OtherTi < MyTi |
minimize(Ss,SolAcc,FinSol).
% etc. for the other two cases
The minimize(SolIn,SolOut) rule is just there to show to the next guy who has to maintain this that the arity-2 predicate minimize/2 is what "client code" would use. minimize/2 passes the work directly to the actual "implementation" which is an arity-3 predicate minimize/3: minimize(SolIn,SolAcc,SolOut).
For the latter, the recursive traversal through the SolIn list is kicked off by the body minimize(SolIn,[],SolOut).
If the program were modularized, minimize(SolIn,SolOut) would be what's being exported by the module. One would also mark what the implementation regards has "in" and "out" variables (sadly only in the comment, the compiler doesn't handle those) according to mode flags: minimize(+SolIn,-SolOut)
Again, this has aspects of imperative programming style "procedure calls" but I always visualize the thread or flow of information going into the "predicate box" at certain argument position and coming back out at another position, much like stitching. (Add things like freeze/2 and the thread needs to have tokens moving along it too, but that's for another time)
Related
Adding Tolerances to Excel LAMBDA functions
I created a LAMBDA function called LOANAMT to calculate loan amounts recursively for a situation in which you need to borrow to fund the loan payment (yes, I know this can be solved algebraically - I'm trying to learn about LAMBDA). I incorporated a tolerance check as my escape clause; if the next round of interest calculations is very close to the previous round, the LAMBDA exits. This worked fine with a hard-coded tolerance level of 0.001: =LAMBDA(opening_balance, base_rate, [interest], LET( _int, IF(ISOMITTED(interest), 0, interest), _new_close, opening_balance + _int, _new_int, _new_close * base_rate, _closing_balance, IF(ABS(_new_int-_int)<0.001, _new_close,LOANAMT(opening_balance,base_rate,_new_int)), _closing_balance ) ) Gave me 106.38290 where opening_balance = 100, base_rate = 6%, which approximately agrees with the algebraic solution. However, when I tried incorporating the tolerance as a parameter of the LAMBDA so that it could be adjusted easily, I got a #NUM error. =LAMBDA(opening_balance, base_rate, tolerance, [interest], LET( _int, IF(ISOMITTED(interest), 0, interest), _new_close, opening_balance + _int, _new_int, _new_close * base_rate, _closing_balance, IF(ABS(_new_int-_int)<tolerance, _new_close,LOANAMT2(opening_balance,base_rate,_new_int)), _closing_balance ) ) Could anyone explain what's going wrong and help me fix this? Thanks.
The second version doesn't pass the tolerance value to the recursive call to LOANAMT2, hence the #NUM! error. This works: LOANAMT2=LAMBDA(opening_balance, base_rate, tolerance, [interest], LET( _int, IF(ISOMITTED(interest), 0, interest), _new_close, opening_balance + _int, _new_int, _new_close * base_rate, _closing_balance, IF(ABS(_new_int-_int)<tolerance, _new_close,LOANAMT2(opening_balance,base_rate,tolerance,_new_int)), _closing_balance ) )
If we rolled the die (6-sided) 1000 time, what is the range of times we'd expect to see a 1 rolled?
I got a question listed below about the confidence interval for rolling a die 1000 times. I'm assuming that the question is using Binomial Distribution but not sure if I'm correct. I guess in the solution, the probability 0.94 comes from 1-0.06. But I'm not sure if we need the probability in this interval, except it is only used for the Z-score, 1.88. Could I assume this question like this? Question: Assume that we are okay with accidentally rejecting H0 6% of the time, assuming H0 is true. If we rolled the die (6-sided) 1000 times, what is the range of times we'd expect to see a 1 rolled? (H0 is the die is fair.) Answer: The interval is (144.50135805579743, 188.8319752775359), with probability = 0.94, mu = 166.67, sigma = 11.785113019775793
We can treat this as a binomial distribution with a success chance p of 1/6 and number of trials n = 1000. Mean value of such a distribution is np, and variance is np(1-p). sigma (or std) is sqrt(variance). However, finding the interval is not so trivial since it requires an inverse CDF. The solution apparently uses normal approximation (p is low, n is high) with a Z-score table (like https://www.math.arizona.edu/~rsims/ma464/standardnormaltable.pdf) thus range = mu +- 1.88 * sigma. Obviously, binomial is discrete, so there cannot be '145.5 times' of rolling 1. scipy.stats.binom.ppf(0.97, 1000, 1/6) and scipy.stats.binom.ppf(0.03, 1000, 1/6) yield a sane 145..189 range.
How is Prolog `shift`/`reset` like other languages?
I found an example of shift-reset delimited continuations in Haskell here: resetT $ do alfa bravo x <- shiftT $ \esc -> do charlie lift $ esc 1 delta lift $ esc 2 return 0 zulu x This will: Perform alfa Perform bravo Perform charlie Bind x to 1, and thus perform zulu 1 Fall off the end of resetT, and jump back to just after esc 1 Perform delta Bind x to 2, and thus perform zulu 2 Fall off the end of resetT, and jump back to just after esc 2 Escape from the resetT, causing it to yield 0 I can't figure out how to write the equivalent code using SWI-Prolog's shift/1 and reset/3. The code below is my attempt. The output is the same, but it seems messy and backwards, and I feel like I'm misusing Ball to get something similar to the esc 1 and esc 2 in the Haskell example. Also, I am not sure what to do with return 0. % not sure about this... example :- reset(step, ball(X), Cont), ( writeln("charlie"), X=1, call(Cont), fail ; writeln("delta"), X=2, call(Cont)). step :- writeln("alfa"), writeln("bravo"), shift(ball(X)), format("zulu ~w~n", X). I'm rather confused: Scheme/Haskell/ML-style shift-reset and Prolog shift-reset seem almost like entirely different things! For example, you pass a lambda into Haskell's shiftT but you do not pass a goal into Prolog's shift/1. Where is the Prolog equivalent of Haskell's \esc -> ... esc 1 or return 0? And where is the Haskell equivalent of Prolog's Ball or call(Cont)? I feel that a "proper" port of the Haskell example above would answer these questions.
The reset and shift operators originally come from Danvy; Filinski,1990. “Abstracting Control”. The corresponding interfaces in Haskell Control.Monad.Trans.Cont conform to the original semantics, except for some type restrictions. The delimited continuation interfaces in SWI-Prolog are not exactly the original reset and shift. They are more closely related to Felleisen,1988's prompt and control or Sitaram’s fcontrol and run operators. Usually, it is not difficult to translate delimited continuation programs from Haskell to Prolog. The difficulty in your example is that it calls the same continuation esc twice with different values. For example, example :- reset(step, ball(X), Cont), X=1, call(Cont), X=2, call(Cont). After the first call(Cont), X is already bound to 1, you cannot rebind it to 2. TomSchrijvers' advice is to create copies of the continuation with fresh unification variables using copy_term/2 (yes, continuations are also terms in SWI-Prolog!), so the Prolog equivalent of your example is example(X) :- reset(step, Ball, Cont), copy_term(Cont+Ball, Cont1+Ball1), copy_term(Cont+Ball, Cont2+Ball2), writeln("charlie"), ball(X1) = Ball1, X1=1, reset(Cont1, _, _), writeln("delta"), ball(X2) = Ball2, X2=2, reset(Cont2, _, _), X=0. step :- writeln("alfa"), writeln("bravo"), shift(ball(X)), format("zulu ~w~n", X), shift(ball(X)). ?- example(X). alfa bravo charlie zulu 1 delta zulu 2 X = 0. More detail discussion, see https://swi-prolog.discourse.group/t/naming-clarification-about-delimited-continuation-reset-3-and-shift-1
Pitty the CW631 paper here: http://www.cs.kuleuven.be/publicaties/rapporten/cw/CW631.pdf doesn’t show Felleisen prompt/control implemented with difference list rules: /* Vanilla conjunction list solve/1 extended to control/3 */ control([], none, []). control([prompt(A)|B], A, B). control([control(L, P, Q)|B], X, Y) :- control(L, P, Q), control(B, X, Y). control([A|B], X, Y) :- rule(A,C,B), control(C, X, Y). Its quite fast, since it does nothing with the continuation, just takes it as is, which I suppose is the spirit of Felleisen. Here the good ole shift/reset: /* SWI-Prolog 8.5.14 */ ?- time(run_state(fib(25), 0, S)). % 2,306,455 inferences, 0.453 CPU in 0.499 seconds (91% CPU, 5090108 Lips) S = 121393 . And here the prompt/control: /* SWI-Prolog 8.5.14 */ ?- time(control([run_state([fib(25)],0,S)],_,_)). % 3,641,788 inferences, 0.891 CPU in 0.980 seconds (91% CPU, 4089025 Lips) S = 121393 . /* Jekejeke Prolog 1.5.4, only 512 MB allocated, JDK 16 */ ?- time(control([run_state([fib(25)],0,S)],_,_)). % Threads 1,656 ms, GC 404 ms, Up 2,086 ms (Current 08/23/22 04:19:56) S = 121393 The test case is here: http://www.rubycap.ch/gist/felleisen2.txt
Hidden Markov Model Coin & Dice Example with Prolog
I got the specific problem from here and wanted to implement it on Cplint as Im learning now the principles of ProbLog So from the above model we get A red die, having six sides, labeled 1 through 6. • A green die, having twelve sides, five of which are labeled 2 through 6, while the remaining seven sides are labeled 1. • A weighted red coin, for which the probability of heads is 0.9 and the probability of tails is 0.1. • A weighted green coin, for which the probability of heads is 0.95 and the probability of tails is 0.05. As a solution, I want to create a sequence of numbers from the set {1, 2, 3, 4, 5, 6} with the following rules: • Begin by rolling the red die and writing down the number that comes up, which is the emission/observation. • Toss the red coin and do one of the following: ➢ If the result is heads, roll the red die and write down the result. ➢ If the result is tails, roll the green die and write down the result. • At each subsequent step, you flip the coin that has the same color as the die you rolled in the previous step. If the coin comes up heads, roll the same die as in the previous step. If the coin comes up tails, switch to the other die. My state diagram for this model has two states, red and green, as shown in the figure. In addition, this figure shows: 1) the state-transition probability matrix A, b) the discrete emission/observation probabilities matrix B, and 3) the initial (prior) probabilities matrix π. The model is not hidden because you know the sequence of states from the colors of the coins and dice. Suppose, however, that someone else is generating the emissions/observations without showing you the dice or the coins. All you see is the sequence of emissions/observations. If you start seeing more 1s than other numbers, you might suspect that the model is in the green state, but you cannot be sure because you cannot see the color of the die being rolled. Consider the Hidden Markov Model (HMM) M=(A, B, π), assuming an observation sequence O=<1,1,2,2,3,6,1,1,1,3> what is the probability the hidden sequence to be H =<RC,GC, GC,RC, RC,GC, GC,GC,GC,GC> where RC and GC stand for Read Coin and Green Coin respectively. Use the cplint or ProbLog to calculate the probability that the model M generated the sequence O. That is, calculate the probability P(H|O) = P(<RC,GC, GC,RC, RC,GC, GC,GC, GC,GC>| <1,1,2,2,3,6,1,1,1,3>) What I did so far are two approaches. 1) :- use_module(library(pita)). :- if(current_predicate(use_rendering/1)). :- use_rendering(c3). :- use_rendering(graphviz). :- endif. :- pita. :- begin_lpad. hmm(O):-hmm1(_,O). hmm1(S,O):-hmm(q1,[],S,O). hmm(end,S,S,[]). hmm(Q,S0,S,[L|O]):- Q\= end, next_state(Q,Q1,S0), letter(Q,L,S0), hmm(Q1,[Q|S0],S,O). next_state(q1,q1,S):0.9; next_state(q1,q2,S):0.1. next_state(q2,q1,S):0.05; next_state(q2,q2,S):0.95. letter(q1,rd1,S):1/6; letter(q1,rd2,S):1/6; letter(q1,rd3,S):1/6; letter(q1,rd4,S):1/6; letter(q1,rd5,S):1/6; letter(q1,rd6,S):1/6. letter(q2,gd1,S):7/12; letter(q2,gd2,S):1/12; letter(q2,gd3,S):1/12; letter(q2,gd4,S):1/12; letter(q2,gd5,S):1/12; letter(q2,gd6,S):1/12. :- end_lpad. state_diagram(digraph(G)):- findall(edge(A -> B,[label=P]), (clause(next_state(A,B,_,_,_), (get_var_n(_,_,_,_,Probs,_),equalityc(_,_,N,_))), nth0(N,Probs,P)), G). which Im creating the diagram and the 2 one is this which I just creating the two coins and dices. I dont know how to continue from this. The 1st one is specific from a example from cplint. I cannot find any other forum specified for this kind of tasks. Seems like problog is "dead" :- use_module(library(pita)). :- if(current_predicate(use_rendering/1)). :- use_rendering(c3). :- endif. :- pita. :- begin_lpad. heads(RC): 0.9; tails(RC) : 0.1:- toss(RC). heads(GC): 0.95; tails(GC) : 0.05:- toss(GC). toss(rc); RD(0,1):1/6;RD(0,2):1/6;RD(0,3):1/6;RD(0,4):1/6;RD(0,5):1/6;RD(0,6):1/6. RD(0,1):1/6;RD(0,2):1/6;RD(0,3):1/6;RD(0,4):1/6;RD(0,5):1/6;RD(0,6):1/6:- X1 is X-1,X1>=0, RD(X1,_), \+ RD(X1,6) GD(0,1):1/12;GD(0,2):1/12;GD(0,3):1/12;GD(0,4):1/12;GD(0,5):1/12;GD(0,6):7/12. GD(0,1):1/12;GD(0,2):1/12;GD(0,3):1/12;GD(0,4):1/12;GD(0,5):1/12;GD(0,6):7/12:- X1 is X1-1,X1>=0, GD(X1,_), \+ GD(X1,12). toss(RC). toss(GC). :- end_lpad.
Not sure if this is still useful but in ProbLog you could have tried something like this: %% Probabilities 1/6::red_die(1,T) ; 1/6::red_die(2,T) ; 1/6::red_die(3,T) ; 1/6::red_die(4,T) ; 1/6::red_die(5,T) ; 1/6::red_die(6,T). 7/12::green_die(1,T) ; 1/12::green_die(2,T) ; 1/12::green_die(3,T) ; 1/12::green_die(4,T) ; 1/12::green_die(5,T) ; 1/12::green_die(6,T). 0.9::red_coin_head(T). 0.95::green_coin_head(T). %% Rules % Start with tossing red toss_red(1). % Toss red if previous toss was red, head. toss_red(T) :- T > 1, Tprev is T - 1, toss_red(Tprev), red_coin_head(Tprev). % Toss red if previous toss was green but tails. toss_red(T) :- T > 1, Tprev is T - 1, toss_green(Tprev), \+green_coin_head(Tprev). % Toss green if previous toss was green, head. toss_green(T) :- T > 1, Tprev is T - 1, toss_green(Tprev), green_coin_head(Tprev). % Toss green if previous toss was red but tails. toss_green(T) :- T > 1, Tprev is T - 1, toss_red(Tprev), \+red_coin_head(Tprev). % Writing results from red_die if next toss is red. results([X],1) :- red_die(X,1), toss_red(1). results([X|Y],T) :- T > 1, Tprev is T - 1, red_die(X,T), toss_red(T), results(Y,Tprev). % Writing results from green_die if next toss is green. results([X|Y],T) :- T > 1, Tprev is T - 1, green_die(X,T), toss_green(T), results(Y,Tprev). results(X) :- length(X, Length), results(X,Length). results(X) :- length(X, Length), results(X,Length). % Query query_state :- toss_red(1), toss_green(2), toss_green(2), toss_red(3), toss_red(4), toss_green(5), toss_green(6), toss_green(7), toss_green(8), toss_green(9). toss_green(10). evidence(results([1,1,2,2,3,6,1,1,1,3])). query(query_state). Which according to this has a probability of 0.00011567338
hmmpos.pl from here seems to be usefull enough to continue
Gerrit prolog rule - setting accumulative voting adequately
I want to create the following rule: The patch will become in submittable only there is 3 votes or more with +1, but THERE SHOULD NOT BE a vote with +2, only votes with +1 will be considered for this criterion. The rule that i have is: % rule : 1+1+1=2 Code-Review % rationale : introduce accumulative voting to determine if a change % is submittable or not and make the change submittable % if the total score is 3 or higher. sum_list([], 0). sum_list([H | Rest], Sum) :- sum_list(Rest,Tmp), Sum is H + Tmp. add_category_min_score(In, Category, Min, P) :- findall(X, gerrit:commit_label(label(Category,X),R),Z), sum_list(Z, Sum), Sum >= Min, !, gerrit:commit_label(label(Category, V), U), V >= 1, !, P = [label(Category,ok(U)) | In]. add_category_min_score(In, Category,Min,P) :- P = [label(Category,need(Min)) | In]. submit_rule(S) :- gerrit:default_submit(X), X =.. [submit | Ls], gerrit:remove_label(Ls,label('Code-Review',_),NoCR), add_category_min_score(NoCR,'Code-Review', 3, Labels), S =.. [submit | Labels]. this rule does not works at all, the problem is with the +2 vote. How can i rework this rule in order to works as i want?
So you want to have min three reviewers that can add +1 and +2 is not allowed. What if you remove developers rights to give +2 from project config and use prolog cookbook example 13 with little modifications? submit_rule(submit(CR)) :- sum(3, 'Code-Review', CR), % gerrit:max_with_block(-1, 1, 'Verified', V). % Sum the votes in a category. Uses a helper function score/2 % to select out only the score values the given category. sum(VotesNeeded, Category, label(Category, ok(_))) :- findall(Score, score(Category, Score), All), sum_list(All, Sum), Sum >= VotesNeeded, !. sum(VotesNeeded, Category, label(Category, need(VotesNeeded))). score(Category, Score) :- gerrit:commit_label(label(Category, Score), User). % Simple Prolog routine to sum a list of integers. sum_list(List, Sum) :- sum_list(List, 0, Sum). sum_list([X|T], Y, S) :- Z is X + Y, sum_list(T, Z, S). sum_list([], S, S).