Binding variables in Prolog - binding

I am having the following issue in a Prolog program.
The mathematical formulation of the problem is as follows:
Let Entanglements = the set of structures of the form entanglement(Symbol, Index, PosX, PosY), where Symbol is a character, Index an integer, and PosX and PosY variables (bound or unbound).
For all entanglement(Symbol, Index, PosX, PosY) in Entanglements, with one of the two variables PosX or PosY bound and the other unbound, bind the unbound variable to Symbol.
After that, let RemEntanglements = all entanglement(Symbol, Index, PosX, PosY) in Entanglements with at least one of PosX and PosY bound.
Question: Given the set Entanglements, what are the Remaining Entanglements (RemEntanglements)?
My code does not function as intended. Could you give a hint as to what I ought to change?
function(Entanglements, RemEntanglements) :-
findall(entanglement(Symbol, Index, PosX, PosY),
(member(entanglement(Symbol, Index, PosX, PosY), Entanglements),
(var(PosX), nonvar(PosY), PosX = Symbol;
var(PosY), nonvar(PosX), PosY = Symbol)),
Changed),
findall(entanglement(Symbol1, Index1, PosX1, PosY1),
(member(entanglement(Symbol1, Index1, PosX1, PosY1),Entanglements),
(var(PosX1);
var(PosY1))),
RemEntanglements).
Test query:
test(RemEntanglements) :-
function([entanglement('0',2,'X',P3),
entanglement('X',3,P3,P1), entanglement('0',4,P6,P7)],
RemEntanglements).
This query should work as follows:
1) Bind P3 to '0', given that entanglement('0',2,'X',P3) has one bound variable and an unbound one
2) RemEntanglements = [entanglement('X',3,'0',P1), entanglement('0',4,P6,P7)], given that P3 was already bound to the '0' symbol, but the others are still unbound.
The answer I got:
[entanglement('0', 2, 'X', _G11664), entanglement('X', 3, _G11655, _G11656), entanglement('X', 3, _G11647, _G11648), entanglement('0', 4, _G11639, _G11640), entanglement('0', 4, _G11631, _G11632)]
Thank you in advance!

I think you're using the wrong predicate: findall(Template,Goal,List) it's a list generator, and works - abstractly - instancing Template in Goal, then copies Template in List. Then any binding in Goal will be undone among executions.
Then I would write in this way
function(Entanglements, RemEntanglements) :-
maplist(instance, Entanglements),
include(one_bound, Entanglements, RemEntanglements).
instance(entanglement(Symbol, _Index, PosX, PosY)) :-
( ( var(PosX), nonvar(PosY) )
-> PosX = Symbol
; ( var(PosY), nonvar(PosX) )
-> PosY = Symbol
; true
).
one_bound(entanglement(_Symbol, _Index, PosX, PosY)) :-
nonvar(PosX) ; nonvar(PosY).
test(RemEntanglements) :-
function([ entanglement('0',2,'X',P3),
entanglement('X',3, P3,_),
entanglement('0',4, _,_)],
RemEntanglements).
that yields
?- test(L).
L = [entanglement('0', 2, 'X', '0'), entanglement('X', 3, '0', 'X')].

The way it is written now, you should at least get rid of singleton variables. They almost always point to an error in the logic of your predicate. For one, you are binding variables in the first findall (to Changed) and then using the original list in the second findall, which is clearly not your intention.
The singleton variables in your test however should be unbound, you can start their names with an underscore to silence the warning.

Related

lua -> how to modify these arguments to be const, or what should I do?

