Prolog - Getting element from a list of lists - matrix

I am having trouble figuring out how to access a single character from a list of strings without using recursion, but instead backtracking.
For example I have this list of Strings and I want to be able to return a single character from one of these strings ('.' 'o', '*'). The program I am working on is treating it as rows and columns. It is a fact in my database that looks like this:
matrix(["...o....",
".******.",
"...o....",
".*...*..",
"..o..*..",
".....*..",
".o...*..",
"....o..o"].
I have the predicate:
get(Row,Col,TheChar) :-
that takes a row and column number (with index starting at 1) and returns the entry (TheEntry) at that specific row and column.
I have a feeling my predicate head might not be build correctly but I'm really more focused on just how to go through each String in the list character by character without recursion and returning that.
I am new to prolog and am having major difficulty with this.
Any help at all would be greatly appreciated!
Thank you!

An implementation of get/3 might look like this:
get(Row,Col,TheChar) :-
matrix(M),
nth(Row,M,RowList),
nth(Col,RowList,TheChar).
Note that TheChar is unified to a character code e.g.
| ?- get(1,4,X).
X = 111
If you want to get see the character you can for instance use atom codes, e.g.
| ?- get(4,2,X), atom_codes(CharAtom,[X]).
X = 42
CharAtom = *
Hope this helps.

using your matrix representation, you could do something like this:
cell(X,Y,Cell) :-
matrix(Rows) ,
Matrix =.. [matrix|Rows] ,
arg(X,Matrix,Cols) ,
Row =.. [row|Cols] ,
arg(Y,Row,Cell)
.
The use of =.. to construct terms on the fly might be a hint that your matrix representation isn't the best. You might consider different representations for your matrix.
Assuming a "standard" matrix with fixed-length rows, you could represent the matrix
A B C D
E F G H
I J K L
in a couple of different ways:
A single string, if the cell values can be represented as a single character and your prolog supports real strings (rather than string-as-list-of-char-atoms):
"ABCDEFGHIJKL"
Lookup is simple and zero-relative (e.g., the first row and the first column are both numbered 0):
( RowLength * RowOffset ) + ColOffset
gives you the index to the appropriate character in the atom. Retrieval consists of a simple substring operation. This has the advantages of speed and simplicity.
a compound term is another option:
matrix( rows( row('A','B','C','D') ,
row('E','F','G','H') ,
row('I','J','K','L')
)
).
Lookup is still simple:
cell(X,Y,Matrix,Value) :-
arg(X,Matrix,Row) ,
arg(Y,Matrix,Cell)
.
A third option might be to use the database to represent your matrix more directly using the database predicates asserta, assertz, retract , retractall , recorda, recordz, recorded, erase. You could build a structure of facts, for instance in the database along the lines of:
matrix( Matrix_Name ).
matrix_cell( Matrix_Name , RowNumber , ColumnNumber , Value ).
This has the advantage of allowing both sparse (empty cells don't need to be represented) and jagged (rows can vary in length) representations.
Another option (last resort,you might say) would be to jump out into a procedural language, if your prolog allows that, and represent the matrix in a more...matrix-like manner. I had to do that once: we ran into huge performance problems with both memory and CPU once the data model got past a certain size. Our solution was to represent the needed relation as a ginormous array of bits, which was trivial to do in C (and not so much in Prolog).
I'm sure you can come up with other methods of representing matrices as well.
TMTOWTDI (Tim-Toady or "There's More Than One Way To Do It") as they say in the Perl community.

Related

Prolog "," operator not working as intended?

I'm super unfamiliar with prolog but I need it for a school project. So, if I use unclear language or incorrect terms, please be understanding. My trouble is that my code is not working how I intended it at all. Here is a bit of my code in the knowledge base:
output(mn,hp,hp,hp).
output(hn,mn,hp,lp).
output(ln,hp,mp,hp).
input(lp,mp,mp,lp):-output(hn,mn,hp,lp).
And here is my query:
?- input(X,mp,mp,lp),output(hn,mn,hp,lp).
I would expect it to return X = lp, as the if-then sentence in the knowledgebase states. However, it returns X=hp, X=mp, and X=lp, which is not what I intended.
I used "trace" to see how it reasoned, and I saw that it called for other outputs. I thought the "," operator meant "and", so it would only look for the output with the values (hn,mn,hp,lp). How can I get my code to only look for if-then sentences with the correct output values? Do I have an incorrect understanding of the "," operator or is the problem due to my knowledge base?
EDIT: Here is the link to my code in SWISH: https://swish.swi-prolog.org/p/i%20wanna%20bash%20my%20head%20in.pl#&togetherjs=AQ4zzkAQk4
EDIT 2: My aim with this project is the following: I'm trying to explain a fuzzy cognitive map with this program. I want the program to determine the values of missing input concepts given the output concepts. So, I need the program to look for the clause with the correct values in output(), and then determine the values inside the relevant input().
With the whole program (88 lines):
?- output(hn,mn,hp,lp).
true.
So this can be completely disregarded in your query - it's true no matter what (constants only) and has no further effect.
Then what counts is:
?- input(X,mp,mp,lp).
X = mp ;
X = lp ;
X = hp ;
false.
No need for Prolog. Use text search to confirm that:
$ grep "mp,mp,lp" proggy.pl
input(mp,mp,mp,lp):-output(mn,hp,hp,hp).
input(mp,mp,lp,hp):-output(hn,lp,hp,hp).
input(mp,mp,lp,mp):-output(hn,mp,hp,hp).
input(lp,mp,mp,lp):-output(hn,mn,hp,lp).%this one is a pain in my ass
input(hp,mp,mp,lp):-output(ln,hp,mp,hp).
input(mp,mp,lp,lp):-output(ln,hp,mp,hp).
of the above, these three lines
input(mp,mp,mp,lp):-output(mn,hp,hp,hp).
input(lp,mp,mp,lp):-output(hn,mn,hp,lp).%this one is a pain in my ass
input(hp,mp,mp,lp):-output(ln,hp,mp,hp).
<-><------>
X MATCH
will match the query: 3 results with X from mn,hn,ln.
Working as expected.
Here is a simpler query:
?- input(X,mp,mp,lp).
This succeeds three times:
X = mp ;
X = lp ;
X = hp ;
false.
I assume you understand why this is: There are several matching clauses for input with different values for X and with bodies that succeed.
Now, you are right that , is conjunction, and that in general a goal A, B can succeed less often than A or B individually, but never more often. A and B typically constrain each other. But, very importantly: If A and B do not share any variables, then they are independent. In this case, the sequence of answers will be the Cartesian product of the answers for A and the answers for B. If A alone succeeds N times and B alone succeeds M times, then A, B without a shared variable will succeed N * M times.
You can only expect to see fewer solutions for a query of the form ?- input(X,mp,mp,lp), OtherGoal. if OtherGoal also contains an occurrence of X. In your query this is not the case. The first conjunct succeeds three times, the second succeeds once, so overall you have 3 * 1 = 3 successes, as you observed.
So the question is: What are you trying to express with your query? You cannot express something like "give me solutions for input, but only by applying certain clauses of output".

selecting matrices based on a variable

Is there a way I can use a command that selects a matrix to use based on a variable?
Need in this /
:If (way to select a matrix based on what variable L equals) (E,F)=1:Output E,F,"O
I don't want to make a specific go-to for every single matrix I need.
This is for creating maps with the matrix in case anyone has a better way.
If i understand correctly you want to get the value from a certain matrix, chosen dynamically depending on the value of a variable. You can kinda do this by putting the names of the matrices into a string, then grab a substring of the string, using sub(, at a dynamic offset, based on L, and then feeding that string into expr( to get a reference to the matrix, ie
:"[A][B][C]"->Str1, sub(Str1,2,1) yields "[B]", expr("[B]") yields Matrix B...so 2 maps to [B]. TI considers the symbol [A] (and all the other matrix vars) to be a single character, so "[A][B][C]" is a 3 character string.
Note that all of the matrix vars need to be input from the MATRIX menu (including inside the string). Typing in the individual [ A ] chracters will not work.
Also note you can't grab indexes off of a matrix returned with expr (ie expr("[A]")(1,2) so you need an extra matrix (I used [J]) to store the result.
For example
:"MAKE SOME MATRICES"
:[[1,2][3,4]]->[A]
:[[5,6][7,8]]->[B]
:[[9,10],[11,12]]->[C]
:"SAMPLE L VALUE"
:2->L
:"STORE REFERENCES TO THE"
:"MATRICES IN A STRING"
:"[A][B][C]"->Str1
:expr(sub(Str1, L, 1))->[J]
:"SHOWS 6"
:[J](1,2)
so then proceed normally with [J]
:If [J](E,F)
: "DO WHATEVER
Tested on an 84 SE, I assume it would work the same for anything in that family, except IIRC some older models only have matrices A-F

How to iterate through structure?

If I have a list like: [atm(abd,bubu,ha), atm(aei),atm(xyz,huhu), atm(aabb,a,e,x)], how could I 'iterate' through the elements of one of the atm structures?
For example, for atm(abd, bubu, ha), I would like to write abd, bubu and ha.
The problem is that the structures have variable length.
Is there a way to transform the structure into a list? Thanks.
Using (=..)/2
#TopologicalSort has already given a nice answer, using (=..)/2 to convert a term to a list of functor and arguments.
This obviously solves the immediate problem very generally.
However, it comes with its own drawbacks too: First and most importantly, (=..)/2 is not a general relation. For example, we have:
?- X =.. Y.
ERROR: Arguments are not sufficiently instantiated
This means that we cannot use this construct to generate solutions. It works only if its arguments are sufficiently instantiated.
Second, using (=..)/2 also comes with the time and memory overhead of constructing and representing a list in addition to the term that is already there in a different form. (And, mutatis mutandis, in the other direction too of course.)
Thus, it may be worth to ask: Are there different ways to solve this task? Are they better suited?
Alternative 1: Doing it manually
How do I convert thee? Let me count the ways.
From the example you cite, we must be able to handle—in order of their appearance—terms of the following forms:
atm/3
atm/1
atm/2
atm/4
The point here is that the number of shown cases is finite, and so we can easily handle them all like this:
atm_list(atm(A), [A]).
atm_list(atm(A,B), [A,B]).
atm_list(atm(A,B,C), [A,B,C]).
atm_list(atm(A,B,C,D), [A,B,C,D]).
To convert a list of such terms, you can use maplist/2:
?- Ls = [atm(abd,bubu,ha), atm(aei),atm(xyz,huhu), atm(aabb,a,e,x)],
maplist(atm_list, Ls, Lists).
Ls = [atm(abd, bubu, ha), atm(aei), atm(xyz, huhu), atm(aabb, a, e, x)],
Lists = [[abd, bubu, ha], [aei], [xyz, huhu], [aabb, a, e, x]].
A major advantage is that this relation is very general and can also be used to generate answers:
?- atm_list(A, Ls).
A = atm(_27464, _27466, _27468),
Ls = [_27464, _27466, _27468] ;
A = atm(_27464),
Ls = [_27464] ;
A = atm(_27464, _27466),
Ls = [_27464, _27466] ;
A = atm(_27464, _27466, _27468, _27470),
Ls = [_27464, _27466, _27468, _27470].
This is also more efficient than using (=..)/2. Clearly, it can only be done if the number of arising cases is finite. (Exercise: Write a Prolog program that generates clauses for all integers 1..N).
Alternative 2: Using lists
There are several well-known criteria for judging whether lists are an appropriate data structure. For example:
Does the empty list make sense in your use case?
Are there sensible cases for all possible lengths?
etc.
Only you can answer this question for your particular use case, so I only show what it could look like: Suppose you represent your whole initial list as follows:
[[abd,bubu,ha],[aei],[xyz,huhu],[aab,a,e,x]]
Then the whole issue does not even arise, because the elements are already specified as lists. Thus, there is no more need to convert anything.
Sure.
If First is atm(abd,bubu,ha) (for example), this code will split it into a list you can go through.
First =.. List.
Then, List will be [atm, abd, bubu, ha].
IDK if this works in your particular version of PROLOG. I'm using SWI-PROLOG. If not, maybe your version has a similar predicate.
For more information, see http://www.swi-prolog.org/pldoc/doc_for?object=(%3D..)/2 .

How to use member predicate to specify constraints in prolog

I'm trying to write a Prolog program which does the following:
I have some relations defined in the Relations list. (For example: [f1,s1] means f1 needs s1) Depending on what features(f1,f2,f3) are selected in the TargetFeat list, I would like to create Result list using constraint programming.
Here is a sample code:
Relations =[[f1, s1], [f2, s2], [f3, s3], [f3, s4]],
TargetFeat = [f3, f1],
Result = [],
member(f3,TargetFeat) #= member(s3,Result), %One of the constraints
labeling(Result).
This doesn't work because #= works only with arithmetic expressions as operands. What are the alternatives to achieve something like this ?
There are many possible ways to model such dependencies with constraints. I consider in this post CLP(FD) and CLP(B) constraints, because they are most commonly used for solving combinatorial tasks.
Consider first CLP(FD), which is more frequently used and more convenient in many ways. When using CLP(FD) constraints, you again have several options to represent your task. However, no matter which model you eventually choose, you must first switch all items in your representation to suitable entitites that the constraint solver can actually reason about. In the case of CLP(FD), this means switching your entities to integers.
Translating your entities to corresponding integers is very straight-forward, and it is one of the reasons why CLP(FD) constraints also suffice to model tasks over domains that actually do not contain integers, but can be mapped to integers. So, let us suppose you are not reasoning about features f1, f2 and f3, but about integers 0, 1, and 2, or any other set of integers that suits you.
You can directly translate your requirements to this new domain. For example, instead of:
[f1,s1] means: f1 needs s1
we can say for example:
0 -> 3 means: 0 needs 3
And this brings us already very close to CLP(FD) constraints that let us model the whole problem. We only need to make one more mental leap to obtain a representation that lets us model all requirements. Instead of concrete integers, we now use CLP(FD) variables to indicate whether or not a specific requirement must be met to obtain the desired features. We shall use the variables R1, R2, R3, ... to denote which requirements are needed, by using either 0 (not needed) or 1 (needed) for each of the possible requirements.
At this point, you must develop a clear mental model of what you actually want to describe. I explain what I have in mind: I want to describe a relation between three things:
a list Fs of features
a list Ds of dependencies between features and requirements
a list Rs of requirements
We have already considered how to represent all these entitites: (1) is a list of integers that represent the features we want to obtain. (2) is a list of F -> R pairs that mean "feature F needs requirement R", and (3) is a list of Boolean variables that indicate whether or not each requirement is eventually needed.
Now let us try to relate all these entitites to one another.
First things first: If no features are desired, it all is trivial:
features_dependencies_requirements([], _, _).
But what if a feature is actually desired? Well, it's simple: We only need to take into account the dependencies of that feature:
features_dependencies_requirements([F|Fs], Ds, Rs) :-
member(F->R, Ds),
so we have in R the requirement of feature F. Now we only need to find the suitable variable in Rs that denotes requirement R. But how do we find the right variable? After all, a Prolog variable "does not have a bow tie", or—to foreigners—lacks a mark by which we could distinguish it from others. So, at this point, we would actually find it convenient to be able to nicely pick a variable out of Rs given the name of its requirement. Let us hence suppose that we represent Rs as a list of pairs of the form I=R, where I is the integer that defines the requirement, and R is the Boolean indicator that denotes whether that requirement is needed. Given this representation, we can define the clause above in its entirety as follows:
features_dependencies_requirements([F|Fs], Ds, Rs) :-
member(F->I, Ds),
member(I=1, Rs),
features_dependencies_requirements(Fs, Ds, Rs).
That's it. This fully relates a list of features, dependencies and requirements in such a way that the third argument indicates which requirements are necessary to obtain the features.
At this point, the attentive reader will see that no CLP(FD) constraints whatsoever were actually used in the code above, and in fact the translation of features to integers was completely unnecessary. We can as well use atoms to denote features and requirements, using the exact same code shown above.
Sample query and answers:
?- features_dependencies_requirements([f3,f1],
[f1->s1,f2->s2,f3->s3,f3->s4],
[s1=S1,s2=S2,s3=S3,s4=S4]).
S1 = S3, S3 = 1 ;
S1 = S4, S4 = 1 ;
false.
Obviously, I have made the following assumption: The dependencies are disjunctive, which means that the feature can be implemented if at least one of the requirements is satisifed. If you want to turn this into a conjunction, you will obviously have to change this. You can start by representing dependencies as F -> [R1,R2,...R_n].
Other than that, can it still be useful to translate your entitites do integers? Yes, because many of your constraints can likely be formulated also with CLP(FD) constraints, and you need integers for this to work.
To get you started, here are two ways that may be usable in your case:
use constraint reification to express what implies what. For example: F #==> R.
use global constraints like table/2 that express relations.
Particularly in the first case, CLP(B) constraints may also be useful. You can always use Boolean variables to express whether a requirement must be met.
Not a solution but some observations that would not fit a comment.
Don't use lists to represent relations. For example, instead of [f1, s1], write requires(f1, s1). If these requirement are fixed, then define requires/2 as a predicate. If you need to identify or enumerate features, consider a feature/1 predicate. For example:
feature(f1).
feature(f2).
...
Same for s1, s2, ... E.g.
support(s1).
support(s2).
...

Prolog manual or custom labeling

I am currently writing a solver for a floor planning problem in Prolog and have some issues with the labeling part.
The current problem is my constraints are posted but when I launch the labeling, it takes forever to find a solution. I would like to bring in some heuristics.
My question is, how do I manually label my variables ? I am afraid that after defining a clpfd variable like this :
X in Xinf..Xsup
and constraining it, If I do something like :
fd_sup(X, Xmax),
X = Xmax,
...
in my custom label, I won't be using the backtrack ability of Prolog to test the other values of X's domain. Am I wrong ?
Also, is there a smarter way to label my variables than writing custom labeling procedures ? My idea of heuristics would consist in trying extrema of a variable domain alternatively (like max(X), min(X), max(X-1), min(X-1) etc...)
Hope you can help me :)
It is not difficult to write a custom labeling procedure, and with most real problems you will eventually need one anyway in order to incorporate problem-specific heuristics.
The two main components of a labeling procedure are
variable selection: from all the remaining (i.e. not yet instantiated) problem variables, pick one to consider next.
value selection or branching: explore, via backtracking, two or more alternative sub-problems by reducing the chosen variable's domain in (usually) complementary ways.
Using this scheme, the default labeling procedure can be written as
label(Xs) :-
( select_variable(X, Xs, Xs1) ->
branch(X),
label(Xs1)
;
true % done, no variables left
).
select_variable(X, [X|Xs], Xs). % 'leftmost' strategy
branch(X) :- indomain(X).
You can now redefine select_variable/3 to implement techniques such as "first-fail", and redefine branch/1 to try domain values in different orders. As long as you make sure that branch/1 enumerates all of X's domain values on backtracking, your search remains complete.
Sometimes you want to try just one domain value first (say, one suggested by a heuristics), but, if it is no good, not commit to another value immediately.
Let's say that, as in your example, you want to try the maximum domain value first. You could write this as
branch(X) :-
fd_sup(X, Xmax),
(
X = Xmax % try the maximum
;
X #\= Xmax % otherwise exclude the maximum
).
Because the two cases are complementary and cover all possible values for X, your search is still complete. However, because of the second alternative, branch/1 can now succeed with an uninstantiated X, which means you must make sure in the labeling procedure that you don't lose this variable from your list. One possibility would be:
label(Xs) :-
( select_variable(X, Xs, Xs1) ->
branch(X),
( var(X) -> append(Xs1, [X], Xs2) ; Xs2=Xs1 ),
label(Xs2)
;
true % done, no variables left
).
First, always try built-in heuristics. ff is often a good strategy.
For custom labeling strategies, it is often easiest to first convert the domain to a list, then reorder the list, and then simply use member/2 to assign the values of the domain using the new order.
A good building black is dom_integers/2, relating a finite CLP(FD) domain to a list of integers:
:- use_module(library(clpfd)).
dom_integers(D, Is) :- phrase(dom_integers_(D), Is).
dom_integers_(I) --> { integer(I) }, [I].
dom_integers_(L..U) --> { numlist(L, U, Is) }, Is.
dom_integers_(D1\/D2) --> dom_integers_(D1), dom_integers_(D2).
Your specific strategy is easily expressed on a list of such ordered integers, relating these integers to a second list where the values occur in the order you describe:
outside_in([]) --> [].
outside_in([I]) --> [I].
outside_in([First|Rest0]) --> [First,Last],
{ append(Rest, [Last], Rest0) },
outside_in(Rest).
Sample query and result:
?- phrase(outside_in([1,2,3,4]), Is).
Is = [1, 4, 2, 3] ;
false.
Combining this with fd_dom/2 and dom_integers/2, we get (bindings for variables other than X omitted):
?- X in 10..20,
fd_dom(X, Dom),
dom_integers(Dom, Is0),
phrase(outside_in(Is0), Is),
member(X, Is).
X = 10 ;
X = 20 ;
X = 11 ;
X = 19 ;
X = 12 ;
X = 18 ;
etc.
Nondeterminism is preserved by member/2.
Make sure to distinguish labeling strategies from additional propagation. These two aspects are currently a bit mixed in your question.
In SWI-Prolog, there is a predicate called clpfd:contracting/1. It does what you describe: It tries values from the domain boundaries, and removes values that can be seen as inconsistent, i.e., for which it is known that no solution exists.
Therefore, if you have a list of variables Vs, you can try: clpfd:contracting(Vs), and see if this helps.
Note that this can also significantly slow down the search, though on the other hand, also help significantly to reduce the search space before even trying any labeling!
To complement the other answers (one contrasting labeling and propagation, one showing a dedicated labeling method), I now tackle a further very important aspect of this question:
Very often, when beginners complain about the speed of their code, it turns out that their code in fact doesn't even terminate! More efficiency would not help in that case.
Hence, this answer points you towards first ensuring actual termination of your relation.
The best way to ensure termination of CLP(FD) programs is to separate them into 2 parts:
the first, called the core relation, simply posts all constraints.
the second uses labeling/2 to perform the actual search.
Have you done this in your program? If not, please do. When this is done, make sure that the core relation, say solution/2 (where the arguments are: a term denoting the task instance, and the list of variables to be labeled) terminates universally by querying:
?- solution(Instance, Vs), false.
If this terminates, then the following also terminates:
?- solution(Instance, Vs), label(Vs), false.
Of course, in larger tasks, you have no chance to actually witness the termination of the latter query, but a good chance to witness the termination of the first query, because setting up the constraints is often much faster than actually obtaining even a a single solution.
Therefore, test whether your core relation terminates!
This follows up on this previous answer by #mat.
If you have got some more CPU cycles to burn, try shave_zs/1 as defined in this previous answer.
shave_zs/1 kind of works like the auxiliary library predicate clpfd:contracting/1. Unlike contracting/1, however, all values are "up for grabs"—not just the ones at the boundary. YMMV!

Resources