Clpfd: Declare variables dynamically?

Beginner question: Is it possible to generate/declare variables dynamically?
I have a factbase representing the elements, attributes, etc. of a xml structure:
xml_fact(Kind, Property, Factid, Parentid, Value)
, e.g.

xml_fact(elem, name, 1, 0, root).
xml_fact(elem, name, 2, 1, child).
xml_fact(attr, name, 3, 2, id).
xml_fact(attr, value, 4, 3, 1111).

Now I need a variable, e.g. for each element:
Root = 1, Child = 2
The goal of this is to reason about additional semantics not expressed by XSD. The xml input is xsd-valided xml for a special use case. I’d like to represent the additional semantics in form of predicates using those variables. With regard to the above example, this can simply be written down. There is only one child node named ‘child’.

  1. How can corresponding variables be generated for any XML data (e.g. multiple child-nodes)?
  2. How to reference those variables?
  3. How could additional information be associated to the variable (e.g. the Factid as initial assignment for tracking changes later on)?

Thanks in advance.
Regards
J

Before you get started, I would suggest you read this tutorial (at least until number 4).

It is important that you try to change your way of thinking about variables and prolog, so that you can understand what is happening; otherwise you will get confused about the results you are getting.

The main change of mind is this: when you write in prolog you are not telling it what to do (in most cases), but you are describing what you want.

For example, if you have a program in /tmp/t.pl like this:

xml_fact(elem, name, 1, 0, root).
xml_fact(elem, name, 2, 1, child).
xml_fact(attr, name, 3, 2, id).
xml_fact(attr, value, 4, 3, 1111).

and then you query:

$ swipl /tmp/t.pl

1 ?- xml_fact(Type, name, Num, 2, id).
Type = attr,
Num = 3.

You are asking prolog: is there a Type and a Num (variables) such that xml_fact(Type, name, Num, 2, id) is true? So a variable in prolog is Uppercase, and is not something you “set” to a value, and then later on “set” to another value. Rather a variable is bound to a value and remains like that for the time it exists in order to make a query or goal be true.

So in the case above, prolog is saying that the variable Type bound to attr and the variable Num bound to 3 give an answer to the query: making it be true.

It is a little bit like math, when you have x + 1 = 2; what is the value of x that satifies the equation? Then you would get the answer x=1. But in Prolog all variables are Uppercase.

NOTE: SWI-Prolog has great support for XML, SGML and HTML. So after you go through the tutorial above, I would suggest you look into SWI-Prolog XML parser, you would use load_xml/3, you would probably use library(xpath) to get the nodes.

Thx for replying,

the factbase is the result of using library(sgml). After parsing the xml the nodes are flattened and a unique id (Factid) is attached. The Factid is used for the mapping node <-> integer as required to build domains for variables.
The idea is to express the valid state/relation/value of xml nodes using constraints. Each node is represented by its Factid.

Example:

  <messagegroup>
    <message name="link1">...</message>
    <message name="link2">...</message>
    ...
    <message name="linkn">...</message>

    <tooltip ref="link1">...</tooltip>
    <tooltip ref="link2">...</tooltip>
    ...
    <tooltip ref="linkn">...</tooltip>
  </messagegroup>

Rule:

  1. For each element named ‘message’ having an attribute ‘name’ exists one element named ‘tooltip’ having an attribute named ‘ref’.
  2. A pair of message/tooltip elements is linked by the value of their name/ref attributes (message.name.value = tooltip.ref.value)
  3. All message and tooltip elements have the same parent.
  4. The values of name attribute are all different (unique links)

MessageNameLink1 #= 4. % The factid of name attribute value 'link1'
MessageNameLink2 #= 10. % The factid of name attribute value 'link2'
MessageNameLinkn #= 1002. % The factid of name attribute value 'linkn'
TooltipRefLink1 #= 36. % The factid of ref attribute value 'link1'
TooltipRefLink2 #= 55. % The factid of ref attribute value 'link2'
TooltipRefLinkn #= 1504. % The factid of ref attribute value 'linkn'

Among others:

c_eq_value(MessageNameLink1, TooltipRefLink1).
c_eq_value(MessageNameLink2, TooltipRefLink2).
...
c_eq_value(MessageNameLinkn, TooltipRefLinkn).

