Discussion:
Getting how many prolog frames a particular variable has existed in thus far
dmiles@users.sourceforge.net
2002-07-31 19:45:19 UTC
Permalink
Hi,

What would be the most efficient way to get how many prolog frames a particular variable has
existed in thus far?
What implications if this was done in the C code would it have?


-Douglas


----------------
* To UNSUBSCRIBE, please use the HTML form at

http://www.swi-prolog.org/mailinglist.html

or send mail to prolog-***@swi.psy.uva.nl using the Subject: "unsubscribe"
(without the quotes) and *no* message body.

** An ARCHIVE of this list is maintained at

http://www.swi.psy.uva.nl/projects/SWI-Prolog/mailinglist/archive/
Jan Wielemaker
2002-08-01 12:45:42 UTC
Permalink
Douglas
Post by ***@users.sourceforge.net
What would be the most efficient way to get how many prolog frames a particular variable has
existed in thus far?
What do you mean by variable and what by frame? Prolog stack frames?
Frames represented in a frame-system? What is a variable? Incarnation
of a variable in the source?
Post by ***@users.sourceforge.net
What implications if this was done in the C code would it have?
Generally the only effect of counting is that it consumes CPU cycles.

--- Jan


----------------
* To UNSUBSCRIBE, please use the HTML form at

http://www.swi-prolog.org/mailinglist.html

or send mail to prolog-***@swi.psy.uva.nl using the Subject: "unsubscribe"
(without the quotes) and *no* message body.

** An ARCHIVE of this list is maintained at

http://www.swi.psy.uva.nl/projects/SWI-Prolog/mailinglist/archive/
dmiles@users.sourceforge.net
2002-08-01 23:44:52 UTC
Permalink
A frame would be a prolog_current_frame(PrologFrame).

Variable would be a member of VarsInThisFrame
from prolog_frame_attribute(PrologFrame,goal,Term),free_varialbes(Term,VarsInThisFrame).

My assumptions:

Whenever a frame makes a child it reuses the same variable references (because children frames
are made with a procedures using some unification)
So it would be possible that a parent frame and a child frame goal could have identical (==)
free variables.

I would be saying the child's variable to have a depth+1 from its parents depth on that same
variable.

So a program like:

a(X):-b(X).
b(X):-c(X).
c(X).

So a call to a(V) reached the c/1 clause would say that V has been around for 2 or 3 prolog
frames.