all!
I came here because I have one problem bugging me for quite some time now. I am using love2d engine as a 'graphical' addition to lua scripting, but this problem is of lua type (I believe, at least).
I have a function:
createNew_keepOld = function (oldImgData, oldImgDraw)
local newImgData = oldImgData --I am assigning old value to another variable
local newImgDraw = oldImgDraw --I am doing the same thing as with data
for x = 0, newImgData:getWidth()-1 do
for y = 0, newImgData:getHeight()-1 do
local r, g, b, a = newImgData:getPixel(x, y)
r = 2*r
g = 2*g
b = 0.5*b
a = 2*a
newImgData:setPixel(x, y, r, g, b, a)
end
end
newImgDraw:replacePixels(newImgData)
return newImgData, newImgDraw
end
When this code finishes, I get the change I need, but not WHERE I want it. I just want to produce two new variables which will store data and image objects. But, in process, original image gets changed.
Is there any way to declare:
name = function (const param, const param)
return some_things
end
So that I get output I need without changing the original stuff? Or is there some problem with my code that I cannot see?
Thanks!
Actually the nature of this problem is both in Love2D and Lua. Anyway.
Quote from Lua Reference Manual 5.3:
Tables, functions, threads, and (full) userdata values are objects: variables do not actually contain these values, only references to them. Assignment, parameter passing, and function returns always manipulate references to such values; these operations do not imply any kind of copy.
Most types from Love2D are of userdata Lua type, so when passing them to your function you are actually passing reference to them, hence you modify the "old" versions in the very end. Those types usually have functions made for copying them.
ImageData does have one and Image does not, but you can do the following:
createNew_keepOld = function (oldImgData, oldImgDraw)
local newImgData = oldImgData:clone()
for x = 0, newImgData:getWidth()-1 do
for y = 0, newImgData:getHeight()-1 do
local r, g, b, a = newImgData:getPixel(x, y)
r = 2*r
g = 2*g
b = 0.5*b
a = 2*a
newImgData:setPixel(x, y, r, g, b, a)
end
end
local newImgDraw = love.graphics.newImage(newImgData, oldImgDraw:getFlags())
return newImgData, newImgDraw
end
Note that I created entirely new Image based on copied ImageData and image flags from the old one.
In Lua when you make a variable equal to a table value you are not copying or duplicating that information. The new variable simply points to the same values as the other variable.
Example:
tbl1 = {}
tbl2 = tbl1
tbl2[1] = 1
print(tbl1[1])
In order to create a newImgDatabased on oldImgData you need to preform a deep copy:
function deepcopy(orig)
local orig_type = type(orig)
local copy
if orig_type == 'table' then
copy = {}
for orig_key, orig_value in next, orig, nil do
copy[deepcopy(orig_key)] = deepcopy(orig_value)
end
setmetatable(copy, deepcopy(getmetatable(orig)))
else -- number, string, boolean, etc
copy = orig
end
return copy
end
Resource for table copying: Lua-Users Wiki: Copy Table
This Solution only works a table type, it will not work for userdata

Loop through matrix

I'm creating a simple matrix like follows:
for x = 0, 50 do
current_level[x] = {}
for y = 0, 50 do
current_level[x][y] = grabTile();
end
end
After that i try to read it, but somehow the x is now a object not a number, while y seems perfectly fine!
How i try reading it:
for x,value in pairs(self.map) do
if value == ni then print("none"); return;end;
for y,object in pairs(value) do
if object == ni then print("none"); return;end;
object:render(x,y); -- Here x is an object
end
end
I'm new to working with lua, so i might be doing something obvious terribly wrong.
How would i make this work?
What i get for x is something like: table: 0x07c8d530
This value stays the same along the complete iteration
object:render(x,y); -- Here x is an object
This line is using colon syntax. It is a syntactic sugar for object.render(object,x,y) call.
So your render() function must have the first self argument declared either explicitly as function render(self, x, y) or implicitly with another syntactic sugar for definition: function object:render(x,y).
Unrelated hint. The first loop will be faster/smaller if transformed to:
for x = 0, 50 do
local row = {}
for y = 0, 50 do
row[y] = grabTile();
end
current_level[x] = row
end

Why is it the same table even though it is not a prototype

