:- module(ic_kernel).
:- export ic_suspensions / 3.
:- export copy_ic_term / 2.
:- export compare_ic_instances / 3.
:- export test_unify_ic / 2.
:- export tr_ic_kernel_out / 2.
:- export tr_ria_ternop / 2.
:- export tr_ria_ternop9 / 2.
:- export tr_ria_ternop1 / 2.
:- export tr_ria_binop / 2.
:- export tr_ria_binop7 / 2.
:- export tr_ria_binop1 / 2.
:- export tr_ria_unop / 2.
:- export tr_ria_unop5 / 2.
:- export tr_ria_unop1 / 2.
:- export tr_ic_c_constant / 2.
:- export ic_stat_register_event / 2.
:- export ic_stat_get / 1.
:- export ic_stat / 1.
:- export ic_event / 1.
:- export msg / 3.
:- export exclude_range / 3.
:- export exclude / 2.
:- export impose_bounds / 3.
:- export impose_domain / 2.
:- export impose_max / 2.
:- export impose_min / 2.
:- export set_var_type / 2.
:- export set_vars_type / 2.
:- export delayed_goals_number / 2.
:- export is_in_domain / 3.
:- export is_in_domain / 2.
:- export set_threshold / 2.
:- export print_solver_var / 2.
:- export get_delta / 2.
:- export get_median / 2.
:- export get_domain_as_list / 2.
:- export get_domain / 2.
:- export get_finite_integer_bounds / 3.
:- export get_integer_bounds / 3.
:- export get_float_bounds / 3.
:- export get_max / 2.
:- export get_min / 2.
:- export get_solver_type / 2.
:- export is_solver_type / 1.
:- export is_exact_solver_var / 1.
:- export is_solver_var / 1.
:- export integers / 1.
:- export reals / 1.
:- export unify_ic / 3.
:- export set_threshold / 1.
:- export get_threshold / 1.
:- export get_domain_size / 2.
:- export get_bounds / 3.
:- export get_ic_attr / 2.
:- reexport ria_unop / 5, ria_binop / 7, ria_ternop / 9 from sepia_kernel.
:- export macro(ic_status_failed / 0, ic_kernel : tr_ic_c_constant / 2, []).
:- export macro(ic_status_unknown / 0, ic_kernel : tr_ic_c_constant / 2, []).
:- export macro(ic_status_entailed / 0, ic_kernel : tr_ic_c_constant / 2, []).
:- export macro(ic_unify_bound_implied / 0, ic_kernel : tr_ic_c_constant / 2, []).
:- export macro(ic_unify_bound_tight / 0, ic_kernel : tr_ic_c_constant / 2, []).
:- export macro(ic_unify_bound_fuzzy / 0, ic_kernel : tr_ic_c_constant / 2, []).
:- export macro(ria_unop / 1, ic_kernel : tr_ria_unop1 / 2, []).
:- export macro(ria_unop / 5, ic_kernel : tr_ria_unop5 / 2, []).
:- export macro(ria_binop / 1, ic_kernel : tr_ria_binop1 / 2, []).
:- export macro(ria_binop / 7, ic_kernel : tr_ria_binop7 / 2, []).
:- export macro(ria_ternop / 1, ic_kernel : tr_ria_ternop1 / 2, []).
:- export macro(ria_ternop / 9, ic_kernel : tr_ria_ternop9 / 2, []).
:- export portray(set_var_type / 2, ic_kernel : tr_ic_kernel_out / 2, [goal]).
:- export portray(set_vars_type / 2, ic_kernel : tr_ic_kernel_out / 2, [goal]).
:- export struct(ic(var_type, lo, hi, bitmap, min, max, hole, type)).
:- comment(summary, "Low-level interface to the common kernel of the IC solver").
:- comment(author, "Warwick Harvey").
:- comment(desc, html("<P>\nThis module provides a low-level interface to the core of the IC solver;\nthat is, a set of predicates for accessing and manipulating IC variables.\nIt is not intended for use by general user code (use the interface provided\nby the `ic' module for that), but rather for those wishing to implement\ntheir own constraints which use IC variables.  This could either be to\naugment IC by providing new constraints or functionality, or to build a\ncomplete constraint solver capable of cooperating with any other solver\nwhich also uses the common numeric variable format provided by IC.</P>\n")).
:- comment(exclude / 2, [amode : exclude(?, ++), args : ["Var" : "Integer variable or integer", "Excl" : "Integer value to exclude"], summary : "Exclude the element Excl from the domain of Var.", see_also : [exclude_range / 3, impose_min / 2, impose_max / 2, impose_domain / 2], desc : html("<P>\n   Primitive for excluding an element from the domain of an integer\n   variable.  The call may fail (when Var is the same integer as Excl),\n   succeed (possibly updating the variable's domain), or instantiate the\n   variable (when Excl was one of only two domain elements left).</P><P>\n\n   Note that this predicate is intended for use only in implementing\n   constraint propagators, and should not be called from ordinary user code\n   (use ic:(Var =\\= Excl) instead).  It differs from the usual constraint\n   predicates with respect to the execution of delayed goals.  If the call\n   to exclude/2 results in a domain change, any delayed goals suspended on\n   that change will be scheduled for execution, as normal.  However,\n   exclude/2 does not call the woken goal scheduler (wake/0), so these goals\n   may not be executed immediately.  (It is possible that under some\n   circumstances the goals will be executed, if wake/0 is called indirectly\n   - one example would be by the unify handler if the variable becomes\n   ground - but this should not be relied upon.)  To ensure that the goals\n   are eventually executed, the caller should arrange for wake/0 to be\n   called at some appropriate point in the subsequent execution.  Please see\n   the \"Advanced Control Features\" section of the User Manual for more\n   information about woken goal management.</P>\n"), eg : "[eclipse 3]: X :: 0..10, exclude(X, 4).\nX = X{[0 .. 3, 5 .. 10]}\nYes (0.00s cpu)\n\n[eclipse 4]: X :: [4, 6], exclude(X, 4).\nX = 6\nYes (0.00s cpu)\n"]).
:- comment(exclude_range / 3, [amode : exclude_range(?, ++, ++), args : ["Var" : "Integer variable or integer", "Lo" : "Integer lower bound of range to exclude", "Hi" : "Integer upper bound of range to exclude"], summary : "Exclude the elements Lo..Hi from the domain of Var.", see_also : [exclude / 2, impose_min / 2, impose_max / 2, impose_domain / 2], desc : html("<P>\n   Primitive for excluding the integers between Lo and Hi (inclusive) from\n   the domain of an integer variable.  The call may fail (when the domain of\n   Var has no elements outside the range Lo..Hi), succeed (possibly updating\n   the variable's domain), or instantiate the variable (in the case where\n   the domain gets restricted to a singleton value).</P><P>\n\n   Note that this predicate is intended for use only in implementing\n   constraint propagators, and should not be called from ordinary user code.\n   It differs from the usual constraint predicates with respect to the\n   execution of delayed goals.  If the call to exclude_range/3 results in a\n   domain change, any delayed goals suspended on that change will be\n   scheduled for execution, as normal.  However, exclude_range/3 does not\n   call the woken goal scheduler (wake/0), so these goals may not be\n   executed immediately.  (It is possible that under some circumstances the\n   goals will be executed, if wake/0 is called indirectly - one example\n   would be by the unify handler if the variable becomes ground - but this\n   should not be relied upon.)  To ensure that the goals are eventually\n   executed, the caller should arrange for wake/0 to be called at some\n   appropriate point in the subsequent execution.  Please see the \"Advanced\n   Control Features\" section of the User Manual for more information about\n   woken goal management.</P>\n"), eg : "[eclipse 3]: X :: 0..10, exclude_range(X, 4, 7).\nX = X{[0 .. 3, 8 .. 10]}\nYes (0.00s cpu)\n\n[eclipse 4]: X :: 0..10, exclude_range(X, 9, 20).\nX = X{0 .. 8}\nYes (0.00s cpu)\n\n[eclipse 5]: X :: [2, 4, 6 .. 10], exclude_range(X, 4, 12).\nX = 2\nYes (0.00s cpu)\n"]).
:- comment(get_ic_attr / 2, [amode : get_ic_attr(?, -), args : ["X" : "A variable", "Attr" : "The IC attribute of <TT>X</TT>"], summary : "Returns the IC attribute of a variable, creating a new attribute if necessary.", fail_if : "X is not a variable", desc : html("<P>\n   If X is a variable and does not already have an IC attribute, it is given\n   a new one.  Attr is then bound to this attribute (new or old).  Attr must\n   be a fresh variable.  Fails if X is not a variable.\n")]).
:- comment(ic_event / 1, [amode : ic_event(++), args : ["Event" : "The short name of the event to record"], summary : "Indicates that the specified event has occured.", see_also : [ic_stat / 1, ic_stat_get / 1, ic_stat_register_event / 2], desc : html("<P>\n   Indicates that the specified event has occured.  Can be left in\n   production code as the call succeeds very quickly when stats gathering is\n   not turned on.\n")]).
:- comment(ic_stat / 1, [amode : ic_stat(++), args : ["Command" : "Statistics related command (eg. turn on, print)"], summary : "Enables/disables/resets/prints stats gathering information", see_also : [ic_stat_register_event / 2, ic_stat_get / 1, ic_event / 1], desc : html("<P>\n   The available commands for controlling statistics gathering are...\n<DL>\n\t<DT>on    <DD>Enables the recording of stats events.\n\t<DT>off   <DD>Disables the recording of stats events.\n\t<DT>reset <DD>Zero's all stats event counters.\n\t<DT>print <DD>Prints, on standard output, the value of all registered\n\t      stats event counters.\n</DL><P>\n   User programs may register their own events to be recorded by calling\n   <TT>ic_stat_register_event/2</TT>.\n")]).
:- comment(ic_stat_get / 1, [amode : ic_stat_get(-), args : ["StatsList" : "The list of stats events description=value pairs"], summary : "Returns the list of stats events description=value pairs", see_also : [ic_stat / 1, ic_stat_get / 1, ic_event / 1], desc : html("<P>\n   Returns the list of stats events description=value pairs.\n<P>\n   IC records the following statistics by default.  Please note that since\n   these depend on the internals of IC, they are subject to change without\n   notice, and should be used as a guide only.\n<DL>\n\t<DT>ic_lin_create\n\t    <DD>Number of linear constraints set up.\n\t<DT>ic_lin_prop\n\t    <DD>Number of times a linear constraint is propagated.\n\t<DT>ic_uni_prop/ic_bin_prop/ic_tern_prop\n\t    <DD>Number of times a non-linear (unary/binary/ternary) operator is\n\t    propagated.\n\t<DT>ic_split\n\t    <DD>Number of domain splits in locate/2,3,4.\n\t<DT>ic_squash\n\t    <DD>Number of squash attempts in squash/3 or locate/4.\n</DL>\n")]).
:- comment(ic_stat_register_event / 2, [amode : ic_stat_register_event(++, ++), args : ["Event" : "The short name of the event", "Description" : "The long name of the event"], summary : "Registers a new stats event to be collected", see_also : [ic_stat / 1, ic_stat_get / 1, ic_event / 1], desc : html("<P>\n   When a program wishes to record events of interest throughout its runtime\n   it can do so by first registering the event type with the stats logger at\n   the beginning of the program.  E.g.\n<PRE>\n\tic_stat_register_event('myevent','My really important event').\n</PRE>\n   Calls to ic_event/1 can then be inserted in the appropriate places\n   throughout the code.  E.g.\n<PRE>\n\tfoo:-\n\t\tic_event('myevent'),\n\t\tbar(X).\t\n</PRE>\n   While stats gathering is not enabled (i.e. without the program explicitly\n   calling <TT>ic_stat(on)</TT>) these events are processed very efficiently, and so\n   can be left in code without incurring any significant overhead.\n")]).
:- comment(impose_bounds / 3, [amode : impose_bounds(?, ++, ++), args : ["Var" : "Variable or number", "Lo" : "Lower bound", "Hi" : "Upper bound"], summary : "Update (if required) the bounds of Var.", see_also : [impose_min / 2, impose_max / 2, ic : $:: / 2, ic : (::) / 2], desc : html("<P>\n   Primitive for updating the upper and lower bounds of Var, also used as\n   the set_bounds handler for the IC attribute.  As with impose_min/2 and\n   impose_max/2, it is intended for use in implementing constraint\n   propagators, and should not be called from ordinary user code (use $::/2\n   or ::/2 instead).  Its semantics is essentially:\n<PRE>\n       impose_min(Var, Lo), impose_max(Var, Hi), wake.\n</PRE>\n   Please see the documentation for impose_min/2 and impose_max/2 for more\n   details.</P>\n")]).
:- comment(impose_domain / 2, [amode : impose_domain(?, ?), args : ["Var" : "Variable or number", "DomVar" : "Variable or number"], summary : "Restrict (if required) the domain of Var t othe domain of DomVar.", see_also : [impose_min / 2, impose_max / 2, impose_bounds / 3, exclude / 2, exclude_range / 3], desc : html("<P>\n   Primitive for restricting the domain of Var to the domain of DomVar.\n   Any values in the domain of Var, which are not also in the domain of\n   DomVar, are removed.  DomVar remains unaffected.  \n   The domain update on Var may fail (when the update empties the domain),\n   succeed (possibly updating the variable's domain), or instantiate the\n   variable (in the case where the domain gets restricted to a singleton\n   value).  Note that if DomVar's type is integer, the integrality will\n   be imposed on Var as well as the domain values.</P><P>\n\n   Note that this predicate is intended for use only in implementing\n   constraint propagators, and should not be called from ordinary user code.\n   The waking behaviour is the same as discussed for impose_min/2 and\n   impose_max/2.  Apart from this, the effect is similar to unifying\n   Var with a copy of DomVar.\n   </P>\n"), eg : "    ?- X::1..9, Y::5..7, impose_domain(X, Y).\n    X = X{5 .. 7}\n    Y = Y{5 .. 7}\n    Yes (0.00s cpu)\n\n    ?- X::1..9, impose_domain(X, 7).\n    X = 7\n    Yes (0.00s cpu)\n\n    ?- X::1..9, Y::4.1..7.5, impose_domain(X, Y).\n    X = X{5 .. 7}\n    Y = Y{4.1 .. 7.5}\n    Yes (0.00s cpu)\n\n    ?- X::1.0..9.0, Y::5..7, impose_domain(X, Y).\n    X = X{5 .. 7}\n    Y = Y{5 .. 7}\n    Yes (0.00s cpu)\n\n    ?- X::1..3, Y::5..7, impose_domain(X, Y).\n    No (0.00s cpu)\n\n    ?- Y::1..5, impose_domain(3, Y).\n    Y = Y{1 .. 5}\n    Yes (0.00s cpu)\n\n    ?- Y::1..5, impose_domain(6, Y).\n    No (0.00s cpu)\n\n    ?- Y::1..5, impose_domain(X, Y).\n    Y = Y{1 .. 5}\n    X = X{1 .. 5}\n    Yes (0.00s cpu)\n"]).
:- comment(impose_max / 2, [amode : impose_max(?, ++), args : ["Var" : "Variable or number", "Bound" : "Upper bound (number)"], summary : "Update (if required) the upper bound of Var.", see_also : [impose_min / 2, impose_bounds / 3, impose_domain / 2, exclude / 2, exclude_range / 3], desc : html("<P>\n   Primitive for updating the upper bound of Var so that it is at most\n   Bound.  A bound update on a variable may fail (when the update empties\n   the domain), succeed (possibly updating the variable's bounds), or\n   instantiate the variable (in the case where the domain gets restricted to\n   a singleton value).  Note that if the variable's type is integer, its\n   bounds will always be adjusted to integral values.</P><P>\n\n   Note that this predicate is intended for use only in implementing\n   constraint propagators, and should not be called from ordinary user code\n   (use ic:(Var =< Bound) instead).  It differs from the usual constraint\n   predicates in several ways.  First, Bound is assumed to be exact (i.e. if\n   it's a float, it's not widened).  Second, if Bound is a bounded real,\n   only its upper bound is significant, and it is this which is imposed on\n   Var.</P><P>\n\n   The final and most important difference relates to the execution of\n   delayed goals.  If the call to impose_max/2 results in a bound change,\n   any delayed goals suspended on that bound will be scheduled for\n   execution, as normal.  However, impose_max/2 does not call the woken goal\n   scheduler (wake/0), so these goals may not be executed immediately.  (It\n   is possible that under some circumstances the goals will be executed, if\n   wake/0 is called indirectly - one example would be by the unify handler\n   if the variable becomes ground - but this should not be relied upon.)  To\n   ensure that the goals are eventually executed, the caller should arrange\n   for wake/0 to be called at some appropriate point in the subsequent\n   execution.  Please see the \"Advanced Control Features\" section of the\n   User Manual for more information about woken goal management.</P>\n"), eg : "[eclipse 3]: X $:: 0..10, impose_min(X, 4.5).\nX = X{4.5 .. 10.0}\nYes (0.00s cpu)\n\n[eclipse 4]: X $:: 0..10, impose_min(X, 4.5), integers([X]).\nX = X{5 .. 10}\nYes (0.00s cpu)\n\n[eclipse 5]: X $:: 0..10, impose_min(X, 4.5), integers([X]), impose_max(X, 5.9).\nX = 5\nYes (0.00s cpu)\n\n[eclipse 6]: X $:: 0..10, impose_min(X, 4.5), impose_max(X, 4.3).\nNo (0.00s cpu)\n"]).
:- comment(impose_min / 2, [amode : impose_min(?, ++), args : ["Var" : "Variable or number", "Bound" : "Lower bound (number)"], summary : "Update (if required) the lower bound of Var.", see_also : [impose_max / 2, impose_bounds / 3, impose_domain / 2, exclude / 2, exclude_range / 3], desc : html("<P>\n   Primitive for updating the lower bound of Var so that it is at least\n   Bound.  A bound update on a variable may fail (when the update empties\n   the domain), succeed (possibly updating the variable's bounds), or\n   instantiate the variable (in the case where the domain gets restricted to\n   a singleton value).  Note that if the variable's type is integer, its\n   bounds will always be adjusted to integral values.</P><P>\n\n   Note that this predicate is intended for use only in implementing\n   constraint propagators, and should not be called from ordinary user code\n   (use ic:(Var >= Bound) instead).  It differs from the usual constraint\n   predicates in several ways.  First, Bound is assumed to be exact (i.e.\n   if it's a float, it's not widened).  Second, if Bound is a bounded real,\n   only its lower bound is significant, and it is this which is imposed on\n   Var.</P><P>\n\n   The final and most important difference relates to the execution of\n   delayed goals.  If the call to impose_min/2 results in a bound change,\n   any delayed goals suspended on that bound will be scheduled for\n   execution, as normal.  However, impose_min/2 does not call the woken goal\n   scheduler (wake/0), so these goals may not be executed immediately.  (It\n   is possible that under some circumstances the goals will be executed, if\n   wake/0 is called indirectly - one example would be by the unify handler\n   if the variable becomes ground - but this should not be relied upon.) To\n   ensure that the goals are eventually executed, the caller should arrange\n   for wake/0 to be called at some appropriate point in the subsequent\n   execution.  Please see the \"Advanced Control Features\" section of the\n   User Manual for more information about woken goal management.</P>\n"), eg : "[eclipse 2]: X $:: 0..10, impose_min(X, 4.5).\nX = X{4.5 .. 10.0}\nYes (0.00s cpu)\n\n[eclipse 3]: X $:: 0..10, impose_min(X, 4.5), integers([X]).\nX = X{5 .. 10}\nYes (0.00s cpu)\n\n[eclipse 4]: X $:: 0..10, impose_min(X, 4.5), integers([X]), impose_max(X, 5.9).\nX = 5\nYes (0.00s cpu)\n\n[eclipse 5]: X $:: 0..10, impose_min(X, 4.5), impose_max(X, 4.3).\nNo (0.00s cpu)\n"]).
:- comment(msg / 3, [amode : msg(-, -, ?), amode : msg(++, ++, ?), args : ["Var1" : "A variable or number", "Var2" : "A variable or number", "MSG" : "Most specific generalisation (variable)"], summary : "Computes the most specific generalisation of Var1 and Var2 that is expressible with ic variables.", desc : html("<P>\n   The most specific generalisation of two intervals is computed and\n   returned as MSG.  MSG will interval over the smallest interval enclosing\n   the input intervals, and have the more general type of the input types.\n   If either Var1 or Var2 are domain-less, or have values that cannot be\n   expressed as ic-domains, MSG remains unbound.\n</P>")]).
:- comment(set_var_type / 2, [amode : set_var_type(?, ++), args : ["Var" : "Variable to set type of", "Type" : "Type to be set 'real' or 'integer'"], summary : "Sets the type of the given variable to the given type.", see_also : [set_vars_type / 2, reals / 1, integers / 1], desc : html("<P>\n   Typically not called directly but indirectly through <TT>reals/1</TT> and\n   <TT>integers/1</TT>.</P>\n")]).
:- comment(set_vars_type / 2, [amode : set_vars_type(?, ++), args : ["Vars" : "Var/list/matrix", "Type" : "Type to be set 'real' or 'integer'"], summary : "Sets the type of the given variables to the given type.", see_also : [set_var_type / 2, reals / 1, integers / 1], desc : html("<P>\n   Typically not called directly but indirectly through <TT>reals/1</TT> and\n   <TT>integers/1</TT>.</P>\n"), exceptions : [4 : "Type is un-instantiated."]]).