With a call to a(foo), there would be no variables in any child. (Therefore a case where we
couldn't count them)

Assumptions about what it would mean in code...

that the struct of a variable when first constructed (initialized) would record it originator
frame.
This would be less expensive the keeping some ref-count (if done, would be better left to a
sibling count for alternative frames)

So mainly what I think I need is just a number that will tell me the frame the variable was
first constructed in.. i could use the current frame reference to subtract possibly.


What i am trying to do is construct a
call_with_var_depth_limit(my_goal(A,B,C),[A,B,C],4,WasExceeded).


Or make a predicate like


b(X):-var(X),depth_of_var(X,Depth),Depth<4,c(X).


What do you think? Would this be useful to others besides me?

-Douglas
-----Original Message-----
Sent: Thursday, August 01, 2002 5:46 AM
Subject: Re: [SWIPL] Getting how many prolog frames a particular
variable has existed in thus far
Douglas
Post by ***@users.sourceforge.net
What would be the most efficient way to get how many prolog
frames a particular variable has
Post by ***@users.sourceforge.net
existed in thus far?
What do you mean by variable and what by frame? Prolog stack frames?
Frames represented in a frame-system? What is a variable?
Incarnation
of a variable in the source?
Post by ***@users.sourceforge.net
What implications if this was done in the C code would it have?
Generally the only effect of counting is that it consumes CPU cycles.
--- Jan
----------------
* To UNSUBSCRIBE, please use the HTML form at
http://www.swi-prolog.org/mailinglist.html
Subject: "unsubscribe"
(without the quotes) and *no* message body.
** An ARCHIVE of this list is maintained at
http://www.swi.psy.uva.nl/projects/SWI-Prolog/mailinglist/archive/
Jan Wielemaker
2002-08-02 09:04:48 UTC
Permalink
Post by ***@users.sourceforge.net
A frame would be a prolog_current_frame(PrologFrame).
Variable would be a member of VarsInThisFrame
from prolog_frame_attribute(PrologFrame,goal,Term),free_varialbes(Term,VarsInThisFrame).
Note that the variables in a goal may be arguments in created or
passed compound terms.
Post by ***@users.sourceforge.net
Whenever a frame makes a child it reuses the same variable references (because children frames
are made with a procedures using some unification)
So it would be possible that a parent frame and a child frame goal could have identical (==)
free variables.
I would be saying the child's variable to have a depth+1 from its parents depth on that same
variable.
a(X):-b(X).
b(X):-c(X).
c(X).
So a call to a(V) reached the c/1 clause would say that V has been around for 2 or 3 prolog
frames.
I think you need some explanations how things work. Your a(X) creates
a frame with a place for the variable. Calling b(X) (disregarding
last-call optimization) creates a frame for b where the variable is a
_reference_ to the original. Calling c(X), the system is clever and
doesn't make a reference to the X in b's frame, but directly to X is
a's frame. Finally, in reality all this is collapsed in this program
due to last-call optimization.

If you would like to do what you want you either need some way of
attributed-variables or you need to disable last-call optimization
and minimization of reference-chains. In that case the length of
the reference chain is the `age' or your variable. This is not
something you want to do lightly.
Post by ***@users.sourceforge.net
With a call to a(foo), there would be no variables in any child. (Therefore a case where we
couldn't count them)
Assumptions about what it would mean in code...
that the struct of a variable when first constructed (initialized) would record it originator
frame.
This would be less expensive the keeping some ref-count (if done, would be better left to a
sibling count for alternative frames)
So mainly what I think I need is just a number that will tell me the frame the variable was
first constructed in.. i could use the current frame reference to subtract possibly.
What i am trying to do is construct a
call_with_var_depth_limit(my_goal(A,B,C),[A,B,C],4,WasExceeded).
Or make a predicate like
b(X):-var(X),depth_of_var(X,Depth),Depth<4,c(X).
What do you think? Would this be useful to others besides me?
What is the more high-level goal you want to achieve? What you want
is pretty hard to do as it basically forces the system to drop
important optimizations. Maybe from a higher perspective it becomes
easier.

--- Jan


----------------
* To UNSUBSCRIBE, please use the HTML form at

http://www.swi-prolog.org/mailinglist.html

or send mail to prolog-***@swi.psy.uva.nl using the Subject: "unsubscribe"
(without the quotes) and *no* message body.

** An ARCHIVE of this list is maintained at

http://www.swi.psy.uva.nl/projects/SWI-Prolog/mailinglist/archive/
dmiles@users.sourceforge.net
2002-08-02 10:43:50 UTC
Permalink
-----Original Message-----
Sent: Friday, August 02, 2002 2:05 AM
Subject: RE: [SWIPL] Getting how many prolog frames a particular
variable has existed in thus far
Post by ***@users.sourceforge.net
A frame would be a prolog_current_frame(PrologFrame).
Variable would be a member of VarsInThisFrame
from
prolog_frame_attribute(PrologFrame,goal,Term),free_varialbes(T
erm,VarsInThisFrame).
Note that the variables in a goal may be arguments in created or
passed compound terms.
Yes very understandable: variables could come or be introduced anywhere like from some
unexpected
compound inner terms I could not expect to foresee all the variables that will get created in a
program.
But with term_expansion I could catch Head variables then while a program loads (those are the
only ones a care to track)

term_expansion((H:-Body),(H:-NewBody)):-
free_variables(H,HeadVars),
convert_to_checks(Body,HeadVars,NewBody).

convert_to_checks(Body,[],Body).
convert_to_checks(Body,[Hv|TVs],((depth_of_variable(Hv,D),D<3),More)):-
convert_to_checks(Body,TVs,More).
I think you need some explanations how things work. Your a(X) creates
a frame with a place for the variable. Calling b(X) (disregarding
last-call optimization) creates a frame for b where the variable is a
_reference_ to the original. Calling c(X), the system is clever and
doesn't make a reference to the X in b's frame, but directly to X is
a's frame. Finally, in reality all this is collapsed in this program
due to last-call optimization.
That is neat that tritely one variable reference ever exists (the one created in a's frame)
So I take it last call optimization makes it so you don't have to walk your way frame by frame
back to a/1.
If you would like to do what you want you either need some way of
attributed-variables or you need to disable last-call optimization
and minimization of reference-chains. In that case the length of
the reference chain is the `age' or your variable. This is not
something you want to do lightly.
I am not sure that last call optimization hurts my cause but instead enhances the knowledge we
are dealing with same == variable.
Now i see that since the variable in b's frame is only _reference_ to the original
I am not dealing with the same variable until its programmatically deference..
But you would know if last call optimization would need turned off. Or if it could remain on and
a C coded variables_creation_frame(-Var,+Frame) could just deference the variable.
Post by ***@users.sourceforge.net
With a call to a(foo), there would be no variables in any
child. (Therefore a case where we
Post by ***@users.sourceforge.net
couldn't count them)
Assumptions about what it would mean in code...
that the struct of a variable when first constructed
(initialized) would record it originator
Post by ***@users.sourceforge.net
frame.
This would be less expensive the keeping some ref-count (if
done, would be better left to a
Post by ***@users.sourceforge.net
sibling count for alternative frames)
So mainly what I think I need is just a number that will
tell me the frame the variable was
Post by ***@users.sourceforge.net
first constructed in.. i could use the current frame
reference to subtract possibly.
Post by ***@users.sourceforge.net
What i am trying to do is construct a
call_with_var_depth_limit(my_goal(A,B,C),[A,B,C],4,WasExceeded).
Or make a predicate like
b(X):-var(X),depth_of_var(X,Depth),Depth<4,c(X).
What do you think? Would this be useful to others besides me?
What is the more high-level goal you want to achieve? What you want
is pretty hard to do as it basically forces the system to drop
important optimizations. Maybe from a higher perspective it becomes
easier.
I am trying to create a similar effect that PTTP http://www.ai.sri.com/~stickel/pttp.html
uses to create iterative deepening. Instead of saying we have deepened my search once per neck
(:-).
I am planning on a more jaggedy productive search that says:

I will only deepen N further while a head variable continues to be unbound during subsequent
prolog necks.
Once the variable has remained unbound for a N depth..
The program may choose to assume it will never be bound and more productive search exists
elsewhere (failing this branch)

This will help create transitive closures and add small amounts of loop detection in that this
program would terminate:

So starting with this program.

:-ensure_loaded(depth_bound_varible_term_expanions).

p(X):-q(X).
q(a).
q(X):-p(X).
q(b).



With the term_expansion above used transliterates the program to:

p(A):-depth_of_var(A,B),B<3,q(A).
q(a).
q(A):-depth_of_var(A,B),B<3,p(A).
q(b).


Then I would use the code:

depth_of_var(X,0):-nonvar(X),!.
depth_of_var(X,N):-
variables_creation_frame(X,Then),
current_prolog_frame(Now),
count_parents(Now,Then,N).

count_parents(Now,Now,0).
count_parents(Now,Then,N):-
prolog_frame_attribute(Now,parent,Parent),
count_parents(Parent,Then,P),
N is P+1.


The variables_creation_frame(-Var,+Frame). would need to dereference that variable and look for
the frame it was first created in.




But the higher level goal/situation is I have a very large and pathological knowledge base..
It is a series of Horn clauses created from cannonicalization of first-order logic. Some of
this
logic contains cycles and paths that do nothing. I am trying to do a complete enough search for
deductive reasoning using propositional resolution. Memoization would solve my remaining
problems.
But so far Tabling/Memoization has failed (core dumps on several prolog systems that claim they
can do it)
(The reason is my table clause cache can contain thousands of entries across hundreds of
predicates) So mainly its a memory issue.
(These other prolog systems only work on toy examples) SWI-Prolog loads my 80 meg source files
with ease.
These others (like XSB, faults on things small as WordNet) BinProlog tends to work mostly but
has it's own set
of issues like it's read/Ns can't load atoms like '#$TheSetOf-All-ThingsBlue' And tends to have
other unexpected features.
(SWI and most others prologs can read such quoted atoms) SWI-Prolog may not be the fastest
prolog out
there but in my opinion the only that is dependable and feature full.
I have done some experiments and found by tracking variables (in my meta interpreter) I have
been able to keep search productive
over my knowledge base and can live w/o memoization in SWI-Prolog.


-Douglas





----------------
* To UNSUBSCRIBE, please use the HTML form at

http://www.swi-prolog.org/mailinglist.html

or send mail to prolog-***@swi.psy.uva.nl using the Subject: "unsubscribe"
(without the quotes) and *no* message body.

** An ARCHIVE of this list is maintained at

http://www.swi.psy.uva.nl/projects/SWI-Prolog/mailinglist/archive/
Jan Wielemaker
2002-08-02 12:48:41 UTC
Permalink
Douglas,
Post by ***@users.sourceforge.net
:-ensure_loaded(depth_bound_varible_term_expanions).
p(X):-q(X).
q(a).
q(X):-p(X).
q(b).
p(A):-depth_of_var(A,B),B<3,q(A).
q(a).
q(A):-depth_of_var(A,B),B<3,p(A).
q(b).
I _think_ I understand your problem. It isn't hard to code this at the
C-level. Below is the implementation. Save this file in
depth_of_var.c in the directory you built SWI-Prolog (you need a version
built from source) and build it using

plld -o depth_of_var -shared -I. -I../src depth_of_var.c

Now use ?- load_foreign_library(depth_of_var).

to get your new predicate. NOTE NOTE NOTE: unlike normal foreign code
this code relies on details of the machinery normally not public. So,
it may stop working and you better recompile it before using it with
a new version of Prolog.

---cut here -----------------------------------------------------------
#include "pl-incl.h"

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
depth_of_var(+Var, -Depth)

Dereference the term Var. If the dereferenced chain ends on the local
stack, return the call-depth difference between my parent frame and the
frame in which Var was created.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

static foreign_t
depth_of_var(term_t var, term_t depth)
{ Word v = valTermRef(var);
LocalFrame fr = environment_frame;
long l0 = levelFrame(fr)-1; /* -1: Use my parent as reference */

deRef(v);
if ( onStackArea(local, v) )
{ DEBUG(0, Sdprintf("Ok, on local stack\n"));
while(fr && fr > (LocalFrame)v)
fr = parentFrame(fr);
if ( fr )
{ l0 -= levelFrame(fr);
return PL_unify_integer(depth, l0);
}
} else
DEBUG(0, Sdprintf("Not on local stack\n"));

fail;
}


install_t
install()
{ PL_register_foreign("depth_of_var", 2, depth_of_var, 0);
}
--cut here -----------------------------------------------------------

Here is the code I used to test:

:- load_foreign_library(depth_of_var).

q :-
q(X),
writeln(X).

q(X) :-
depth_of_var(X, D),
format('Depth = ~w~n', [D]),
D < 5,
q(X),
notail.

notail.

Running this says:

1 ?- q.
Depth = 1
Depth = 2
Depth = 3
Depth = 4
Depth = 5

No

You can adapt the code to throw an exception if the variable does not
origine in a local frame. The above version fails silently. The print
statements indicate what happens.
Post by ***@users.sourceforge.net
(SWI and most others prologs can read such quoted atoms) SWI-Prolog may not
be the fastest prolog out
there but in my opinion the only that is dependable and feature full.
I have done some experiments and found by tracking variables (in my meta
interpreter) I have been able to keep search productive
over my knowledge base and can live w/o memoization in SWI-Prolog.
Thanks

--- Jan

P.s. If this results in anything of general interest please consider to
cooperate in adding it to SWI-Prolog. For now I think this is
`playground'.


----------------
* To UNSUBSCRIBE, please use the HTML form at

http://www.swi-prolog.org/mailinglist.html

or send mail to prolog-***@swi.psy.uva.nl using the Subject: "unsubscribe"
(without the quotes) and *no* message body.

** An ARCHIVE of this list is maintained at

http://www.swi.psy.uva.nl/projects/SWI-Prolog/mailinglist/archive/
dmiles@users.sourceforge.net
2002-08-02 20:09:19 UTC
Permalink
Post by Jan Wielemaker
I _think_ I understand your problem.
Yes you correctly identified.
Post by Jan Wielemaker
NOTE NOTE NOTE: unlike normal foreign code
this code relies on details of the machinery normally not public. So,
it may stop working and you better recompile it before using it with
a new version of Prolog.
Yep I just saw that now in practice when i thought much hadn't changed since last build :)

"pl: relocation error: /opt/sourceforge/logicmoo/src/swi_interface/depth_of_var.so: undefined
symbol: _LD"

But works great when my src/ and pl from the same generation.
Was perfect example for the test.
Post by Jan Wielemaker
You can adapt the code to throw an exception if the variable does not
origine in a local frame. The above version fails silently.
The print statements indicate what happens.
Excellent, and good idea checking if it was not from the local stack.
And also the: /* -1: Use my parent as reference */
I only modified it to return a zero for !isVar
And now I am having a blast in pl-incl.h seeing what other simular evils can be had :)
Post by Jan Wielemaker
P.s. If this results in anything of general interest please
consider to cooperate in adding it to SWI-Prolog. For now I think this is
`playground'.
I hope so .. I expect to keep the inference engine for logicmoo opensourced (hehe so others can
help fix code!)
But yes, hopefully others wil find uses for a depth_of_var/2 It seems it's not overly specific
to just my use,
people could use it for just keeping track of depth of their program (for example PTTP could see
performace gains.
(So it does not have to keep arround global depth counters))

Thank you again,
Douglas



----------------
* To UNSUBSCRIBE, please use the HTML form at

http://www.swi-prolog.org/mailinglist.html

or send mail to prolog-***@swi.psy.uva.nl using the Subject: "unsubscribe"
(without the quotes) and *no* message body.

** An ARCHIVE of this list is maintained at

http://www.swi.psy.uva.nl/projects/SWI-Prolog/mailinglist/archive/
Loading...