with

c_eq_value(Var1, Var2) :-
  xml_fact(_, _, Var1, _, Value),
  xml_fact(_, _, Var2, _, Value).

This should result in true. if all constrains are satisfied -> the xml is semantically wellformed as constrainted.
If we got a false. it should be possible to repair the non-wellformed xml by ‘simply’ widen the domains of variables as such that the solver could find solutions that satisfy the constraints.

Example: Change the attribute value of the last tooltip to:

<tooltip ref="brokenlinkn">...</tooltip>

and change the domains of the variables to

TooltipRefLink1 in 4\/10\/ ... \/1002
TooltipRefLink2 in 4\/10\/ ... \/1002
TooltipRefLinkn in 4\/10\/ ... \/1002

should allow the solver to reduce the domain to 1002 (‘linkn’) for variable TooltipRefLinkn.

The first approach is a validation check and results in a true/false statement.
The second approach is a repair whereas the solutions could be ‘false.’ (= not repairable) or 1…m permutations of values from the variable domains which all satify the given constraints. Each permutation (=solution) is a set of transitions from the initial factid to another factid.
To fully specify the semantics it requires several rules which constrain differnt aspects of semantic wellformdness. It is possible that different rules refer to the same variable to constraint it further. As far as I know there’s no global scope for variables to share between predicates(?). The only way I found is using nb_set/get but this is not the prolog way I guess.
Maybe I made my problem more clear. Any suggestions regarding my questions or generally regarding a possible way to do that?

Thanks again
Regards
J

There are some bits and pieces missing in your description or my mind. You cannot use nb_set/get as these copy the argument. You may need to do fun stuff using b_setval/2 and b_getval/2. That allows you to share a variable between Prolog clauses. It isn’t really clear to me what this sharing should do …

Hi jan,

thank for your hints.
The variable sharing is an idea to avoid using predicate arguments because there maybe be a lot of variables running through multiple (rule-)predicates. But that’s the prolog way, isn’t it?

Desired layout maybe something like this:

check_semantics(Xml, Solutions) :-
  create_factbase(Xml),    % unless better ideas suggested: using assert(xml_fact(...)) here
  rule_1(Solutions),       % e.g. checking message/tooltip semantics
  rule_2(Solutions),       % e.g. other checking involving message elements, etc.
  ...
  rule_m(Solutions).

Finally I’m looking for something like

assert(var(<TheVarRef>, InitVal, ...))

if Var is labeled != InitVal it signals a change an is therefore part of a repair.

Yes, but there are several ways to cope with this. An old example are DCG (grammar) rules using --> to separate head and body which causes term expansion to add the difference list arguments that deal with the list. If you have a lot of such context variables you can pack them into a single compound term or dict (much like passing an object/struct).

Keeping the Solutions in a global variable could make sense in this scenario. The term you get from b_getval/2 is really a shared Prolog term with exactly the same semantics as a passed argument.

I’m afraid I need more context for that …

Well, this is part of the overall idea behind repairing “something” non-wellformed by using constraints and a constraint solver. The InitVal represents the initial value, the status of the input before the domain of the variable is widened to allow other values. If the solver choose a value != InitVal to satisfy all constraints this is a sign, that something must be changed to get valid xml, e.g. replacing the wrong attr-value in <tooltip ref="brokenlinkn">...</tooltip> with the valid value linkn. Both values are represented by different factids (e.g brokenlinkn → 45, linkn → 1002).
I think in Prolog you could do:

retract(xml_fact(attr, value, 45, 44, 'brokenlinkn')).
assertz(xml_fact(attr, value, 1002, 44, 'linkn')).

to apply the fix. Factid 44 here refers to the parent node. Hope, that helps…

Instead of manually writing one variable for each fact, consider using lists to hold many variables.

something like this:

validate_link_eq(...) :-
   %... use aggregate_all(count, ...., Count) 
   %...  to get MsgCount and TooltipCount
   length(MsgLinks, MsgCount), %MsgLinks is now a list of variables
   length(TooltipLinks, TooltipCount), % TooltipLinks is now a list of vars
   %... apply contrainsts to MsgLinks and TooltipLinks here...

You can then pass the variable list to many predicates.