I have this code:
function createRect(x, y, w, h)
local rect = {
type = "rect",
x = x,
y = y,
w = w,
h = h,
translate = function(rect, vector)
assert(vector.type == "vector2d")
local rect = shapes.createRect(rect.x + vector.x, rect.y + vector.y, rect.w, rect.h)
end,
}
return rect
end
translate = function(rect, vector)
assert(vector.type == "vector2d")
local rect = shapes.createRect(rect.x + vector.x, rect.y + vector.y, rect.w, rect.h)
end
local o = createRect(2,3,4,5)
local q = createRect(2,3,4,5)
print(o.translate, q.translate, translate)
Which is some very easy code and is written to test factory functions in Lua and is very reminiscent of the JS module pattern. Something people usually complain about when talking about factory functions is the memory footprint.
Because o and q are just assigned, of course they have different translate() functions, I assumed.
However I was proven wrong:
function: 0x7fcdbe600d50 function: 0x7fcdbe600d50 function: 0x7fcdbe600d90
Why is this? How can this even be? I assumed to be o.translate and q.translate to be different functions, however they are the same...
How can this even be? I assumed to be o.translate and q.translate to be different functions, however they are the same...
Normally you are correct, however Lua 5.2 introduced an optimization where anonymous functions may be cached if certain conditions are met. Specifically, if the values it references doesn't change between construction then the first created instance of that anonymous function gets reused.
Running your example in repl.it, Lua 5.1, shows this as one possible output:
function: 0xb81f30 function: 0xb81f00 function: 0xb82ca0
But running it under melpon.org/wandbox, Lua 5.2+, shows:
function: 0x14f0650 function: 0x14f0650 function: 0x14efb40
In your example, createRect creates and returns a different rect table for every call but the field rect.translate is being assigned the same anonymous function as the lua value due to this optimization.
Also see
http://lua-users.org/lists/lua-l/2010-07/threads.html#00339
http://lua-users.org/lists/lua-l/2010-07/msg00862.html
http://lua-users.org/lists/lua-l/2010-05/threads.html#00617

Trying to obtain cost for a given path

