1% ---------------------------------------------------------------------- 2% BEGIN LICENSE BLOCK 3% Version: CMPL 1.1 4% 5% The contents of this file are subject to the Cisco-style Mozilla Public 6% License Version 1.1 (the "License"); you may not use this file except 7% in compliance with the License. You may obtain a copy of the License 8% at www.eclipse-clp.org/license. 9% 10% Software distributed under the License is distributed on an "AS IS" 11% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See 12% the License for the specific language governing rights and limitations 13% under the License. 14% 15% The Original Code is The ECLiPSe Constraint Logic Programming System. 16% The Initial Developer of the Original Code is Cisco Systems, Inc. 17% Portions created by the Initial Developer are 18% Copyright (C) 1992-2006 Cisco Systems, Inc. All Rights Reserved. 19% 20% Contributor(s): ECRC GmbH 21% Contributor(s): IC-Parc, Imperal College London 22% 23% END LICENSE BLOCK 24% 25% System: ECLiPSe Constraint Logic Programming System 26% Version: $Id: suspend.pl,v 1.4 2010/04/04 08:13:37 jschimpf Exp $ 27% ---------------------------------------------------------------------- 28 29% 30% SEPIA PROLOG MODULE 31% 32% IDENTIFICATION: suspend.pl 33% 34% AUTHOR: Micha Meier 35% Joachim Schimpf 36% 37% CONTENTS: Coroutining with three suspension lists: 38% 39% - one for goals to be woken on instantiation only 40% - one for binding with any metaterm 41% - one for general "constrained-ness" 42% 43% The code for metaterm handlers should be used 44% as template for writing user-defined extensions; 45% simply replace 'suspend' in the predicate names by 46% the name of the attribute and re-use the code. 47% 48 49:- module(suspend, [], sepia_kernel). 50 51% This structure is already defined and exported in the kernel 52%:- export struct(suspend(inst, constrained, bound)). 53 54:- comment(categories, ["Constraints","Algorithms"]). 55:- comment(summary, 56 "Lazy-checking versions of arithmetic primitives, and the suspend-attribute"). 57:- comment(date, "$Date: 2010/04/04 08:13:37 $"). 58:- comment(copyright, "Cisco Systems, Inc"). 59:- comment(author, "Micha Meier, ECRC, Joachim Schimpf, ECRC and IC-Parc"). 60:- comment(desc, html("\ 61 This library provides the following: 62<UL> 63 <LI>the <B>suspend</B> pseudo-solver for general arithmetic 64 <LI>the <B>suspend</B> attribute 65</UL> 66 The suspend pseudo-solver for arithmetic comparisons simply consists 67 of suspending (lazy-checking) versions of all arithmetic comparisons 68 (>/2, #>/2, etc). These all suspend until all their variables 69 have been instantiated, then they wake up and test the condition, 70 succeeding or failing as appropriate. Together with a search routine, 71 this provides the means to implement simple test-and-generate algorithms. 72<P> 73 The suspend-attribute is a basis for the implementation of similar 74 user-defined data-driven computations that react to variable instantiation, 75 variable binding, or general variable-constraining events. The suspend- 76 attribute defines the following three suspension lists (and thus waking 77 conditions) for a variable: 78<DL> 79 <DT><STRONG>inst</STRONG><DD> 80 woken when variable is instantiated. 81 <DT><STRONG>bound</STRONG><DD> 82 woken when variable is bound, even to an other variable. 83 <DT><STRONG>constrained</STRONG><DD> 84 woken when variable is (further) constrained. This is 85 triggered by the notify_constrained built-in. 86</DL> 87 These three lists can be used as waking conditions in the suspend/3,4 88 built-in. Variables using the suspend-attribute do not have to be 89 declared specially, the attribute is implicitly created when needed. 90 ")). 91 92:- import 93 (:@)/3, 94 eval/3, 95 get_flag_body/4, 96 insert_suspension/4, 97 setarg/3, 98 suspensions_to_goals/3 99 from sepia_kernel. 100 101%---------------------------------------------------------------- 102% attribute declaration 103%---------------------------------------------------------------- 104 105% CAUTION: when changing handlers, update meta.pl accordingly!!! 106:- meta_attribute(suspend, [ 107 unify: unify_suspend/2, 108 suspensions: suspensions_suspend/3, 109 delayed_goals_number: delayed_goals_number_suspend/2 110 ]). 111 112%---------------------------------------------------------------- 113% unify handler 114%---------------------------------------------------------------- 115 116:- pragma(system). 117:- pragma(nodebug). 118 119% unify_suspend(+Term, Attribute) 120unify_suspend(_, Attr) :- 121 /*** ANY + VAR ***/ 122 var(Attr). % Ignore if no attribute for this extension 123unify_suspend(Term, Attr) :- 124 compound(Attr), 125 unify_term_suspend(Term, Attr). 126 127 128% We wake every time a variable is touched. 129:- mode unify_term_suspend(?, +). 130unify_term_suspend(Term, AttrX) :- 131 atomic(Term), % The metaterm was instantiated, wake all 132 /*** NONVAR + META ***/ 133 AttrX = suspend{bound:B, inst:I, constrained:C}, 134 % schedule_woken/1 is faster than schedule_suspensions/2 but can 135 % be used only if the lists are no longer needed after waking 136 schedule_woken(C), 137 schedule_woken(B), 138 schedule_woken(I). 139unify_term_suspend(Term, AttrX) :- 140 compound(Term), % The metaterm was instantiated, wake all 141 /*** NONVAR + META ***/ 142 schedule_suspensions(constrained of suspend, AttrX), 143 AttrX = suspend{bound:B, inst:I, constrained:Cnew}, 144 schedule_woken(B), 145 schedule_woken(I), 146 % the constrained list may still contain demons after scheduling, 147 % forward them to the variables in the bound term 148 ( Cnew = [] -> 149 true 150 ; 151 term_variables(Term, Vars), 152 ( Vars = [] -> true ; forward_constrained_list(Cnew, Vars) ) 153 ). 154unify_term_suspend(Y{AttrY}, AttrX) :- 155 -?-> 156 unify_suspend_suspend(Y, AttrX, AttrY). 157 158unify_suspend_suspend(_, AttrX, AttrY) :- 159 var(AttrY), % No attribute for this extension 160 /*** VAR + META ***/ 161 AttrX = AttrY. % Keep both lists, do not wake 162unify_suspend_suspend(_, AttrX, AttrY) :- 163 nonvar(AttrY), 164 /*** META + META ***/ 165 AttrX = suspend{inst:XI-YI, bound:BX, constrained:CX}, 166 AttrY = suspend{inst:YI-YI0, bound:BY, constrained:CY}, 167 setarg(inst of suspend, AttrY, XI-YI0), 168 169 % merge the bound-lists and wake those suspensions that were in both lists 170 merge_intersect(BX, BY, BXY, BoundSuspsToWake), 171 schedule_woken(BoundSuspsToWake), 172 setarg(bound of suspend, AttrY, BXY), 173 174 % treat the constrained-lists exactly like the bounds-lists 175 merge_intersect(CX, CY, CXY, ConstrSuspsToWake), 176 schedule_woken(ConstrSuspsToWake), 177 setarg(constrained of suspend, AttrY, CXY). 178 179 180forward_constrained_list([], _Vars). 181forward_constrained_list([Susp|Susps], Vars) :- 182 ( is_suspension(Susp) -> 183 insert_suspension(Vars, Susp, constrained of suspend) 184 ; 185 true % dead suspension 186 ), 187 forward_constrained_list(Susps, Vars). 188 189 190:- mode merge_intersect(+,+,-,-). 191merge_intersect([], L2, L2, []) :- !. 192merge_intersect(L1, [], L1, []) :- !. 193merge_intersect(L1, L2, Merged, Common) :- 194 % sort and remove duplicates (descending, because the lists are 195 % likely to be already in descending order, due to new suspensions 196 % always being inserted in front) 197 sort(0, >, L1, S1), 198 sort(0, >, L2, S2), 199 % merge and extract common elements 200 merge(0, >=, S1, S2, S12), 201 S12 = [S|Ss], 202 split_unique_common(S, Ss, Merged, Common). 203 204 split_unique_common(S1, [], [S1], []). 205 split_unique_common(S1, [S2|Ss], Merged, Common) :- 206 ( S1 == S2 -> 207 Common = [S1|Common0], 208 split_unique_common(S2, Ss, Merged, Common0) 209 ; 210 Merged = [S1|Merged0], 211 split_unique_common(S2, Ss, Merged0, Common) 212 ). 213 214 215%---------------------------------------------------------------- 216% suspensions handler 217%---------------------------------------------------------------- 218 219suspensions_suspend(_{Attr}, Goals, G0) :- 220 -?-> 221 susp_suspend(Attr, Goals, G0). 222 223susp_suspend(AttrX, Susps, Susps) :- var(AttrX), !. 224susp_suspend(suspend{inst:I-_, bound:B, constrained:C}, [I,B,C|Ss], Ss). 225 226 227%---------------------------------------------------------------- 228% delayed goals number handler 229%---------------------------------------------------------------- 230 231delayed_goals_number_suspend(_{AttrX}, N) :- 232 -?-> 233 dgn_suspend(AttrX, N). 234 235dgn_suspend(AttrX, 0) :- 236 /*** VAR ***/ 237 var(AttrX), 238 !. 239dgn_suspend(suspend{inst:I-_, bound:B, constrained:C}, N) :- 240 /*** META ***/ 241 count_active_suspensions(I, 0, N0), 242 count_active_suspensions(B, N0, N1), 243 count_active_suspensions(C, N1, N). 244 245count_active_suspensions(Susps, N0, N) :- 246 var(Susps), 247 !, 248 N = N0. 249count_active_suspensions([], N, N). 250count_active_suspensions([Susp|Susps], N0, N) :- 251 ( is_suspension(Susp) -> 252 N1 is N0 + 1 253 ; 254 N1 = N0 255 ), 256 count_active_suspensions(Susps, N1, N). 257 258 259:- untraceable 260 unify_suspend/2, 261 suspensions_suspend/3, 262 delayed_goals_number_suspend/2. 263 264 265%---------------------------------------------------------------- 266% Sepia's delay clauses (backward compatibility) 267% Source transformation for if/2 268%---------------------------------------------------------------- 269 270:- export tr_if_suspend/3. 271:- export macro((if)/2, tr_if_suspend/3, [clause]). 272 273:- mode tr_if_suspend(+, -, +). 274tr_if_suspend(Clause, (Head :- -?-> NewBody, Susp), _M) :- 275 Clause = no_macro_expansion(delay Head if Body), 276 translate_goal(Body, NewBody, VarList, [], BVarList, []), 277 check_varlists(VarList, BVarList, Clause), 278 strip_varlist(VarList, VarList1), 279 strip_varlist(BVarList, BVarList1), 280 handle_suspension(Head, VarList1, BVarList1, Susp). 281 282:- mode translate_goal(?, -, ?, -, ?, -). 283translate_goal(Goal, Goal, Vars, Vars, BV, BV) :- var(Goal), !. 284translate_goal((Goal, Goals), (NewGoal, NewGoals), Out, In, BOut, BIn) :- !, 285 translate_goal(Goal, NewGoal, Mid, In, BMid, BIn), 286 translate_goal(Goals, NewGoals, Out, Mid, BOut, BMid). 287translate_goal((Goal -> Goals), (NewGoal -> NewGoals), Out, In, BOut, BIn) :- !, 288 translate_goal(Goal, NewGoal, Mid, In, BMid, BIn), 289 translate_goal(Goals, NewGoals, Out, Mid, BOut, BMid). 290translate_goal((Goal ; Goals), (NewGoal, Out=VarsL, BOut = BVarsL ; 291 NewGoals, Out=VarsR, BOut = BVarsR), 292 [Out], In, [BOut], BIn) :- !, 293 translate_goal(Goal, NewGoal, VarsL0, In, BVarsL0, BIn), 294 check_varlists(VarsL0, BVarsL0, Goal), 295 strip_varlist(VarsL0, VarsL), 296 strip_varlist(BVarsL0, BVarsL), 297 translate_goal(Goals, NewGoals, VarsR0, In, BVarsR0, BIn), 298 check_varlists(VarsR0, BVarsR0, Goal), 299 strip_varlist(VarsR0, VarsR), 300 strip_varlist(BVarsR0, BVarsR). 301translate_goal(var(X), var(X), [X|Out], Out, V,V) :- 302 !. 303translate_goal(X \== Y, 304 (sepia_kernel: \==(X, Y, Vars), 305 ( Vars = [Var] -> Out = [Var|In], BOut = BIn 306 ; BOut = [Vars|BIn], Out = In 307 ) 308 ), 309 [Out], In, [BOut], BIn) :- !. 310translate_goal(nonground(X), nonground(X, Var), [Var|Out], Out, V,V) :- 311 !. 312translate_goal(nonground(N, X), nonground(N, X, Vars), [Vars|Out], Out, V,V) :- 313 !. 314translate_goal(Goal, Goal, Vars, Vars, BVars, BVars). 315 316handle_suspension(Head, List, BL, (!, make_suspension(Head, 0, S), Body)) :- 317 handle_i_susp(S, List, BL, Body). 318 319handle_i_susp(Susp, [], BList, Body) :- 320 -?-> 321 !, 322 bound_suspension(Susp, BList, Body). 323handle_i_susp(Susp, List, [], Body) :- 324 -?-> 325 !, 326 inst_suspension(Susp, List, Body). 327handle_i_susp(Susp, List, BList, (BI, BB)) :- 328 inst_suspension(Susp, List, BI), 329 bound_suspension(Susp, BList, BB). 330 331inst_suspension(S, List, 332 insert_suspension(List, S, inst of suspend, suspend)). 333 334bound_suspension(S, List, 335 insert_suspension(List, S, bound of suspend, suspend)). 336 337 338:- mode check_varlists(+,+,?). 339check_varlists([], [], Culprit) :- !, 340 error(272, Culprit). 341check_varlists(_, _, _). 342 343:- mode strip_varlist(+,-). 344strip_varlist([], []) :- !. 345strip_varlist([X], X) :- !. % avoid list if single element 346strip_varlist(L, L). 347 348 349%---------------------------------------------------------------------- 350% Delaying arithmetic 351%---------------------------------------------------------------------- 352 353:- export 354 op(750, fx, [neg]), 355 op(760, yfx, [and]), 356 op(770, yfx, [or]), 357 op(780, yfx, [=>]), 358 op(700, xfx, [#::,$::,$=,$\=,$>=,$=<,$>,$<]). 359 360:- export 361 :: /2, 362 $:: /2, 363 #:: /2, 364 integers/1, 365 reals/1, 366 =:= /2, 367 =\= /2, 368 >= /2, 369 =< /2, 370 > /2, 371 < /2, 372 $= /2, 373 $\= /2, 374 $>= /2, 375 $=< /2, 376 $> /2, 377 $< /2, 378 #= /2, 379 #\= /2, 380 #>= /2, 381 #=< /2, 382 #> /2, 383 #< /2, 384 and/2, 385 or/2, 386 => /2, 387 (neg)/1. 388 389 390 % integers(X) - X is an integer or a list of integers 391integers(Tail) :- var(Tail), !, 392 suspend(integers(Tail), 2, Tail->inst). 393integers([]) :- !. 394integers([X|Xs]) :- !, 395 one_integer(X), 396 integers(Xs). 397integers(X) :- integer(X). 398 399 one_integer(X) :- var(X), 400 suspend(integer(X), 2, X->inst). 401 one_integer(X) :- integer(X). 402 403 404 % reals(X) - X is a number or a list of numbers 405reals(Tail) :- var(Tail), !, 406 suspend(reals(Tail), 2, Tail->inst). 407reals([]) :- !. 408reals([X|Xs]) :- !, 409 one_number(X), 410 reals(Xs). 411reals(X) :- number(X). 412 413 one_number(X) :- var(X), 414 suspend(number(X), 2, X->inst). 415 one_number(X) :- number(X). 416 417 418:- tool((::)/2, '::_body'/3). 419:- tool(($::)/2, '$::_body'/3). 420:- tool((#::)/2, '#::_body'/3). 421:- tool((#=)/2, '#=_body'/3). 422:- tool((#\=)/2, '#\\=_body'/3). 423:- tool((#=<)/2, '#=<_body'/3). 424:- tool((#>=)/2, '#>=_body'/3). 425:- tool((#<)/2, '#<_body'/3). 426:- tool((#>)/2, '#>_body'/3). 427:- tool(($=)/2, '$=_body'/3). 428:- tool(($\=)/2, '$\\=_body'/3). 429:- tool(($=<)/2, '$=<_body'/3). 430:- tool(($>=)/2, '$>=_body'/3). 431:- tool(($<)/2, '$<_body'/3). 432:- tool(($>)/2, '$>_body'/3). 433:- tool((=:=)/2, '=:=_body'/3). 434:- tool((=\=)/2, '=\\=_body'/3). 435:- tool((=<)/2, '=<_body'/3). 436:- tool((>=)/2, '>=_body'/3). 437:- tool((<)/2, '<_body'/3). 438:- tool((>)/2, '>_body'/3). 439:- tool((and)/2, 'and_body'/3). 440:- tool((or)/2, 'or_body'/3). 441:- tool((=>)/2, '=>_body'/3). 442:- tool((neg)/1, 'neg_body'/2). 443 444'::_body'(X, Range, M) :- delay_until_ground(X :: Range, M). 445'$::_body'(X, Range, M) :- delay_until_ground(X $:: Range, M). 446'#::_body'(X, Range, M) :- delay_until_ground(X #:: Range, M). 447'#=_body'(X, Y, M) :- delay_until_ground(X #= Y, M). 448'#\\=_body'(X, Y, M) :- delay_until_ground(X #\= Y, M). 449'#=<_body'(X, Y, M) :- delay_until_ground(X #=< Y, M). 450'#>=_body'(X, Y, M) :- delay_until_ground(X #>= Y, M). 451'#<_body'(X, Y, M) :- delay_until_ground(X #< Y, M). 452'#>_body'(X, Y, M) :- delay_until_ground(X #> Y, M). 453'$=_body'(X, Y, M) :- delay_until_ground(X =:= Y, M). 454'$\\=_body'(X, Y, M) :- delay_until_ground(X =\= Y, M). 455'$=<_body'(X, Y, M) :- delay_until_ground(X =< Y, M). 456'$>=_body'(X, Y, M) :- delay_until_ground(X >= Y, M). 457'$<_body'(X, Y, M) :- delay_until_ground(X < Y, M). 458'$>_body'(X, Y, M) :- delay_until_ground(X > Y, M). 459'=:=_body'(X, Y, M) :- delay_until_ground(X =:= Y, M). 460'=\\=_body'(X, Y, M) :- delay_until_ground(X =\= Y, M). 461'=<_body'(X, Y, M) :- delay_until_ground(X =< Y, M). 462'>=_body'(X, Y, M) :- delay_until_ground(X >= Y, M). 463'<_body'(X, Y, M) :- delay_until_ground(X < Y, M). 464'>_body'(X, Y, M) :- delay_until_ground(X > Y, M). 465'and_body'(X, Y, M) :- delay_until_ground(X and Y, M). 466'or_body'(X, Y, M) :- delay_until_ground(X or Y, M). 467'=>_body'(X, Y, M) :- delay_until_ground(X => Y, M). 468'neg_body'(X, M) :- delay_until_ground(neg X, M). 469 470 471 delay_until_ground(Goal, M) :- 472 ( nonground(Goal, Var) -> 473 suspend(delay_until_ground(Goal, Susp, M), 2, Var->inst, Susp) 474 ; 475 ground_check(Goal, M) 476 ). 477 478 :- demon delay_until_ground/3. 479 delay_until_ground(Goal, Susp, M) :- 480 ( nonground(Goal, Var) -> 481 insert_suspension(Var, Susp, inst of suspend) 482 ; 483 kill_suspension(Susp), 484 ground_check(Goal, M) 485 ). 486 487 488% Note on the #-constraints: Implementation via 489% X #? ... :- XI is X, integer(XI), ... 490% is not quite right, but almost. # is supposed to impose integrality on 491% all vars in X (except those within user-defined functions?), but we only 492% check whether the result is integral. This only breaks down for fix/1, 493% sgn/1, numerator/1 and denominator/1 (which seems acceptable), because 494% all other functions propagate non-integrality through. 495 496ground_check(Xs :: Range, M) :- 497 eval_range(Xs, Range, From, To, Type, M), 498 check_range(Xs, From, To, Type). 499ground_check(Xs $:: Range, M) :- 500 eval_range(Xs, Range, From, To, _Type, M), 501 check_range(Xs, From, To, number). 502ground_check(Xs #:: Range, M) :- 503 eval_range(Xs, Range, From, To, Type, M), 504 ( Type == integer -> 505 check_range(Xs, From, To, Type) 506 ; 507 error(5, Xs :: Range, M) 508 ). 509ground_check(integers(Xs), _M) :- check_integers(Xs). 510ground_check(reals(Xs), _M) :- check_numbers(Xs). 511ground_check(X =:= Y, M) :- :@(sepia_kernel, (X =:= Y), M). 512ground_check(X =\= Y, M) :- :@(sepia_kernel, (X =\= Y), M). 513ground_check(X >= Y, M) :- :@(sepia_kernel, (X >= Y), M). 514ground_check(X =< Y, M) :- :@(sepia_kernel, (X =< Y), M). 515ground_check(X > Y, M) :- :@(sepia_kernel, (X > Y), M). 516ground_check(X < Y, M) :- :@(sepia_kernel, (X < Y), M). 517ground_check(X $= Y, M) :- :@(sepia_kernel, (X =:= Y), M). 518ground_check(X $\= Y, M) :- :@(sepia_kernel, (X =\= Y), M). 519ground_check(X $>= Y, M) :- :@(sepia_kernel, (X >= Y), M). 520ground_check(X $=< Y, M) :- :@(sepia_kernel, (X =< Y), M). 521ground_check(X $> Y, M) :- :@(sepia_kernel, (X > Y), M). 522ground_check(X $< Y, M) :- :@(sepia_kernel, (X < Y), M). 523ground_check(X #= Y, M) :- eval(X,XI,M), integer(XI), eval(Y,YI,M), integer(YI), :@(sepia_kernel, (XI =:= YI), M). 524ground_check(X #\= Y, M) :- eval(X,XI,M), integer(XI), eval(Y,YI,M), integer(YI), :@(sepia_kernel, (XI =\= YI), M). 525ground_check(X #>= Y, M) :- eval(X,XI,M), integer(XI), eval(Y,YI,M), integer(YI), :@(sepia_kernel, (XI >= YI), M). 526ground_check(X #=< Y, M) :- eval(X,XI,M), integer(XI), eval(Y,YI,M), integer(YI), :@(sepia_kernel, (XI =< YI), M). 527ground_check(X #> Y, M) :- eval(X,XI,M), integer(XI), eval(Y,YI,M), integer(YI), :@(sepia_kernel, (XI > YI), M). 528ground_check(X #< Y, M) :- eval(X,XI,M), integer(XI), eval(Y,YI,M), integer(YI), :@(sepia_kernel, (XI < YI), M). 529ground_check(X and Y, M) :- eval(X,XI,M), bool(XI), eval(Y,YI,M), bool(YI), sepia_kernel:(XI+YI > 1). 530ground_check(X or Y, M) :- eval(X,XI,M), bool(XI), eval(Y,YI,M), bool(YI), sepia_kernel:(XI+YI > 0). 531ground_check(X => Y, M) :- eval(X,XI,M), bool(XI), eval(Y,YI,M), bool(YI), sepia_kernel:(YI-XI >= 0). 532ground_check(neg X, M) :- eval(X,0,M). 533 534 535:- mode eval_range(?,++,-,-,-,+). 536eval_range(_X, From0..To0, From, To, Type, M) :- !, 537 eval(From0, From, M), 538 eval(To0, To, M), 539 ( integer(From), integer(To) -> 540 Type = integer 541 ; 542 Type = number 543 ). 544eval_range(X, Range, _From, _To, _Type, M) :- 545 error(5, X::Range, M). 546 547 548:- mode check_range(++,+,+,+). 549check_range(X, From, To, Type) :- number(X), !, 550 check_range_number(X, From, To, Type). 551check_range([], _From, _To, _Type) :- !. 552check_range(List, From, To, Type) :- List = [_|_], !, 553 check_range_list(List, From, To, Type). 554check_range(subscript(Array,Index), From, To, Type) :- !, 555 subscript(Array, Index, Elems), 556 check_range(Elems, From, To, Type). 557check_range(X, From, To, _Type) :- !, 558 error(5, X::From..To). 559 560 check_range_list([], _From, _To, _Type) :- !. 561 check_range_list([X|Xs], From, To, Type) :- !, 562 check_range_number(X, From, To, Type), 563 check_range_list(Xs, From, To, Type). 564 check_range_list(X, From, To, _Type) :- 565 error(5, X::From..To). 566 567 check_range_number(X, From, To, integer) :- 568 sepia_kernel:(From =< X), 569 sepia_kernel:(X =< To), 570 integer(X). 571 check_range_number(X, From, To, number) :- 572 sepia_kernel:(From =< X), 573 sepia_kernel:(X =< To). 574 575 576:- mode check_integers(++). 577check_integers([]) :- !. 578check_integers([X|Xs]) :- !, 579 integer(X), 580 check_integers(Xs). 581check_integers(X) :- 582 error(5, integers(X)). 583 584:- mode check_numbers(++). 585check_numbers([]) :- !. 586check_numbers([X|Xs]) :- !, 587 number(X), 588 check_numbers(Xs). 589check_numbers(X) :- 590 error(5, reals(X)). 591 592bool(0). 593bool(1). 594 595 596%- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 597% Reified versions 598% 599% Problem: what does #=(X,Y,B) mean? 600% 601% - The proper reification of #=(X,Y) would be 602% 603% #=(X,Y,B) :- integers(X,BX), integers(Y,BY), $=(X,Y,BZ), $=(BX+BY+BZ,3,B). 604% 605% but this is not really what a user expects. 606% 607% - instead it means 608% 609% #=(X,Y,B) :- integers(X), integers(Y), $=(X,Y,B). 610%- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 611 612:- export 613 :: /3, 614 $:: /3, 615 #:: /3, 616 =:= /3, 617 =\= /3, 618 > /3, 619 < /3, 620 >= /3, 621 =< /3, 622 $= /3, 623 $\= /3, 624 $> /3, 625 $< /3, 626 $>= /3, 627 $=< /3, 628 #= /3, 629 #\= /3, 630 #>= /3, 631 #=< /3, 632 #< /3, 633 #> /3, 634 and/3, 635 or/3, 636 => /3, 637 (neg)/2. 638 639:- tool((::)/3, '::_body'/4). 640:- tool(($::)/3, '$::_body'/4). 641:- tool((#::)/3, '#::_body'/4). 642:- tool((#=)/3, '#=_body'/4). 643:- tool((#\=)/3, '#\\=_body'/4). 644:- tool((#=<)/3, '#=<_body'/4). 645:- tool((#>=)/3, '#>=_body'/4). 646:- tool((#<)/3, '#<_body'/4). 647:- tool((#>)/3, '#>_body'/4). 648:- tool(($=)/3, '$=_body'/4). 649:- tool(($\=)/3, '$\\=_body'/4). 650:- tool(($=<)/3, '$=<_body'/4). 651:- tool(($>=)/3, '$>=_body'/4). 652:- tool(($<)/3, '$<_body'/4). 653:- tool(($>)/3, '$>_body'/4). 654:- tool((=:=)/3, '=:=_body'/4). 655:- tool((=\=)/3, '=\\=_body'/4). 656:- tool((=<)/3, '=<_body'/4). 657:- tool((>=)/3, '>=_body'/4). 658:- tool((<)/3, '<_body'/4). 659:- tool((>)/3, '>_body'/4). 660:- tool((and)/3, 'and_body'/4). 661:- tool((or)/3, 'or_body'/4). 662:- tool((=>)/3, '=>_body'/4). 663:- tool((neg)/2, 'neg_body'/3). 664 665 666'::_body'(X, Range, B, M) :- one_number(X), reified(X :: Range, B, M). 667'$::_body'(X, Range, B, M) :- one_number(X), reified(X $:: Range, B, M). 668'#::_body'(X, Range, B, M) :- one_number(X), reified(X #:: Range, B, M). 669'#=_body'(X, Y, B, M) :- reified(X #= Y, B, M). 670'#\\=_body'(X, Y, B, M) :- reified(X #\= Y, B, M). 671'#=<_body'(X, Y, B, M) :- reified(X #=< Y, B, M). 672'#>=_body'(X, Y, B, M) :- reified(X #>= Y, B, M). 673'#<_body'(X, Y, B, M) :- reified(X #< Y, B, M). 674'#>_body'(X, Y, B, M) :- reified(X #> Y, B, M). 675'$=_body'(X, Y, B, M) :- reified(X $= Y, B, M). 676'$\\=_body'(X, Y, B, M) :- reified(X $\= Y, B, M). 677'$=<_body'(X, Y, B, M) :- reified(X $=< Y, B, M). 678'$>=_body'(X, Y, B, M) :- reified(X $>= Y, B, M). 679'$<_body'(X, Y, B, M) :- reified(X $< Y, B, M). 680'$>_body'(X, Y, B, M) :- reified(X $> Y, B, M). 681'=:=_body'(X, Y, B, M) :- reified(X =:= Y, B, M). 682'=\\=_body'(X, Y, B, M) :- reified(X =\= Y, B, M). 683'=<_body'(X, Y, B, M) :- reified(X =< Y, B, M). 684'>=_body'(X, Y, B, M) :- reified(X >= Y, B, M). 685'<_body'(X, Y, B, M) :- reified(X < Y, B, M). 686'>_body'(X, Y, B, M) :- reified(X > Y, B, M). 687'and_body'(X, Y, B, M) :- reified(X and Y, B, M). 688'or_body'(X, Y, B, M) :- reified(X or Y, B, M). 689'=>_body'(X, Y, B, M) :- reified(X => Y, B, M). 690'neg_body'(X, B, M) :- reified(neg X, B, M). 691 692 693reified(Goal, Bool, M) :- 694 ( nonground(Goal, Var) -> 695 suspend(delay_reified(Goal, Bool, Susp, M), 2, Var->inst, Susp) 696 ; 697 ( ground_check(Goal, M) -> Bool=1 ; Bool=0 ) % Goal is ground 698 ). 699 700 :- demon delay_reified/4. 701 delay_reified(Goal, Bool, Susp, M) :- 702 ( nonground(Goal, Var) -> 703 insert_suspension(Var, Susp, inst of suspend) 704 ; 705 kill_suspension(Susp), 706 ( ground_check(Goal, M) -> Bool=1 ; Bool=0 ) % Goal is ground 707 ). 708 709 710%- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 711% Pretty printing 712%- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 713 714:- export 715 portray_delayed_goals/2, 716 portray(delay_until_ground/3, portray_delayed_goals/2, [goal]). 717 718portray_delayed_goals(delay_until_ground(Goal, _Susp, _M), Pretty) :- -?-> !, 719 Pretty = suspend:Goal. 720 721 722:- export 723 portray_delay_reified/2, 724 portray(delay_reified/4, portray_delay_reified/2, [goal]). 725 726portray_delay_reified(delay_reified(Goal, Bool, _Susp, _M), Pretty) :- -?-> !, 727 Goal =.. [Op|Args], 728 append(Args, [Bool], NewArgs), 729 ReifGoal =.. [Op|NewArgs], 730 Pretty = suspend:ReifGoal. 731 732 733%-------------------------------------------------------------------- 734% Comments doc 735%-------------------------------------------------------------------- 736 737:- comment((::)/2, [ 738 summary: "Range constraint with optional integrality constraint", 739 template: "?Vars :: ?Range", 740 args: ["Vars": "Variable or number, or a list of variables or numbers", 741 "Range": "Variable or Lo..Hi, where Lo and Hi are variables or numeric expressions" 742 ], 743 see_also:[($::)/2, (#::)/2, (::)/3, integers/1, reals/1], 744 fail_if: "Vars contains numbers that do not fall within Range, or violate the optional integrality constraint.", 745 eg:" 746 % with integrality constraint 747 ?- X :: 1 .. 5, X = 3. 748 X = 3 749 Yes (0.00s cpu) 750 751 ?- X :: 1 .. 5, X = 6. 752 No (0.00s cpu) 753 754 ?- X :: 1 .. 5, X = 3.0. 755 No (0.00s cpu) 756 757 % without integrality constraint 758 ?- X :: 1.0 .. 5.0, X = 3. 759 X = 3 760 Yes (0.00s cpu) 761 762 ?- X :: 1.0 .. 5.0, X = 3.0. 763 X = 3.0 764 Yes (0.00s cpu) 765 ", 766 desc: html("\ 767 This constraint suspends until its arguments are ground. It then succeeds 768 iff all the elements of the list Vars are numbers within the range 769 specified by Range. 770<P> 771 The range must eventually be in the form Lo..Hi, where Lo and Hi are 772 expressions evaluating to numbers. If both are integers, then Vars must 773 also be integers (integer or list of integers).")] 774). 775 776:- comment((#::)/2, [ 777 summary: "Range constraint combined with integrality constraint", 778 template: "?Vars #:: ?Range", 779 see_also:[($::)/2, (::)/2, (#::)/3, integers/1, reals/1], 780 args: ["Vars": "Variable or integer, or a list of variables or integers", 781 "Range": "Variable or Lo..Hi, where Lo and Hi are variables or integer expressions" 782 ], 783 exceptions:[5 : "Range contains non-integers."], 784 fail_if: "Vars contains non-integers or integers that do not fall within Range.", 785 eg:" 786 ?- X #:: 1 .. 5, X = 3. 787 X = 3 788 Yes (0.00s cpu) 789 790 ?- X #:: 1 .. 5, X = 6. 791 No (0.00s cpu) 792 793 ?- X #:: 1 .. 5, X = 3.0. 794 No (0.00s cpu) 795 ", 796 desc: html("\ 797 This constraint suspends until its arguments are ground. It then succeeds 798 iff all the elements of the list Vars are integers within the range 799 specified by Range. 800<P> 801 The range must eventually be in the form Lo..Hi, where Lo and Hi are 802 expressions evaluating to integers.")] 803). 804 805:- comment(($::)/2, [ 806 summary: "Pure range constraint", 807 template: "?Vars #:: ?Range", 808 args: ["Vars": "Variable or number, or a list of variables or numbers", 809 "Range": "Variable or Lo..Hi, where Lo and Hi are variables or numeric expressions" 810 ], 811 see_also:[(::)/2, (#::)/2, ($::)/3, integers/1, reals/1], 812 fail_if: "Vars contains numbers that do not fall within Range.", 813 eg:" 814 ?- X $:: 1 .. 5, X = 3.0. 815 X = 3.0 816 Yes (0.00s cpu) 817 818 ?- X $:: 1 .. 5, X = 3. 819 X = 3 820 Yes (0.00s cpu) 821 822 ?- X $:: 1.0 .. 5.0, X = 3. 823 X = 3 824 Yes (0.00s cpu) 825 826 ?- X $:: 1.0 .. 5.0, X = 3.0. 827 X = 3.0 828 Yes (0.00s cpu) 829 ", 830 desc: html("\ 831 This constraint suspends until its arguments are ground. It then succeeds 832 iff all the elements of the list Vars are numbers within the range 833 specified by Range. 834<P> 835 The range must eventually be in the form Lo..Hi, where Lo and Hi are 836 expressions evaluating to numbers. The type of these numbers is irrelevant.")] 837). 838 839:- comment((::)/3, [ 840 summary: "Reified range constraint with optional integrality constraint", 841 args: ["Var": "Variable or number", 842 "Range": "Variable or Lo..Hi, where Lo and Hi are variables or numeric expressions", 843 "Bool": "Variable, 0 or 1" 844 ], 845 see_also:[(::)/2], 846 eg:" 847 ?- ::(X, 1 .. 5, B), X = 3. 848 B = 1 849 X = 3 850 Yes (0.00s cpu) 851 852 ?- ::(X, 1.0 .. 5.0, B), X = 3.0. 853 B = 1 854 X = 3.0 855 Yes (0.00s cpu) 856 857 % range violated 858 ?- ::(X, 1 .. 5, B), X = 6. 859 B = 0 860 X = 6 861 Yes (0.00s cpu) 862 863 % integrality violated 864 ?- ::(X, 1 .. 5, B), X = 3.0. 865 B = 0 866 X = 3.0 867 Yes (0.00s cpu) 868 ", 869 desc: html("\ 870 Reified version of ::/2, i.e. the truth value of the range constraint is 871 reflected in the value of the 0/1 variable Bool. 872<P> 873 This constraint suspends until its first two arguments are ground. 874 It then unifies Bool according to the truth value of the corresponding 875 ::/2 constraint. 876<P> 877 Note: as opposed to ::/2, the first argument cannot be a list. 878 ")] 879). 880 881:- comment((#::)/3, [ 882 summary: "Reified range constraint combined with integrality constraint", 883 args: ["Vars": "Variable or integer, or a list of variables or integers", 884 "Range": "Variable or Lo..Hi, where Lo and Hi are variables or integer expressions", 885 "Bool": "Variable, 0 or 1" 886 ], 887 see_also:[(#::)/2], 888 exceptions:[5 : "Range contains non-integers."], 889 eg:" 890 ?- #::(X, 1 .. 5, B), X = 3. 891 B = 1 892 X = 3 893 Yes (0.00s cpu) 894 895 % range violated 896 ?- #::(X, 1 .. 5, B), X = 6. 897 B = 0 898 X = 6 899 Yes (0.00s cpu) 900 901 % integrality violated 902 ?- #::(X, 1 .. 5, B), X = 3.0. 903 B = 0 904 X = 3.0 905 Yes (0.00s cpu) 906 ", 907 desc: html("\ 908 Reified version of #::/2, i.e. the truth value of the range constraint is 909 reflected in the value of the 0/1 variable Bool. 910<P> 911 This constraint suspends until its first two arguments are ground. 912 It then unifies Bool according to the truth value of the corresponding 913 #::/2 constraint. 914<P> 915 Note: as opposed to #::/2, the first argument cannot be a list. 916 ")] 917). 918 919:- comment(($::)/3, [ 920 summary: "Reified pure range constraint", 921 args: ["Vars": "Variable or number, or a list of variables or numbers", 922 "Range": "Variable or Lo..Hi, where Lo and Hi are variables or numeric expressions", 923 "Bool": "Variable, 0 or 1" 924 ], 925 see_also:[($::)/2], 926 eg:" 927 ?- $::(X, 1 .. 5, B), X = 3.0. 928 B = 1 929 X = 3.0 930 Yes (0.00s cpu) 931 932 % range violated 933 ?- $::(X, 1 .. 5, B), X = 6. 934 B = 0 935 X = 6 936 Yes (0.00s cpu) 937 ", 938 desc: html("\ 939 Reified version of $::/2, i.e. the truth value of the range constraint is 940 reflected in the value of the 0/1 variable Bool. 941<P> 942 This constraint suspends until its first two arguments are ground. 943 It then unifies Bool according to the truth value of the corresponding 944 $::/2 constraint. 945<P> 946 Note: as opposed to $::/2, the first argument cannot be a list. 947 ")] 948). 949 950:- comment(integers/1, [ 951 summary: "Constrain Vars to be integers", 952 args: ["Vars": "List of variables or integers"], 953 see_also:[(::)/2, (#::)/2, reals/1], 954 fail_if: "Vars contains non-integers.", 955 desc: html("\ 956 This constraint suspends until its argument is ground. It then succeeds 957 iff Vars is an integer or a list of integers.")] 958). 959 960:- comment(reals/1, [ 961 summary: "Constrain Vars to be a number or list of numbers", 962 args: ["Vars": "List of variables or numbers"], 963 see_also:[(::)/2, ($::)/2, integers/1], 964 fail_if: "Vars contains non-numbers.", 965 eg:" 966 ?- reals(L), L = [3.4, 7]. 967 L = [3.4, 7] 968 Yes (0.00s cpu) 969 970 ", 971 desc: html("\ 972 This constraint suspends until its argument is ground. It then succeeds 973 iff Vars is a number or a list of numbers (any type).")] 974). 975 976:- comment((=:=)/2, [ 977 summary: "The value of Expr1 is equal to the value of Expr2.", 978 template: "?Expr1 =:= ?Expr2", 979 see_also:[(=:=)/3, _:(=:=)/2], 980 args:["Expr1" : "An arithmetic expression", "Expr2" : "An arithmetic expression"], 981 fail_if:" fails if the value of Expr1 is not equal to the value of Expr2", 982 exceptions:[24 : "Expr1 or Expr2 is not an arithmetic expression."], 983 984 desc: html("\ 985 Suspends until both Expr1 and Expr2 are ground, and then both arguments 986 are evaluated and compared, succeeding iff they are equal (beware of 987 rounding errors when comparing reals). 988") 989]). 990 991:- comment((=\=)/2, [ 992 summary: "The value of Expr1 is not equal to the value of Expr2.", 993 template: "?Expr1 =\\= ?Expr2", 994 see_also:[(=\=)/3, _:(=\=)/2], 995 args:["Expr1" : "An arithmetic expression", "Expr2" : "An arithmetic expression"], 996 fail_if:" fails if the value of Expr1 is equal to the value of Expr2", 997 exceptions:[24 : "Expr1 or Expr2 is not an arithmetic expression."], 998 999 desc: html("\ 1000 Suspends until both Expr1 and Expr2 are ground, and then both arguments 1001 are evaluated and compared, succeeding iff they are not equal (beware of 1002 rounding errors when comparing reals). 1003") 1004]). 1005 1006:- comment((>=)/2, [ 1007 summary: "The value of Expr1 is greater than or equal to the value of Expr2.", 1008 template: "?Expr1 >= ?Expr2", 1009 see_also:[(>=)/3, _:(>=)/2], 1010 args:["Expr1" : "An arithmetic expression", "Expr2" : "An arithmetic expression"], 1011 fail_if:" fails if the value of Expr1 is smaller than the value of Expr2", 1012 exceptions:[24 : "Expr1 or Expr2 is not an arithmetic expression."], 1013 1014 desc: html("\ 1015 Suspends until both Expr1 and Expr2 are ground, and then both arguments 1016 are evaluated and compared, succeeding iff Expr1 is greater than or equal to 1017 Expr2 (beware of rounding errors when comparing reals). 1018") 1019]). 1020 1021:- comment((=<)/2, [ 1022 summary: "The value of Expr1 is less than or equal to the value of Expr2.", 1023 template: "?Expr1 =< ?Expr2", 1024 see_also:[(=<)/3, _:(=<)/2], 1025 args:["Expr1" : "An arithmetic expression", "Expr2" : "An arithmetic expression"], 1026 fail_if:" fails if the value of Expr1 is greater than the value of Expr2", 1027 exceptions:[24 : "Expr1 or Expr2 is not an arithmetic expression."], 1028 1029 desc: html("\ 1030 Suspends until both Expr1 and Expr2 are ground, and then both arguments 1031 are evaluated and compared, succeeding iff Expr1 is less than or equal to 1032 Expr2 (beware of rounding errors when comparing reals). 1033") 1034]). 1035 1036:- comment((>)/2, [ 1037 summary: "The value of Expr1 is greater than the value of Expr2.", 1038 template: "?Expr1 > ?Expr2", 1039 see_also:[(>)/3, _:(>)/2], 1040 args:["Expr1" : "An arithmetic expression", "Expr2" : "An arithmetic expression"], 1041 fail_if:" fails if the value of Expr1 is not greater than the value of Expr2", 1042 exceptions:[24 : "Expr1 or Expr2 is not an arithmetic expression."], 1043 1044 desc: html("\ 1045 Suspends until both Expr1 and Expr2 are ground, and then both arguments 1046 are evaluated and compared, succeeding iff Expr1 is greater than Expr2 1047 (beware of rounding errors when comparing reals). 1048") 1049]). 1050 1051:- comment((<)/2, [ 1052 summary: "The value of Expr1 is less than the value of Expr2.", 1053 template: "?Expr1 < ?Expr2", 1054 see_also:[(<)/3, _:(<)/2], 1055 args:["Expr1" : "An arithmetic expression", "Expr2" : "An arithmetic expression"], 1056 fail_if:" fails if the value of Expr1 is not less than the value of Expr2", 1057 exceptions:[24 : "Expr1 or Expr2 is not an arithmetic expression."], 1058 1059 desc: html("\ 1060 Suspends until both Expr1 and Expr2 are ground, and then both arguments 1061 are evaluated and compared, succeeding iff Expr1 is less than Expr2 1062 (beware of rounding errors when comparing reals). 1063") 1064]). 1065 1066:- comment(($=)/2, [ 1067 summary: "The value of Expr1 is equal to the value of Expr2.", 1068 template: "?Expr1 $= ?Expr2", 1069 see_also:[($=)/3, suspend:(=:=)/2, _:($=)/2], 1070 args:["Expr1" : "An arithmetic expression", "Expr2" : "An arithmetic expression"], 1071 fail_if:" fails if the value of Expr1 is not equal to the value of Expr2", 1072 exceptions:[24 : "Expr1 or Expr2 is not an arithmetic expression."], 1073 1074 desc: html("\ 1075 Suspends until both Expr1 and Expr2 are ground, and then both arguments 1076 are evaluated and compared, succeeding iff they are equal (beware of 1077 rounding errors when comparing reals). 1078") 1079]). 1080 1081:- comment(($\=)/2, [ 1082 summary: "The value of Expr1 is not equal to the value of Expr2.", 1083 template: "?Expr1 $\\= ?Expr2", 1084 see_also:[($\=)/3, suspend:(=\=)/2, _:($\=)/2], 1085 args:["Expr1" : "An arithmetic expression", "Expr2" : "An arithmetic expression"], 1086 fail_if:" fails if the value of Expr1 is equal to the value of Expr2", 1087 exceptions:[24 : "Expr1 or Expr2 is not an arithmetic expression."], 1088 1089 desc: html("\ 1090 Suspends until both Expr1 and Expr2 are ground, and then both arguments 1091 are evaluated and compared, succeeding iff they are not equal (beware of 1092 rounding errors when comparing reals). 1093") 1094]). 1095 1096:- comment(($>=)/2, [ 1097 summary: "The value of Expr1 is greater than or equal to the value of Expr2.", 1098 template: "?Expr1 $>= ?Expr2", 1099 see_also:[($>=)/3, suspend:(>=)/2, _:($>=)/2], 1100 args:["Expr1" : "An arithmetic expression", "Expr2" : "An arithmetic expression"], 1101 fail_if:" fails if the value of Expr1 is smaller than the value of Expr2", 1102 exceptions:[24 : "Expr1 or Expr2 is not an arithmetic expression."], 1103 1104 desc: html("\ 1105 Suspends until both Expr1 and Expr2 are ground, and then both arguments 1106 are evaluated and compared, succeeding iff Expr1 is than greater or equal 1107 to Expr2 (beware of rounding errors when comparing reals). 1108") 1109]). 1110 1111:- comment(($=<)/2, [ 1112 summary: "The value of Expr1 is less than or equal to the value of Expr2.", 1113 template: "?Expr1 $=< ?Expr2", 1114 see_also:[($=<)/3, suspend:(=<)/2, _:($=<)/2], 1115 args:["Expr1" : "An arithmetic expression", "Expr2" : "An arithmetic expression"], 1116 fail_if:" fails if the value of Expr1 is greater than the value of Expr2", 1117 exceptions:[24 : "Expr1 or Expr2 is not an arithmetic expression."], 1118 1119 desc: html("\ 1120 Suspends until both Expr1 and Expr2 are ground, and then both arguments 1121 are evaluated and compared, succeeding iff Expr1 is less than or equal to 1122 Expr2 (beware of rounding errors when comparing reals). 1123") 1124]). 1125 1126:- comment(($>)/2, [ 1127 summary: "The value of Expr1 is greater than the value of Expr2.", 1128 template: "?Expr1 $> ?Expr2", 1129 see_also:[($>)/3, suspend:(>)/2, _:($>)/2], 1130 args:["Expr1" : "An arithmetic expression", "Expr2" : "An arithmetic expression"], 1131 fail_if:" fails if the value of Expr1 is not greater than the value of Expr2", 1132 exceptions:[24 : "Expr1 or Expr2 is not an arithmetic expression."], 1133 1134 desc: html("\ 1135 Suspends until both Expr1 and Expr2 are ground, and then both arguments 1136 are evaluated and compared, succeeding iff Expr1 is greater than Expr2 1137 (beware of rounding errors when comparing reals). 1138") 1139]). 1140 1141:- comment(($<)/2, [ 1142 summary: "The value of Expr1 is less than the value of Expr2.", 1143 template: "?Expr1 $< ?Expr2", 1144 see_also:[($<)/3, suspend:(<)/2, _:($<)/2], 1145 args:["Expr1" : "An arithmetic expression", "Expr2" : "An arithmetic expression"], 1146 fail_if:" fails if the value of Expr1 is not less than the value of Expr2", 1147 exceptions:[24 : "Expr1 or Expr2 is not an arithmetic expression."], 1148 1149 desc: html("\ 1150 Suspends until both Expr1 and Expr2 are ground, and then both arguments 1151 are evaluated and compared, succeeding iff Expr1 is less than Expr2 1152 (beware of rounding errors when comparing reals). 1153") 1154]). 1155 1156:- comment((#=)/2, [ 1157 summary: "The integer value of Expr1 is equal to the integer value of Expr2.", 1158 template: "?Expr1 #= ?Expr2", 1159 see_also:[(#=)/3, _:(#=)/2], 1160 args:["Expr1" : "An integer arithmetic expression", 1161 "Expr2" : "An integer arithmetic expression"], 1162 fail_if:" fails if the value of Expr1 is not equal to the value of Expr2, or if either do not evaluate to an integer.", 1163 exceptions:[24 : "Expr1 or Expr2 is not an arithmetic expression."], 1164 1165 desc: html("\ 1166 Suspends until both Expr1 and Expr2 are ground, and then both arguments 1167 are evaluated and compared, succeeding iff they are both integers and are 1168 equal. 1169") 1170]). 1171 1172:- comment((#\=)/2, [ 1173 summary: "The integer value of Expr1 is not equal to the integer value of Expr2.", 1174 template: "?Expr1 #\\= ?Expr2", 1175 see_also:[(#\=)/3, _:(#\=)/2], 1176 args:["Expr1" : "An integer arithmetic expression", 1177 "Expr2" : "An integer arithmetic expression"], 1178 fail_if:" fails if the value of Expr1 is equal to the value of Expr2, or if either do not evaluate to an integer.", 1179 exceptions:[24 : "Expr1 or Expr2 is not an arithmetic expression."], 1180 1181 desc: html("\ 1182 Suspends until both Expr1 and Expr2 are ground, and then both arguments 1183 are evaluated and compared, succeeding iff they are both integers and are 1184 not equal. 1185") 1186]). 1187 1188:- comment((#>=)/2, [ 1189 summary: "The integer value of Expr1 is greater than or equal to the integer value of Expr2.", 1190 template: "?Expr1 #>= ?Expr2", 1191 see_also:[(#>=)/3, _:(#>=)/2], 1192 args:["Expr1" : "An integer arithmetic expression", 1193 "Expr2" : "An integer arithmetic expression"], 1194 fail_if:" fails if the value of Expr1 is less than the value of Expr2, or if either do not evaluate to an integer.", 1195 exceptions:[24 : "Expr1 or Expr2 is not an arithmetic expression."], 1196 1197 desc: html("\ 1198 Suspends until both Expr1 and Expr2 are ground, and then both arguments 1199 are evaluated and compared, succeeding iff they are both integers and 1200 Expr1 is greater than or equal to Expr2. 1201") 1202]). 1203 1204:- comment((#=<)/2, [ 1205 summary: "The integer value of Expr1 is less than or equal to the integer value of Expr2.", 1206 template: "?Expr1 #=< ?Expr2", 1207 see_also:[(#=<)/3, _:(#=<)/2], 1208 args:["Expr1" : "An integer arithmetic expression", 1209 "Expr2" : "An integer arithmetic expression"], 1210 fail_if:" fails if the value of Expr1 is greater than the value of Expr2, or if either do not evaluate to an integer.", 1211 exceptions:[24 : "Expr1 or Expr2 is not an arithmetic expression."], 1212 1213 desc: html("\ 1214 Suspends until both Expr1 and Expr2 are ground, and then both arguments 1215 are evaluated and compared, succeeding iff they are both integers and 1216 Expr1 is less than or equal to Expr2. 1217") 1218]). 1219 1220:- comment((#>)/2, [ 1221 summary: "The integer value of Expr1 is greater than the integer value of Expr2.", 1222 template: "?Expr1 #> ?Expr2", 1223 see_also:[(#>)/3, _:(#>)/2], 1224 args:["Expr1" : "An integer arithmetic expression", 1225 "Expr2" : "An integer arithmetic expression"], 1226 fail_if:" fails if the value of Expr1 is not greater than the value of Expr2, or if either do not evaluate to an integer.", 1227 exceptions:[24 : "Expr1 or Expr2 is not an arithmetic expression."], 1228 1229 desc: html("\ 1230 Suspends until both Expr1 and Expr2 are ground, and then both arguments 1231 are evaluated and compared, succeeding iff they are both integers and 1232 Expr1 is greater than Expr2. 1233") 1234]). 1235 1236:- comment((#<)/2, [ 1237 summary: "The integer value of Expr1 is less than the integer value of Expr2.", 1238 template: "?Expr1 #< ?Expr2", 1239 see_also:[(#<)/3, _:(#<)/2], 1240 args:["Expr1" : "An integer arithmetic expression", 1241 "Expr2" : "An integer arithmetic expression"], 1242 fail_if:" fails if the value of Expr1 is not less than the value of Expr2, or if either do not evaluate to an integer.", 1243 exceptions:[24 : "Expr1 or Expr2 is not an arithmetic expression."], 1244 1245 desc: html("\ 1246 Suspends until both Expr1 and Expr2 are ground, and then both arguments 1247 are evaluated and compared, succeeding iff they are both integers and 1248 Expr1 is less than Expr2. 1249") 1250]). 1251 1252:- comment((=:=)/3, [ 1253 summary: "Reified arithmetic comparison", 1254 see_also:[(=:=)/2,($=)/3], 1255 args:["Expr1" : "An arithmetic expression", "Expr2" : "An arithmetic expression", "Bool":"Variable, 0 or 1"], 1256 exceptions:[24 : "Expr1 or Expr2 is not an arithmetic expression."], 1257 desc: html("\ 1258 Reified version of =:=/2, i.e. the truth value of the comparison is 1259 reflected in the value of the 0/1 variable Bool. 1260<P> 1261 This constraint suspends until its first two arguments are ground. 1262 It then unifies Bool according to the truth value of the corresponding 1263 =:=/2 constraint. 1264") 1265]). 1266 1267:- comment(($=)/3, [ 1268 summary: "Reified arithmetic comparison", 1269 see_also:[($=)/2,(=:=)/3], 1270 args:["Expr1" : "An arithmetic expression", "Expr2" : "An arithmetic expression", "Bool":"Variable, 0 or 1"], 1271 exceptions:[24 : "Expr1 or Expr2 is not an arithmetic expression."], 1272 desc: html("\ 1273 Reified version of $=/2, i.e. the truth value of the comparison is 1274 reflected in the value of the 0/1 variable Bool. 1275<P> 1276 This constraint suspends until its first two arguments are ground. 1277 It then unifies Bool according to the truth value of the corresponding 1278 $=/2 constraint. 1279") 1280]). 1281 1282:- comment((#=)/3, [ 1283 summary: "Reified arithmetic comparison", 1284 see_also:[(#=)/2], 1285 args:["Expr1" : "An arithmetic expression", "Expr2" : "An arithmetic expression", "Bool":"Variable, 0 or 1"], 1286 exceptions:[24 : "Expr1 or Expr2 is not an arithmetic expression."], 1287 desc: html("\ 1288 Reified version of #=/2, i.e. the truth value of the comparison is 1289 reflected in the value of the 0/1 variable Bool. 1290<P> 1291 This constraint suspends until its first two arguments are ground. 1292 It then unifies Bool according to the truth value of the corresponding 1293 #=/2 constraint. 1294") 1295]). 1296 1297:- comment((=\=)/3, [ 1298 summary: "Reified arithmetic comparison", 1299 see_also:[(=\=)/2,($\=)/3], 1300 args:["Expr1" : "An arithmetic expression", "Expr2" : "An arithmetic expression", "Bool":"Variable, 0 or 1"], 1301 exceptions:[24 : "Expr1 or Expr2 is not an arithmetic expression."], 1302 desc: html("\ 1303 Reified version of =\\=/2, i.e. the truth value of the comparison is 1304 reflected in the value of the 0/1 variable Bool. 1305<P> 1306 This constraint suspends until its first two arguments are ground. 1307 It then unifies Bool according to the truth value of the corresponding 1308 =\\=/2 constraint. 1309") 1310]). 1311 1312:- comment(($\=)/3, [ 1313 summary: "Reified arithmetic comparison", 1314 see_also:[($\=)/2,(=\=)/3], 1315 args:["Expr1" : "An arithmetic expression", "Expr2" : "An arithmetic expression", "Bool":"Variable, 0 or 1"], 1316 exceptions:[24 : "Expr1 or Expr2 is not an arithmetic expression."], 1317 desc: html("\ 1318 Reified version of $\\=/2, i.e. the truth value of the comparison is 1319 reflected in the value of the 0/1 variable Bool. 1320<P> 1321 This constraint suspends until its first two arguments are ground. 1322 It then unifies Bool according to the truth value of the corresponding 1323 $\\=/2 constraint. 1324") 1325]). 1326 1327:- comment((#\=)/3, [ 1328 summary: "Reified arithmetic comparison", 1329 see_also:[(#\=)/2], 1330 args:["Expr1" : "An arithmetic expression", "Expr2" : "An arithmetic expression", "Bool":"Variable, 0 or 1"], 1331 exceptions:[24 : "Expr1 or Expr2 is not an arithmetic expression."], 1332 desc: html("\ 1333 Reified version of #\\=/2, i.e. the truth value of the comparison is 1334 reflected in the value of the 0/1 variable Bool. 1335<P> 1336 This constraint suspends until its first two arguments are ground. 1337 It then unifies Bool according to the truth value of the corresponding 1338 #\\=/2 constraint. 1339") 1340]). 1341 1342:- comment((>=)/3, [ 1343 summary: "Reified arithmetic comparison", 1344 see_also:[(>=)/2,($>=)/3], 1345 args:["Expr1" : "An arithmetic expression", "Expr2" : "An arithmetic expression", "Bool":"Variable, 0 or 1"], 1346 exceptions:[24 : "Expr1 or Expr2 is not an arithmetic expression."], 1347 desc: html("\ 1348 Reified version of >=/2, i.e. the truth value of the comparison is 1349 reflected in the value of the 0/1 variable Bool. 1350<P> 1351 This constraint suspends until its first two arguments are ground. 1352 It then unifies Bool according to the truth value of the corresponding 1353 >=/2 constraint. 1354") 1355]). 1356 1357:- comment(($>=)/3, [ 1358 summary: "Reified arithmetic comparison", 1359 see_also:[($>=)/2,(>=)/3], 1360 args:["Expr1" : "An arithmetic expression", "Expr2" : "An arithmetic expression", "Bool":"Variable, 0 or 1"], 1361 exceptions:[24 : "Expr1 or Expr2 is not an arithmetic expression."], 1362 desc: html("\ 1363 Reified version of $>=/2, i.e. the truth value of the comparison is 1364 reflected in the value of the 0/1 variable Bool. 1365<P> 1366 This constraint suspends until its first two arguments are ground. 1367 It then unifies Bool according to the truth value of the corresponding 1368 $>=/2 constraint. 1369") 1370]). 1371 1372:- comment((#>=)/3, [ 1373 summary: "Reified arithmetic comparison", 1374 see_also:[(#>=)/2], 1375 args:["Expr1" : "An arithmetic expression", "Expr2" : "An arithmetic expression", "Bool":"Variable, 0 or 1"], 1376 exceptions:[24 : "Expr1 or Expr2 is not an arithmetic expression."], 1377 desc: html("\ 1378 Reified version of #>=/2, i.e. the truth value of the comparison is 1379 reflected in the value of the 0/1 variable Bool. 1380<P> 1381 This constraint suspends until its first two arguments are ground. 1382 It then unifies Bool according to the truth value of the corresponding 1383 #>=/2 constraint. 1384") 1385]). 1386 1387:- comment((=<)/3, [ 1388 summary: "Reified arithmetic comparison", 1389 see_also:[(=<)/2,($=<)/3], 1390 args:["Expr1" : "An arithmetic expression", "Expr2" : "An arithmetic expression", "Bool":"Variable, 0 or 1"], 1391 exceptions:[24 : "Expr1 or Expr2 is not an arithmetic expression."], 1392 desc: html("\ 1393 Reified version of =</2, i.e. the truth value of the comparison is 1394 reflected in the value of the 0/1 variable Bool. 1395<P> 1396 This constraint suspends until its first two arguments are ground. 1397 It then unifies Bool according to the truth value of the corresponding 1398 =</2 constraint. 1399") 1400]). 1401 1402:- comment(($=<)/3, [ 1403 summary: "Reified arithmetic comparison", 1404 see_also:[($=<)/2,(=<)/3], 1405 args:["Expr1" : "An arithmetic expression", "Expr2" : "An arithmetic expression", "Bool":"Variable, 0 or 1"], 1406 exceptions:[24 : "Expr1 or Expr2 is not an arithmetic expression."], 1407 desc: html("\ 1408 Reified version of $=</2, i.e. the truth value of the comparison is 1409 reflected in the value of the 0/1 variable Bool. 1410<P> 1411 This constraint suspends until its first two arguments are ground. 1412 It then unifies Bool according to the truth value of the corresponding 1413 $=</2 constraint. 1414") 1415]). 1416 1417:- comment((#=<)/3, [ 1418 summary: "Reified arithmetic comparison", 1419 see_also:[(#=<)/2], 1420 args:["Expr1" : "An arithmetic expression", "Expr2" : "An arithmetic expression", "Bool":"Variable, 0 or 1"], 1421 exceptions:[24 : "Expr1 or Expr2 is not an arithmetic expression."], 1422 desc: html("\ 1423 Reified version of #=</2, i.e. the truth value of the comparison is 1424 reflected in the value of the 0/1 variable Bool. 1425<P> 1426 This constraint suspends until its first two arguments are ground. 1427 It then unifies Bool according to the truth value of the corresponding 1428 #=</2 constraint. 1429") 1430]). 1431 1432:- comment((>)/3, [ 1433 summary: "Reified arithmetic comparison", 1434 see_also:[(>)/2,($>)/3], 1435 args:["Expr1" : "An arithmetic expression", "Expr2" : "An arithmetic expression", "Bool":"Variable, 0 or 1"], 1436 exceptions:[24 : "Expr1 or Expr2 is not an arithmetic expression."], 1437 desc: html("\ 1438 Reified version of >/2, i.e. the truth value of the comparison is 1439 reflected in the value of the 0/1 variable Bool. 1440<P> 1441 This constraint suspends until its first two arguments are ground. 1442 It then unifies Bool according to the truth value of the corresponding 1443 >/2 constraint. 1444") 1445]). 1446 1447:- comment(($>)/3, [ 1448 summary: "Reified arithmetic comparison", 1449 see_also:[($>)/2,(>)/3], 1450 args:["Expr1" : "An arithmetic expression", "Expr2" : "An arithmetic expression", "Bool":"Variable, 0 or 1"], 1451 exceptions:[24 : "Expr1 or Expr2 is not an arithmetic expression."], 1452 desc: html("\ 1453 Reified version of $>/2, i.e. the truth value of the comparison is 1454 reflected in the value of the 0/1 variable Bool. 1455<P> 1456 This constraint suspends until its first two arguments are ground. 1457 It then unifies Bool according to the truth value of the corresponding 1458 $>/2 constraint. 1459") 1460]). 1461 1462:- comment((#>)/3, [ 1463 summary: "Reified arithmetic comparison", 1464 see_also:[(#>)/2], 1465 args:["Expr1" : "An arithmetic expression", "Expr2" : "An arithmetic expression", "Bool":"Variable, 0 or 1"], 1466 exceptions:[24 : "Expr1 or Expr2 is not an arithmetic expression."], 1467 desc: html("\ 1468 Reified version of #>/2, i.e. the truth value of the comparison is 1469 reflected in the value of the 0/1 variable Bool. 1470<P> 1471 This constraint suspends until its first two arguments are ground. 1472 It then unifies Bool according to the truth value of the corresponding 1473 #>/2 constraint. 1474") 1475]). 1476 1477:- comment((<)/3, [ 1478 summary: "Reified arithmetic comparison", 1479 see_also:[(<)/2,($<)/3], 1480 args:["Expr1" : "An arithmetic expression", "Expr2" : "An arithmetic expression", "Bool":"Variable, 0 or 1"], 1481 exceptions:[24 : "Expr1 or Expr2 is not an arithmetic expression."], 1482 desc: html("\ 1483 Reified version of </2, i.e. the truth value of the comparison is 1484 reflected in the value of the 0/1 variable Bool. 1485<P> 1486 This constraint suspends until its first two arguments are ground. 1487 It then unifies Bool according to the truth value of the corresponding 1488 </2 constraint. 1489") 1490]). 1491 1492:- comment(($<)/3, [ 1493 summary: "Reified arithmetic comparison", 1494 see_also:[($<)/2,(<)/3], 1495 args:["Expr1" : "An arithmetic expression", "Expr2" : "An arithmetic expression", "Bool":"Variable, 0 or 1"], 1496 exceptions:[24 : "Expr1 or Expr2 is not an arithmetic expression."], 1497 desc: html("\ 1498 Reified version of $</2, i.e. the truth value of the comparison is 1499 reflected in the value of the 0/1 variable Bool. 1500<P> 1501 This constraint suspends until its first two arguments are ground. 1502 It then unifies Bool according to the truth value of the corresponding 1503 $</2 constraint. 1504") 1505]). 1506 1507:- comment((#<)/3, [ 1508 summary: "Reified arithmetic comparison", 1509 see_also:[(#<)/2], 1510 args:["Expr1" : "An arithmetic expression", "Expr2" : "An arithmetic expression", "Bool":"Variable, 0 or 1"], 1511 exceptions:[24 : "Expr1 or Expr2 is not an arithmetic expression."], 1512 desc: html("\ 1513 Reified version of #</2, i.e. the truth value of the comparison is 1514 reflected in the value of the 0/1 variable Bool. 1515<P> 1516 This constraint suspends until its first two arguments are ground. 1517 It then unifies Bool according to the truth value of the corresponding 1518 #</2 constraint. 1519") 1520]). 1521 1522 1523:- comment((and)/2, [ 1524 summary: "Both Expr1 and Expr2 arithmetically evaluate to 1", 1525 template: "?Expr1 and ?Expr2", 1526 see_also:[(and)/3, (or)/2, (=>)/2, (neg)/1, _:(and)/2], 1527 args:["Expr1" : "A boolean expression", 1528 "Expr2" : "A boolean expression"], 1529 fail_if:"Expr1 or Expr2 do not both evaluate to 1", 1530 eg:" 1531 ?- B and 1, B = 1. 1532 B = 1 1533 Yes (0.00s cpu) 1534 1535 ?- B and 1, B = 0. 1536 No (0.00s cpu) 1537 1538 % arguments are typically reifiable expressions: 1539 ?- X > 5 and X < 7, X = 7. 1540 No (0.00s cpu) 1541 1542 % the previous example is equivalent to: 1543 ?- >(X,5,B1), <(X,7,B2), B1 and B2, X=7. 1544 No (0.00s cpu) 1545 1546 % and/or/=>/neg are themselves reifiable: 1547 ?- X > 5 and neg(X < 7), X = 7. 1548 X = 7 1549 Yes (0.00s cpu) 1550 ", 1551 exceptions:[24 : "Expr1 or Expr2 is not an arithmetic expression."], 1552 desc: html("\ 1553 Suspends until both Expr1 and Expr2 are ground, and then both arguments 1554 are evaluated. Succeeds if both evaluate to 1. 1555<P> 1556 Typically, the expressions contains reifiable constraints, in which case 1557 a corresponding reified constraint is set up, and the expression is 1558 replaced by the resulting boolean variable. 1559") 1560]). 1561 1562:- comment((or)/2, [ 1563 summary: "At least one of Expr1 or Expr2 arithmetically evaluate to 1", 1564 template: "?Expr1 or ?Expr2", 1565 see_also:[(or)/3, (and)/2, (=>)/2, (neg)/1, _:(or)/2], 1566 args:["Expr1" : "A boolean expression", 1567 "Expr2" : "A boolean expression"], 1568 fail_if:"Neither Expr1 nor Expr2 evaluates to 1", 1569 eg:" 1570 ?- B or 1, B = 0. 1571 B = 0 1572 Yes (0.00s cpu) 1573 1574 ?- B or 0, B = 0. 1575 No (0.00s cpu) 1576 1577 % arguments are typically reifiable expressions: 1578 ?- X > 7 or X < 5, X = 7. 1579 No (0.00s cpu) 1580 1581 % the previous example is equivalent to: 1582 ?- >(X,7,B1), <(X,5,B2), B1 or B2, X=7. 1583 No (0.00s cpu) 1584 1585 % and/or/=>/neg are themselves reifiable: 1586 ?- X > 7 or neg(X < 5), X = 7. 1587 X = 7 1588 Yes (0.00s cpu) 1589 ", 1590 exceptions:[24 : "Expr1 or Expr2 is not an arithmetic expression."], 1591 desc: html("\ 1592 Suspends until both Expr1 and Expr2 are ground, and then both arguments 1593 are evaluated. Succeeds if at least one evaluates to 1. 1594<P> 1595 Typically, the expressions contains reifiable constraints, in which case 1596 a corresponding reified constraint is set up, and the expression is 1597 replaced by the resulting boolean variable. 1598") 1599]). 1600 1601:- comment((=>)/2, [ 1602 summary: "If Expr1 arithmetically evaluates to 1, so does Expr2 (implication)", 1603 template: "?Expr1 => ?Expr2", 1604 see_also:[(=>)/3, (and)/2, (or)/2, (neg)/1, _:(=>)/2], 1605 args:["Expr1" : "A boolean expression", 1606 "Expr2" : "A boolean expression"], 1607 fail_if:"Expr1 evaluates to 1 and Expr2 evaluates to 0", 1608 eg:" 1609 ?- 0 => B, B = 0. 1610 B = 0 1611 Yes (0.00s cpu) 1612 1613 ?- 0 => B, B = 1. 1614 B = 1 1615 Yes (0.00s cpu) 1616 1617 ?- 1 => B, B = 0. 1618 No (0.00s cpu) 1619 1620 ?- 1 => B, B = 1. 1621 B = 1 1622 Yes (0.00s cpu) 1623 1624 % arguments are typically reifiable expressions: 1625 ?- X > Y => X > Y+10, X = 5, Y = 3. 1626 No (0.00s cpu) 1627 1628 % the previous example is equivalent to: 1629 ?- >(X,Y,B1), >(X,Y+10,B2), B1 => B2, X = 5, Y = 3. 1630 No (0.00s cpu) 1631 1632 % and/or/=>/neg are themselves reifiable: 1633 ?- neg(A => B) or (C => D), A=1, B=0, C=0, D=1. 1634 A = 1 1635 B = 0 1636 C = 0 1637 D = 1 1638 Yes (0.00s cpu) 1639 ", 1640 exceptions:[24 : "Expr1 or Expr2 is not an arithmetic expression."], 1641 desc: html("\ 1642 Suspends until both Expr1 and Expr2 are ground, and then both arguments 1643 are evaluated. Succeeds if the truth of Expr1 implies Expr2, i.e. if Expr1 1644 evaluates to 1, Expr2 must evaluate to 1, otherwise Expr2 can evaluate to 1645 1 or 0. Logically equivalent to 1646 <PRE> 1647 neg(Expr1) or Expr2. 1648 </PRE> 1649 Typically, the expressions contains reifiable constraints, in which case 1650 a corresponding reified constraint is set up, and the expression is 1651 replaced by the resulting boolean variable. 1652") 1653]). 1654 1655:- comment((neg)/1, [ 1656 summary: "Expr arithmetically evaluates to 0", 1657 template: "neg ?Expr", 1658 see_also:[(neg)/2, (and)/2, (or)/2, (=>)/2, _:(neg)/1], 1659 args:["Expr" : "A boolean expression"], 1660 fail_if:"Expr does not evaluate to 0", 1661 eg:" 1662 ?- neg B, B = 1. 1663 No (0.00s cpu) 1664 1665 ?- neg B, B = 0. 1666 B = 0 1667 Yes (0.00s cpu) 1668 1669 % arguments are typically reifiable expressions: 1670 ?- neg X > 7, X = 8. 1671 No (0.00s cpu) 1672 1673 % the previous example is equivalent to: 1674 ?- >(X,7,B), neg B, X=8. 1675 No (0.00s cpu) 1676 1677 % and/or/=>/neg are themselves reifiable: 1678 ?- neg(X > 7 or X < 5), X = 7. 1679 X = 7 1680 Yes (0.00s cpu) 1681 ", 1682 exceptions:[24 : "Expr is not an arithmetic expression."], 1683 desc: html("\ 1684 Suspends until Expr is ground, and then evaluates it. Succeeds if it 1685 evaluates to 0. 1686<P> 1687 Typically, the expression contains reifiable constraints, in which case 1688 a corresponding reified constraint is set up, and the expression is 1689 replaced by the resulting boolean variable. 1690") 1691]). 1692 1693:- comment((and)/3, [ 1694 summary: "Reified boolean operation", 1695 see_also:[(and)/2], 1696 args:["Expr1" : "An arithmetic expression", "Expr2" : "An arithmetic expression", "Bool":"Variable, 0 or 1"], 1697 exceptions:[24 : "Expr1 or Expr2 is not an arithmetic expression."], 1698 desc: html("\ 1699 Reified version of and/2, i.e. the truth value of the boolean operation 1700 is reflected in the value of the 0/1 variable Bool. 1701<P> 1702 This constraint suspends until its first two arguments are ground. 1703 It then unifies Bool according to the truth value of the corresponding 1704 and/2 constraint. 1705") 1706]). 1707 1708:- comment((or)/3, [ 1709 summary: "Reified boolean operation", 1710 see_also:[(or)/2], 1711 args:["Expr1" : "An arithmetic expression", "Expr2" : "An arithmetic expression", "Bool":"Variable, 0 or 1"], 1712 exceptions:[24 : "Expr1 or Expr2 is not an arithmetic expression."], 1713 desc: html("\ 1714 Reified version of or/2, i.e. the truth value of the boolean operation 1715 is reflected in the value of the 0/1 variable Bool. 1716<P> 1717 This constraint suspends until its first two arguments are ground. 1718 It then unifies Bool according to the truth value of the corresponding 1719 or/2 constraint. 1720") 1721]). 1722 1723:- comment((=>)/3, [ 1724 summary: "Reified boolean operation", 1725 see_also:[(=>)/2], 1726 args:["Expr1" : "An arithmetic expression", "Expr2" : "An arithmetic expression", "Bool":"Variable, 0 or 1"], 1727 exceptions:[24 : "Expr1 or Expr2 is not an arithmetic expression."], 1728 desc: html("\ 1729 Reified version of =>/2, i.e. the truth value of the boolean operation 1730 is reflected in the value of the 0/1 variable Bool. 1731<P> 1732 This constraint suspends until its first two arguments are ground. 1733 It then unifies Bool according to the truth value of the corresponding 1734 =>/2 constraint. 1735") 1736]). 1737 1738:- comment((neg)/2, [ 1739 summary: "Reified boolean operation", 1740 see_also:[(neg)/1], 1741 args:["Expr" : "An arithmetic expression", "Bool":"Variable, 0 or 1"], 1742 exceptions:[24 : "Expr is not an arithmetic expression."], 1743 desc: html("\ 1744 Reified version of neg/1, i.e. the truth value of the boolean operation 1745 is reflected in the value of the 0/1 variable Bool. 1746<P> 1747 This constraint suspends until its first argument is ground. 1748 It then unifies Bool according to the truth value of the corresponding 1749 neg/1 constraint. 1750") 1751]). 1752 1753