:- module(tentative).
:- export tent_trace_array / 3.
:- export tent_is_ / 3.
:- export tent_is / 2.
:- export get_changeable_value / 2.
:- export suspend_on_change / 2.
:- export tent_minimize_random_ / 4.
:- export tent_minimize_random / 3.
:- export vs_random_index / 2.
:- export vs_random / 2.
:- export vs_random_violated_index / 2.
:- export vs_random_violated / 2.
:- export vs_random_worst_index / 2.
:- export vs_random_worst / 2.
:- export vs_worst_index / 2.
:- export vs_worst / 2.
:- export vs_all_worst_index / 2.
:- export vs_all_worst / 2.
:- export vs_violated_index / 2.
:- export vs_violated / 2.
:- export vs_all_violated_index / 2.
:- export vs_all_violated / 2.
:- export vs_all / 2.
:- export vs_member / 2.
:- export vs_element / 3.
:- export vs_size / 2.
:- export vs_create / 2.
:- export cs_random_worst / 2.
:- export cs_all_worst / 2.
:- export cs_random_violated / 2.
:- export cs_all_violated / 2.
:- export cs_all / 2.
:- export cs_current_violations / 2.
:- export cs_violations / 2.
:- export cs_clear_satisfied / 1.
:- export cs_clear_all / 1.
:- export :~ / 2.
:- export cs_create / 2.
:- export tent_implements_ / 3.
:- export tent_implements / 2.
:- export random_sample / 3.
:- export register_for_notification / 3.
:- export var_inc_violations / 2.
:- export tent_fix / 1.
:- export random_element / 2.
:- export tent_set_random / 2.
:- export tent_set_all / 2.
:- export tent_set_attr / 2.
:- export tent_set / 2.
:- export var_get_violations / 2.
:- export tent_get / 2.
:- export has_tent_value / 1.
:- export unify_tentative / 2.
:- export print_tentative / 2.
:- export op(700, xfx, tent_get).
:- export op(700, xfx, tent_set).
:- export struct(monitored_constraint(alias, violations, suspensions)).
:- export op(700, xfx, tent_implements).
:- export op(800, xfx, alias).
:- export op(900, xfx, :~).
:- export op(700, xfx, tent_is).
:- tool(tent_is / 2,tent_is_ / 3).
:- tool(tent_minimize_random / 3,tent_minimize_random_ / 4).
:- tool(tent_implements / 2,tent_implements_ / 3).
:- comment(tent_is_ / 3, hidden).
:- comment(tent_minimize_random_ / 4, hidden).
:- comment(tent_implements_ / 3, hidden).
:- comment(summary, "A framework for Local Search based on tentative values").
:- comment(author, "Joachim Schimpf").
:- comment(date, "$Date: 2008/04/02 00:23:04 $").
:- comment(copyright, "Cisco Systems").
:- comment(see_also, [library(tentative_constraints)]).
:- comment(desc, html("\n    <h3>Overview</h3>\n<P>\n    This is a library for implementing Local Search algorithms.\n    It is intended as a successor for library(repair).\n</P><P>\n    This library provides the following concepts and primitives:\n<UL><LI>\n    A variable can be given a <EM>tentative value</EM>. This is a value which\n    is attached to the variable, but does not constrain the variable.\n</LI><LI>\n    Tentative values are observed by <EM>monitored constraints</EM>. A monitored\n    constraint checks whether a constraint is satisfied given the current\n    tentative values of its variables, or computes a measure of violatedness\n    for a tentatively violated constraint.\n</LI><LI>\n    <EM>Violatedness</EM> can be attached to constraints and to variables.\n    Typically, when a constraint is tentatively violated, this increases\n    the violatedness count of the constraint itself, and the violatedness\n    count of those variables that can be made responsible for the violation.\n</LI></UL>\n    Actual constraint implementations can be found in the library\n    <EM>lib(tentative_constraints)</EM>.\n</P>\n\n    <h3>Tentative Values</h3>\n<P>\n    A tentative value (TV) can be an atomic term or a (possibly nonground)\n    compound term. It is a conscious design choice not to allow variable\n    tentative values.\n    A tentative value can be attached to a variable, and freely changed.\n    It is not possible to remove a variable's tentative value once\n    it has had one, it can only be replaced by a different one.\n    The change of tentative value can be used as a trigger condition for\n    waking delayed goals.\n</P><P>\n    Instantiating a tentative variable to a value V is equivalent to first\n    setting/changing its tentative value to V, and then instantiating to V.\n    Unifying two tentative variables is not supported and raises an error.\n</P><P>\n    Variables with tentative value are printed in the following format:\n<PRE>\n\tX{99 -> 7}\n</PRE>\n    where the first number (99) is the tentative value, and the second\n    number (7) is the variable's violation count.\n</P><P>\n    The primitives related to tentative values are:\n<blockquote><dl>\n    <dt>has_tent_value(?X)</dt>\n\t<dd>X has a tentative (of definitive) value</dd>\n    <dt>tent_get(?X, -Val)</dt>\n\t<dd>get tentative values</dd>\n    <dt>tent_set(?X, -Val)</dt>\n\t<dd>set tentative values</dd>\n    <dt>tent_set_all(?Xs, +Val)</dt>\n\t<dd>set multiple identical tentative values</dd>\n    <dt>tent_set_random(?Xs, +Range)</dt>\n\t<dd>set multiple random tentative values</dd>\n    <dt>tent_fix(?X)</dt>\n\t<dd>instantiate to tentative value</dd>\n    <dt>var_get_violations(?X, -Violations)</dt>\n\t<dd>get the number of violations the variable is currently involved in</dd>\n    <dt>var_inc_violations(?Var, +Delta)</dt>\n\t<dd>add Delta to Var's violation counter</dd>\n</dl></blockquote>\n    All these operations are undone on backtracking.\n</P>\n\n\n    <h3>Variable Sets</h3>\n<P>\n    Tentative variables can be grouped into indexed sets, from which elements\n    (or their index) can then be selected according to different criteria.\n    The corresponding predicates are:\n<blockquote><dl>\n    <dt>vs_create(+Vars, -VarSet)</dt>\n        <dd>construct a variable set from the variables in Vars</dd>\n    <dt>vs_all(+VS, -Vs)</dt>\n        <dd>get a list of all the variables in the set</dd>\n    <dt>vs_element(+VS, +I, -V)</dt>\n        <dd>get a particular variable from the set</dd>\n    <dt>vs_member(+VS, -V)</dt>\n        <dd>enumerate all variables from the set</dd>\n    <dt>vs_random(+VS, -Vs), vs_random_index(+VS, -Is)</dt>\n        <dd>pick a random variable from the set</dd>\n    <dt>vs_random_violated(+VS, -Vs), vs_random_violated_index(+VS, -Is)</dt>\n        <dd>pick a random violated variable from the set</dd>\n    <dt>vs_all_violated(+VS, -Vs), vs_all_violated_index(+VS, -Is)</dt>\n        <dd>get a list of all violated variables from the set</dd>\n    <dt>vs_violated(+VS, -V), vs_violated_index(+VS, -I)</dt>\n        <dd>enumerate all violated variables from the set</dd>\n    <dt>vs_random_worst(+VarSet, -WorstVar), vs_random_worst_index(+VarSet, -I)</dt>\n    \t<dd>pick a random variable with maximum violations from the set</dd>\n    <dt>vs_all_worst(+VS, -Vs), vs_all_worst_index(+VS, -Is)</dt>\n        <dd>get a list of all the maximally violated variables from the set</dd>\n    <dt>vs_worst(+VS, -V), vs_worst_index(+VS, -I)</dt>\n        <dd>enumerate all maximally violated variables from the set</dd>\n</dl></blockquote>\n</P>\n\n\n    <h3>Constraint Sets</h3>\n<P>\n    To monitor a constraint's tentative violatedness, it must be added\n    to a constraint set.  The predicates to create, add and remove\n    constraints from a constraint set are:\n<blockquote><dl>\n    <dt>CS :~ C</dt>\n    \t<dd>add a constraint to the constraint set</dd>\n    <dt>cs_create(-CS, +Options)</dt>\n    \t<dd>create an empty constraint set</dd>\n    <dt>cs_clear_all(+CS)</dt>\n    \t<dd>remove all constraints from the constraint set</dd>\n    <dt>cs_clear_satisfied(+CS)</dt>\n    \t<dd>remove all satisfied constraints from the constraint set</dd>\n</dl></blockquote>\n    The total violation count of all the constraints in the set can be\n    accessed through the following predicates:\n<blockquote><dl>\n    <dt>cs_violations(+CS, -VioVar)</dt>\n    \t<dd>get a tentative variable reflecting violatedness of the constraint set</dd>\n    <dt>cs_current_violations(+CS, -Vio)</dt>\n    \t<dd>get the current violatedness of the constraint set (integer)</dd>\n</dl></blockquote>\n    Constraints from the constraint set can be selected according to\n    different criteria through the following predicates:\n<blockquote><dl>\n    <dt>cs_random_worst(+CS, -C)</dt>\n    \t<dd>get a random worst violated constraint from the constraint set</dd>\n    <dt>cs_all_worst(+CS, -Cs)</dt>\n    \t<dd>get all worst violated constraints from the constraint set</dd>\n    <dt>cs_all_violated(+CS, -Cs)</dt>\n    \t<dd>get all violated constraints from the constraint set</dd>\n    <dt>cs_random_violated(+CS, -Cs)</dt>\n    \t<dd>get a random violated constraint from the constraint set</dd>\n    <dt>cs_all(+CS, -Cs)</dt>\n    \t<dd>get all constraints from the constraint set</dd>\n</dl></blockquote>\n</P>\n\n\n    <h3>Invariants</h3>\n<P>\n    There is currently one primitive to maintain arithmetic invariants:\n<blockquote><dl>\n    <dt>-Res tent_is +Expr</dt>\n    \t<dd>the tentative value of Res is the tentative result of Expr</dd>\n</dl></blockquote>\n</P>\n\n\n    <h3>Search and Randomised Primitives</h3>\n<P>\n    The following primitives support the implementation of the actual\n    Local Search routines:\n<blockquote><dl>\n    <dt>tent_minimize_random(MoveGenerator, Violations, MoveId)</dt>\n    \t<dd>Find a best neighbour using MoveGenerator</dd>\n\n    <dt>random_element(+Range, -Value)</dt>\n\t<dd>Pick a random element from Range</dd>\n\n    <dt>random_sample(+Range, +N, -Value)</dt>\n    \t<dd>Succeed N times with random values from Range</dd>\n</dl></blockquote>\n</P>\n\n\n    <h3>Tracing</h3>\n<P>\n    A simple tracing facility is provided via\n<blockquote><dl>\n    <dt>tent_trace_array(+Stream, +Name, +ArrayList)</dt>\n    \t<dd>Print a message whenever a tentative value changes</dd>\n</dl></blockquote>\n\n    Also, the Visualisation Tools can be used with this library,\n    by creating viewables with type changeable(tentative,Type).\n</P>\n\n\n    <h3>Constraint implementation interface</h3>\n<P>\n    Constraints are implemented by an implementation predicate. A constraint\n    is linked to its implementation predicate by a tent_implements/2\n    declaration, e.g.\n<pre>\n\t:- alldifferent_t/2 tent_implements alldifferent/1.\n</pre>\n    The implementation predicate must have one more argument than the\n    constraint itself.  The extra (last) argument is a structure\n<pre>\n\tstruct(monitored_constraint(\n\t\talias,\t\t% the constraint goal (or equivalent term)\n\t\tviolations,\t% a tentative variable\n\t\tsuspensions\t% suspensions of the monitoring goals\n\t)\n</pre>\n    The implementation predicate is supposed to update the constraint's\n    violation TV plus the violation counters of the variables that occur\n    in the constraint. It should do this by suspending on the variable's\n    tent_chg list, and by registering for exact change notification via:\n<blockquote><dl>\n    <dt>register_for_notification(?TV, +Tag, ?Receiver)</dt>\n    \t<dd>register to receive messages about changes to TV's tentative value</dd>\n</dl></blockquote>\n     This messaging facility is based upon the primitive in lib(notify_ports).\n</P>\n\n\n    <h3>Constraints</h3>\n<P>\n    Actual constraint implementations can be found in the library\n    <EM>lib(tentative_constraints)</EM>.\n</P>\n\n\n    <h3>Example</h3>\n<P>\n    See <EM>lib(tentative_constraints)</EM>.\n</P>\n")).
:- comment(:~ / 2, [summary : "Add a constraint to a constraint set", template : "CS :~ ConstrSpec", amode : (:~(?, +) is det), args : ["CS" : "Constraint set or free variable", "ConstrSpec" : "A constraint specification"], see_also : [cs_create / 2, cs_clear_all / 1, cs_clear_satisfied / 1, cs_violations / 2, cs_current_violations / 2, cs_random_worst / 2, cs_all_worst / 2, cs_all_violated / 2, cs_random_violated / 2, cs_all / 2, tent_implements / 2], desc : html("<P>\n\tAdd a constraint to a constraint set. After adding, the constraint\n\twill be part of the constraint set, and add to its total violatedness.\n\tThe amount of violatedness contributed by the constraint depends on\n\tthe constraint's implementation, but can be scaled.\n\t</P><P>\n\tThree forms of constraint specification are recognised here:\n\t<DL>\n\t<DT>Constraint</DT>\n\t    <DD>A constraint goal. The constraint must have a 'tentative\n\t    implementation', i.e. a predicate must be defined that takes one\n\t    additional argument and implements the violation monitoring for\n\t    the constraint (see constraint implementation interface).</DD>\n\t<DT>Weight * Constraint</DT>\n\t    <DD>where Weight is an integer. This means that the constraints\n\t    violatedness is scaled with the factor Weight before being added\n\t    to the total violatedness of the constraint set.</DD>\n\t<DT>Constraint alias Term</DT>\n\t    <DD>Term is the term that can be retrieved from the constraint\n\t    set, in place of the constraint goal itself (see cs_all/2 etc).</DD>\n\t<DT>Weight * Constraint alias Term</DT>\n\t    <DD>Conbination of both modifiers above.</DD>\n\t</DL>\n\t<P>\n\tIf CS is a free variable, a new constraint set will be implicitly\n\tcreated (as if created with cs_create(CS, [])).\n\t</P>\n    "), eg : "\n    ?- length(Xs, 5), tent_set_all(Xs, 99), CS :~ alldifferent(Xs).\n    Xs = [Xi{99 -> 4}, Xi{99 -> 4}, Xi{99 -> 4}, Xi{99 -> 4}, Xi{99 -> 4}]\n    CS = constraint_set(TotalVio{10 -> 0}, ...)\n    There is 1 delayed goal.\n    Yes (0.00s cpu)\n    "]).
:- comment(cs_all / 2, [summary : "Get all constraints in the constraint set", amode : (cs_all(+, -) is det), args : ["CS" : "Constraint set", "Cstr" : "A list of constraints (output)"], see_also : [cs_all_violated / 2, cs_all_worst / 2], desc : html("\n\t<P>\n\tReturns a list of all constraints in the constraint set.\n\t</P><P>\n\tIf the constraints were added with aliases (see :~ /2),\n\tthe alias term is retrieved instead of the constraint goal.\n\t</P>\n    "), eg : "\n    ?- [X, Y] tent_set [3, 4], CS :~ (X $= Y), CS :~ (X $\\= Y), cs_all(CS, C).\n    X = X{3 -> 0}\n    Y = Y{4 -> 0}\n    CS = constraint_set(TotalVio{1 -> 0}, ...)\n    C = [X{3 -> 0} $\\= Y{4 -> 0}, X $= Y]\n    There are 2 delayed goals.\n    Yes (0.00s cpu)\n    "]).
:- comment(cs_all_violated / 2, [summary : "Get all violated constraints in the constraint set", amode : (cs_all_violated(+, -) is det), args : ["CS" : "Constraint set", "Cstr" : "A list of constraints (output)"], see_also : [cs_all / 2, cs_all_worst / 2], desc : html("\n\t<P>\n\tReturns a list of all currently violated constraints in the\n\tconstraint set, i.e. all the constraints whose violation count\n\tis currently nonzero.\n\t</P><P>\n\tIf the constraints were added with aliases (see :~ /2),\n\tthe alias term is retrieved instead of the constraint goal.\n\t</P>\n    "), eg : "\n    ?- [X, Y] tent_set [3, 4], CS :~ (X $= Y), CS :~ (X $\\= Y), cs_all_violated(CS, C).\n    X = X{3 -> 0}\n    Y = Y{4 -> 0}\n    CS = constraint_set(TotalVio{1 -> 0}, ...)\n    C = [X{3 -> 0} $= Y{4 -> 0}]\n    There are 2 delayed goals.\n    Yes (0.00s cpu)\n    "]).
:- comment(cs_all_worst / 2, [summary : "Get all worst violated constraints in the constraint set", amode : (cs_all_worst(+, -) is det), args : ["CS" : "Constraint set", "Cstr" : "A list of constraints (output)"], see_also : [cs_all / 2, cs_all_violated / 2], desc : html("\n\t<P>\n\tReturns a list of all the worst violated constraints in the\n\tconstraint set, i.e. all the constraints that have maximum\n\tviolation count among the constraints in the set.\n\t</P><P>\n\tIf the constraints were added with aliases (see :~ /2),\n\tthe alias term is retrieved instead of the constraint goal.\n\t</P>\n    "), eg : "\n    ?- [X, Y] tent_set [3, 4], CS :~ (X $= Y), CS :~ (X $\\= Y), cs_all_worst(CS, C).\n    X = X{3 -> 0}\n    Y = Y{4 -> 0}\n    CS = constraint_set(TotalVio{1 -> 0}, ...)\n    C = [X{3 -> 0} $= Y{4 -> 0}]\n    There are 2 delayed goals.\n    Yes (0.00s cpu)\n    "]).
:- comment(cs_clear_all / 1, [summary : "Clean up the constraint set completely", amode : (cs_clear_all(+) is det), args : ["CS" : "Constraint set"], see_also : [cs_clear_satisfied / 1], desc : html("\n\t<P>\n\tClean up the constraint set completely. All delayed goals related\n\tto this constraint set will be removed and the constraints forgotten.\n\tA constraint set that has been cleaned up should not be used any longer.\n\t</P>\n    ")]).
:- comment(cs_clear_satisfied / 1, [summary : "Remove the satisfied constraints from the constraint set", amode : (cs_clear_satisfied(+) is det), args : ["CS" : "Constraint set"], see_also : [cs_clear_all / 1], desc : html("\n\t<P>\n\tRemove all currently satisfied constraints from the constraint set.\n\tThis means, even if they become violated again later, they will no\n\tlonger contribute to the set's violatedness count.  All delayed goals\n\trelated to these constraints will be removed and the constraints\n\tforgotten.\n\t</P>\n    ")]).
:- comment(cs_create / 2, [summary : "Create an empty constraint set", amode : (cs_create(-, ++) is det), args : ["CS" : "Constraint set (output)", "Options" : "List of options"], see_also : [:~ / 2, cs_clear_all / 1, cs_clear_satisfied / 1, cs_violations / 2, cs_current_violations / 2, cs_random_worst / 2, cs_all_worst / 2, cs_all_violated / 2, cs_random_violated / 2, cs_all / 2], desc : html("\n\tCreate an empty constraint set. No options are currently supported.\n\tA constraint set is an abstract data structure which should only\n\tbe accessed through the cs_xxx group of predicates. Its purpose\n\tis to group constraints together and organise access to these\n\tconstraints based on their violatedness counts.\n    "), eg : "\n    ?- cs_create(CS, []).\n    CS = constraint_set(Violations{0 -> 0}, [])\n    Yes (0.00s cpu)\n    "]).
:- comment(cs_current_violations / 2, [summary : "Get the current violatedness of the constraint set", amode : (cs_current_violations(+, -) is det), args : ["CS" : "Constraint set", "Vio" : "An integer (output)"], see_also : [cs_violations / 2], desc : html("\n\t<P>\n\tReturns an integer representing the current violatedness of\n\tthe constraint set.\n\t</P>\n    "), eg : "\n    ?- length(Xs, 5), tent_set_all(Xs, 99), CS :~ alldifferent(Xs),\n       cs_current_violations(CS, V).\n    Xs = [Xi{99 -> 4}, Xi{99 -> 4}, Xi{99 -> 4}, Xi{99 -> 4}, Xi{99 -> 4}]\n    CS = constraint_set(TotalVio{10 -> 0}, ...)\n    V = 10\n    There is 1 delayed goal.\n    Yes (0.00s cpu)\n    "]).
:- comment(cs_random_violated / 2, [summary : "Get random violated constraints in the constraint set", amode : (cs_random_violated(+, -) is semidet), fail_if : "Fails if there is no violated constraint in the set", args : ["CS" : "Constraint set", "Cstr" : "A constraint term (output)"], see_also : [cs_random_worst / 2, cs_all_violated / 2], desc : html("\n\t<P>\n\tReturns a currently violated constraint from the constraint set,\n\ti.e. all the constraints whose violation count is currently nonzero.\n\tIf there are several, a random one is returned.\n\t</P><P>\n\tIf the constraints were added with aliases (see :~ /2),\n\tthe alias term is retrieved instead of the constraint goal.\n\t</P>\n    "), eg : "\n    ?- [X, Y] tent_set [3, 4], CS :~ (X $= Y), CS :~ (X $\\= Y),\n       cs_random_violated(CS, C).\n    X = X{3 -> 0}\n    Y = Y{4 -> 0}\n    CS = constraint_set(TotalVio{1 -> 0}, ...)\n    C = X{3 -> 0} $= Y{4 -> 0}\n    There are 2 delayed goals.\n    Yes (0.00s cpu)\n    "]).
:- comment(cs_random_worst / 2, [summary : "Get random worst violated constraint from the constraint set", amode : (cs_random_worst(+, -) is semidet), fail_if : "Fails if there is no violated constraint in the set", args : ["CS" : "Constraint set", "Cstr" : "A constraint term (output)"], see_also : [cs_random_violated / 2, cs_all_worst / 2], desc : html("\n\t<P>\n\tReturns a worst violated constraint from the constraint set, i.e.\n\ta constraint that has maximum violation count among the constraints\n\tin the set. If there are several, a random one is picked.\n\t</P><P>\n\tIf the constraints were added with aliases (see :~ /2),\n\tthe alias term is retrieved instead of the constraint goal.\n\t</P>\n    "), eg : "\n    ?- [X, Y] tent_set [3, 4], CS :~ (X $= Y), CS :~ (X $\\= Y), cs_random_worst(CS, C).\n    X = X{3 -> 0}\n    Y = Y{4 -> 0}\n    CS = constraint_set(TotalVio{1 -> 0}, ...)\n    C = X{3 -> 0} $= Y{4 -> 0}\n    There are 2 delayed goals.\n    Yes (0.00s cpu)\n    "]).
:- comment(cs_violations / 2, [summary : "Get a tentative variable reflecting the violatedness of the constraint set", amode : (cs_violations(+, -) is det), args : ["CS" : "Constraint set", "Vio" : "A tentative variable (output)"], see_also : [cs_current_violations / 2], desc : html("\n\t<P>\n\tReturns a tentative variable reflecting the (current and future)\n\tviolatedness of the constraint set.\n\t</P>\n    "), eg : "\n    ?- length(Xs, 5), tent_set_all(Xs, 99), CS :~ alldifferent(Xs),\n       cs_violations(CS, V).\n    Xs = [Xi{99 -> 4}, Xi{99 -> 4}, Xi{99 -> 4}, Xi{99 -> 4}, Xi{99 -> 4}]\n    CS = constraint_set(V{10 -> 0}, ...)\n    V = V{10 -> 0}\n    There is 1 delayed goal.\n    Yes (0.00s cpu)\n    "]).
:- comment(has_tent_value / 1, [summary : "X has a tentative value (succeeds also for X nonvar)", args : ["X" : "Any term"], amode : (has_tent_value(?) is semidet), see_also : [tent_set / 2, tent_get / 2, tent_fix / 1], desc : html("\n    \tSucceeds if X is a variable with a tentative value, or if X is\n\ta nonvariable (i.e. has a definitive value).\n    "), eg : "\n    ?- tent_set(X, 27), has_tent_value(X).\n    X = X{27 -> 0}\n    Yes (0.00s cpu)\n\n    ?- has_tent_value(_).\n    No (0.00s cpu)\n\n    ?- has_tent_value(35).\n    Yes (0.00s cpu)\n    "]).
:- comment(random_element / 2, [summary : "Pick random element from range or collection", amode : (random_element(+, -) is semidet), fail_if : "The range specification is empty or invalid", args : ["Values" : "Specification of possible values", "X" : "Output variable"], see_also : [random / 1, frandom / 1, random_sample / 3, tent_set_random / 2], desc : html("\n\t<P>\n\tSelect a random value from the given specification of possible\n\tvalues.  The Values specification can be\n\t</P>\n\t<DL>\n\t<DT>Min..Max</DT>\n\t    <DD>A range of integers from Min to Max</DD>\n\t<DT>List</DT>\n\t    <DD>A list of possible values</DD>\n\t<DT>Array</DT>\n\t    <DD>An array of possible values</DD>\n\t</DL>\n    "), eg : "\n    ?- random_element(3 .. 7, X).\n    X = 5\n    Yes (0.00s cpu)\n\n    ?- random_element([a, b, c, d], X).\n    X = a\n    Yes (0.00s cpu)\n\n    ?- random_element([a, b, c, d], X).\n    X = c\n    Yes (0.00s cpu)\n\n    "]).
:- comment(random_sample / 3, [summary : "Nondeterministically pick SampleSize random elements", amode : (random_sample(+, +, -) is nondet), args : ["Values" : "Specification of possible values", "SampleSize" : "Integer", "X" : "Output variable"], see_also : [random / 1, frandom / 1, random_element / 2, tent_set_random / 2], desc : html("\n\tThis predicate succeeds SampleSize times. Each time it succeeds,\n\tit returns a random value from the given specification of possible\n\tvalues.  The Values specification are as in random_element/2.\n    "), eg : "\n    ?- random_sample(0 .. 9, 3, X).\n    X = 9\n    Yes (0.00s cpu, solution 1, maybe more)\n    X = 0\n    Yes (0.03s cpu, solution 2, maybe more)\n    X = 5\n    Yes (0.03s cpu, solution 3)\n    "]).
:- comment(register_for_notification / 3, [summary : "Constraint implementation: register for notification", amode : register_for_notification(?, +, ?), args : ["X" : "A non-free term, usually a tentative variable", "Tag" : "A user-defined term", "Receiver" : "A notification-receiver (input or output)"], see_also : [library(notify_ports)], desc : html("\n\t<P>\n\tThis is part of the interface for implementing tentative constraints.\n\tIt sets up a receiver in the sense of lib(notify_ports), such\n\tthat every time the tentative value of X changes, a message\n\tis sent to this receiver. The message has the form\n\t</P><PRE>\n\t\tTag:chg(Old,New)\n\t</PRE><P>\n\twhere Tag is the parameter given here in the setup (e.g. the\n\tindex of a variable within the constraint where it occurs),\n\tOld is the tentative value before the change, and New the\n\ttentative value after the change.\n\t</P><P>\n\tThe same receiver can register for many variables. Messages\n\tfrom the different variables are distinguished by their Tag.\n\t</P><P>\n\tSuch a receiver would typically be used by a demon that is woken\n\tup on tentative value change (tent_chg of tentative), to obtain\n\tprecise information about the changes that caused the wakeup.\n\t</P>\n    "), eg : "\n    tent_trace_array(Stream, Name, Xs) :-\n\t    ( foreacharg(X,Xs,I), param(Stream,Name) do\n\t\tregister_for_notification(X, I, Receiver),\n\t\tsuspend(tent_trace_demon(Stream, Name, Receiver, Susp),\n\t\t\t1, X->tent_chg, Susp)\n\t    ).\n\n\t:- demon tent_trace_demon/4.\n\ttent_trace_demon(Stream, Name, Receiver, Susp) :-\n\t    foreachnotification(tent_trace_demon,\n\t\t    I:Notification, [Stream, Name], Receiver, Status, (\n\t\tprintf(Stream, \"%w[%w]: %w%n\", [Name,I,Notification])\n\t    )),\n\t    ( Status = closed ->\n\t\twriteln(Stream, Name:Status),\n\t\tkill_suspension(Susp)\n\t    ; true ).\n    "]).
:- comment(tent_fix / 1, [summary : "Instantiate X to its tentative value", args : ["X" : "Any term, typically containing tentative variables"], amode : (tent_fix(?) is det), exceptions : [tentative_value_not_set : "X (or a subterm of X) has no tentative value"], see_also : [tent_set / 2, has_tent_value / 1, tent_get / 2], desc : html("\n\tThis is a shorthand for\n\t<PRE>\n\t\ttent_get(X, TV), X = TV.\n\t</PRE>\n    "), eg : "\n    ?- tent_set(X, 27), tent_fix(X).\n    X = 27\n    Yes (0.00s cpu)\n\n    ?- X = foo(_, _), tent_set(X, foo(27, 99)), tent_fix(X).\n    X = foo(27, 99)\n    Yes (0.00s cpu)\n    "]).
:- comment(tent_get / 2, [summary : "Get X's tentative value", amode : (tent_get(?, -) is det), exceptions : [tentative_value_not_set : "X (or a subterm of X) has no tentative value"], args : ["X" : "Any term, typically a variable", "TV" : "Will be bound to a (nonvar) term"], see_also : [tent_set / 2, has_tent_value / 1, tent_fix / 1], desc : html("\n    \tGet a variable's (or a whole term's) tentative value, i.e. create a\n\tterm TV that represents the current tentative value of X. \n\t<UL>\n    \t<LI>If X is a tentative variable, TV is bound to the tentative value.</LI>\n\t<LI>If X is a variable without tentative value, an error is raised.</LI>\n    \t<LI>If X is atomic, its tentative value is the same as X.</LI>\n\t<LI>If X is a compound term, TV will be bound to a corresponding compound\n\tterm with all variables replaced by their tentative values. The resulting\n\tterm TV will be a proper instance of X.</LI>\n\t</UL>\n    "), eg : "\n    ?- tent_set(X, 27), tent_get(X, TV).\n    X = X{27 -> 0}\n    TV = 27\n    Yes (0.00s cpu)\n\n    ?- tent_set(X, 27), tent_set(X, 99), tent_get(X, TV).\n    X = X{99 -> 0}\n    TV = 99\n    Yes (0.00s cpu)\n\n    ?- X = foo(Y), tent_set(X, foo(27)), X tent_get TV.\n    X = foo(Y{27 -> 0})\n    Y = Y{27 -> 0}\n    TV = foo(27)\n    Yes (0.00s cpu)\n\n    ?- tent_get(27, TV).\n    TV = 27\n    Yes (0.00s cpu)\n\n    ?- tent_get(X, TV).\n    uncaught exception in exit_block(tentative_value_not_set)\n    Abort\n\n    ?- tent_get(foo(X), TV).\n    uncaught exception in exit_block(tentative_value_not_set)\n    Abort\n    "]).
:- comment(tent_implements / 2, [summary : "Associate a constraint with a tentative value implementation", template : "++ImplSpec tent_implements ++ConsSpec", amode : (tent_implements(++, ++) is det), args : ["ImplSpec" : "Term of the form Atom/Integer", "ConsSpec" : "Term of the form Atom/Integer"], see_also : [:~ / 2], desc : html("\n\tThis declaration is part of the constraint implementation interface.\n\tIt links the name/arity of the constraint in the constraint model to\n\tthe name/arity of the predicate that implements the tentative value\n\tsemantics of the constraint.  For example, the declaration\n\t<PRE>\n\t    :- alldifferent_t/2 tent_implements alldifferent/1.\n\t</PRE>\n\tmeans that whenever an alldifferent/1 constraint is added to a\n\tconstraint set, e.g. by using\n\t<PRE>\n\t    ..., CSet :~ alldifferent(List), ...\n\t</PRE>\n\tthen the alldifferent_t(List, Monitor) is invoked to implement\n\tthis constraint.\n    ")]).
:- comment(tent_is / 2, [summary : "Maintain tentative result of arithmetic expression", template : "?Result tent_is +Expr", amode : (tent_is(+, ?) is det), args : ["Result" : "A (free or tentative) variable", "Expr" : "Arithmetic expression containing tentative variables"], see_also : [tent_set / 2, tent_get / 2], desc : html("\n\t<P>\n\tImplementation of arithemtic invariants.\n\t</P><P>\n\tThis is similar to the normal arithmetic is/2 predicate, but\n\tevaluates the expression based on the tentative values of its\n\tvariables.  The result is delivered as (an update to) the\n\ttentative value of the Result variable.  Once initiated,\n\ttent_is will stay active and keep updating Result's tentative\n\tvalue eagerly whenever the tentative value of any variable in\n\tExpression changes.\n\t</P>\n    "), eg : "\n    ?- [X, Y] tent_set [3, 4], Z tent_is X + Y.\n    X = X{3 -> 0}\n    Y = Y{4 -> 0}\n    Z = Z{7 -> 0}\n    Yes (0.00s cpu)\n\n    ?- [X, Y] tent_set [3, 4], Z tent_is X + Y, X tent_set 7.\n    X = X{7 -> 0}\n    Y = Y{4 -> 0}\n    Z = Z{11 -> 0}\n    Yes (0.00s cpu)\n    "]).
:- comment(tent_minimize_random / 3, [summary : "Find a move that minimizes violations", amode : tent_minimize_random(+, ?, -), fail_if : "Fails if MoveGenerator fails", args : ["MoveGenerator" : "A goal", "Violations" : "A tentative variable", "MoveId" : "Placeholder for move identifier"], see_also : [tent_set / 2], desc : html("\n\tThis metapredicate finds a local search move that minimizes\n\tviolations. It requries that the tentative variables and constraints\n\tover them have been set up beforehand. \n\t<P>\n    \tMoveGenerator is a nondeterministic goal that implements a local\n\tsearch step. It should explore all neighbours on backtracking.\n\tA move should be made by changing tentative values, and\n\tinstantiating MoveId to a unique identifier for every move.\n\t<P>\n\tViolations should be a tentative variable that reflects the\n\ttotal problem violations that are to be minimized.\n\t<P>\n\tMoveId is a variable which occurs in MoveGenerator. At the end of\n\tminimization, it will contain the ID of the best move. If there\n\tare multiple moves of the same quality, a random one is returned.\n\t<P>\n\tAfter tent_minimize_random/3 succeeds, all the trial moves are undone\n\tand the computation state is as before the call. Only the MoveId\n\tcontains the identifier of the best move. This move can then be\n\tcommitted to by performing it again according to MoveId.\n    "), eg : "\n\n    % This example tries 8 moves that lead to different tentative values\n    % of Viol. One of the moves that lead to a value of 1 is selected.\n\n    ?-  Viol tent_set 0,\n\ttent_minimize_random((\n\t\tbetween(1, 8, 1, MoveId),\n\t\targ(MoveId, viol(9,5,6,1,3,6,1,9), N),\n\t\tViol tent_set N\n\t    ), Viol, MoveId).\n     ...\n     MoveId = 7\t\t% 4 or 7, the result is random!\n     Yes (0.00s cpu)\n    "]).
:- comment(tent_set / 2, [summary : "Set X's tentative value to TV", amode : (tent_set(-, +) is det), amode : (tent_set(+, +) is semidet), fail_if : "TV is not an instance of X", exceptions : ["4" : "TV is not sufficiently instantiated"], args : ["X" : "Any term, typically a variable", "TV" : "A (nonvar) term"], see_also : [tent_get / 2, has_tent_value / 1, tent_fix / 1], desc : html("\n\tGive a variable (or several variables within a term) a tentative value.\n\tA tentative value cannot be itself a variable.\n\t<UL>\n\t<LI>If X is a variable without tentative value, it will be given the\n\ttentative value TV. In addition, its violatedness count will be\n\tinitialised to 0.</LI>\n\t<LI>If X already has a tentative value, its tentative value is\n\tchanged to TV. (Note that this may trigger further computation!)\n\tThe violatedness count remains unchanged.</LI>\n\t<LI>If X is already instantiated, TV must be a strict instance of X.\n\tVariables within X are given tentative values from the corresponding\n\tinstantiated parts of TV.</LI>\n\t</UL>\n    "), eg : "\n    ?- tent_set(X, 27).\n    X = X{27 -> 0}\n    Yes (0.00s cpu)\n\n    ?- tent_set(X, 27), tent_set(X, 99).\n    X = X{99 -> 0}\n    Yes (0.00s cpu)\n\n    ?- tent_set(foo(X), foo(27)).\n    X = X{27 -> 0}\n    Yes (0.00s cpu)\n\n    ?- tent_set(X, Y).\n    instantiation fault in X tent_set Y\n    Abort\n    "]).
:- comment(tent_set_all / 2, [summary : "Set the tentative values of all variables within Vars to the same value TV", amode : (tent_set_all(?, +) is det), args : ["Vars" : "A term", "TV" : "A (nonvar) term"], see_also : [tent_set / 2, tent_set_random / 2], desc : html("\n\tAssign the tentative value TV to each variable in the term Vars.\n\tVars would typically be a list (or array) of variables.\n    "), eg : "\n    ?- tent_set_all([A, B, C], 3).\n    A = A{3 -> 0}\n    B = B{3 -> 0}\n    C = C{3 -> 0}\n    Yes (0.00s cpu)\n\n    ?- length(L, 5), tent_set_all(L, 3).\n    L = [Xi{3 -> 0}, Xi{3 -> 0}, Xi{3 -> 0}, Xi{3 -> 0}, Xi{3 -> 0}]\n    Yes (0.00s cpu)\n    "]).
:- comment(tent_set_random / 2, [summary : "Set the tentative value of each variable within Vars to a random value from the given Range", amode : (tent_set_random(?, ++) is det), args : ["Vars" : "A term", "Values" : "Specification of possible values"], see_also : [tent_set / 2, tent_set_all / 2], desc : html("\n\tAssign to each variable in Vars a random value from the given\n\tspecification of possible values.  The Values specification can be\n\t<DL>\n\t<DT>Min..Max</DT>\n\t    <DD>A range of integers from Min to Max</DD>\n\t<DT>List</DT>\n\t    <DD>A list of possible values</DD>\n\t<DT>Array</DT>\n\t    <DD>An array of possible values</DD>\n\t</DL>\n    "), eg : "\n    ?- length(L, 5), tent_set_random(L, 1 .. 9).\n    L = [Xi{2 -> 0}, Xi{3 -> 0}, Xi{7 -> 0}, Xi{5 -> 0}, Xi{3 -> 0}]\n    Yes (0.00s cpu)\n\n    ?- length(L, 5), tent_set_random(L, [a, e, i, o, u]).\n    L = [Xi{o -> 0}, Xi{e -> 0}, Xi{o -> 0}, Xi{e -> 0}, Xi{e -> 0}]\n    Yes (0.00s cpu)\n\n    ?- length(L, 5), tent_set_random(L, [](a, e, i, o, u)).\n    L = [Xi{u -> 0}, Xi{i -> 0}, Xi{a -> 0}, Xi{o -> 0}, Xi{a -> 0}]\n    Yes (0.00s cpu)\n    "]).
:- comment(tent_trace_array / 3, [summary : "Simple tracing facility for several variables", amode : (tent_trace_array(+, +, +) is det), args : ["Stream" : "A stream identifier", "Name" : "Usually atom or string (but general term allowed)", "ArrayList" : "Array or list of tentative variables"], see_also : [library(viewable)], desc : html("\n\t<P>\n\tThis predicate sets up a demon that prints a message whenever the\n\ttentative value of one of the variables in ArrayList changes.\n\tThe message is printed onto Stream and is of the form\n\t</P><PRE>\n\t\tName[Index]: chg(Old,New)\n\t</PRE><P>\n\twhere Index is the index of the changed variable in the given\n\tarray, Old is the tentative value before the change, and New\n\tthe tentative value after the change.\n\t</P><P>\n\tAnother way of tracing tentative value changes is by using the\n\tVisualisation Tools.\n\t</P>\n    "), eg : "\n    ?- Xs = [X,Y], tent_set(Xs, [1,2]),\n      tent_trace_array(output, hello, Xs),\n      tent_set(X, 7),\n      tent_set(Y, 3),\n      tent_set([X,Y], [5,5]).\n\n    hello[1]: chg(1, 7)\n    hello[2]: chg(2, 3)\n    hello[1]: chg(7, 5)\n    hello[2]: chg(3, 5)\n\n    Xs = [X{5 -> 0}, Y{5 -> 0}]\n    There are 2 delayed goals.\n    Yes (0.02s cpu)\n    "]).
:- comment(var_get_violations / 2, [summary : "Get X's violation count", amode : (var_get_violations(?, -) is det), exceptions : [tentative_value_not_set : "X is a variable without tentative value"], args : ["X" : "A a tentative variable or instantiated term", "Violations" : "Variable, will be bound to a number"], see_also : [tent_set / 2, var_inc_violations / 2], desc : html("\n\tGet X's violations count. The violation count of a tentative variable\n\tis the cumulative result of all previous increments of that count.\n\tThe violation count of a nonvariable term is 0.\n    "), eg : "\n    ?- tent_set(X, 27), var_get_violations(X, V).\n    X = X{27 -> 0}\n    V = 0\n    Yes (0.00s cpu)\n\n    ?- tent_set(X, 27), var_inc_violations(X, 3), var_get_violations(X, V).\n    X = X{27 -> 3}\n    V = 3\n    Yes (0.00s cpu)\n\n    ?- var_get_violations(a, V).\n    V = 0\n    Yes (0.00s cpu)\n\n    ?- var_get_violations(_, V).\n    uncaught exception in exit_block(tentative_value_not_set)\n    Abort\n    "]).
:- comment(var_inc_violations / 2, [summary : "Increment X's violation count by Delta", amode : (var_inc_violations(?, +) is semidet), args : ["X" : "A a tentative variable", "Delta" : "A number"], fail_if : "Fails if X is a variable without tentative value", see_also : [tent_set / 2, has_tent_value / 1, tent_get / 2, var_get_violations / 2], desc : html("\n\tIncrement X's violation count by Delta. X should be a variable with\n\ta tentative value. The initial violation count for every variable is 0.\n\t<P>\n\tCalling var_inc_violations/2 on a nonvariable has no effect and\n\tsilently succeeds.\n    "), eg : "\n    ?- tent_set(X, 27), var_inc_violations(X, 3).\n    X = X{27 -> 3}\n    Yes (0.00s cpu)\n\n    ?- tent_set(X, 27), var_inc_violations(X, 3), var_inc_violations(X, 1).\n    X = X{27 -> 4}\n    Yes (0.00s cpu)\n\n    ?- tent_set(X, 27), var_inc_violations(X, 3), var_inc_violations(X, -1).\n    X = X{27 -> 2}\n    Yes (0.00s cpu)\n\n    ?- var_inc_violations(foo, 3).\n    Yes (0.00s cpu)\n\n    ?- var_inc_violations(_, 3).\n    No (0.00s cpu)\n    "]).
:- comment(vs_all / 2, [summary : "Retrieve all variables from a varset", amode : (vs_all(+, -) is det), args : ["VS" : "A varset", "Vars" : "A list of tentative variables (output)"], see_also : [vs_create / 2, vs_random / 2, vs_member / 2], desc : html("\n\tRetrieve all variables from a varset.\n    "), eg : "\n    ?- Vars=[A,B,C], tent_set(Vars, [1,2,3]),\n       vs_create(Vars, VS), vs_all(VS, VSVars).\n    Vars = [A{1 -> 0}, B{2 -> 0}, C{3 -> 0}]\n    VS = ...\n    VSVars = [C{3 -> 0}, B{2 -> 0}, A{1 -> 0}]\n    Yes (0.00s cpu)\n    "]).
:- comment(vs_all_violated / 2, [summary : "Retrieve all violated variables from a varset", amode : (vs_all_violated(+, -) is det), args : ["VS" : "A varset", "Vars" : "A list of tentative variables (output)"], see_also : [vs_random_violated / 2, vs_violated / 2, vs_all_violated_index / 2], desc : html("\n\tRetrieve all variables from a varset which have nonzero violation\n\tcounts.\n    "), eg : "\n    ?- Vars=[A,B,C], tent_set(Vars, [1,2,3]), vs_create(Vars, VS),\n       var_inc_violations(B, 1), vs_all_violated(VS, VSVars).\n    Vars = [A{1 -> 0}, B{2 -> 1}, C{3 -> 0}]\n    VS = ...\n    VSVars = [B{2 -> 1}]\n    Yes (0.00s cpu)\n    "]).
:- comment(vs_all_violated_index / 2, [summary : "Retrieve all violated variable indices from a varset", amode : (vs_all_violated_index(+, -) is det), args : ["VS" : "A varset", "Vars" : "A list of integers (output)"], see_also : [vs_random_violated_index / 2, vs_violated_index / 2, vs_all_violated / 2], desc : html("\n\tRetrieve all variable indices from a varset which have nonzero\n\tviolation counts.\n    "), eg : "\n    ?- Vars=[A,B,C], tent_set(Vars, [1,2,3]), vs_create(Vars, VS),\n       var_inc_violations(B, 1), vs_all_violated(VS, VSIs).\n    Vars = [A{1 -> 0}, B{2 -> 1}, C{3 -> 0}]\n    VS = ...\n    VSVars = [2]\n    Yes (0.00s cpu)\n    "]).
:- comment(vs_all_worst / 2, [summary : "Retrieve all worst violated variables from a varset", amode : (vs_all_worst(+, -) is det), args : ["VS" : "A varset", "Vars" : "A list of tentative variables (output)"], see_also : [vs_random_worst / 2, vs_worst / 2, vs_all_worst_index / 2], desc : html("\n\tRetrieve all variables from a varset whose violation count is\n\tmaximal in the varset.\n    "), eg : "\n    ?- Vars=[A,B,C], tent_set(Vars, [1,2,3]), vs_create(Vars, VS),\n       var_inc_violations(A, 2),\n       var_inc_violations(B, 1),\n       var_inc_violations(C, 2),\n       vs_all_worst(VS, VSVars).\n    Vars = [A{1 -> 2}, B{2 -> 1}, C{3 -> 2}]\n    VS = ...\n    VSVars = [A{1 -> 2}, C{3 -> 2}]\n    Yes (0.00s cpu)\n    "]).
:- comment(vs_all_worst_index / 2, [summary : "Retrieve all worst violated variable indices from a varset", amode : (vs_all_worst_index(+, -) is det), args : ["VS" : "A varset", "Vars" : "A list of integers (output)"], see_also : [vs_random_worst_index / 2, vs_worst_index / 2, vs_all_worst / 2], desc : html("\n\tRetrieve all variable indices from a varset whose violation count is\n\tmaximal in the varset.\n    ")]).
:- comment(vs_create / 2, [summary : "Construct a varset from the variables in Vars", amode : (vs_create(?, -) is semidet), fail_if : "Vars contains variables without tentative values", args : ["Vars" : "A term containing tentative variables", "VS" : "Varset (output)"], see_also : [tent_set / 2, vs_size / 2, vs_element / 3, vs_all / 2, vs_all_violated / 2, vs_all_worst / 2, vs_all_violated_index / 2, vs_all_worst_index / 2, vs_random / 2, vs_random_violated / 2, vs_random_worst / 2, vs_random_index / 2, vs_random_violated_index / 2, vs_random_worst_index / 2, vs_member / 2, vs_violated / 2, vs_worst / 2, vs_violated_index / 2, vs_worst_index / 2], desc : html("\n\tCreate an abstract 'varset' from the tentative variables in a term.\n\tA varset is an ordered set of variables that can be accessed by\n\tindex, or by their violation properties. Elements are indexed from\n\t1 to size of the set.\n    "), eg : "\n    ?- Vars = [_,_,_], tent_set_all(Vars, 99), vs_create(Vars, VS).\n    Vars = [Xi{99 -> 0}, Xi{99 -> 0}, Xi{99 -> 0}]\n    VS = ...\n    Yes (0.00s cpu)\n    "]).
:- comment(vs_element / 3, [summary : "Get an element of a varset by index", amode : (vs_element(+, +, -) is det), args : ["VS" : "A varset", "I" : "A positive integer", "X" : "A variable (output)"], see_also : [vs_create / 2, vs_size / 2], desc : html("\n\tGet the Ith element of a varset. I must be between 1 and the\n\tsize of the set.\n    "), eg : "\n    ?- Vars=[A,B,C], vs_create(Vars, VS), vs_element(VS, 1, X).\n    VS = ...\n    X = C\n    Yes (0.00s cpu)\n    "]).
:- comment(vs_member / 2, [summary : "Succeed for each element of a varset", amode : (vs_member(+, -) is nondet), args : ["VS" : "A varset", "X" : "A variable (output)"], see_also : [vs_create / 2, vs_element / 3, vs_all / 2, vs_random / 2], desc : html("\n\tBacktrack over all elements of a varset.\n    ")]).
:- comment(vs_random / 2, [summary : "Retrieve a random variable from a varset", amode : (vs_random(+, -) is semidet), args : ["VS" : "A varset", "Var" : "Tentative variable (output)"], see_also : [vs_create / 2, vs_element / 3, vs_random_index / 2], desc : html("\n\tRetrieve a random variable from a varset.\n    "), eg : "\n    ?- Vars=[A,B,C], tent_set(Vars, [a,b,c]), vs_create(Vars, VS),\n       vs_random(VS, Var).\n    Vars = [Var{a -> 0}, B{b -> 0}, C{c -> 0}]\n    VS = ...\n    Var = Var{a -> 0}\t% A, B or C, the result is random!\n    Yes (0.00s cpu)\n    "]).
:- comment(vs_random_index / 2, [summary : "Retrieve a random variable index from a varset", amode : (vs_random_index(+, -) is semidet), args : ["VS" : "A varset", "Var" : "An integer (output)"], see_also : [vs_create / 2, vs_element / 3, vs_random / 2], desc : html("\n\tRetrieve a random variable index from a varset.\n    "), eg : "\n    ?- Vars=[A,B,C], tent_set(Vars, [a,b,c]), vs_create(Vars, VS),\n       vs_random(VS, I).\n    Vars = [A{a -> 0}, B{b -> 0}, C{c -> 0}]\n    VS = ...\n    I = 1\t\t% 1, 2 or 3, the result is random!\n    Yes (0.00s cpu)\n    "]).
:- comment(vs_random_violated / 2, [summary : "Retrieve a random violated variable from a varset", amode : (vs_random_violated(+, -) is semidet), args : ["VS" : "A varset", "Var" : "Tentative variable (output)"], see_also : [vs_all_violated / 2, vs_violated / 2, vs_random_violated_index / 2], fail_if : "The varset does not contain a violated variable", desc : html("\n\tRetrieve a variable from a varset whose violation count is\n\tnonzero. If there are more than one, a random candidate is returned.\n    "), eg : "\n    ?- Vars=[A,B,C], tent_set(Vars, [a,b,c]), vs_create(Vars, VS),\n       var_inc_violations(A, 2),\n       var_inc_violations(C, 1),\n       vs_random_violated(VS, Var).\n    Vars = [Var{a -> 2}, B{b -> 0}, C{c -> 1}]\n    VS = ...\n    Var = Var{a -> 2}\t% A or C, the result is random!\n    Yes (0.00s cpu)\n    "]).
:- comment(vs_random_violated_index / 2, [summary : "Retrieve a random violated variable index from a varset", amode : (vs_random_violated_index(+, -) is semidet), args : ["VS" : "A varset", "I" : "An integer variable (output)"], see_also : [vs_all_violated_index / 2, vs_violated_index / 2, vs_random_violated / 2], fail_if : "The varset does not contain a violated variable", desc : html("\n\tRetrieve a variable index from a varset whose violation count is\n\tnonzero. If there are more than one, a random candidate is returned.\n    "), eg : "\n    ?- Vars=[A,B,C], tent_set(Vars, [a,b,c]), vs_create(Vars, VS),\n       var_inc_violations(A, 2),\n       var_inc_violations(C, 1),\n       vs_random_violated(VS, I).\n    Vars = [A{a -> 2}, B{b -> 0}, C{c -> 1}]\n    VS = ...\n    I = 1\t\t% 1 or 3, the result is random!\n    Yes (0.00s cpu)\n    "]).
:- comment(vs_random_worst / 2, [summary : "Retrieve a worst violated variable from a varset", amode : (vs_random_worst(+, -) is semidet), fail_if : "Fails if there is no violated variable in the set", args : ["VS" : "A varset", "Var" : "Tentative variable (output)"], see_also : [vs_all_worst / 2, vs_worst / 2, vs_random_worst_index / 2], desc : html("\n\tRetrieve a variable from a varset whose violation count is\n\tmaximal in the varset. In case of ties, a random candidate\n\tis returned.\n    "), eg : "\n    ?- Vars=[A,B,C], tent_set(Vars, [1,2,3]), vs_create(Vars, VS),\n       var_inc_violations(A, 2),\n       var_inc_violations(B, 1),\n       var_inc_violations(C, 2),\n       vs_random_worst(VS, Worst).\n    Vars = [A{1 -> 2}, B{2 -> 1}, Worst{3 -> 2}]\n    VS = ...\n    Worst = Worst{3 -> 2}       % A or C, the result is random!\n    Yes (0.00s cpu)\n    "]).
:- comment(vs_random_worst_index / 2, [summary : "Retrieve a worst violated variable index from a varset", amode : (vs_random_worst_index(+, -) is semidet), fail_if : "Fails if there is no violated variable in the set", args : ["VS" : "A varset", "Var" : "An integer (output)"], see_also : [vs_all_worst_index / 2, vs_worst_index / 2, vs_random_worst / 2], desc : html("\n\tRetrieve a variable index from a varset whose violation count is\n\tmaximal in the varset. In case of ties, a random candidate\n\tis returned.\n    "), eg : "\n    ?- Vars=[A,B,C], tent_set(Vars, [1,2,3]), vs_create(Vars, VS),\n       var_inc_violations(A, 2),\n       var_inc_violations(B, 1),\n       var_inc_violations(C, 2),\n       vs_random_worst(VS, Worst).\n    Vars = [A{1 -> 2}, B{2 -> 1}, Worst{3 -> 2}]\n    VS = ...\n    Worst = 1       % 1 or 3, the result is random!\n    Yes (0.00s cpu)\n    "]).
:- comment(vs_size / 2, [summary : "Get the size of a varset", amode : (vs_size(+, -) is det), args : ["VS" : "A varset", "N" : "An integer (output)"], see_also : [vs_create / 2, vs_element / 3], desc : html("\n\tGet the size (number of elements) of a varset.\n    "), eg : "\n    ?- Vars=[A,B,C], vs_create(Vars, VS), vs_size(VS, N).\n    VS = ...\n    N = 3\n    Yes (0.00s cpu)\n    "]).
:- comment(vs_violated / 2, [summary : "Succeeds for each violated variable from a varset", amode : (vs_violated(+, -) is nondet), args : ["VS" : "A varset", "Vars" : "A tentative variable (output)"], see_also : [vs_all_violated / 2, vs_random_violated / 2, vs_violated_index / 2], desc : html("\n\tBacktrack over all variables from a varset which have nonzero\n\tviolation counts.\n    ")]).
:- comment(vs_violated_index / 2, [summary : "Succeeds for each violated variable index from a varset", amode : (vs_violated_index(+, -) is nondet), args : ["VS" : "A varset", "Vars" : "An integer (output)"], see_also : [vs_all_violated_index / 2, vs_random_violated_index / 2, vs_violated / 2], desc : html("\n\tBacktrack over all variable indices from a varset which have\n\tnonzero violation counts.\n    ")]).
:- comment(vs_worst / 2, [summary : "Succeeds for each worst violated variable from a varset", amode : (vs_worst(+, -) is nondet), args : ["VS" : "A varset", "Vars" : "A tentative variable (output)"], see_also : [vs_all_worst / 2, vs_random_worst / 2, vs_worst_index / 2], desc : html("\n\tBacktrack over all variable indices from a varset whose violation\n\tcount is maximal in the varset.\n    ")]).
:- comment(vs_worst_index / 2, [summary : "Succeeds for each worst violated variable index from a varset", amode : (vs_worst_index(+, -) is nondet), args : ["VS" : "A varset", "Vars" : "An integer (output)"], see_also : [vs_all_worst_index / 2, vs_random_worst_index / 2, vs_worst / 2], desc : html("\n\tBacktrack over all variable indices from a varset whose violation\n\tcount is maximal in the varset.\n    ")]).