I am new to Prolog
I am trying in Prolog a rule that gives me a given path from a node to another and also gives me the total weight of the path.
I have succeeded to get all the edges of the path but I am not able to show the weight of the path. I debbuged it and it is seen that variable S adds up to the whole weight of the path but in the way back, deletes all the elements. My idea is to add the total weight to P.
Code:
notIn(A,[]).
notIn(A,[H|T]):- A\==H,notIn(A,T).
path(X,X,_,[], S, P).
path(X,Y,[X|Cs], S, P) :-
path(X,Y,[X],Cs, S, P), P is S+W.
path(X,Y,Visited,[Z|Cs], S, P) :-
connection(X,Z,W),
notIn(Z,Visited),
path(Z,Y,[Z|Visited],Cs, S+W, P).
? path(ori, dest, X, 0, P).
Your predicate almost works. There are only two issues and some details I'd like to address. Firstly it would aid readability greatly to separate predicates with different arities. So let's put the one rule of path/5 in front of the two rules of path/6 like so:
path(X,Y,[X|Cs], S, P) :-
path(X,Y,[X],Cs, S, P),
P is S+W. % <-(1)
path(X,X,_,[], S, P).
path(X,Y,Visited,[Z|Cs], S, P) :-
connection(X,Z,W),
notIn(Z,Visited),
path(Z,Y,[Z|Visited],Cs, S+W, P). % <-(2)
Looking at your example query path/5 seems to be the predicate you want to call to find paths. In the second goal of its single rule (marked as % <-(1)) you are using the built-in is/2 with the expression S+W on the right hand side. The variable W appears here for the first time and thus is unbound. This leads to an instantiation error as illustrated by the following example:
?- X is 1+W.
ERROR!!
INSTANTIATION ERROR- in arithmetic: expected bound value
However, since you are only using path/5 to call path/6 there is no need for that goal. Secondly, in the second rule of path/6, in the last goal you are passing S+W as argument instead of evaluating it first. To see what happens, let's remove the goal marked % <-(1) from path/5 and add an example graph to your code:
connection(ori,a,2).
connection(a,b,5).
connection(b,a,4).
connection(b,dest,1).
Now consider your example query with an additional goal:
?- path(ori, dest, X, 0, P), Weight is P.
P = 0+2+5+1,
Weight = 8,
X = [ori,a,b,dest] ? ;
no
As you see the argument S+W leads to the final weight being an expression rather than a value. Consider adding a goal S1 is S+W before the recursive goal and pass S1 as an argument. Thirdly you are using the built-in (\==)/2 in your predicate notIn/2. This comparison succeeds or fails without side effect or unification. This is fine as long as both arguments are bound to values but are problematic when used with unbound variables. Consider the following queries:
?- X=Y, X\==Y.
no
fails as expected but:
?- X\==Y, X=Y.
X = Y
succeeds as X\==Y has no effect to the variables, so they can be unified in the next goal. It is a good idea to use dif/2 instead:
?- X=Y, dif(X,Y).
no
?- dif(X,Y), X=Y.
no
Lastly, two minor suggestions: First, since you are using the 4th argument of path/5 to pass 0 as a start-value for the weight, you might as well do that in the single goal of the rule, thereby simplifying the interface to path/4. Second, it would be nice to have a more descriptive name for the predicate that reflects its declarative nature, say start_end_path_weight/4. So your code would then look something like this:
notIn(A,[]).
notIn(A,[H|T]):-
dif(A,H),
notIn(A,T).
start_end_path_weight(X,Y,[X|Cs], P) :-
path(X,Y,[X],Cs, 0, P).
path(X,X,_,[], P, P).
path(X,Y,Visited,[Z|Cs], S, P) :-
connection(X,Z,W),
notIn(Z,Visited),
S1 is S+W,
path(Z,Y,[Z|Visited],Cs, S1, P).
With these modifications your example query looks like this:
?- start_end_path_weight(ori,dest,X,W).
W = 8,
X = [ori,a,b,dest] ? ;
no
Here's how to improve upon #tas's answer by using clpfd for arithmetics instead of (is)/2:
:- use_module(library(clpfd)).
start_end_path_weight(X,Y,[X|Cs], P) :-
path(X,Y,[X],Cs, 0, P).
path(X,X,_,[], P, P).
path(X,Y,Visited,[Z|Cs], S, P) :-
connection(X,Z,W),
notIn(Z,Visited)
maplist(dif(Z),Visited),
S1 is S+W
S1 #= S+W, S1 #=< P,
path(Z,Y,[Z|Visited],Cs, S1, P).
Limiting the maximum costs? Piece of cake!
Consider the following InterRail subset ...
... translated to Prolog ...
connection(X,Y,D) :- to_fro_dt(X,Y,D).
connection(X,Y,D) :- to_fro_dt(Y,X,D).
to_fro_dt(aberdeen,edinburgh,140). to_fro_dt(amsterdam,berlin,370). to_fro_dt(amsterdam,brussels,113). to_fro_dt(amsterdam,cologne,158). to_fro_dt(amsterdam,copenhagen,675). to_fro_dt(ancona,igoumenitsa,900). to_fro_dt(athens,patras,215). to_fro_dt(athens,/* for consistency */piraeus,5). to_fro_dt(athens,thessaloniki,265). to_fro_dt(bar,belgrade,572). to_fro_dt(barcelona,madrid,170). to_fro_dt(barcelona,marseille,280). to_fro_dt(barcelona,sevilla,330). to_fro_dt(barcelona,valencia,175). to_fro_dt(bari,igoumenitsa,570). to_fro_dt(bari,rome,240). to_fro_dt(belfast,dublin,240). to_fro_dt(belgrade,bucharest,730). to_fro_dt(belgrade,budapest,450). to_fro_dt(belgrade,sarajevo,540). to_fro_dt(belgrade,skopje,525). to_fro_dt(belgrade,sofia,485). to_fro_dt(bergen,oslo,405). to_fro_dt(berlin,cologne,260). to_fro_dt(berlin,hamburg,95). to_fro_dt(berlin,munich,345). to_fro_dt(berlin,prague,275). to_fro_dt(berlin,warsaw,365). to_fro_dt(bern,frankfurt,235). to_fro_dt(bern,lyon,230). to_fro_dt(bern,milan,240). to_fro_dt(birmingham,edinburgh,265). to_fro_dt(birmingham,holyhead,245). to_fro_dt(birmingham,london,105). to_fro_dt(bologna,florence,37). to_fro_dt(bologna,milan,60). to_fro_dt(bordeaux,lyon,375). to_fro_dt(bordeaux,madrid,660). to_fro_dt(bordeaux,paris,180). to_fro_dt(bristol,london,105). to_fro_dt(brussels,cologne,107). to_fro_dt(brussels,frankfurt,190). to_fro_dt(brussels,london,140). to_fro_dt(brussels,paris,85). to_fro_dt(bucharest,budapest,830). to_fro_dt(bucharest,sofia,540). to_fro_dt(bucharest,zagreb,365). to_fro_dt(budapest,ljubljana,540). to_fro_dt(budapest,vienna,165). to_fro_dt(budapest,warsaw,680). to_fro_dt(budapest,zagreb,365). to_fro_dt(catania,naples,450). to_fro_dt(cologne,frankfurt,82). to_fro_dt(copenhagen,hamburg,270). to_fro_dt(copenhagen,oslo,520). to_fro_dt(copenhagen,stockholm,315). to_fro_dt(cork,dublin,165). to_fro_dt(dublin,holyhead,195). to_fro_dt(dublin,westport,210). to_fro_dt(edinburgh,glasgow,50). to_fro_dt(faro,lisbon,230). to_fro_dt(florence,rome,95). to_fro_dt(florence,venice,123). to_fro_dt(frankfurt,hamburg,220). to_fro_dt(frankfurt,munich,190). to_fro_dt(frankfurt,paris,235). to_fro_dt(hamburg,munich,350). to_fro_dt(helsinki,rovaniemi,570). to_fro_dt(helsinki,turku,110). to_fro_dt(heraklion,piraeus,390). to_fro_dt(igoumenitsa,patras,360). to_fro_dt(istanbul,sofia,775). to_fro_dt(istanbul,thessaloniki,720). to_fro_dt(kiruna,stockholm,960). to_fro_dt(lisbon,madrid,610). to_fro_dt(lisbon,porto,165). to_fro_dt(ljubljana,venice,540). to_fro_dt(ljubljana,zagreb,140). to_fro_dt(london,paris,135). to_fro_dt(london,penzance,305). to_fro_dt(lyon,marseille,100). to_fro_dt(lyon,paris,115). to_fro_dt(madrid,'málaga',165). to_fro_dt(madrid,pamplona,180). to_fro_dt(madrid,santander,270). to_fro_dt(madrid,santiago,425). to_fro_dt(madrid,sevilla,155). to_fro_dt(madrid,valencia,105). to_fro_dt(marseille,montpellier,140). to_fro_dt(marseille,nice,155). to_fro_dt(milan,munich,465). to_fro_dt(milan,nice,310). to_fro_dt(milan,venice,155). to_fro_dt(munich,prague,365). to_fro_dt(munich,venice,425). to_fro_dt(munich,vienna,250). to_fro_dt(naples,rome,70). to_fro_dt(oslo,stockholm,380). to_fro_dt(paris,rennes,120). to_fro_dt(piraeus,rhodes,710). to_fro_dt(prague,vienna,270). to_fro_dt(prague,warsaw,520). to_fro_dt(sarajevo,zagreb,550). to_fro_dt(skopje,sofia,540). to_fro_dt(skopje,thessaloniki,240). to_fro_dt(sofia,thessaloniki,400). to_fro_dt(split,zagreb,335). to_fro_dt(stockholm,/* added by hand */turku,725). to_fro_dt(stockholm,'östersund',420). to_fro_dt(trondheim,'östersund',230). to_fro_dt(venice,vienna,440). to_fro_dt(vienna,warsaw,450).
... let's find paths that
start in Vienna
include at least 2 other cities
and have a cumulative travel time of 10 hours (or less)!
?- W #=< 600, Path = [_,_,_|_], start_end_path_weight(vienna, _, Path, W).
W = 530, Path = [vienna,budapest,zagreb] ;
W = 595, Path = [vienna,munich,berlin] ;
W = 440, Path = [vienna,munich,frankfurt] ;
W = 522, Path = [vienna,munich,frankfurt,cologne] ;
W = 600, Path = [vienna,munich,hamburg] ;
W = 545, Path = [vienna,prague,berlin] ;
W = 563, Path = [vienna,venice,florence] ;
W = 600, Path = [vienna,venice,florence,bologna] ;
W = 595, Path = [vienna,venice,milan] ;
false. % terminates universally fast

How can I print multiple objects to console.log with dart?

In javascript, if I have 3 variables like this:
var x = 1
var y = 'cat'
var z = {color: 'blue'}
I can log all of them like this:
console.log('The values are:', x, y, z)
In dart, you can import 'dart:html' and it will map print to console.log in the compiled javascript. But print only takes one parameter - not 3. This dart will fail when the compiled js runs in the browser:
print('The values are:', x, y, z)
The only thing I can think to do is stringify these arguments and join them into one string, and print that. But then I lose Chrome's ability to expand objects that are printed to the console.
Is it possible to print multiple objects with one print statement (or similar statement)? If so, how?
What about: ?
print('The values are: ${[x, y, z]}')
or
print('The values are: $x, $y, $z')
or
['The values are:', x, y, z].forEach(print);
In Dart, you can import dart:html which gives you access to the window.console. Unfortunately, its log method can only take one argument. You can wrap your objects in a list though:
import 'dart:html';
var x = 1
var y = 'cat'
var z = {color: 'blue'}
window.console.log([x, y, z]);
use
print("$x,$y,$z");
or
stdout.write("$x,$y,$z");

Resources