261 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
		
		
			
		
	
	
			261 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
| 
								 | 
							
								/*  $Id$
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Part of CPL(R) (Constraint Logic Programming over Reals)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Author:        Leslie De Koninck
							 | 
						||
| 
								 | 
							
								    E-mail:        Leslie.DeKoninck@cs.kuleuven.be
							 | 
						||
| 
								 | 
							
								    WWW:           http://www.swi-prolog.org
							 | 
						||
| 
								 | 
							
										   http://www.ai.univie.ac.at/cgi-bin/tr-online?number+95-09
							 | 
						||
| 
								 | 
							
								    Copyright (C): 2004, K.U. Leuven and
							 | 
						||
| 
								 | 
							
										   1992-1995, Austrian Research Institute for
							 | 
						||
| 
								 | 
							
										              Artificial Intelligence (OFAI),
							 | 
						||
| 
								 | 
							
											      Vienna, Austria
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    This software is part of Leslie De Koninck's master thesis, supervised
							 | 
						||
| 
								 | 
							
								    by Bart Demoen and daily advisor Tom Schrijvers.  It is based on CLP(Q,R)
							 | 
						||
| 
								 | 
							
								    by Christian Holzbaur for SICStus Prolog and distributed under the
							 | 
						||
| 
								 | 
							
								    license details below with permission from all mentioned authors.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    This program is free software; you can redistribute it and/or
							 | 
						||
| 
								 | 
							
								    modify it under the terms of the GNU General Public License
							 | 
						||
| 
								 | 
							
								    as published by the Free Software Foundation; either version 2
							 | 
						||
| 
								 | 
							
								    of the License, or (at your option) any later version.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    This program is distributed in the hope that it will be useful,
							 | 
						||
| 
								 | 
							
								    but WITHOUT ANY WARRANTY; without even the implied warranty of
							 | 
						||
| 
								 | 
							
								    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
							 | 
						||
| 
								 | 
							
								    GNU General Public License for more details.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    You should have received a copy of the GNU Lesser General Public
							 | 
						||
| 
								 | 
							
								    License along with this library; if not, write to the Free Software
							 | 
						||
| 
								 | 
							
								    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    As a special exception, if you link this library with other files,
							 | 
						||
| 
								 | 
							
								    compiled with a Free Software compiler, to produce an executable, this
							 | 
						||
| 
								 | 
							
								    library does not by itself cause the resulting executable to be covered
							 | 
						||
| 
								 | 
							
								    by the GNU General Public License. This exception does not however
							 | 
						||
| 
								 | 
							
								    invalidate any other reasons why the executable file might be covered by
							 | 
						||
| 
								 | 
							
								    the GNU General Public License.
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								:- module(bb_r,
							 | 
						||
| 
								 | 
							
									[
							 | 
						||
| 
								 | 
							
									    bb_inf/3,	
							 | 
						||
| 
								 | 
							
									    bb_inf/5,
							 | 
						||
| 
								 | 
							
									    vertex_value/2
							 | 
						||
| 
								 | 
							
									]).
							 | 
						||
| 
								 | 
							
								:- use_module(bv_r,
							 | 
						||
| 
								 | 
							
									[
							 | 
						||
| 
								 | 
							
									    deref/2,
							 | 
						||
| 
								 | 
							
									    deref_var/2,
							 | 
						||
| 
								 | 
							
									    determine_active_dec/1,
							 | 
						||
| 
								 | 
							
									    inf/2,
							 | 
						||
| 
								 | 
							
									    iterate_dec/2,
							 | 
						||
| 
								 | 
							
									    sup/2,
							 | 
						||
| 
								 | 
							
									    var_with_def_assign/2
							 | 
						||
| 
								 | 
							
									]).
							 | 
						||
| 
								 | 
							
								:- use_module(nf_r,
							 | 
						||
| 
								 | 
							
									[
							 | 
						||
| 
								 | 
							
									    {}/1,
							 | 
						||
| 
								 | 
							
									    entailed/1,
							 | 
						||
| 
								 | 
							
									    nf/2,
							 | 
						||
| 
								 | 
							
									    nf_constant/2,
							 | 
						||
| 
								 | 
							
									    repair/2,
							 | 
						||
| 
								 | 
							
									    wait_linear/3		
							 | 
						||
| 
								 | 
							
									]).
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
								% bb_inf(Ints,Term,Inf)
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								% Finds the infimum of Term where the variables Ints are to be integers.
							 | 
						||
| 
								 | 
							
								% The infimum is stored in Inf.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								bb_inf(Is,Term,Inf) :-
							 | 
						||
| 
								 | 
							
									bb_inf(Is,Term,Inf,_,0.001).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								bb_inf(Is,Term,Inf,Vertex,Eps) :-
							 | 
						||
| 
								 | 
							
									nf(Eps,ENf),
							 | 
						||
| 
								 | 
							
									nf_constant(ENf,EpsN),
							 | 
						||
| 
								 | 
							
									wait_linear(Term,Nf,bb_inf_internal(Is,Nf,EpsN,Inf,Vertex)).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								% ---------------------------------------------------------------------
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								% bb_inf_internal(Is,Lin,Eps,Inf,Vertex)
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								% Finds an infimum Inf for linear expression in normal form Lin, where
							 | 
						||
| 
								 | 
							
								% all variables in Is are to be integers. Eps denotes the margin in which
							 | 
						||
| 
								 | 
							
								% we accept a number as an integer (to deal with rounding errors etc.).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								bb_inf_internal(Is,Lin,Eps,_,_) :-
							 | 
						||
| 
								 | 
							
									bb_intern(Is,IsNf,Eps),
							 | 
						||
| 
								 | 
							
									nb_delete(prov_opt),
							 | 
						||
| 
								 | 
							
									repair(Lin,LinR),	% bb_narrow ...
							 | 
						||
| 
								 | 
							
									deref(LinR,Lind),
							 | 
						||
| 
								 | 
							
									var_with_def_assign(Dep,Lind),
							 | 
						||
| 
								 | 
							
									determine_active_dec(Lind),
							 | 
						||
| 
								 | 
							
									bb_loop(Dep,IsNf,Eps),
							 | 
						||
| 
								 | 
							
									fail.
							 | 
						||
| 
								 | 
							
								bb_inf_internal(_,_,_,Inf,Vertex) :-
							 | 
						||
| 
								 | 
							
									catch(nb_getval(prov_opt,InfVal-Vertex),_,fail),
							 | 
						||
| 
								 | 
							
									{Inf =:= InfVal},
							 | 
						||
| 
								 | 
							
									nb_delete(prov_opt).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								% bb_loop(Opt,Is,Eps)
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								% Minimizes the value of Opt where variables Is have to be integer values.
							 | 
						||
| 
								 | 
							
								% Eps denotes the rounding error that is acceptable. This predicate can be
							 | 
						||
| 
								 | 
							
								% backtracked to try different strategies.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								bb_loop(Opt,Is,Eps) :-
							 | 
						||
| 
								 | 
							
									bb_reoptimize(Opt,Inf),
							 | 
						||
| 
								 | 
							
									bb_better_bound(Inf),
							 | 
						||
| 
								 | 
							
									vertex_value(Is,Ivs),
							 | 
						||
| 
								 | 
							
									(   bb_first_nonint(Is,Ivs,Eps,Viol,Floor,Ceiling)
							 | 
						||
| 
								 | 
							
									->  bb_branch(Viol,Floor,Ceiling),
							 | 
						||
| 
								 | 
							
									    bb_loop(Opt,Is,Eps)
							 | 
						||
| 
								 | 
							
									;   round_values(Ivs,RoundVertex),
							 | 
						||
| 
								 | 
							
									    nb_setval(prov_opt,Inf-RoundVertex) % new provisional optimum
							 | 
						||
| 
								 | 
							
									).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								% bb_reoptimize(Obj,Inf)
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								% Minimizes the value of Obj and puts the result in Inf.
							 | 
						||
| 
								 | 
							
								% This new minimization is necessary as making a bound integer may yield a
							 | 
						||
| 
								 | 
							
								% different optimum. The added inequalities may also have led to binding.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								bb_reoptimize(Obj,Inf) :- 
							 | 
						||
| 
								 | 
							
									var(Obj),
							 | 
						||
| 
								 | 
							
									iterate_dec(Obj,Inf).
							 | 
						||
| 
								 | 
							
								bb_reoptimize(Obj,Inf) :- 
							 | 
						||
| 
								 | 
							
									nonvar(Obj),
							 | 
						||
| 
								 | 
							
									Inf = Obj.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								% bb_better_bound(Inf)
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								% Checks if the new infimum Inf is better than the previous one (if such exists).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								bb_better_bound(Inf) :-
							 | 
						||
| 
								 | 
							
									catch((nb_getval(prov_opt,Inc-_),Inf - Inc < -1.0e-10),_,true).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								% bb_branch(V,U,L)
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								% Stores that V =< U or V >= L, can be used for different strategies within bb_loop/3.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								bb_branch(V,U,_) :- {V =< U}.
							 | 
						||
| 
								 | 
							
								bb_branch(V,_,L) :- {V >= L}.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								% vertex_value(Vars,Values)
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								% Returns in <Values> the current values of the variables in <Vars>.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								vertex_value([],[]).
							 | 
						||
| 
								 | 
							
								vertex_value([X|Xs],[V|Vs]) :-
							 | 
						||
| 
								 | 
							
									rhs_value(X,V),
							 | 
						||
| 
								 | 
							
									vertex_value(Xs,Vs).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								% rhs_value(X,Value)
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								% Returns in <Value> the current value of variable <X>.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rhs_value(Xn,Value) :- 
							 | 
						||
| 
								 | 
							
									(   nonvar(Xn)
							 | 
						||
| 
								 | 
							
									->  Value = Xn
							 | 
						||
| 
								 | 
							
									;   var(Xn)
							 | 
						||
| 
								 | 
							
									->  deref_var(Xn,Xd),
							 | 
						||
| 
								 | 
							
									    Xd = [I,R|_],
							 | 
						||
| 
								 | 
							
									    Value is R+I
							 | 
						||
| 
								 | 
							
									).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								% bb_first_nonint(Ints,Rhss,Eps,Viol,Floor,Ceiling)
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								% Finds the first variable in Ints which doesn't have an active integer bound.
							 | 
						||
| 
								 | 
							
								% Rhss contain the Rhs (R + I) values corresponding to the variables.
							 | 
						||
| 
								 | 
							
								% The first variable that hasn't got an active integer bound, is returned in
							 | 
						||
| 
								 | 
							
								% Viol. The floor and ceiling of its actual bound is returned in Floor and Ceiling.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								bb_first_nonint([I|Is],[Rhs|Rhss],Eps,Viol,F,C) :-
							 | 
						||
| 
								 | 
							
									(   Floor is floor(Rhs+1.0e-10),
							 | 
						||
| 
								 | 
							
									    Ceiling is ceiling(Rhs-1.0e-10),
							 | 
						||
| 
								 | 
							
									    Eps - min(Rhs-Floor,Ceiling-Rhs) < -1.0e-10
							 | 
						||
| 
								 | 
							
									->  Viol = I,
							 | 
						||
| 
								 | 
							
									    F = Floor,
							 | 
						||
| 
								 | 
							
									    C = Ceiling
							 | 
						||
| 
								 | 
							
									;   bb_first_nonint(Is,Rhss,Eps,Viol,F,C)
							 | 
						||
| 
								 | 
							
									).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								% round_values([X|Xs],[Xr|Xrs])
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								% Rounds of the values of the first list into the second list.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								round_values([],[]).
							 | 
						||
| 
								 | 
							
								round_values([X|Xs],[Y|Ys]) :-
							 | 
						||
| 
								 | 
							
									Y is round(X),
							 | 
						||
| 
								 | 
							
									round_values(Xs,Ys).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								% bb_intern([X|Xs],[Xi|Xis],Eps)
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								% Turns the elements of the first list into integers into the second
							 | 
						||
| 
								 | 
							
								% list via bb_intern/4.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								bb_intern([],[],_).
							 | 
						||
| 
								 | 
							
								bb_intern([X|Xs],[Xi|Xis],Eps) :-
							 | 
						||
| 
								 | 
							
									nf(X,Xnf),
							 | 
						||
| 
								 | 
							
									bb_intern(Xnf,Xi,X,Eps),
							 | 
						||
| 
								 | 
							
									bb_intern(Xs,Xis,Eps).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								% bb_intern(Nf,X,Term,Eps)
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								% Makes sure that Term which is normalized into Nf, is integer.
							 | 
						||
| 
								 | 
							
								% X contains the possibly changed Term. If Term is a variable,
							 | 
						||
| 
								 | 
							
								% then its bounds are hightened or lowered to the next integer.
							 | 
						||
| 
								 | 
							
								% Otherwise, it is checked it Term is integer.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								bb_intern([],X,_,_) :- 
							 | 
						||
| 
								 | 
							
									!,
							 | 
						||
| 
								 | 
							
									X = 0.0.
							 | 
						||
| 
								 | 
							
								bb_intern([v(I,[])],X,_,Eps) :- 
							 | 
						||
| 
								 | 
							
									!,
							 | 
						||
| 
								 | 
							
									X = I,
							 | 
						||
| 
								 | 
							
									min(I-floor(I+1e-010),ceiling(I-1e-010)-I) - Eps < 1e-010.
							 | 
						||
| 
								 | 
							
								bb_intern([v(One,[V^1])],X,_,_) :-
							 | 
						||
| 
								 | 
							
									Test is One - 1.0,
							 | 
						||
| 
								 | 
							
									Test =< 1e-010,
							 | 
						||
| 
								 | 
							
									Test >= -1e-010,
							 | 
						||
| 
								 | 
							
									!,
							 | 
						||
| 
								 | 
							
									V = X,
							 | 
						||
| 
								 | 
							
									bb_narrow_lower(X),
							 | 
						||
| 
								 | 
							
									bb_narrow_upper(X).
							 | 
						||
| 
								 | 
							
								bb_intern(_,_,Term,_) :-
							 | 
						||
| 
								 | 
							
									throw(instantiation_error(bb_inf(Term,_,_),1)).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								% bb_narrow_lower(X)
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								% Narrows the lower bound so that it is an integer bound.
							 | 
						||
| 
								 | 
							
								% We do this by finding the infimum of X and asserting that X
							 | 
						||
| 
								 | 
							
								% is larger than the first integer larger or equal to the infimum
							 | 
						||
| 
								 | 
							
								% (second integer if X is to be strict larger than the first integer).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								bb_narrow_lower(X) :-
							 | 
						||
| 
								 | 
							
									(   inf(X,Inf)
							 | 
						||
| 
								 | 
							
									->  Bound is ceiling(Inf-1.0e-10),
							 | 
						||
| 
								 | 
							
									    (   entailed(X > Bound)
							 | 
						||
| 
								 | 
							
									    ->  {X >= Bound+1}
							 | 
						||
| 
								 | 
							
									    ;   {X >= Bound}
							 | 
						||
| 
								 | 
							
									    )
							 | 
						||
| 
								 | 
							
									;   true
							 | 
						||
| 
								 | 
							
									).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								% bb_narrow_upper(X)
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								% See bb_narrow_lower/1. This predicate handles the upper bound.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								bb_narrow_upper(X) :-
							 | 
						||
| 
								 | 
							
									(   sup(X,Sup)
							 | 
						||
| 
								 | 
							
									->  Bound is floor(Sup+1.0e-10),
							 | 
						||
| 
								 | 
							
									    (   entailed(X < Bound)
							 | 
						||
| 
								 | 
							
									    ->  {X =< Bound-1}
							 | 
						||
| 
								 | 
							
									    ;   {X =< Bound}
							 | 
						||
| 
								 | 
							
									    )
							 | 
						||
| 
								 | 
							
									;   true
							 | 
						||
| 
								 | 
							
									).
							 |