CLP(R) package

git-svn-id: https://yap.svn.sf.net/svnroot/yap/trunk@1417 b08c6af1-5177-4d33-ba66-4b1c6b8b522a
This commit is contained in:
vsc 2005-10-28 17:51:01 +00:00
parent 4d94446c25
commit c33738d557
20 changed files with 8908 additions and 0 deletions

71
LGPL/clpr/Makefile.in Normal file
View File

@ -0,0 +1,71 @@
#
# default base directory for YAP installation
# (EROOT for architecture-dependent files)
#
prefix = @prefix@
ROOTDIR = $(prefix)
EROOTDIR = @exec_prefix@
SHELL=@SHELL@
PLBASE=@PLBASE@
PLARCH=@PLARCH@
PL=@PL@
XPCEBASE=$(PLBASE)/xpce
PKGDOC=$(PLBASE)/doc/packages
PCEHOME=../../xpce
LIBDIR=$(PLBASE)/library
SHAREDIR=$(ROOTDIR)/share/Yap
CLPRDIR=$(SHAREDIR)/clpr
EXDIR=$(PKGDOC)/examples/clpr
DESTDIR=
srcdir=@srcdir@
CLPRSOURCEDIR=$(srcdir)/clpr
INSTALL=@INSTALL@
INSTALL_PROGRAM=@INSTALL_PROGRAM@
INSTALL_DATA=@INSTALL_DATA@
CLPRPRIV= $(CLPRSOURCEDIR)/arith_r.pl $(CLPRSOURCEDIR)/bb.pl $(CLPRSOURCEDIR)/bv.pl $(CLPRSOURCEDIR)/class.pl $(CLPRSOURCEDIR)/dump.pl $(CLPRSOURCEDIR)/fourmotz.pl \
$(CLPRSOURCEDIR)/geler.pl $(CLPRSOURCEDIR)/ineq.pl $(CLPRSOURCEDIR)/itf3.pl $(CLPRSOURCEDIR)/nf.pl $(CLPRSOURCEDIR)/nfr.pl $(CLPRSOURCEDIR)/ordering.pl \
$(CLPRSOURCEDIR)/project.pl $(CLPRSOURCEDIR)/redund.pl $(CLPRSOURCEDIR)/store.pl $(CLPRSOURCEDIR)/ugraphs.pl
LIBPL= $(srcdir)/clpr.yap $(srcdir)/clpr.pl
EXAMPLES=
all::
@echo "Nothing to be done for this package"
install: $(LIBPL)
mkdir -p $(DESTDIR)$(CLPRDIR)
$(INSTALL_DATA) $(LIBPL) $(DESTDIR)$(SHAREDIR)
$(INSTALL_DATA) $(CLPRPRIV) $(DESTDIR)$(CLPRDIR)
$(INSTALL_DATA) $(srcdir)/README $(DESTDIR)$(CLPRDIR)
rpm-install: install
pdf-install: install-examples
html-install: install-examples
install-examples::
# mkdir -p $(DESTDIR)$(EXDIR)
# (cd Examples && $(INSTALL_DATA) $(EXAMPLES) $(DESTDIR)$(EXDIR))
uninstall:
(cd $(CLPDIR) && rm -f $(LIBPL))
rm -rf $(CLPRDIR)
check::
# $(PL) -q -f clpr_test.pl -g test,halt -t 'halt(1)'
################################################################
# Clean
################################################################
clean:
rm -f *~ *% config.log
distclean: clean
rm -f config.h config.cache config.status Makefile
rm -rf autom4te.cache

22
LGPL/clpr/README Normal file
View File

@ -0,0 +1,22 @@
SWI-Prolog CLP(R)
-----------------
Author: Leslie De Koninck, K.U. Leuven as part of a thesis with supervisor
Bart Demoen and daily advisor Tom Schrijvers. Integrated into
the main SWI-Prolog source by Jan Wielemaker.
This software is based on the CLP(Q,R) implementation by Christian
Holzbauer and released with permission from all above mentioned authors
and Christian Holzbauer under the standard SWI-Prolog license schema:
GPL-2 + statement to allow linking with proprietary software.
The sources of this package are maintained in packages/clpr in the
SWI-Prolog source distribution. The documentation source is in
man/lib/clpr.doc as part of the overall SWI-Prolog documentation.
Full documentation on CLP(Q,R) can be found at
http://www.ai.univie.ac.at/cgi-bin/tr-online?number+95-09

10
LGPL/clpr/clpr.pl Normal file
View File

@ -0,0 +1,10 @@
:- load_files(library(swi),[silent(true)]).
:- yap_flag(unknown,error).
:- include('clpr.pl').

10
LGPL/clpr/clpr.yap Normal file
View File

@ -0,0 +1,10 @@
:- load_files(library(swi),[silent(true)]).
:- yap_flag(unknown,error).
:- include('clpr.pl').

85
LGPL/clpr/clpr/arith_r.pl Normal file
View File

@ -0,0 +1,85 @@
/* $Id: arith_r.pl,v 1.1 2005-10-28 17:51:01 vsc Exp $
Part of CPL(R) (Constraint Logic Programming over Reals)
Author: Leslie De Koninck
E-mail: Tom.Schrijvers@cs.kuleuven.ac.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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(arith_r,
[
arith_eps/1,
arith_normalize/2,
integerp/1,
integerp/2
]).
arith_eps(1.0e-10). % for Monash #zero expansion 1.0e-12
eps(1.0e-10,-1.0e-10).
arith_normalize(X,Norm) :-
var(X),
!,
raise_exception(instantiation_error(arith_normalize(X,Norm),1)).
arith_normalize(rat(N,D),Norm) :- rat_float(N,D,Norm).
arith_normalize(X,Norm) :-
number(X),
Norm is float(X).
integerp(X) :-
floor(/*float?*/X)=:=X.
integerp(X,I) :-
floor(/*float?*/X)=:=X,
I is integer(X).
% copied from arith.pl.
rat_float(Nx,Dx,F) :-
limit_encoding_length(Nx,Dx,1023,Nxl,Dxl),
F is Nxl / Dxl.
limit_encoding_length(0,D,_,0,D) :- !. % msb ...
limit_encoding_length(N,D,Bits,Nl,Dl) :-
Shift is min(max(msb(abs(N)),msb(D))-Bits,
min(msb(abs(N)),msb(D))),
Shift > 0,
!,
Ns is N>>Shift,
Ds is D>>Shift,
Gcd is gcd(Ns,Ds),
Nl is Ns//Gcd,
Dl is Ds//Gcd.
limit_encoding_length(N,D,_,N,D).

301
LGPL/clpr/clpr/bb.pl Normal file
View File

@ -0,0 +1,301 @@
/* $Id: bb.pl,v 1.1 2005-10-28 17:51:01 vsc Exp $
Part of CPL(R) (Constraint Logic Programming over Reals)
Author: Leslie De Koninck
E-mail: Tom.Schrijvers@cs.kuleuven.ac.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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,
[
bb_inf/3,
bb_inf/5,
vertex_value/2
]).
:- use_module(bv,
[
deref/2,
deref_var/2,
determine_active_dec/1,
inf/2,
iterate_dec/2,
sup/2,
var_with_def_assign/2
]).
:- use_module(nf,
[ {}/1,
entailed/1,
nf/2,
nf_constant/2,
repair/2,
wait_linear/3
]).
:- dynamic blackboard_incumbent/1.
% 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),
(
retract(blackboard_incumbent(_)) ->
true
;
true
),
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) :-
retract(blackboard_incumbent(InfVal-Vertex)), % GC
{ Inf =:= InfVal }.
% 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),
(
retract(blackboard_incumbent(_)) ->
assert(blackboard_incumbent(Inf-RoundVertex))
;
assert(blackboard_incumbent(Inf-RoundVertex))
)
).
% 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) :-
blackboard_incumbent(Inc-_),
!,
Inf - Inc < -1e-010.
bb_better_bound(_).
% 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,Rhss)
%
% Returns in Rhss, the Rhs values corresponding to the Vars via rhs_value/2.
vertex_value([],[]).
vertex_value([X|Xs],[V|Vs]) :-
rhs_value(X,V),
vertex_value(Xs,Vs).
% rhs_value(X,Rhs)
%
% Returns the Rhs value of variable X. This is the value by which the
% variable is actively bounded. If X is a nonvar, the value of X is returned.
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 float(floor(Rhs)),
Ceiling is float(ceiling(Rhs)),
Eps - min(Rhs-Floor,Ceiling-Rhs) < -1e-010 ->
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 = float(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-float(floor(I)),float(ceiling(I))-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,_) :-
raise_exception(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 float(ceiling(Inf)),
(
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 float(floor(Sup)),
(
entailed(X < Bound) ->
{X =< Bound-1}
;
{X =< Bound}
)
;
true
).

1805
LGPL/clpr/clpr/bv.pl Normal file

File diff suppressed because it is too large Load Diff

154
LGPL/clpr/clpr/class.pl Normal file
View File

@ -0,0 +1,154 @@
/* $Id: class.pl,v 1.1 2005-10-28 17:51:01 vsc Exp $
Part of CPL(R) (Constraint Logic Programming over Reals)
Author: Leslie De Koninck
E-mail: Tom.Schrijvers@cs.kuleuven.ac.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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(class,
[
class_allvars/2,
class_new/4,
class_drop/2,
class_basis/2,
class_basis_add/3,
class_basis_drop/2,
class_basis_pivot/3,
class_get_prio/2,
class_put_prio/2,
ordering/1,
arrangement/2
]).
:- use_module(ordering,
[
combine/3,
ordering/1,
arrangement/2
]).
% called when two classes are unified: the allvars lists are appended to eachother, as well as the basis
% lists.
%
% note: La=[A,B,...,C|Lat], Lb=[D,E,...,F|Lbt], so new La = [A,B,...,C,D,E,...,F|Lbt]
attr_unify_hook(class(La,Lat,ABasis,PrioA),Y) :-
!,
var(Y),
get_attr(Y,class,class(Lb,Lbt,BBasis,PrioB)),
Lat = Lb,
append(ABasis,BBasis,CBasis),
combine(PrioA,PrioB,PrioC),
put_attr(Y,class,class(La,Lbt,CBasis,PrioC)).
attr_unify_hook(_,_).
class_new(Class,All,AllT,Basis) :-
put_attr(Su,class,class(All,AllT,Basis,[])),
Su = Class.
class_get_prio(Class,Priority) :- get_attr(Class,class,class(_,_,_,Priority)).
class_put_prio(Class,Priority) :-
get_attr(Class,class,class(All,AllT,Basis,_)),
put_attr(Class,class,class(All,AllT,Basis,Priority)).
class_drop(Class,X) :-
get_attr(Class,class,class(Allvars,Tail,Basis,Priority)),
delete_first(Allvars,X,NewAllvars),
delete_first(Basis,X,NewBasis),
put_attr(Class,class,class(NewAllvars,Tail,NewBasis,Priority)).
class_allvars(Class,All) :- get_attr(Class,class,class(All,_,_,_)).
% class_basis(Class,Basis)
%
% Returns the basis of class Class.
class_basis(Class,Basis) :- get_attr(Class,class,class(_,_,Basis,_)).
% class_basis_add(Class,X,NewBasis)
%
% adds X in front of the basis and returns the new basis
class_basis_add(Class,X,NewBasis) :-
NewBasis = [X|Basis],
get_attr(Class,class,class(All,AllT,Basis,Priority)),
put_attr(Class,class,class(All,AllT,NewBasis,Priority)).
% class_basis_drop(Class,X)
%
% removes the first occurence of X from the basis (if exists)
class_basis_drop(Class,X) :-
get_attr(Class,class,class(All,AllT,Basis0,Priority)),
delete_first(Basis0,X,Basis),
Basis0 \== Basis, % anything deleted ?
!,
put_attr(Class,class,class(All,AllT,Basis,Priority)).
class_basis_drop(_,_).
% class_basis_pivot(Class,Enter,Leave)
%
% removes first occurence of Leave from the basis and adds Enter in front of the basis
class_basis_pivot(Class,Enter,Leave) :-
get_attr(Class,class,class(All,AllT,Basis0,Priority)),
delete_first(Basis0,Leave,Basis1),
put_attr(Class,class,class(All,AllT,[Enter|Basis1],Priority)).
% delete_first(Old,Element,New)
%
% removes the first occurence of Element from Old and returns the result in New
%
% note: test via syntactic equality, not unifiability
delete_first(L,_,Res) :-
var(L),
!,
Res = L.
delete_first([],_,[]).
delete_first([Y|Ys],X,Res) :-
(
X==Y ->
Res = Ys
;
Res = [Y|Tail],
delete_first( Ys, X, Tail)
).

341
LGPL/clpr/clpr/dump.pl Normal file
View File

@ -0,0 +1,341 @@
/* $Id: dump.pl,v 1.1 2005-10-28 17:51:01 vsc Exp $
Part of CPL(R) (Constraint Logic Programming over Reals)
Author: Leslie De Koninck
E-mail: Tom.Schrijvers@cs.kuleuven.ac.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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(dump,
[
dump/3,
projecting_assert/1
]).
:- use_module(class,
[
class_allvars/2
]).
:- use_module(geler,
[
collect_nonlin/3
]).
:- use_module(library(assoc),
[
empty_assoc/1,
get_assoc/3,
put_assoc/4,
assoc_to_list/2
]).
:- use_module(itf3,
[
dump_linear/4,
dump_nonzero/4
]).
:- use_module(project,
[
project_attributes/2
]).
:- use_module(ordering,
[ ordering/1
]).
:- dynamic blackboard_copy/1. % replacement of bb_put and bb_delete by dynamic predicate
this_linear_solver(clpr).
% dump(Target,NewVars,Constraints)
%
% Returns in Constraints, the constraints that currently hold on Target where all variables
% in Target are copied to new variables in NewVars and the constraints are given on these new
% variables. In short, you can safely manipulate NewVars and Constraints without changing the
% constraints on Target.
dump([],[],[]).
dump(Target,NewVars,Constraints) :-
(
(
proper_varlist(Target) ->
true
;
% Target is not a list of variables
raise_exception(instantiation_error(dump(Target,NewVars,Constraints),1))
),
ordering(Target),
related_linear_vars(Target,All), % All contains all variables of the classes of Target variables.
nonlin_crux(All,Nonlin),
project_attributes(Target,All),
related_linear_vars(Target,Again), % project drops/adds vars
all_attribute_goals(Again,Gs,Nonlin),
empty_assoc(D0),
mapping(Target,NewVars,D0,D1), % late (AVL suffers from put_atts)
copy(Gs,Copy,D1,_), % strip constraints
(
blackboard_copy(_) ->
retract(blackboard_copy(_)),
assert(blackboard_copy(NewVars/Copy))
;
assert(blackboard_copy(NewVars/Copy))
),
fail % undo projection
;
retract(blackboard_copy(NewVars/Constraints)) % garbage collect
).
:- meta_predicate projecting_assert(:).
projecting_assert(QClause) :-
strip_module(QClause, Module, Clause), % JW: SWI-Prolog not always qualifies the term!
copy_term(Clause,Copy,Constraints),
l2c(Constraints,Conj), % fails for []
this_linear_solver(Sm), % proper module for {}/1
!,
(
Copy = (H:-B) -> % former rule
Module:assert((H:-Sm:{Conj},B))
; % former fact
Module:assert((Copy:-Sm:{Conj}))
).
projecting_assert(Clause) :- % not our business
assert(Clause).
copy_term(Term,Copy,Constraints) :-
(
term_variables(Term,Target), % get all variables in Term
related_linear_vars(Target,All), % get all variables of the classes of the variables in Term
nonlin_crux(All,Nonlin), % get a list of all the nonlinear goals of these variables
project_attributes(Target,All),
related_linear_vars(Target,Again), % project drops/adds vars
all_attribute_goals(Again,Gs,Nonlin),
empty_assoc(D0),
copy(Term/Gs,TmpCopy,D0,_), % strip constraints
(
blackboard_copy(_) ->
retract(blackboard_copy(_)),
assert(blackboard_copy(TmpCopy))
;
assert(blackboard_copy(TmpCopy))
),
fail % undo projection
;
retract(blackboard_copy(Copy/Constraints)) % garbage collect
).
% l2c(Lst,Conj)
%
% converts a list to a round list: [a,b,c] -> (a,b,c) and [a] becomes a
l2c([X|Xs],Conj) :-
(
Xs = [] ->
Conj = X
;
Conj = (X,Xc),
l2c(Xs,Xc)
).
% proper_varlist(List)
%
% Returns whether Lst is a list of variables.
% First predicate is to avoid unification of a variable with a list.
proper_varlist(X) :-
var(X),
!,
fail.
proper_varlist([]).
proper_varlist([X|Xs]) :-
var(X),
proper_varlist(Xs).
% related_linear_vars(Vs,All)
%
% Generates a list of all variables that are in the classes of the variables in Vs.
related_linear_vars(Vs,All) :-
empty_assoc(S0),
related_linear_sys(Vs,S0,Sys),
related_linear_vars(Sys,All,[]).
% related_linear_sys(Vars,Assoc,List)
%
% Generates in List, a list of all to classes to which variables in Vars belong.
% Assoc should be an empty association list and is used internally.
% List contains elements of the form C-C where C is a class and both C's are equal.
related_linear_sys([],S0,L0) :- assoc_to_list(S0,L0).
related_linear_sys([V|Vs],S0,S2) :-
(
get_attr(V,itf3,(_,_,_,_,class(C),_)) ->
put_assoc(C,S0,C,S1)
;
S1 = S0
),
related_linear_sys(Vs,S1,S2).
% related_linear_vars(Classes,[Vars|VarsTail],VarsTail)
%
% Generates a difference list of all variables in the classes in Classes.
% Classes contains elements of the form C-C where C is a class and both C's are equal.
related_linear_vars([]) --> [].
related_linear_vars([S-_|Ss]) -->
{
class_allvars(S,Otl)
},
cpvars(Otl),
related_linear_vars(Ss).
% cpvars(Vars,Out,OutTail)
%
% Makes a new difference list of the difference list Vars.
% All nonvars are removed.
cpvars(Xs) --> {var(Xs)}, !.
cpvars([X|Xs]) -->
(
{var(X)} ->
[X]
;
[]
),
cpvars(Xs).
% nonlin_crux(All,Gss)
%
% Collects all pending non-linear constraints of variables in All.
% This marks all nonlinear goals of the variables as run and cannot
% be reversed manually.
nonlin_crux(All,Gss) :-
collect_nonlin(All,Gs,[]), % collect the nonlinear goals of variables All
% this marks the goals as run and cannot be reversed manually
this_linear_solver(Solver),
nonlin_strip(Gs,Solver,Gss).
% nonlin_strip(Gs,Solver,Res)
%
% Removes the goals from Gs that are not from solver Solver.
nonlin_strip([],_,[]).
nonlin_strip([M:What|Gs],Solver,Res) :-
(
M == Solver ->
(
What = {G} ->
Res = [G|Gss]
;
Res = [What|Gss]
)
;
Res = Gss
),
nonlin_strip(Gs,Solver,Gss).
all_attribute_goals([]) --> [].
all_attribute_goals([V|Vs]) -->
dump_linear(V,toplevel),
dump_nonzero(V,toplevel),
all_attribute_goals(Vs).
% mapping(L1,L2,AssocIn,AssocOut)
%
% Makes an association mapping of lists L1 and L2:
% L1 = [L1H|L1T] and L2 = [L2H|L2T] then the association L1H-L2H is formed
% and the tails are mapped similarly.
mapping([],[],D0,D0).
mapping([T|Ts],[N|Ns],D0,D2) :-
put_assoc(T,D0,N,D1),
mapping(Ts,Ns,D1,D2).
% copy(Term,Copy,AssocIn,AssocOut)
%
% Makes a copy of Term by changing all variables in it to new ones and
% building an association between original variables and the new ones.
% E.g. when Term = test(A,B,C), Copy = test(D,E,F) and an association between
% A and D, B and E and C and F is formed in AssocOut. AssocIn is input association.
copy(Term,Copy,D0,D1) :-
var(Term),
(
get_assoc(Term,D0,New) ->
Copy = New,
D1 = D0
;
put_assoc(Term,D0,Copy,D1)
).
copy(Term,Copy,D0,D1) :-
nonvar(Term), % Term is a functor
functor(Term,N,A),
functor(Copy,N,A), % Copy is new functor with the same name and arity as Term
copy(A,Term,Copy,D0,D1).
% copy(Nb,Term,Copy,AssocIn,AssocOut)
%
% Makes a copy of the Nb arguments of Term by changing all variables in it to
% new ones and building an association between original variables and the new ones.
% See also copy/4
copy(0,_,_,D0,D0) :- !.
copy(1,T,C,D0,D1) :-
!,
arg(1,T,At1),
arg(1,C,Ac1),
copy(At1,Ac1,D0,D1).
copy(2,T,C,D0,D2) :- !,
arg(1,T,At1),
arg(1,C,Ac1),
copy(At1,Ac1,D0,D1),
arg(2,T,At2),
arg(2,C,Ac2),
copy(At2,Ac2,D1,D2).
copy(N,T,C,D0,D2) :-
arg(N,T,At),
arg(N,C,Ac),
copy(At,Ac,D0,D1),
N1 is N-1,
copy(N1,T,C,D1,D2).
end_of_file.

499
LGPL/clpr/clpr/fourmotz.pl Normal file
View File

@ -0,0 +1,499 @@
/* $Id: fourmotz.pl,v 1.1 2005-10-28 17:51:01 vsc Exp $
Part of CPL(R) (Constraint Logic Programming over Reals)
Author: Leslie De Koninck
E-mail: Tom.Schrijvers@cs.kuleuven.ac.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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(fourmotz,
[
fm_elim/3
]).
:- use_module(bv,
[
allvars/2,
basis_add/2,
detach_bounds/1,
pivot/4,
var_with_def_intern/4
]).
:- use_module(class,
[
class_allvars/2
]).
:- use_module(project,
[
drop_dep/1,
drop_dep_one/1,
make_target_indep/2
]).
:- use_module(redund,
[
redundancy_vars/1
]).
:- use_module(store,
[
add_linear_11/3,
add_linear_f1/4,
indep/2,
nf_coeff_of/3,
normalize_scalar/2
]).
fm_elim(Vs,Target,Pivots) :-
prefilter(Vs,Vsf),
fm_elim_int(Vsf,Target,Pivots).
% prefilter(Vars,Res)
%
% filters out target variables and variables that do not occur in bounded linear equations.
% Stores that the variables in Res are to be kept independent.
prefilter([],[]).
prefilter([V|Vs],Res) :-
(
get_attr(V,itf3,(Ty,St,Li,Or,Cl,Fo,No,n,_,Ke)),
occurs(V) -> % V is a nontarget variable that occurs in a bounded linear equation
Res = [V|Tail],
put_attr(V,itf3,(Ty,St,Li,Or,Cl,Fo,No,n,keep_indep,Ke)),
prefilter(Vs,Tail)
;
prefilter(Vs,Res)
).
%
% the target variables are marked with an attribute, and we get a list
% of them as an argument too
%
fm_elim_int([],_,Pivots) :- % done
unkeep(Pivots).
fm_elim_int(Vs,Target,Pivots) :-
Vs = [_|_],
(
best(Vs,Best,Rest) ->
occurences(Best,Occ),
elim_min(Best,Occ,Target,Pivots,NewPivots)
; % give up
NewPivots = Pivots,
Rest = []
),
fm_elim_int(Rest,Target,NewPivots).
% best(Vs,Best,Rest)
%
% Finds the variable with the best result (lowest Delta) in fm_cp_filter
% and returns the other variables in Rest.
best(Vs,Best,Rest) :-
findall(Delta-N,fm_cp_filter(Vs,Delta,N),Deltas),
keysort(Deltas,[_-N|_]),
select_nth(Vs,N,Best,Rest).
% fm_cp_filter(Vs,Delta,N)
%
% For an indepenent variable V in Vs, which is the N'th element in Vs,
% find how many inequalities are generated when this variable is eliminated.
% Note that target variables and variables that only occur in unbounded equations
% should have been removed from Vs via prefilter/2
fm_cp_filter(Vs,Delta,N) :-
length(Vs,Len), % Len = number of variables in Vs
mem(Vs,X,Vst), % Selects a variable X in Vs, Vst is the list of elements after X in Vs
get_attr(X,itf3,(_,_,lin(Lin),order(OrdX),_,_,_,n,_)), % no target variable
indep(Lin,OrdX), % X is an independent variable
occurences(X,Occ),
Occ = [_|_],
cp_card(Occ,0,Lnew),
length(Occ,Locc),
Delta is Lnew-Locc,
length(Vst,Vstl),
N is Len-Vstl. % X is the Nth element in Vs
% mem(Xs,X,XsT)
%
% If X is a member of Xs, XsT is the list of elements after X in Xs.
mem([X|Xs],X,Xs).
mem([_|Ys],X,Xs) :- mem(Ys,X,Xs).
% select_nth(List,N,Nth,Others)
%
% Selects the N th element of List, stores it in Nth and returns the rest of the list in Others.
select_nth(List,N,Nth,Others) :-
select_nth(List,1,N,Nth,Others).
select_nth([X|Xs],N,N,X,Xs) :- !.
select_nth([Y|Ys],M,N,X,[Y|Xs]) :-
M1 is M+1,
select_nth(Ys,M1,N,X,Xs).
%
% fm_detach + reverse_pivot introduce indep t_none, which
% invalidates the invariants
%
elim_min(V,Occ,Target,Pivots,NewPivots) :-
crossproduct(Occ,New,[]),
activate_crossproduct(New),
reverse_pivot(Pivots),
fm_detach(Occ),
allvars(V,All),
redundancy_vars(All), % only for New \== []
make_target_indep(Target,NewPivots),
drop_dep(All).
%
% restore NF by reverse pivoting
%
reverse_pivot([]).
reverse_pivot([I:D|Ps]) :-
get_attr(D,itf3,(type(Dt),St,Li,Or,Cl,Fo,No,Ta,KI,_)),
put_attr(D,itf3,(type(Dt),St,Li,Or,Cl,Fo,No,Ta,KI,n)), % no longer
get_attr(I,itf3,(_,_,_,order(OrdI),class(ClI),_)),
pivot(D,ClI,OrdI,Dt),
reverse_pivot(Ps).
% unkeep(Pivots)
%
%
unkeep([]).
unkeep([_:D|Ps]) :-
get_attr(D,itf3,(Ty,St,Li,Or,Cl,Fo,No,Ta,KI,_)),
put_attr(D,itf3,(Ty,St,Li,Or,Cl,Fo,No,Ta,KI,n)),
drop_dep_one(D),
unkeep(Ps).
%
% All we drop are bounds
%
fm_detach( []).
fm_detach([V:_|Vs]) :-
detach_bounds(V),
fm_detach(Vs).
% activate_crossproduct(Lst)
%
% For each inequality Lin =< 0 (or Lin < 0) in Lst, a new variable is created:
% Var = Lin and Var =< 0 (or Var < 0). Var is added to the basis.
activate_crossproduct([]).
activate_crossproduct([lez(Strict,Lin)|News]) :-
Z = 0.0,
var_with_def_intern(t_u(Z),Var,Lin,Strict),
% Var belongs to same class as elements in Lin
basis_add(Var,_),
activate_crossproduct(News).
% ------------------------------------------------------------------------------
% crossproduct(Lst,Res,ResTail)
%
% See crossproduct/4
% This predicate each time puts the next element of Lst as First in crossproduct/4
% and lets the rest be Next.
crossproduct([]) --> [].
crossproduct([A|As]) -->
crossproduct(As,A),
crossproduct(As).
% crossproduct(Next,First,Res,ResTail)
%
% Eliminates a variable in linear equations First + Next and stores the generated
% inequalities in Res.
% Let's say A:K1 = First and B:K2 = first equation in Next.
% A = ... + K1*V + ...
% B = ... + K2*V + ...
% Let K = -K2/K1
% then K*A + B = ... + 0*V + ...
% from the bounds of A and B, via cross_lower/7 and cross_upper/7, new inequalities
% are generated. Then the same is done for B:K2 = next element in Next.
crossproduct([],_) --> [].
crossproduct([B:Kb|Bs],A:Ka) -->
{
get_attr(A,itf3,(type(Ta),strictness(Sa),lin(LinA),_)),
get_attr(B,itf3,(type(Tb),strictness(Sb),lin(LinB),_)),
K is -Kb/Ka,
add_linear_f1(LinA,K,LinB,Lin) % Lin doesn't contain the target variable anymore
},
(
{ 0.0 - K < -1e-010 } -> % K > 0: signs were opposite
{ Strict is Sa \/ Sb },
cross_lower(Ta,Tb,K,Lin,Strict),
cross_upper(Ta,Tb,K,Lin,Strict)
; % La =< A =< Ua -> -Ua =< -A =< -La
{
flip(Ta,Taf),
flip_strict(Sa,Saf),
Strict is Saf \/ Sb
},
cross_lower(Taf,Tb,K,Lin,Strict),
cross_upper(Taf,Tb,K,Lin,Strict)
),
crossproduct(Bs,A:Ka).
% cross_lower(Ta,Tb,K,Lin,Strict,Res,ResTail)
%
% Generates a constraint following from the bounds of A and B.
% When A = LinA and B = LinB then Lin = K*LinA + LinB. Ta is the type
% of A and Tb is the type of B. Strict is the union of the strictness
% of A and B. If K is negative, then Ta should have been flipped (flip/2).
% The idea is that if La =< A =< Ua and Lb =< B =< Ub (=< can also be <)
% then if K is positive, K*La + Lb =< K*A + B =< K*Ua + Ub.
% if K is negative, K*Ua + Lb =< K*A + B =< K*La + Ub.
% This predicate handles the first inequality and adds it to Res in the form
% lez(Sl,Lhs) meaning K*La + Lb - (K*A + B) =< 0 or K*Ua + Lb - (K*A + B) =< 0
% with Sl being the strictness and Lhs the lefthandside of the equation.
% See also cross_upper/7
cross_lower(Ta,Tb,K,Lin,Strict) -->
{
lower(Ta,La),
lower(Tb,Lb),
!,
L is K*La+Lb,
normalize_scalar(L,Ln),
Mone = -1.0,
add_linear_f1(Lin,Mone,Ln,Lhs),
Sl is Strict >> 1 % normalize to upper bound
},
[ lez(Sl,Lhs) ].
cross_lower(_,_,_,_,_) --> [].
% cross_upper(Ta,Tb,K,Lin,Strict,Res,ResTail)
%
% See cross_lower/7
% This predicate handles the second inequality:
% -(K*Ua + Ub) + K*A + B =< 0 or -(K*La + Ub) + K*A + B =< 0
cross_upper(Ta,Tb,K,Lin,Strict) -->
{
upper(Ta,Ua),
upper(Tb,Ub),
!,
U is -(K*Ua+Ub),
normalize_scalar(U,Un),
add_linear_11(Un,Lin,Lhs),
Su is Strict /\ 1 % normalize to upper bound
},
[ lez(Su,Lhs) ].
cross_upper(_,_,_,_,_) --> [].
% lower(Type,Lowerbound)
%
% Returns the lowerbound of type Type if it has one.
% E.g. if type = t_l(L) then Lowerbound is L,
% if type = t_lU(L,U) then Lowerbound is L,
% if type = t_u(U) then fails
lower(t_l(L),L).
lower(t_lu(L,_),L).
lower(t_L(L),L).
lower(t_Lu(L,_),L).
lower(t_lU(L,_),L).
% upper(Type,Upperbound)
%
% Returns the upperbound of type Type if it has one.
% See lower/2
upper(t_u(U),U).
upper(t_lu(_,U),U).
upper(t_U(U),U).
upper(t_Lu(_,U),U).
upper(t_lU(_,U),U).
% flip(Type,FlippedType)
%
% Flips the lower and upperbound, so the old lowerbound becomes the new upperbound and
% vice versa.
flip(t_l(X),t_u(X)).
flip(t_u(X),t_l(X)).
flip(t_lu(X,Y),t_lu(Y,X)).
flip(t_L(X),t_u(X)).
flip(t_U(X),t_l(X)).
flip(t_lU(X,Y),t_lu(Y,X)).
flip(t_Lu(X,Y),t_lu(Y,X)).
% flip_strict(Strict,FlippedStrict)
%
% Does what flip/2 does, but for the strictness.
flip_strict(0,0).
flip_strict(1,2).
flip_strict(2,1).
flip_strict(3,3).
% cp_card(Lst,CountIn,CountOut)
%
% Counts the number of bounds that may generate an inequality in
% crossproduct/3
cp_card([],Ci,Ci).
cp_card([A|As],Ci,Co) :-
cp_card(As,A,Ci,Cii),
cp_card(As,Cii,Co).
% cp_card(Next,First,CountIn,CountOut)
%
% Counts the number of bounds that may generate an inequality in
% crossproduct/4.
cp_card([],_,Ci,Ci).
cp_card([B:Kb|Bs],A:Ka,Ci,Co) :-
get_attr(A,itf3,(type(Ta),_)),
get_attr(B,itf3,(type(Tb),_)),
K is -Kb/Ka,
(
0.0- K < -1e-010 -> % K > 0: signs were opposite
cp_card_lower(Ta,Tb,Ci,Cii),
cp_card_upper(Ta,Tb,Cii,Ciii)
;
flip(Ta,Taf),
cp_card_lower(Taf,Tb,Ci,Cii),
cp_card_upper(Taf,Tb,Cii,Ciii)
),
cp_card(Bs,A:Ka,Ciii,Co).
% cp_card_lower(TypeA,TypeB,SIn,SOut)
%
% SOut = SIn + 1 if both TypeA and TypeB have a lowerbound.
cp_card_lower(Ta,Tb,Si,So) :-
lower(Ta,_),
lower(Tb,_),
!,
So is Si+1.
cp_card_lower(_,_,Si,Si).
% cp_card_upper(TypeA,TypeB,SIn,SOut)
%
% SOut = SIn + 1 if both TypeA and TypeB have an upperbound.
cp_card_upper(Ta,Tb,Si,So) :-
upper(Ta,_),
upper(Tb,_),
!,
So is Si+1.
cp_card_upper(_,_,Si,Si).
% ------------------------------------------------------------------------------
% occurences(V,Occ)
%
% Returns in Occ the occurrences of variable V in the linear equations of dependent variables
% with bound =\= t_none in the form of D:K where D is a dependent variable and K is the scalar
% of V in the linear equation of D.
occurences(V,Occ) :-
get_attr(V,itf3,(_,_,_,order(OrdV),class(C),_)),
class_allvars(C,All),
occurences(All,OrdV,Occ).
% occurences(De,OrdV,Occ)
%
% Returns in Occ the occurrences of variable V with order OrdV in the linear equations of
% dependent variables De with bound =\= t_none in the form of D:K where D is a dependent
% variable and K is the scalar of V in the linear equation of D.
occurences(De,_,[]) :-
var(De),
!.
occurences([D|De],OrdV,Occ) :-
(
get_attr(D,itf3,(type(Type),_,lin(Lin),_)),
occ_type_filter(Type),
nf_coeff_of(Lin,OrdV,K) ->
Occ = [D:K|Occt],
occurences(De,OrdV,Occt)
;
occurences(De,OrdV,Occ)
).
% occ_type_filter(Type)
%
% Succeeds when Type is any other type than t_none. Is used in occurences/3 and occurs/2
occ_type_filter(t_l(_)).
occ_type_filter(t_u(_)).
occ_type_filter(t_lu(_,_)).
occ_type_filter(t_L(_)).
occ_type_filter(t_U(_)).
occ_type_filter(t_lU(_,_)).
occ_type_filter(t_Lu(_,_)).
% occurs(V)
%
% Checks whether variable V occurs in a linear equation of a dependent variable with a bound
% =\= t_none.
occurs(V) :-
get_attr(V,itf3,(_,_,_,order(OrdV),class(C),_)),
class_allvars(C,All),
occurs(All,OrdV).
% occurs(De,OrdV)
%
% Checks whether variable V with order OrdV occurs in a linear equation of any dependent variable
% in De with a bound =\= t_none.
occurs(De,_) :-
var(De),
!,
fail.
occurs([D|De],OrdV) :-
(
get_attr(D,itf3,(type(Type),_,lin(Lin),_)),
occ_type_filter(Type),
nf_coeff_of(Lin,OrdV,_) ->
true
;
occurs(De,OrdV)
).

230
LGPL/clpr/clpr/geler.pl Normal file
View File

@ -0,0 +1,230 @@
/* $Id: geler.pl,v 1.1 2005-10-28 17:51:01 vsc Exp $
Part of CPL(R) (Constraint Logic Programming over Reals)
Author: Leslie De Koninck
E-mail: Tom.Schrijvers@cs.kuleuven.ac.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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(geler_r,
[
geler/2,
project_nonlin/3,
collect_nonlin/3
]).
%:- attribute goals/1, all_nonlin/1.
attribute_goal(X,Goals) :-
get_attr(X,geler_r,g(goals(Gs),_)),
nonexhausted(Gs,Goals,[]),
Goals = [_|_].
attribute_goal(X,Conj) :-
get_attr(X,geler_r,g(_,all_nonlin(Goals))),
l2conj(Goals,Conj).
% l2conj(List,Conj)
%
% turns a List into a conjunction of the form (El,Conj) where Conj
% is of the same form recursively and El is an element of the list
l2conj([X|Xs],Conj) :-
(
Xs = [],
Conj = X
;
Xs = [_|_],
Conj = (X,Xc),
l2conj(Xs,Xc)
).
% nonexhausted(Goals,OutList,OutListTail)
%
% removes the goals that have already run from Goals
% and puts the result in the difference list OutList
nonexhausted(run(Mutex,G)) -->
(
{var(Mutex)} ->
[G]
;
[]
).
nonexhausted((A,B)) -->
nonexhausted(A),
nonexhausted(B).
attr_unify_hook(g(goals(Gx),_),Y) :-
!,
(
var(Y),
(
% possibly mutual goals. these need to be run. other goals are run
% as well to remove redundant goals.
get_attr(Y,geler_r,g(goals(Gy),Other)) ->
Later = [Gx,Gy],
(
Other = n ->
del_attr(Y,geler_r)
;
put_attr(Y,geler_r,g(n,Other))
)
;
% no goals in Y, so no mutual goals of X and Y, store goals of X in Y
% no need to run any goal.
get_attr(Y,geler_r,g(n,Other)) ->
Later = [],
put_attr(Y,geler_r,g(goals(Gx),Other))
;
Later = [],
put_attr(Y,geler_r,g(goals(Gx),n))
)
;
nonvar(Y),
Later = [Gx]
),
call_list(Later).
attr_unify_hook(_,_). % no goals in X
% call_list(List)
%
% Calls all the goals in List.
call_list([]).
call_list([G|Gs]) :-
call(G),
call_list(Gs).
%
% called from project.pl
%
project_nonlin(_,Cvas,Reachable) :-
collect_nonlin(Cvas,L,[]),
sort(L,Ls),
term_variables(Ls,Reachable).
%put_attr(_,all_nonlin(Ls)).
collect_nonlin([]) --> [].
collect_nonlin([X|Xs]) -->
(
{get_attr(X,geler_r,g(goals(Gx),_))} ->
trans(Gx),
collect_nonlin(Xs)
;
collect_nonlin(Xs)
).
% trans(Goals,OutList,OutListTail)
%
% transforms the goals (of the form run(Mutex,Goal)
% that are in Goals (in the conjunction form, see also l2conj)
% that have not been run (var(Mutex) into a readable output format
% and notes that they're done (Mutex = done). Because of the Mutex
% variable, each goal is only added once (so not for each variable).
trans((A,B)) -->
trans(A),
trans(B).
trans(run(Mutex,Gs)) -->
(
{var(Mutex)} ->
{Mutex = done},
transg(Gs)
;
[]
).
transg((A,B)) -->
!,
transg(A),
transg(B).
transg(M:G) -->
!,
M:transg(G).
transg(G) --> [G].
% run(Mutex,G)
%
% Calls goal G if it has not yet run (Mutex is still variable)
% and stores that it has run (Mutex = done). This is done so
% that when X = Y and X and Y are in the same goal, that goal
% is called only once.
run(Mutex,_) :- nonvar(Mutex).
run(Mutex,G) :-
var(Mutex),
Mutex = done,
call(G).
% geler(Vars,Goal)
%
% called by nf.pl when an unsolvable non-linear expression is found
% Vars contain the variables of the expression, Goal contains the predicate of nf.pl to be called when
% the variables are bound.
geler(Vars,Goal) :-
attach(Vars,run(_Mutex,Goal)).
% one goal gets the same mutex on every var, so it is run only once
% attach(Vars,Goal)
%
% attaches a new goal to be awoken when the variables get bounded.
% when the old value of the attribute goals = OldGoal, then the new value = (Goal,OldGoal)
attach([],_).
attach([V|Vs],Goal) :-
(
var(V),
get_attr(V,geler_r,g(goals(Gv),Other)) ->
put_attr(V,geler_r,g(goals((Goal,Gv)),Other))
;
get_attr(V,geler_r,(n,Other)) ->
put_attr(V,geler_r,g(goals(Goal),Other))
;
put_attr(V,geler_r,g(goals(Goal),n))
),
attach(Vs,Goal).

1530
LGPL/clpr/clpr/ineq.pl Normal file

File diff suppressed because it is too large Load Diff

399
LGPL/clpr/clpr/itf3.pl Normal file
View File

@ -0,0 +1,399 @@
/* $Id: itf3.pl,v 1.1 2005-10-28 17:51:01 vsc Exp $
Part of CPL(R) (Constraint Logic Programming over Reals)
Author: Leslie De Koninck
E-mail: Tom.Schrijvers@cs.kuleuven.ac.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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.
*/
% attribute = (type(_),strictness(_),lin(_),order(_),class(_),forward(_),nonzero,
% target,keep_indep,keep)
:- module(itf3,
[
dump_linear/4,
dump_nonzero/4
]).
:- use_module(arith_r).
:- use_module(bv,
[
deref/2,
detach_bounds_vlv/5,
dump_var/6,
dump_nz/5,
solve/1,
solve_ord_x/3
]).
:- use_module(nf,
[
nf/2
]).
:- use_module(store,
[
add_linear_11/3,
indep/2,
nf_coeff_of/3
]).
:- use_module(class,
[
class_drop/2
]).
this_linear_solver(clpr).
%
% Parametrize the answer presentation mechanism
% (toplevel,compiler/debugger ...)
%
:- dynamic presentation_context/1.
% replaces the old presentation context by a new one.
presentation_context(Old,New) :-
clause(presentation_context(Current), _),
!,
Current = Old,
retractall(presentation_context(_)),
assert(presentation_context(New)).
presentation_context(toplevel,New) :- assert(presentation_context(New)). %default
%
% attribute_goal( V, V:Atts) :- get_atts( V, Atts).
%
attribute_goal(V,Goal) :-
presentation_context(Cont,Cont),
dump_linear(V,Cont,Goals,Gtail),
dump_nonzero(V,Cont,Gtail,[]),
l2wrapped(Goals,Goal).
l2wrapped([],true).
l2wrapped([X|Xs],Conj) :-
(
Xs = [],
wrap(X,Conj)
;
Xs = [_|_],
wrap(X,Xw),
Conj = (Xw,Xc),
l2wrapped(Xs,Xc)
).
%
% Tests should be pulled out of the loop ...
%
wrap(C,W) :-
prolog_flag(typein_module,Module),
this_linear_solver(Solver),
(
Module == Solver ->
W = {C}
;
predicate_property(Module:{_},imported_from(Solver)) ->
W = {C}
;
W = Solver:{C}
).
dump_linear(V,Context) -->
{
get_attr(V,itf3,(type(Type),_,lin(Lin),_)),
!,
Lin = [I,_|H]
},
%
% This happens if not all target variables can be made independend
% Example: examples/option.pl:
% | ?- go2(S,W).
%
% W = 21/4,
% S>=0,
% S<50 ? ;
%
% W>5,
% S=221/4-W, this line would be missing !!!
% W=<21/4
%
(
{Type=t_none; get_attr(V,itf3,(_,_,_,_,_,_,_,n,_))} ->
[]
;
dump_v(Context,t_none,V,I,H)
),
%
(
{Type=t_none, get_attr(V,itf3,(_,_,_,_,_,_,_,n,_)) } -> % nonzero produces such
[]
;
dump_v(Context,Type,V,I,H)
).
dump_linear(_,_) --> [].
dump_v(toplevel,Type,V,I,H) --> dump_var(Type,V,I,H).
% dump_v(compiler,Type,V,I,H) --> compiler_dump_var(Type,V,I,H).
dump_nonzero(V,Cont) -->
{
get_attr(V,itf3,(_,_,lin(Lin),_,_,_,nonzero,_)),
!,
Lin = [I,_|H]
},
dump_nz(Cont,V,H,I).
dump_nonzero(_,_) --> [].
dump_nz(toplevel,V,H,I) --> dump_nz(V,H,I).
% dump_nz(compiler,V,H,I) --> compiler_dump_nz(V,H,I).
numbers_only(Y) :-
var(Y),
!.
numbers_only(Y) :-
arith_normalize(Y,Y),
!.
numbers_only(Y) :-
this_linear_solver(Solver),
(
Solver == clpr ->
What = 'a real number'
;
Solver == clpq ->
What = 'a rational number'
),
raise_exception(type_error(_X = Y,2,What,Y)).
attr_unify_hook((n,n,n,n,n,n,n,_),_) :- !.
attr_unify_hook((_,_,_,_,_,forward(F),_),Y) :-
!,
fwd_deref(F,Y).
attr_unify_hook((Ty,St,Li,Or,Cl,_,No,_),Y) :-
% numbers_only(Y),
verify_nonzero(No,Y),
verify_type(Ty,St,Y,Later,[]),
verify_lin(Or,Cl,Li,Y),
call_list(Later).
% call_list(List)
%
% Calls all the goals in List.
call_list([]).
call_list([G|Gs]) :-
call(G),
call_list(Gs).
%%%%
fwd_deref(X,Y) :-
nonvar(X),
X = Y.
fwd_deref(X,Y) :-
var(X),
(
get_attr(X,itf3,itf(_,_,_,forward(F),_,_,_,_,_,_)) ->
fwd_deref(F,Y)
;
X = Y
).
% verify_nonzero(Nonzero,Y)
%
% if Nonzero = nonzero, then verify that Y is not zero
% (if possible, otherwise set Y to be nonzero)
verify_nonzero(nonzero,Y) :-
!,
(
var(Y) ->
(
get_attr(Y,itf3,itf(A,B,C,D,E,F,_,H,I,J)) ->
put_attr(Y,itf3,itf(A,B,C,D,E,F,nonzero,H,I,J))
;
put_attr(Y,itf3,itf(n,n,n,n,n,n,nonzero,n,n,n))
)
;
TestY = Y - 0.0, % Y =\= 0
(
TestY < -1e-010 ->
true
;
TestY > 1e-010
)
).
verify_nonzero(_,_). % X is not nonzero
% verify_type(type(Type),strictness(Strict),Y,[OL|OLT],OLT)
%
% if possible verifies whether Y satisfies the type and strictness of X
% if not possible to verify, then returns the constraints that follow from
% the type and strictness
verify_type(type(Type),strictness(Strict),Y) -->
!,
verify_type2(Y,Type,Strict).
verify_type(_,_,_) --> [].
verify_type2(Y,TypeX,StrictX) -->
{var(Y)},
!,
verify_type_var(TypeX,Y,StrictX).
verify_type2(Y,TypeX,StrictX) -->
{verify_type_nonvar(TypeX,Y,StrictX)}.
% verify_type_nonvar(Type,Nonvar,Strictness)
%
% verifies whether the type and strictness are satisfied with the Nonvar
verify_type_nonvar(t_none,_,_). % no bounds
verify_type_nonvar(t_l(L),Value,S) :- ilb(S,L,Value). % passive lower bound
verify_type_nonvar(t_u(U),Value,S) :- iub(S,U,Value). % passive upper bound
verify_type_nonvar(t_lu(L,U),Value,S) :- % passive lower and upper bound
ilb(S,L,Value),
iub(S,U,Value).
verify_type_nonvar(t_L(L),Value,S) :- ilb(S,L,Value). % active lower bound
verify_type_nonvar(t_U(U),Value,S) :- iub(S,U,Value). % active upper bound
verify_type_nonvar(t_Lu(L,U),Value,S) :- % active lower and passive upper bound
ilb(S,L,Value),
iub(S,U,Value).
verify_type_nonvar(t_lU(L,U),Value,S) :- % passive lower and active upper bound
ilb(S,L,Value),
iub(S,U,Value).
% ilb(Strict,Lower,Value) & iub(Strict,Upper,Value)
%
% check whether Value is satisfiable with the given lower/upper bound and strictness
% strictness is encoded as follows:
% 2 = strict lower bound
% 1 = strict upper bound
% 3 = strict lower and upper bound
% 0 = no strict bounds
ilb(S,L,V) :-
S /\ 2 =:= 0,
!,
L - V < 1e-010.
ilb(_,L,V) :- L - V < -1e-010.
iub(S,U,V) :-
S /\ 1 =:= 0,
!,
V - U < 1e-010.
iub(_,U,V) :- V - U < -1e-010.
%
% Running some goals after X=Y simplifies the coding. It should be possible
% to run the goals here and taking care not to put_atts/2 on X ...
%
% verify_type_var(Type,Var,Strictness,[OutList|OutListTail],OutListTail)
%
% returns the inequalities following from a type and strictness satisfaction test with Var
verify_type_var(t_none,_,_) --> []. % no bounds, no inequalities
verify_type_var(t_l(L),Y,S) --> llb(S,L,Y). % passive lower bound
verify_type_var(t_u(U),Y,S) --> lub(S,U,Y). % passive upper bound
verify_type_var(t_lu(L,U),Y,S) --> % passive lower and upper bound
llb(S,L,Y),
lub(S,U,Y).
verify_type_var(t_L(L),Y,S) --> llb(S,L,Y). % active lower bound
verify_type_var(t_U(U),Y,S) --> lub(S,U,Y). % active upper bound
verify_type_var(t_Lu(L,U),Y,S) --> % active lower and passive upper bound
llb(S,L,Y),
lub(S,U,Y).
verify_type_var(t_lU(L,U),Y,S) --> % passive lower and active upper bound
llb(S,L,Y),
lub(S,U,Y).
% llb(Strict,Lower,Value,[OL|OLT],OLT) and lub(Strict,Upper,Value,[OL|OLT],OLT)
%
% returns the inequalities following from the lower and upper bounds and the strictness
% see also lb and ub
llb(S,L,V) -->
{S /\ 2 =:= 0},
!,
[{L =< V}].
llb(_,L,V) --> [{L < V}].
lub(S,U,V) -->
{S /\ 1 =:= 0},
!,
[{V =< U}].
lub(_,U,V) --> [{V < U}].
%
% We used to drop X from the class/basis to avoid trouble with subsequent
% put_atts/2 on X. Now we could let these dead but harmless updates happen.
% In R however, exported bindings might conflict, e.g. 0 \== 0.0
%
% If X is indep and we do _not_ solve for it, we are in deep shit
% because the ordering is violated.
%
verify_lin(order(OrdX),class(Class),lin(LinX),Y) :-
!,
(
indep(LinX,OrdX) ->
detach_bounds_vlv(OrdX,LinX,Class,Y,NewLinX), % if there were bounds, they are requeued already
class_drop(Class,Y),
nf(-Y,NfY),
deref(NfY,LinY),
add_linear_11(NewLinX,LinY,Lind),
(
nf_coeff_of(Lind,OrdX,_) -> % X is element of Lind
solve_ord_x(Lind,OrdX,Class)
;
solve(Lind) % X is gone, can safely solve Lind
)
;
class_drop(Class,Y),
nf(-Y,NfY),
deref(NfY,LinY),
add_linear_11(LinX,LinY,Lind),
solve(Lind)
).
verify_lin(_,_,_,_).

1251
LGPL/clpr/clpr/nf.pl Normal file

File diff suppressed because it is too large Load Diff

87
LGPL/clpr/clpr/nfr.pl Normal file
View File

@ -0,0 +1,87 @@
/* $Id: nfr.pl,v 1.1 2005-10-28 17:51:01 vsc Exp $
Part of CPL(R) (Constraint Logic Programming over Reals)
Author: Leslie De Koninck
E-mail: Tom.Schrijvers@cs.kuleuven.ac.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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(nfr,
[
transg/3
]).
:- use_module(nf,
[
nf2term/2
]).
% transg(Goal,[OutList|OutListTail],OutListTail)
%
% puts the equalities and inequalities that are implied by the elements in Goal
% in the difference list OutList
%
% called by geler.pl for project.pl
transg(resubmit_eq(Nf)) -->
{
nf2term([],Z),
nf2term(Nf,Term)
},
[clpr:{Term=Z}].
transg(resubmit_lt(Nf)) -->
{
nf2term([],Z),
nf2term(Nf,Term)
},
[clpr:{Term<Z}].
transg(resubmit_le(Nf)) -->
{
nf2term([],Z),
nf2term(Nf,Term)
},
[clpr:{Term=<Z}].
transg(resubmit_ne(Nf)) -->
{
nf2term([],Z),
nf2term(Nf,Term)
},
[clpr:{Term=\=Z}].
transg(wait_linear_retry(Nf,Res,Goal)) -->
{
nf2term(Nf,Term)
},
[clpr:{Term=Res},Goal].

210
LGPL/clpr/clpr/ordering.pl Normal file
View File

@ -0,0 +1,210 @@
/* $Id: ordering.pl,v 1.1 2005-10-28 17:51:01 vsc Exp $
Part of CPL(R) (Constraint Logic Programming over Reals)
Author: Leslie De Koninck
E-mail: Tom.Schrijvers@cs.kuleuven.ac.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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(ordering,
[
combine/3,
ordering/1,
arrangement/2
]).
:- use_module(class,
[
class_get_prio/2,
class_put_prio/2
]).
:- use_module(bv,
[
var_intern/2
]).
:- use_module(ugraphs,
[
add_edges/3,
add_vertices/3,
top_sort/2
]).
ordering(X) :-
var(X),
!,
fail.
ordering(A>B) :-
!,
ordering(B<A).
ordering(A<B) :-
join_class([A,B],Class),
class_get_prio(Class,Ga),
!,
add_edges([],[A-B],Gb),
combine(Ga,Gb,Gc),
class_put_prio(Class,Gc).
ordering(Pb) :-
Pb = [_|Xs],
join_class(Pb,Class),
class_get_prio(Class,Ga),
!,
(
Xs = [],
add_vertices([],Pb,Gb)
;
Xs=[_|_],
gen_edges(Pb,Es,[]),
add_edges([],Es,Gb)
),
combine(Ga,Gb,Gc),
class_put_prio(Class,Gc).
ordering(_).
arrangement(Class,Arr) :-
class_get_prio(Class,G),
normalize(G,Gn),
top_sort(Gn,Arr),
!.
arrangement(_,_) :- raise_exception(unsatisfiable_ordering).
join_class([],_).
join_class([X|Xs],Class) :-
(
var(X) ->
var_intern(X,Class)
;
true
),
join_class(Xs,Class).
% combine(Ga,Gb,Gc)
%
% Combines the vertices of Ga and Gb into Gc.
combine(Ga,Gb,Gc) :-
normalize(Ga,Gan),
normalize(Gb,Gbn),
ugraphs:graph_union(Gan,Gbn,Gc).
%
% both Ga and Gb might have their internal ordering invalidated
% because of bindings and aliasings
%
normalize([],[]) :- !.
normalize(G,Gsgn) :-
G = [_|_],
keysort(G,Gs), % sort vertices on key
group(Gs,Gsg), % concatenate vertices with the same key
normalize_vertices(Gsg,Gsgn). % normalize
normalize_vertices([],[]).
normalize_vertices([X-Xnb|Xs],Res) :-
(
normalize_vertex(X,Xnb,Xnorm) ->
Res = [Xnorm|Xsn],
normalize_vertices(Xs,Xsn)
;
normalize_vertices(Xs,Res)
).
% normalize_vertex(X,Nbs,X-Nbss)
%
% Normalizes a vertex X-Nbs into X-Nbss by sorting Nbs, removing duplicates (also of X)
% and removing non-vars.
normalize_vertex(X,Nbs,X-Nbsss) :-
var(X),
sort(Nbs,Nbss),
strip_nonvar(Nbss,X,Nbsss).
% strip_nonvar(Nbs,X,Res)
%
% Turns vertext X-Nbs into X-Res by removing occurrences of X from Nbs and removing
% non-vars. This to normalize after bindings have occurred. See also normalize_vertex/3.
strip_nonvar([],_,[]).
strip_nonvar([X|Xs],Y,Res) :-
(
X==Y -> % duplicate of Y
strip_nonvar(Xs,Y,Res)
;
var(X) -> % var: keep
Res = [X|Stripped],
strip_nonvar(Xs,Y,Stripped)
; % nonvar: remove
nonvar(X),
Res = [] % because Vars<anything
).
gen_edges([]) --> [].
gen_edges([X|Xs]) -->
gen_edges(Xs,X),
gen_edges(Xs).
gen_edges([],_) --> [].
gen_edges([Y|Ys],X) -->
[X-Y],
gen_edges(Ys,X).
% group(Vert,Res)
%
% Concatenates vertices with the same key.
group([],[]).
group([K-Kl|Ks],Res) :-
group(Ks,K,Kl,Res).
group([],K,Kl,[K-Kl]).
group([L-Ll|Ls],K,Kl,Res) :-
(
K==L ->
append(Kl,Ll,KLl),
group(Ls,K,KLl,Res)
;
Res = [K-Kl|Tail],
group(Ls,L,Ll,Tail)
).

286
LGPL/clpr/clpr/project.pl Normal file
View File

@ -0,0 +1,286 @@
/* $Id: project.pl,v 1.1 2005-10-28 17:51:01 vsc Exp $
Part of CPL(R) (Constraint Logic Programming over Reals)
Author: Leslie De Koninck
E-mail: Tom.Schrijvers@cs.kuleuven.ac.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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.
*/
%
% Answer constraint projection
%
%:- public project_attributes/2. % xref.pl
:- module(project,
[
drop_dep/1,
drop_dep_one/1,
make_target_indep/2,
project_attributes/2
]).
:- use_module(class,
[
class_allvars/2
]).
:- use_module(geler,
[
project_nonlin/3
]).
:- use_module(fourmotz,
[
fm_elim/3
]).
:- use_module(redund,
[
redundancy_vars/1,
systems/3
]).
:- use_module(bv,
[
pivot/4
]).
:- use_module(ordering,
[
arrangement/2
]).
:- use_module(store,
[
indep/2,
renormalize/2
]).
%
% interface predicate
%
% May be destructive (either acts on a copy or in a failure loop)
%
project_attributes(TargetVars,Cvas) :-
sort(TargetVars,Tvs), % duplicates ?
sort(Cvas,Avs), % duplicates ?
mark_target(Tvs),
project_nonlin(Tvs,Avs,NlReachable),
(
Tvs == [] ->
drop_lin_atts(Avs)
;
redundancy_vars(Avs), % removes redundant bounds (redund.pl)
make_target_indep(Tvs,Pivots), % pivot partners are marked to be kept during elim.
mark_target(NlReachable), % after make_indep to express priority
drop_dep(Avs),
fm_elim(Avs,Tvs,Pivots),
impose_ordering(Avs)
).
% mark_target(Vars)
%
% Marks the variables in Vars as target variables.
mark_target([]).
mark_target([V|Vs]) :-
get_attr(V,itf3,(Ty,St,Li,Or,Cl,Fo,No,_,RAtt)),
put_attr(V,itf3,(Ty,St,Li,Or,Cl,Fo,No,target,RAtt)),
mark_target(Vs).
% mark_keep(Vars)
%
% Mark the variables in Vars to be kept during elimination.
mark_keep([]).
mark_keep([V|Vs]) :-
get_attr(V,itf3,(Ty,St,Li,Or,Cl,Fo,No,Ta,KI,_)),
put_attr(V,itf3,(Ty,St,Li,Or,Cl,Fo,No,Ta,KI,keep)),
mark_keep(Vs).
%
% Collect the pivots in reverse order
% We have to protect the target variables pivot partners
% from redundancy eliminations triggered by fm_elim,
% in order to allow for reverse pivoting.
%
make_target_indep(Ts,Ps) :- make_target_indep(Ts,[],Ps).
% make_target_indep(Targets,Pivots,PivotsTail)
%
% Tries to make as many targetvariables independent by pivoting them with a non-target
% variable. The pivots are stored as T:NT where T is a target variable and NT a non-target
% variable. The non-target variables are marked to be kept during redundancy eliminations.
make_target_indep([],Ps,Ps).
make_target_indep([T|Ts],Ps0,Pst) :-
(
get_attr(T,itf3,(type(Type),_,lin(Lin),_)),
Lin = [_,_|H],
nontarget(H,Nt) ->
Ps1 = [T:Nt|Ps0],
get_attr(Nt,itf3,(Ty,St,Li,order(Ord),class(Class),Fo,No,Ta,KI,_)),
put_attr(Nt,itf3,(Ty,St,Li,order(Ord),class(Class),Fo,No,Ta,KI,keep)),
pivot(T,Class,Ord,Type)
;
Ps1 = Ps0
),
make_target_indep(Ts,Ps1,Pst).
% nontarget(Hom,Nt)
%
% Finds a nontarget variable in homogene part Hom.
% Hom contains elements of the form l(V*K,OrdV).
% A nontarget variable has no target attribute and no keep_indep attribute.
nontarget([l(V*_,_)|Vs],Nt) :-
(
get_attr(V,itf3,(_,_,_,_,_,_,_,n,n,_)) ->
Nt = V
;
nontarget(Vs,Nt)
).
% drop_dep(Vars)
%
% Does drop_dep_one/1 on each variable in Vars.
drop_dep(Vs) :-
var(Vs),
!.
drop_dep([]).
drop_dep([V|Vs]) :-
drop_dep_one(V),
drop_dep(Vs).
% drop_dep_one(V)
%
% If V is an unbounded dependent variable that isn't a target variable, shouldn't be kept
% and is not nonzero, drops all linear attributes of V.
% The linear attributes are: type, strictness, linear equation (lin), class and order.
drop_dep_one(V) :-
get_attr(V,itf3,(type(t_none),_,lin(Lin),order(OrdV),_,Fo,n,n,KI,n)),
\+ indep(Lin,OrdV),
!,
put_attr(V,itf3,(n,n,n,n,n,Fo,n,n,KI,n)).
drop_dep_one(_).
% drop_lin_atts(Vs)
%
% Removes the linear attributes of the variables in Vs.
% The linear attributes are type, strictness, linear equation (lin), order and class.
drop_lin_atts([]).
drop_lin_atts([V|Vs]) :-
get_attr(V,itf3,(_,_,_,_,_,RAtt)),
put_attr(V,itf3,(n,n,n,n,n,RAtt)),
drop_lin_atts(Vs).
impose_ordering(Cvas) :-
systems(Cvas,[],Sys),
impose_ordering_sys(Sys).
impose_ordering_sys([]).
impose_ordering_sys([S|Ss]) :-
arrangement(S,Arr), % ordering.pl
arrange(Arr,S),
impose_ordering_sys(Ss).
arrange([],_).
arrange(Arr,S) :-
Arr = [_|_],
class_allvars(S,All),
order(Arr,1,N),
order(All,N,_),
renorm_all(All),
arrange_pivot(All).
order(Xs,N,M) :-
var(Xs),
!,
N = M.
order([],N,N).
order([X|Xs],N,M) :-
(
get_attr(X,itf3,(_,_,_,order(O),_)),
var(O) ->
O = N,
N1 is N+1,
order(Xs,N1,M)
;
order(Xs,N,M)
).
% renorm_all(Vars)
%
% Renormalizes all linear equations of the variables in difference list Vars to reflect
% their new ordering.
renorm_all(Xs) :-
var(Xs),
!.
renorm_all([X|Xs]) :-
(
get_attr(X,itf3,(Ty,St,lin(Lin),RAtt)) ->
renormalize(Lin,New),
put_attr(X,itf3,(Ty,St,lin(New),RAtt)),
renorm_all(Xs)
;
renorm_all(Xs)
).
% arrange_pivot(Vars)
%
% If variable X of Vars has type t_none and has a higher order than the first element of
% its linear equation, then it is pivoted with that element.
arrange_pivot(Xs) :-
var(Xs),
!.
arrange_pivot([X|Xs]) :-
(
get_attr(X,itf3,(type(t_none),_,lin(Lin),order(OrdX),_)),
Lin = [_,_|[l(Y*_,_)|_]],
get_attr(Y,itf3,(_,_,_,order(OrdY),class(Class),_)),
compare(<,OrdY,OrdX) ->
pivot(X,Class,OrdY,t_none),
arrange_pivot(Xs)
;
arrange_pivot(Xs)
).

304
LGPL/clpr/clpr/redund.pl Normal file
View File

@ -0,0 +1,304 @@
/* $Id: redund.pl,v 1.1 2005-10-28 17:51:01 vsc Exp $
Part of CPL(R) (Constraint Logic Programming over Reals)
Author: Leslie De Koninck
E-mail: Tom.Schrijvers@cs.kuleuven.ac.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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(redund,
[
redundancy_vars/1,
systems/3
]).
:- use_module(bv,
[
detach_bounds/1,
intro_at/3
]).
:- use_module(class,
[
class_allvars/2
]).
:- use_module(nf, [{}/1]).
%
% redundancy removal (semantic definition)
%
% done:
% +) deal with active bounds
% +) indep t_[lu] -> t_none invalidates invariants (fixed)
%
% systems(Vars,SystemsIn,SystemsOut)
%
% Returns in SystemsOut the different classes to which variables in Vars
% belong. Every class only appears once in SystemsOut.
systems([],Si,Si).
systems([V|Vs],Si,So) :-
(
var(V),
get_attr(V,itf3,(_,_,_,_,class(C),_)),
not_memq(Si,C) ->
systems(Vs,[C|Si],So)
;
systems(Vs,Si,So)
).
% not_memq(Lst,El)
%
% Succeeds if El is not a member of Lst (doesn't use unification).
not_memq([],_).
not_memq([Y|Ys],X) :-
X \== Y,
not_memq(Ys,X).
% redundancy_systems(Classes)
%
% Does redundancy removal via redundancy_vs/1 on all variables in the classes Classes.
redundancy_systems([]).
redundancy_systems([S|Sys]) :-
class_allvars(S,All),
redundancy_vs(All),
redundancy_systems(Sys).
% redundancy_vars(Vs)
%
% Does the same thing as redundancy_vs/1 but has some extra timing facilities that
% may be used.
redundancy_vars(Vs) :-
!,
redundancy_vs(Vs).
redundancy_vars(Vs) :-
statistics(runtime,[Start|_]),
redundancy_vs(Vs),
statistics(runtime,[End|_]),
Duration is End-Start,
format(user_error,"% Redundancy elimination took ~d msec~n",Duration).
% redundancy_vs(Vs)
%
% Removes redundant bounds from the variables in Vs via redundant/3
redundancy_vs(Vs) :-
var(Vs),
!.
redundancy_vs([]).
redundancy_vs([V|Vs]) :-
(
get_attr(V,itf3,(type(Type),strictness(Strict),_)),
redundant(Type,V,Strict) ->
redundancy_vs(Vs)
;
redundancy_vs(Vs)
).
% redundant(Type,Var,Strict)
%
% Removes redundant bounds from variable Var with type Type and strictness Strict.
% A redundant bound is one that is satisfied anyway (so adding the inverse of the bound
% makes the system infeasible. This predicate can either fail or succeed but a success
% doesn't necessarily mean a redundant bound.
redundant(t_l(L),X,Strict) :-
detach_bounds(X), % drop temporarily
% if not redundant, backtracking will restore bound
negate_l(Strict,L,X),
red_t_l. % negate_l didn't fail, redundant bound
redundant(t_u(U),X,Strict) :-
detach_bounds(X),
negate_u(Strict,U,X),
red_t_u.
redundant(t_lu(L,U),X,Strict) :-
strictness_parts(Strict,Sl,Su),
(
get_attr(X,itf3,(_,_,RAtt)),
put_attr(X,itf3,(type(t_u(U)),strictness(Su),RAtt)),
negate_l(Strict,L,X) ->
red_t_l,
(
redundant(t_u(U),X,Strict) ->
true
;
true
)
;
get_attr(X,itf3,(_,_,RAtt)),
put_attr(X,itf3,(type(t_l(L)),strictness(Sl),RAtt)),
negate_u(Strict,U,X) ->
red_t_u
;
true
).
redundant(t_L(L),X,Strict) :-
Bound is -L,
intro_at(X,Bound,t_none), % drop temporarily
detach_bounds(X),
negate_l(Strict,L,X),
red_t_L.
redundant(t_U(U),X,Strict) :-
Bound is -U,
intro_at(X,Bound,t_none), % drop temporarily
detach_bounds(X),
negate_u(Strict,U,X),
red_t_U.
redundant(t_Lu(L,U),X,Strict) :-
strictness_parts(Strict,Sl,Su),
(
Bound is -L,
intro_at(X,Bound,t_u(U)),
get_attr(X,itf3,(Ty,_,RAtt)),
put_attr(X,itf3,(Ty,strictness(Su),RAtt)),
negate_l(Strict,L,X) ->
red_t_l,
(
redundant(t_u(U),X,Strict) ->
true
;
true
)
;
get_attr(X,itf3,(_,_,RAtt)),
put_attr(X,itf3,(type(t_L(L)),strictness(Sl),RAtt)),
negate_u(Strict,U,X) ->
red_t_u
;
true
).
redundant(t_lU(L,U),X,Strict) :-
strictness_parts(Strict,Sl,Su),
(
get_attr(X,itf3,(_,_,RAtt)),
put_attr(X,itf3,(type(t_U(U)),strictness(Su),RAtt)),
negate_l(Strict,L,X) ->
red_t_l,
(
redundant(t_U(U),X,Strict) ->
true
;
true
)
;
Bound is -U,
intro_at(X,Bound,t_l(L)),
get_attr(X,itf3,(Ty,_,RAtt)),
put_attr(X,itf3,(Ty,strictness(Sl),RAtt)),
negate_u(Strict,U,X) ->
red_t_u
;
true
).
% strictness_parts(Strict,Lower,Upper)
%
% Splits strictness Strict into two parts: one related to the lowerbound and
% one related to the upperbound.
strictness_parts(Strict,Lower,Upper) :-
Lower is Strict /\ 2,
Upper is Strict /\ 1.
% negate_l(Strict,Lowerbound,X)
%
% Fails if X does not necessarily satisfy the lowerbound and strictness
% In other words: if adding the inverse of the lowerbound (X < L or X =< L)
% does not result in a failure, this predicate fails.
negate_l(0,L,X) :-
{ L > X },
!,
fail.
negate_l(1,L,X) :-
{ L > X },
!,
fail.
negate_l(2,L,X) :-
{ L >= X },
!,
fail.
negate_l(3,L,X) :-
{ L >= X },
!,
fail.
negate_l(_,_,_).
% negate_u(Strict,Upperbound,X)
%
% Fails if X does not necessarily satisfy the upperbound and strictness
% In other words: if adding the inverse of the upperbound (X > U or X >= U)
% does not result in a failure, this predicate fails.
negate_u(0,U,X) :-
{ U < X },
!,
fail.
negate_u(1,U,X) :-
{ U =< X },
!,
fail.
negate_u(2,U,X) :-
{ U < X },
!,
fail.
negate_u(3,U,X) :-
{ U =< X },
!,
fail.
negate_u(_,_,_).
% Profiling: these predicates are called during redundant and can be used
% to count the number of redundant bounds.
red_t_l.
red_t_u.
red_t_L.
red_t_U.

485
LGPL/clpr/clpr/store.pl Normal file
View File

@ -0,0 +1,485 @@
/* $Id: store.pl,v 1.1 2005-10-28 17:51:01 vsc Exp $
Part of CPL(R) (Constraint Logic Programming over Reals)
Author: Leslie De Koninck
E-mail: Tom.Schrijvers@cs.kuleuven.ac.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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(store,
[
add_linear_11/3,
add_linear_f1/4,
add_linear_ff/5,
normalize_scalar/2,
delete_factor/4,
mult_linear_factor/3,
nf_rhs_x/4,
indep/2,
isolate/3,
nf_substitute/4,
mult_hom/3,
nf2sum/3,
nf_coeff_of/3,
renormalize/2
]).
:- use_module(arith_r,
[
arith_normalize/2
]).
% normalize_scalar(S,[N,Z])
%
% Transforms a scalar S into a linear expression [S,0]
normalize_scalar(S,[N,Z]) :-
arith_normalize(S,N),
Z = 0.0.
% renormalize(List,Lin)
%
% Renormalizes the not normalized linear expression in List into
% a normalized one. It does so to take care of unifications.
% (e.g. when a variable X is bound to a constant, the constant is added to
% the constant part of the linear expression; when a variable X is bound to
% another variable Y, the scalars of both are added)
renormalize(List,Lin) :-
List = [I,R|Hom],
length(Hom,Len),
renormalize_log(Len,Hom,[],Lin0),
add_linear_11([I,R],Lin0,Lin).
% renormalize_log(Len,Hom,HomTail,Lin)
%
% Logarithmically renormalizes the homogene part of a not normalized
% linear expression. See also renormalize/2.
renormalize_log(1,[Term|Xs],Xs,Lin) :-
!,
Term = l(X*_,_),
renormalize_log_one(X,Term,Lin).
renormalize_log(2,[A,B|Xs],Xs,Lin) :-
!,
A = l(X*_,_),
B = l(Y*_,_),
renormalize_log_one(X,A,LinA),
renormalize_log_one(Y,B,LinB),
add_linear_11(LinA,LinB,Lin).
renormalize_log(N,L0,L2,Lin) :-
P is N>>1,
Q is N-P,
renormalize_log(P,L0,L1,Lp),
renormalize_log(Q,L1,L2,Lq),
add_linear_11(Lp,Lq,Lin).
% renormalize_log_one(X,Term,Res)
%
% Renormalizes a term in X: if X is a nonvar, the term becomes a scalar.
renormalize_log_one(X,Term,Res) :-
var(X),
Term = l(X*K,_),
get_attr(X,itf3,(_,_,_,order(OrdX),_)), % Order might have changed
Z = 0.0,
Res = [Z,Z,l(X*K,OrdX)].
renormalize_log_one(X,Term,Res) :-
nonvar(X),
Term = l(X*K,_),
Xk is X*K,
normalize_scalar(Xk,Res).
% ----------------------------- sparse vector stuff ---------------------------- %
% add_linear_ff(LinA,Ka,LinB,Kb,LinC)
%
% Linear expression LinC is the result of the addition of the 2 linear expressions
% LinA and LinB, each one multiplied by a scalar (Ka for LinA and Kb for LinB).
add_linear_ff(LinA,Ka,LinB,Kb,LinC) :-
LinA = [Ia,Ra|Ha],
LinB = [Ib,Rb|Hb],
LinC = [Ic,Rc|Hc],
Ic is Ia*Ka+Ib*Kb,
Rc is Ra*Ka+Rb*Kb,
add_linear_ffh(Ha,Ka,Hb,Kb,Hc).
% add_linear_ffh(Ha,Ka,Hb,Kb,Hc)
%
% Homogene part Hc is the result of the addition of the 2 homogene parts Ha and Hb,
% each one multiplied by a scalar (Ka for Ha and Kb for Hb)
add_linear_ffh([],_,Ys,Kb,Zs) :- mult_hom(Ys,Kb,Zs).
add_linear_ffh([l(X*Kx,OrdX)|Xs],Ka,Ys,Kb,Zs) :-
add_linear_ffh(Ys,X,Kx,OrdX,Xs,Zs,Ka,Kb).
% add_linear_ffh(Ys,X,Kx,OrdX,Xs,Zs,Ka,Kb)
%
% Homogene part Zs is the result of the addition of the 2 homogene parts Ys and
% [l(X*Kx,OrdX)|Xs], each one multiplied by a scalar (Ka for [l(X*Kx,OrdX)|Xs] and Kb for Ys)
add_linear_ffh([],X,Kx,OrdX,Xs,Zs,Ka,_) :- mult_hom([l(X*Kx,OrdX)|Xs],Ka,Zs).
add_linear_ffh([l(Y*Ky,OrdY)|Ys],X,Kx,OrdX,Xs,Zs,Ka,Kb) :-
compare(Rel,OrdX,OrdY),
(
Rel = (=),
!,
Kz is Kx*Ka+Ky*Kb,
(
TestKz is Kz - 0.0, % Kz =:= 0
TestKz =< 1e-010,
TestKz >= -1e-010 ->
!,
add_linear_ffh(Xs,Ka,Ys,Kb,Zs)
;
Zs = [l(X*Kz,OrdX)|Ztail],
add_linear_ffh(Xs,Ka,Ys,Kb,Ztail)
)
;
Rel = (<),
!,
Zs = [l(X*Kz,OrdX)|Ztail],
Kz is Kx*Ka,
add_linear_ffh(Xs,Y,Ky,OrdY,Ys,Ztail,Kb,Ka)
;
Rel = (>),
!,
Zs = [l(Y*Kz,OrdY)|Ztail],
Kz is Ky*Kb,
add_linear_ffh(Ys,X,Kx,OrdX,Xs,Ztail,Ka,Kb)
).
% add_linear_f1(LinA,Ka,LinB,LinC)
%
% special case of add_linear_ff with Kb = 1
add_linear_f1(LinA,Ka,LinB,LinC) :-
LinA = [Ia,Ra|Ha],
LinB = [Ib,Rb|Hb],
LinC = [Ic,Rc|Hc],
Ic is Ia*Ka+Ib,
Rc is Ra*Ka+Rb,
add_linear_f1h(Ha,Ka,Hb,Hc).
% add_linear_f1h(Ha,Ka,Hb,Hc)
%
% special case of add_linear_ffh/5 with Kb = 1
add_linear_f1h([],_,Ys,Ys).
add_linear_f1h([l(X*Kx,OrdX)|Xs],Ka,Ys,Zs) :-
add_linear_f1h(Ys,X,Kx,OrdX,Xs,Zs,Ka).
% add_linear_f1h(Ys,X,Kx,OrdX,Xs,Zs,Ka)
%
% special case of add_linear_ffh/8 with Kb = 1
add_linear_f1h([],X,Kx,OrdX,Xs,Zs,Ka) :- mult_hom([l(X*Kx,OrdX)|Xs],Ka,Zs).
add_linear_f1h([l(Y*Ky,OrdY)|Ys],X,Kx,OrdX,Xs,Zs,Ka) :-
compare(Rel,OrdX,OrdY),
(
Rel = (=),
!,
Kz is Kx*Ka+Ky,
(
TestKz is Kz - 0.0, % Kz =:= 0
TestKz =< 1e-010,
TestKz >= -1e-010 ->
!,
add_linear_f1h(Xs,Ka,Ys,Zs)
;
Zs = [l(X*Kz,OrdX)|Ztail],
add_linear_f1h(Xs,Ka,Ys,Ztail)
)
;
Rel = (<),
!,
Zs = [l(X*Kz,OrdX)|Ztail],
Kz is Kx*Ka,
add_linear_f1h(Xs,Ka,[l(Y*Ky,OrdY)|Ys],Ztail)
;
Rel = (>),
!,
Zs = [l(Y*Ky,OrdY)|Ztail],
add_linear_f1h(Ys,X,Kx,OrdX,Xs,Ztail,Ka)
).
% add_linear_11(LinA,LinB,LinC)
%
% special case of add_linear_ff with Ka = 1 and Kb = 1
add_linear_11(LinA,LinB,LinC) :-
LinA = [Ia,Ra|Ha],
LinB = [Ib,Rb|Hb],
LinC = [Ic,Rc|Hc],
Ic is Ia+Ib,
Rc is Ra+Rb,
add_linear_11h(Ha,Hb,Hc).
% add_linear_11h(Ha,Hb,Hc)
%
% special case of add_linear_ffh/5 with Ka = 1 and Kb = 1
add_linear_11h([],Ys,Ys).
add_linear_11h([l(X*Kx,OrdX)|Xs],Ys,Zs) :-
add_linear_11h(Ys,X,Kx,OrdX,Xs,Zs).
% add_linear_11h(Ys,X,Kx,OrdX,Xs,Zs)
%
% special case of add_linear_ffh/8 with Ka = 1 and Kb = 1
add_linear_11h([],X,Kx,OrdX,Xs,[l(X*Kx,OrdX)|Xs]).
add_linear_11h([l(Y*Ky,OrdY)|Ys],X,Kx,OrdX,Xs,Zs) :-
compare(Rel,OrdX,OrdY),
(
Rel = (=),
!,
Kz is Kx+Ky,
(
TestKz is Kz - 0.0, % Kz =:= 0
TestKz =< 1e-010,
TestKz >= -1e-010 ->
!,
add_linear_11h(Xs,Ys,Zs)
;
Zs = [l(X*Kz,OrdX)|Ztail],
add_linear_11h(Xs,Ys,Ztail)
)
;
Rel = (<),
!,
Zs = [l(X*Kx,OrdX)|Ztail],
add_linear_11h(Xs,Y,Ky,OrdY,Ys,Ztail)
;
Rel = (>),
!,
Zs = [l(Y*Ky,OrdY)|Ztail],
add_linear_11h(Ys,X,Kx,OrdX,Xs,Ztail)
).
% mult_linear_factor(Lin,K,Res)
%
% Linear expression Res is the result of multiplication of linear
% expression Lin by scalar K
mult_linear_factor(Lin,K,Mult) :-
TestK is K - 1.0, % K =:= 1
TestK =< 1e-010,
TestK >= -1e-010, % avoid copy
!,
Mult = Lin.
mult_linear_factor(Lin,K,Res) :-
Lin = [I,R|Hom],
Res = [Ik,Rk|Mult],
Ik is I*K,
Rk is R*K,
mult_hom(Hom,K,Mult).
% mult_hom(Hom,K,Res)
%
% Homogene part Res is the result of multiplication of homogene part
% Hom by scalar K
mult_hom([],_,[]).
mult_hom([l(A*Fa,OrdA)|As],F,[l(A*Fan,OrdA)|Afs]) :-
Fan is F*Fa,
mult_hom(As,F,Afs).
% nf_substitute(Ord,Def,Lin,Res)
%
% Linear expression Res is the result of substitution of Var in
% linear expression Lin, by its definition in the form of linear
% expression Def
nf_substitute(OrdV,LinV,LinX,LinX1) :-
delete_factor(OrdV,LinX,LinW,K),
add_linear_f1(LinV,K,LinW,LinX1).
% delete_factor(Ord,Lin,Res,Coeff)
%
% Linear expression Res is the result of the deletion of the term
% Var*Coeff where Var has ordering Ord from linear expression Lin
delete_factor(OrdV,Lin,Res,Coeff) :-
Lin = [I,R|Hom],
Res = [I,R|Hdel],
delete_factor_hom(OrdV,Hom,Hdel,Coeff).
% delete_factor_hom(Ord,Hom,Res,Coeff)
%
% Homogene part Res is the result of the deletion of the term
% Var*Coeff from homogene part Hom
delete_factor_hom(VOrd,[Car|Cdr],RCdr,RKoeff) :-
Car = l(_*Koeff,Ord),
compare(Rel,VOrd,Ord),
(
Rel= (=),
!,
RCdr = Cdr,
RKoeff=Koeff
;
Rel= (>),
!,
RCdr = [Car|RCdr1],
delete_factor_hom(VOrd,Cdr,RCdr1,RKoeff)
).
% nf_coeff_of(Lin,OrdX,Coeff)
%
% Linear expression Lin contains the term l(X*Coeff,OrdX)
nf_coeff_of(Lin,VOrd,Coeff) :-
Lin = [_,_|Hom],
nf_coeff_hom(Hom,VOrd,Coeff),
!.
% nf_coeff_hom(Lin,OrdX,Coeff)
%
% Linear expression Lin contains the term l(X*Coeff,OrdX) where the
% order attribute of X = OrdX
nf_coeff_hom([l(_*K,OVar)|Vs],OVid,Coeff) :-
compare(Rel,OVid,OVar),
(
Rel = (=),
!,
Coeff = K
;
Rel = (>),
!,
nf_coeff_hom(Vs,OVid,Coeff)
).
% nf_rhs_x(Lin,OrdX,Rhs,K)
%
% Rhs = R + I where Lin = [I,R|Hom] and l(X*K,OrdX) is a term of Hom
nf_rhs_x(Lin,OrdX,Rhs,K) :-
Lin = [I,R|Tail],
nf_coeff_hom(Tail,OrdX,K),
Rhs is R+I. % late because X may not occur in H
% isolate(OrdN,Lin,Lin1)
%
% Linear expression Lin1 is the result of the transformation of linear expression
% Lin = 0 which contains the term l(New*K,OrdN) into an equivalent expression Lin1 = New.
isolate(OrdN,Lin,Lin1) :-
delete_factor(OrdN,Lin,Lin0,Coeff),
K is -1.0/Coeff,
mult_linear_factor(Lin0,K,Lin1).
% indep(Lin,OrdX)
%
% succeeds if Lin = [0,_|[l(X*1,OrdX)]]
indep(Lin,OrdX) :-
Lin = [I,_|[l(_*K,OrdY)]],
OrdX == OrdY,
TestK is K - 1.0, % K =:= 1
TestK =< 1e-010,
TestK >= -1e-010,
TestI is I - 0.0, % I =:= 0
TestI =< 1e-010,
TestI >= -1e-010.
% nf2sum(Lin,Sofar,Term)
%
% Transforms a linear expression into a sum
% (e.g. the expression [5,_,[l(X*2,OrdX),l(Y*-1,OrdY)]] gets transformed into 5 + 2*X - Y)
nf2sum([],I,I).
nf2sum([X|Xs],I,Sum) :-
(
TestI is I - 0.0, % I =:= 0
TestI =< 1e-010,
TestI >= -1e-010 ->
X = l(Var*K,_),
(
TestK is K - 1.0, % K =:= 1
TestK =< 1e-010,
TestK >= -1e-010 ->
hom2sum(Xs,Var,Sum)
;
TestK is K - -1.0, % K =:= -1
TestK =< 1e-010,
TestK >= -1e-010 ->
hom2sum(Xs,-Var,Sum)
;
hom2sum(Xs,K*Var,Sum)
)
;
hom2sum([X|Xs],I,Sum)
).
% hom2sum(Hom,Sofar,Term)
%
% Transforms a linear expression into a sum
% this predicate handles all but the first term
% (the first term does not need a concatenation symbol + or -)
% see also nf2sum/3
hom2sum([],Term,Term).
hom2sum([l(Var*K,_)|Cs],Sofar,Term) :-
(
TestK is K - 1.0, % K =:= 1
TestK =< 1e-010,
TestK >= -1e-010 ->
Next = Sofar + Var
;
TestK is K - -1.0, % K =:= -1
TestK =< 1e-010,
TestK >= -1e-010 ->
Next = Sofar - Var
;
K - 0.0 < -1e-010 ->
Ka is -K,
Next = Sofar - Ka*Var
;
Next = Sofar + K*Var
),
hom2sum(Cs,Next,Term).

828
LGPL/clpr/clpr/ugraphs.pl Normal file
View File

@ -0,0 +1,828 @@
/* Copyright(C) 1992, Swedish Institute of Computer Science */
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% File : UGRAPHS.PL %
% Maintainer : Mats Carlsson %
% New versions of transpose/2, reduce/2, top_sort/2 by Dan Sahlin %
% Updated: 3 September 1999 %
% Purpose: Unweighted graph-processing utilities %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
/* Adapted from shared code written by Richard A O'Keefe */
/* An unweighted directed graph (ugraph) is represented as a list of
(vertex-neighbors) pairs, where the pairs are in standard order
(as produced by keysort with unique keys) and the neighbors of
each vertex are also in standard order (as produced by sort), and
every neighbor appears as a vertex even if it has no neighbors
itself.
An undirected graph is represented as a directed graph where for
each edge (U,V) there is a symmetric edge (V,U).
An edge (U,V) is represented as the term U-V.
A vertex can be any term. Two vertices are distinct iff they are
not identical (==).
A path is represented as a list of vertices.
No vertex can appear twice in a path.
*/
:- module(ugraphs, [
vertices_edges_to_ugraph/3,
vertices/2,
edges/2,
add_vertices/3,
del_vertices/3,
add_edges/3,
del_edges/3,
transpose/2,
neighbors/3,
neighbours/3,
complement/2,
compose/3,
transitive_closure/2,
symmetric_closure/2,
top_sort/2,
max_path/5,
min_path/5,
min_paths/3,
path/3,
reduce/2,
reachable/3,
random_ugraph/3,
min_tree/3,
clique/3,
independent_set/3,
coloring/3,
colouring/3
]).
:- use_module(library(ordsets),
[ ord_del_element/3,
ord_add_element/3,
ord_subset/2,
ord_union/3,
ord_union/4,
ord_disjoint/2,
ord_intersection/3
]).
:- use_module(library(lists), [
append/3,
member/2,
reverse/2
]).
:- use_module(library(assoc), [
list_to_assoc/2,
ord_list_to_assoc/2,
get_assoc/3,
get_assoc/5
]).
/*:- use_module(random, [
random/1
]).
*/
% vertices_edges_to_ugraph(+Vertices, +Edges, -Graph)
% is true if Vertices is a list of vertices, Edges is a list of edges,
% and Graph is a graph built from Vertices and Edges. Vertices and
% Edges may be in any order. The vertices mentioned in Edges do not
% have to occur explicitly in Vertices. Vertices may be used to
% specify vertices that are not connected to any edges.
vertices_edges_to_ugraph(Vertices0, Edges, Graph) :-
sort(Vertices0, Vertices1),
sort(Edges, EdgeSet),
edges_vertices(EdgeSet, Bag),
sort(Bag, Vertices2),
ord_union(Vertices1, Vertices2, VertexSet),
group_edges(VertexSet, EdgeSet, Graph).
edges_vertices([], []).
edges_vertices([From-To|Edges], [From,To|Vertices]) :-
edges_vertices(Edges, Vertices).
group_edges([], _, []).
group_edges([Vertex|Vertices], Edges, [Vertex-Neibs|G]) :-
group_edges(Edges, Vertex, Neibs, RestEdges),
group_edges(Vertices, RestEdges, G).
group_edges([V0-X|Edges], V, [X|Neibs], RestEdges) :- V0==V, !,
group_edges(Edges, V, Neibs, RestEdges).
group_edges(Edges, _, [], Edges).
% vertices(+Graph, -Vertices)
% unifies Vertices with the vertices in Graph.
vertices([], []).
vertices([Vertex-_|Graph], [Vertex|Vertices]) :- vertices(Graph, Vertices).
% edges(+Graph, -Edges)
% unifies Edges with the edges in Graph.
edges([], []).
edges([Vertex-Neibs|G], Edges) :-
edges(Neibs, Vertex, Edges, MoreEdges),
edges(G, MoreEdges).
edges([], _, Edges, Edges).
edges([Neib|Neibs], Vertex, [Vertex-Neib|Edges], MoreEdges) :-
edges(Neibs, Vertex, Edges, MoreEdges).
% add_vertices(+Graph1, +Vertices, -Graph2)
% is true if Graph2 is Graph1 with Vertices added to it.
add_vertices(Graph0, Vs0, Graph) :-
sort(Vs0, Vs),
vertex_units(Vs, Graph1),
graph_union(Graph0, Graph1, Graph).
% del_vertices(+Graph1, +Vertices, -Graph2)
% is true if Graph2 is Graph1 with Vertices and all edges to and from
% Vertices removed from it.
del_vertices(Graph0, Vs0, Graph) :-
sort(Vs0, Vs),
graph_del_vertices(Graph0, Vs, Vs, Graph).
% add_edges(+Graph1, +Edges, -Graph2)
% is true if Graph2 is Graph1 with Edges and their "to" and "from"
% vertices added to it.
add_edges(Graph0, Edges0, Graph) :-
sort(Edges0, EdgeSet),
edges_vertices(EdgeSet, Vs0),
sort(Vs0, Vs),
group_edges(Vs, EdgeSet, Graph1),
graph_union(Graph0, Graph1, Graph).
% del_edges(+Graph1, +Edges, -Graph2)
% is true if Graph2 is Graph1 with Edges removed from it.
del_edges(Graph0, Edges0, Graph) :-
sort(Edges0, EdgeSet),
edges_vertices(EdgeSet, Vs0),
sort(Vs0, Vs),
group_edges(Vs, EdgeSet, Graph1),
graph_difference(Graph0, Graph1, Graph).
vertex_units([], []).
vertex_units([V|Vs], [V-[]|Us]) :- vertex_units(Vs, Us).
graph_union(G0, [], G) :- !, G = G0.
graph_union([], G, G).
graph_union([V1-N1|G1], [V2-N2|G2], G) :-
compare(C, V1, V2),
graph_union(C, V1, N1, G1, V2, N2, G2, G).
graph_union(<, V1, N1, G1, V2, N2, G2, [V1-N1|G]) :-
graph_union(G1, [V2-N2|G2], G).
graph_union(=, V, N1, G1, _, N2, G2, [V-N|G]) :-
ord_union(N1, N2, N),
graph_union(G1, G2, G).
graph_union(>, V1, N1, G1, V2, N2, G2, [V2-N2|G]) :-
graph_union([V1-N1|G1], G2, G).
graph_difference(G0, [], G) :- !, G = G0.
graph_difference([], _, []).
graph_difference([V1-N1|G1], [V2-N2|G2], G) :-
compare(C, V1, V2),
graph_difference(C, V1, N1, G1, V2, N2, G2, G).
graph_difference(<, V1, N1, G1, V2, N2, G2, [V1-N1|G]) :-
graph_difference(G1, [V2-N2|G2], G).
graph_difference(=, V, N1, G1, _, N2, G2, [V-N|G]) :-
ord_subtract(N1, N2, N),
graph_difference(G1, G2, G).
graph_difference(>, V1, N1, G1, _, _, G2, G) :-
graph_difference([V1-N1|G1], G2, G).
graph_del_vertices(G1, [], Set, G) :- !,
graph_del_vertices(G1, Set, G).
graph_del_vertices([], _, _, []).
graph_del_vertices([V1-N1|G1], [V2|Vs], Set, G) :-
compare(C, V1, V2),
graph_del_vertices(C, V1, N1, G1, V2, Vs, Set, G).
graph_del_vertices(<, V1, N1, G1, V2, Vs, Set, [V1-N|G]) :-
ord_subtract(N1, Set, N),
graph_del_vertices(G1, [V2|Vs], Set, G).
graph_del_vertices(=, _, _, G1, _, Vs, Set, G) :-
graph_del_vertices(G1, Vs, Set, G).
graph_del_vertices(>, V1, N1, G1, _, Vs, Set, G) :-
graph_del_vertices([V1-N1|G1], Vs, Set, G).
graph_del_vertices([], _, []).
graph_del_vertices([V1-N1|G1], Set, [V1-N|G]) :-
ord_subtract(N1, Set, N),
graph_del_vertices(G1, Set, G).
% transpose(+Graph, -Transpose)
% is true if Transpose is the graph computed by replacing each edge
% (u,v) in Graph by its symmetric edge (v,u). It can only be used
% one way around. The cost is O(N log N).
transpose(Graph, Transpose) :-
transpose_edges(Graph, TEdges, []),
sort(TEdges, TEdges2),
vertices(Graph, Vertices),
group_edges(Vertices, TEdges2, Transpose).
transpose_edges([]) --> [].
transpose_edges([Vertex-Neibs|G]) -->
transpose_edges(Neibs, Vertex),
transpose_edges(G).
transpose_edges([], _) --> [].
transpose_edges([Neib|Neibs], Vertex) --> [Neib-Vertex],
transpose_edges(Neibs, Vertex).
% neighbours(+Vertex, +Graph, -Neighbors)
% neighbors(+Vertex, +Graph, -Neighbors)
% is true if Vertex is a vertex in Graph and Neighbors are its neighbors.
neighbours(Vertex, Graph, Neighbors) :-
neighbors(Vertex, Graph, Neighbors).
neighbors(V, [V0-Neighbors|_], Neighbors) :- V0==V, !.
neighbors(V, [_|Graph], Neighbors) :- neighbors(V, Graph, Neighbors).
% complement(+Graph, -Complement)
% Complement is the complement graph of Graph, i.e. the graph that has
% the same vertices as Graph but only the edges that are not in Graph.
complement(Graph, Complement) :-
vertices(Graph, Vertices),
complement(Graph, Vertices, Complement).
complement([], _, []).
complement([V-Neibs|Graph], Vertices, [V-Others|Complement]) :-
ord_add_element(Neibs, V, Neibs1),
ord_subtract(Vertices, Neibs1, Others),
complement(Graph, Vertices, Complement).
% compose(+G1, +G2, -Composition)
% computes Composition as the composition of two graphs, which need
% not have the same set of vertices.
compose(G1, G2, Composition) :-
vertices(G1, V1),
vertices(G2, V2),
ord_union(V1, V2, V),
compose(V, G1, G2, Composition).
compose([], _, _, []).
compose([V0|Vertices], [V-Neibs|G1], G2, [V-Comp|Composition]) :- V==V0, !,
compose1(Neibs, G2, [], Comp),
compose(Vertices, G1, G2, Composition).
compose([V|Vertices], G1, G2, [V-[]|Composition]) :-
compose(Vertices, G1, G2, Composition).
compose1([V1|Vs1], [V2-N2|G2], SoFar, Comp) :- !,
compare(Rel, V1, V2),
compose1(Rel, V1, Vs1, V2, N2, G2, SoFar, Comp).
compose1(_, _, Comp, Comp).
compose1(<, _, Vs1, V2, N2, G2, SoFar, Comp) :-
compose1(Vs1, [V2-N2|G2], SoFar, Comp).
compose1(>, V1, Vs1, _, _, G2, SoFar, Comp) :-
compose1([V1|Vs1], G2, SoFar, Comp).
compose1(=, V1, Vs1, V1, N2, G2, SoFar, Comp) :-
ord_union(N2, SoFar, Next),
compose1(Vs1, G2, Next, Comp).
% transitive_closure(+Graph, -Closure)
% computes Closure as the transitive closure of Graph in O(N^3) time.
transitive_closure(Graph, Closure) :-
warshall(Graph, Graph, Closure).
warshall([], Closure, Closure).
warshall([V-_|G], E, Closure) :-
neighbors(V, E, Y),
warshall(E, V, Y, NewE),
warshall(G, NewE, Closure).
warshall([], _, _, []).
warshall([X-Neibs|G], V, Y, [X-NewNeibs|NewG]) :-
ord_subset([V], Neibs), !,
ord_del_element(Y, X, Y1),
ord_union(Neibs, Y1, NewNeibs),
warshall(G, V, Y, NewG).
warshall([X-Neibs|G], V, Y, [X-Neibs|NewG]) :-
warshall(G, V, Y, NewG).
% symmetric_closure(+Graph, -Closure)
% computes Closure as the symmetric closure of Graph, i.e. for each
% edge (u,v) in Graph, add its symmetric edge (v,u). Approx O(N log N)
% time. This is useful for making a directed graph undirected.
symmetric_closure(Graph, Closure) :-
transpose(Graph, Transpose),
symmetric_closure(Graph, Transpose, Closure).
symmetric_closure([], [], []).
symmetric_closure([V-Neibs1|Graph], [V-Neibs2|Transpose], [V-Neibs|Closure]) :-
ord_union(Neibs1, Neibs2, Neibs),
symmetric_closure(Graph, Transpose, Closure).
% top_sort(+Graph, -Sorted)
% finds a topological ordering of a Graph and returns the ordering
% as a list of Sorted vertices. Fails iff no ordering exists, i.e.
% iff the graph contains cycles. Approx O(N log N) time.
top_sort(Graph, Sorted) :-
fanin_counts(Graph, Counts),
get_top_elements(Counts, Top, 0, I),
ord_list_to_assoc(Counts, Map),
top_sort(Top, I, Map, Sorted).
top_sort([], 0, _, []).
top_sort([V-VN|Top0], I, Map0, [V|Sorted]) :-
dec_counts(VN, I, J, Map0, Map, Top0, Top),
top_sort(Top, J, Map, Sorted).
dec_counts([], I, I, Map, Map, Top, Top).
dec_counts([N|Ns], I, K, Map0, Map, Top0, Top) :-
get_assoc(N, Map0, NN-C0, Map1, NN-C),
C is C0-1,
(C=:=0 -> J is I-1, Top1 = [N-NN|Top0]; J = I, Top1 = Top0),
dec_counts(Ns, J, K, Map1, Map, Top1, Top).
get_top_elements([], [], I, I).
get_top_elements([V-(VN-C)|Counts], Top0, I, K) :-
(C=:=0 -> J = I, Top0 = [V-VN|Top1]; J is I+1, Top0 = Top1),
get_top_elements(Counts, Top1, J, K).
fanin_counts(Graph, Counts) :-
transpose_edges(Graph, Edges0, []),
keysort(Edges0, Edges),
fanin_counts(Graph, Edges, Counts).
fanin_counts([], [], []).
fanin_counts([V-VN|Graph], Edges, [V-(VN-C)|Counts]) :-
fanin_counts(Edges, V, 0, C, Edges1),
fanin_counts(Graph, Edges1, Counts).
fanin_counts([V-_|Edges0], V0, C0, C, Edges) :-
V==V0, !,
C1 is C0+1,
fanin_counts(Edges0, V0, C1, C, Edges).
fanin_counts(Edges, _, C, C, Edges).
% max_path(+V1, +V2, +Graph, -Path, -Cost)
% is true if Path is a list of vertices constituting a longest path
% of cost Cost from V1 to V2 in Graph, there being no cyclic paths from
% V1 to V2. Takes O(N^2) time.
max_path(Initial, Final, Graph, Path, Cost) :-
transpose(Graph, TGraph),
max_path_init(Initial, Final, Graph, TGraph, TGraph2, Order),
max_path_init(TGraph2, Val0),
max_path(Order, TGraph2, Val0, Val),
max_path_select(Val, Path, Cost).
max_path_init(Initial, Final, Graph, TGraph, TGraph2, Order) :-
reachable(Initial, Graph, InitialReachable),
reachable(Final, TGraph, FinalReachable),
ord_intersection(InitialReachable, FinalReachable, Reachable),
subgraph(TGraph, Reachable, TGraph2),
top_sort(TGraph2, Order).
max_path_init([], []).
max_path_init([V-_|G], [V-([]-0)|Val]) :- max_path_init(G, Val).
max_path_select([V-(Longest-Max)|Val], Path, Cost) :-
max_path_select(Val, V, Longest, Path, Max, Cost).
max_path_select([], V, Path, [V|Path], Cost, Cost).
max_path_select([V1-(Path1-Cost1)|Val], V2, Path2, Path, Cost2, Cost) :-
( Cost1>Cost2 ->
max_path_select(Val, V1, Path1, Path, Cost1, Cost)
; max_path_select(Val, V2, Path2, Path, Cost2, Cost)
).
max_path([], _, Val, Val).
max_path([V|Order], Graph, Val0, Val) :-
neighbors(V, Graph, Neibs),
neighbors(V, Val0, Item),
max_path_update(Neibs, V-Item, Val0, Val1),
max_path(Order, Graph, Val1, Val).
%% [MC] 3.8.6: made determinate
max_path_update([], _, Val, Val).
max_path_update([N|Neibs], Item, [Item0|Val0], Val) :-
Item0 = V0-(_-Cost0),
N==V0, !,
Item = V-(Path-Cost),
Cost1 is Cost+1,
( Cost1>Cost0 -> Val = [V0-([V|Path]-Cost1)|Val1]
; Val = [Item0|Val1]
),
max_path_update(Neibs, Item, Val0, Val1).
max_path_update(Neibs, Item, [X|Val0], [X|Val]) :-
Neibs = [_|_],
max_path_update(Neibs, Item, Val0, Val).
subgraph([], _, []).
subgraph([V-Neibs|Graph], Vs, [V-Neibs1|Subgraph]) :-
ord_subset([V], Vs), !,
ord_intersection(Neibs, Vs, Neibs1),
subgraph(Graph, Vs, Subgraph).
subgraph([_|Graph], Vs, Subgraph) :-
subgraph(Graph, Vs, Subgraph).
% min_path(+V1, +V2, +Graph, -Path, -Length)
% is true if Path is a list of vertices constituting a shortest path
% of length Length from V1 to V2 in Graph. Takes O(N^2) time.
min_path(Initial, Final, Graph, Path, Length) :-
min_path([[Initial]|Q], Q, [Initial], Final, Graph, Rev),
reverse(Rev, Path),
length(Path, N),
Length is N-1.
min_path(Head0, Tail0, Closed0, Final, Graph, Rev) :-
Head0 \== Tail0,
Head0 = [Sofar|Head],
Sofar = [V|_],
( V==Final -> Rev = Sofar
; neighbors(V, Graph, Neibs),
ord_union(Closed0, Neibs, Closed, Neibs1),
enqueue(Neibs1, Sofar, Tail0, Tail),
min_path(Head, Tail, Closed, Final, Graph, Rev)
).
enqueue([], _) --> [].
enqueue([V|Vs], Sofar) --> [[V|Sofar]], enqueue(Vs, Sofar).
% min_paths(+Vertex, +Graph, -Tree)
% is true if Tree is a tree of all the shortest paths from Vertex to
% every other vertex in Graph. This is the single-source shortest
% paths problem. The algorithm is straightforward.
min_paths(Vertex, Graph, Tree) :-
min_paths([Vertex], Graph, [Vertex], List),
keysort(List, Tree).
min_paths([], _, _, []).
min_paths([Q|R], Graph, Reach0, [Q-New|List]) :-
neighbors(Q, Graph, Neibs),
ord_union(Reach0, Neibs, Reach, New),
append(R, New, S),
min_paths(S, Graph, Reach, List).
% path(+Vertex, +Graph, -Path)
% is given a Graph and a Vertex of that Graph, and returns a maximal
% Path rooted at Vertex, enumerating more Paths on backtracking.
path(Initial, Graph, Path) :-
path([Initial], [], Graph, Path).
path(Q, Not, Graph, Path) :-
Q = [Qhead|_],
neighbors(Qhead, Graph, Neibs),
ord_subtract(Neibs, Not, Neibs1),
( Neibs1 = [] -> reverse(Q, Path)
; ord_add_element(Not, Qhead, Not1),
member(N, Neibs1),
path([N|Q], Not1, Graph, Path)
).
% reduce(+Graph, -Reduced)
% is true if Reduced is the reduced graph for Graph. The vertices of
% the reduced graph are the strongly connected components of Graph.
% There is an edge in Reduced from u to v iff there is an edge in
% Graph from one of the vertices in u to one of the vertices in v. A
% strongly connected component is a maximal set of vertices where
% each vertex has a path to every other vertex.
% Algorithm from "Algorithms" by Sedgewick, page 482, Tarjan's algorithm.
% Approximately linear in the maximum of arcs and nodes (O(N log N)).
reduce(Graph, Reduced) :-
strong_components(Graph, SCCS, Map),
reduced_vertices_edges(Graph, Vertices, Map, Edges, []),
sort(Vertices, Vertices1),
sort(Edges, Edges1),
group_edges(Vertices1, Edges1, Reduced),
sort(SCCS, Vertices1).
strong_components(Graph, SCCS, A) :-
nodeinfo(Graph, Nodeinfo, Vertices),
ord_list_to_assoc(Nodeinfo, A0),
visit(Vertices, 0, _, A0, A, 0, _, [], _, SCCS, []).
visit([], Min, Min, A, A, I, I, Stk, Stk) --> [].
visit([V|Vs], Min0, Min, A0, A, I, M, Stk0, Stk) -->
{get_assoc(V, A0, node(Ns,J,Eq), A1, node(Ns,K,Eq))},
( {J>0} ->
{J=K, J=Min1, A1=A3, I=L, Stk0=Stk2}
; {K is I+1},
visit(Ns, K, Min1, A1, A2, K, L, [V|Stk0], Stk1),
( {K>Min1} -> {A2=A3, Stk1=Stk2}
; pop(V, Eq, A2, A3, Stk1, Stk2, [])
)
),
{Min2 is min(Min0,Min1)},
visit(Vs, Min2, Min, A3, A, L, M, Stk2, Stk).
pop(V, Eq, A0, A, [V1|Stk0], Stk, SCC0) -->
{get_assoc(V1, A0, node(Ns,_,Eq), A1, node(Ns,16'100000,Eq))},
( {V==V1} -> [SCC], {A1=A, Stk0=Stk, sort([V1|SCC0], SCC)}
; pop(V, Eq, A1, A, Stk0, Stk, [V1|SCC0])
).
nodeinfo([], [], []).
nodeinfo([V-Ns|G], [V-node(Ns,0,_)|Nodeinfo], [V|Vs]) :-
nodeinfo(G, Nodeinfo, Vs).
reduced_vertices_edges([], [], _) --> [].
reduced_vertices_edges([V-Neibs|Graph], [V1|Vs], Map) -->
{get_assoc(V, Map, N), N=node(_,_,V1)},
reduced_edges(Neibs, V1, Map),
reduced_vertices_edges(Graph, Vs, Map).
reduced_edges([], _, _) --> [].
reduced_edges([V|Vs], V1, Map) -->
{get_assoc(V, Map, N), N=node(_,_,V2)},
({V1==V2} -> []; [V1-V2]),
reduced_edges(Vs, V1, Map).
% reachable(+Vertex, +Graph, -Reachable)
% is given a Graph and a Vertex of that Graph, and returns the set
% of vertices that are Reachable from that Vertex. Takes O(N^2)
% time.
reachable(Initial, Graph, Reachable) :-
reachable([Initial], Graph, [Initial], Reachable).
reachable([], _, Reachable, Reachable).
reachable([Q|R], Graph, Reach0, Reachable) :-
neighbors(Q, Graph, Neighbors),
ord_union(Reach0, Neighbors, Reach1, New),
append(R, New, S),
reachable(S, Graph, Reach1, Reachable).
% random_ugraph(+P, +N, -Graph)
% where P is a probability, unifies Graph with a random graph of N
% vertices where each possible edge is included with probability P.
random_ugraph(P, N, Graph) :-
( float(P), P >= 0.0, P =< 1.0 -> true
; prolog:illarg(domain(float,between(0.0,1.0)),
random_ugraph(P,N,Graph), 1)
),
( integer(N), N >= 0 -> true
; prolog:illarg(domain(integer,>=(0)),
random_ugraph(P,N,Graph), 2)
),
random_ugraph(0, N, P, Graph).
random_ugraph(N, N, _, Graph) :- !, Graph = [].
random_ugraph(I, N, P, [J-List|Graph]) :-
J is I+1,
random_neighbors(N, J, P, List, []),
random_ugraph(J, N, P, Graph).
random_neighbors(0, _, _, S0, S) :- !, S = S0.
random_neighbors(N, J, P, S0, S) :-
( N==J -> S1 = S
; random(X), X > P -> S1 = S
; S1 = [N|S]
),
M is N-1,
random_neighbors(M, J, P, S0, S1).
random(X) :- % JW: was undefined. Assume
X is random(10000)/10000. % we need 0<=X<=1
% min_tree(+Graph, -Tree, -Cost)
% is true if Tree is a spanning tree of an *undirected* Graph with
% cost Cost, if it exists. Using a version of Prim's algorithm.
min_tree([V-Neibs|Graph], Tree, Cost) :-
length(Graph, Cost),
prim(Cost, Neibs, Graph, [V], Edges),
vertices_edges_to_ugraph([], Edges, Tree).
%% [MC] 3.8.6: made determinate
prim(0, [], _, _, []) :- !.
prim(I, [V|Vs], Graph, Reach, [V-W,W-V|Edges]) :-
neighbors(V, Graph, Neibs),
ord_subtract(Neibs, Reach, Neibs1),
ord_subtract(Neibs, Neibs1, [W|_]),
ord_add_element(Reach, V, Reach1),
ord_union(Vs, Neibs1, Vs1),
J is I-1,
prim(J, Vs1, Graph, Reach1, Edges).
% clique(+Graph, +K, -Clique)
% is true if Clique is a maximal clique (complete subgraph) of N
% vertices of an *undirected* Graph, where N>=K. Adapted from
% Algorithm 457, "Finding All Cliques of an Undirected Graph [H]",
% Version 1, by Coen Bron and Joep Kerbosch, CACM vol. 6 no. 9 pp.
% 575-577, Sept. 1973.
clique(Graph, K, Clique) :-
( integer(K), K >= 0 -> true
; prolog:illarg(domain(integer,>=(0)),
clique(Graph,K,Clique), 2)
),
J is K-1,
prune(Graph, [], J, Graph1),
clique1(Graph1, J, Clique).
clique1([], J, []) :- J < 0.
clique1([C-Neibs|Graph], J, [C|Clique]) :-
neighbor_graph(Graph, Neibs, C, Vs, Graph1),
J1 is J-1,
prune(Graph1, Vs, J1, Graph2),
clique1(Graph2, J1, Clique).
clique1([C-Neibs|Graph], J, Clique) :-
prune(Graph, [C], J, Graph2),
clique1(Graph2, J, Clique),
\+ ord_subset(Clique, Neibs).
neighbor_graph([], _, _, [], []).
neighbor_graph([V0-Neibs0|Graph0], [V|Vs], W, Del, [V-Neibs|Graph]) :-
V0==V, !,
ord_del_element(Neibs0, W, Neibs),
neighbor_graph(Graph0, Vs, W, Del, Graph).
neighbor_graph([V-_|Graph0], Vs, W, [V|Del], Graph) :-
neighbor_graph(Graph0, Vs, W, Del, Graph).
prune(Graph0, [], K, Graph) :- K =< 0, !, Graph = Graph0.
prune(Graph0, Vs0, K, Graph) :-
prune(Graph0, Vs0, K, Graph1, Vs1),
( Vs1==[] -> Graph = Graph1
; prune(Graph1, Vs1, K, Graph)
).
prune([], _, _, [], []).
prune([V-Ns0|Graph0], Vs1, K, [V-Ns|Graph], Vs2) :-
ord_disjoint([V], Vs1),
ord_subtract(Ns0, Vs1, Ns),
length(Ns, I),
I >= K, !,
prune(Graph0, Vs1, K, Graph, Vs2).
prune([V-_|Graph0], Vs1, K, Graph, Vs2) :-
( ord_disjoint([V], Vs1) -> Vs2 = [V|Vs3]
; Vs2 = Vs3
),
prune(Graph0, Vs1, K, Graph, Vs3).
% independent_set(+Graph, +K, -Set)
% is true if Set is a maximal independent (unconnected) set of N
% vertices of an *undirected* Graph, where N>=K.
independent_set(Graph, K, Set) :-
complement(Graph, Complement),
clique(Complement, K, Set).
% colouring(+Graph, +K, -Coloring)
% coloring(+Graph, +K, -Coloring)
% is true if Coloring is a mapping from vertices to colors 1..N of
% an *undirected* Graph such that all edges have distinct end colors,
% where N=<K. Adapted from "New Methods to Color the Vertices of a
% Graph", by D. Brelaz, CACM vol. 4 no. 22 pp. 251-256, April 1979.
% Augmented with ideas from Matula's smallest-last ordering.
colouring(Graph, K, Coloring) :-
coloring(Graph, K, Coloring).
coloring(Graph, K, Coloring) :-
( integer(K), K >= 0 -> true
; prolog:illarg(domain(integer,>=(0)),
coloring(Graph,K,Coloring), 2)
),
color_map(Graph, Coloring),
color_map(Graph, Graph1, Coloring, Coloring),
coloring(Graph1, K, 0, [], Stack),
color_stack(Stack).
coloring([], _, _, Stk0, Stk) :- !, Stk0 = Stk.
coloring(Graph, K, InUse, Stk0, Stk) :-
select_vertex(Graph, K, Compare, -, 0+0, V-Ns),
graph_del_vertices(Graph, [V], [V], Graph1),
( Compare = < ->
coloring(Graph1, K, InUse, [V-Ns|Stk0], Stk)
; M is min(K,InUse+1),
vertex_color(Ns, 1, M, V),
add_color(Graph1, Ns, V, Graph2),
InUse1 is max(V,InUse),
coloring(Graph2, K, InUse1, Stk0, Stk)
).
% select_vertex(+Graph, +K, -Comp, +Pair0, +Rank, -Pair)
% return any vertex with degree<K right away (Comp = <) else return
% vertex with max. saturation degree (Comp = >=), break ties using
% max. degree
select_vertex([], _, >=, Pair, _, Pair).
select_vertex([V-Neibs|Graph], K, Comp, Pair0, Rank0, Pair) :-
evaluate_vertex(Neibs, 0, Rank),
( Rank < K -> Comp = <, Pair = V-Neibs
; Rank @> Rank0 ->
select_vertex(Graph, K, Comp, V-Neibs, Rank, Pair)
; select_vertex(Graph, K, Comp, Pair0, Rank0, Pair)
).
evaluate_vertex([V|Neibs], Deg, Rank) :- var(V), !,
Deg1 is Deg+1,
evaluate_vertex(Neibs, Deg1, Rank).
evaluate_vertex(Neibs, Deg, Sat+Deg) :-
prolog:length(Neibs, 0, Sat).
add_color([], _, _, []).
add_color([V-Neibs|Graph], [W|Vs], C, [V-Neibs1|Graph1]) :- V==W, !,
ord_add_element(Neibs, C, Neibs1),
add_color(Graph, Vs, C, Graph1).
add_color([Pair|Graph], Vs, C, [Pair|Graph1]) :-
add_color(Graph, Vs, C, Graph1).
vertex_color([V|Vs], I, M, Color) :- V@<I, !,
vertex_color(Vs, I, M, Color).
vertex_color([I|Vs], I, M, Color) :- !,
I<M, J is I+1, vertex_color(Vs, J, M, Color).
vertex_color(_, I, _, I).
vertex_color(Vs, I, M, Color) :-
I<M, J is I+1, vertex_color(Vs, J, M, Color).
color_stack([]).
color_stack([V-Neibs|Stk]) :- sort(Neibs, Set), color_stack(Set, 1, V, Stk).
color_stack([I|Is], I, V, Stk) :- !, J is I+1, color_stack(Is, J, V, Stk).
color_stack(_, V, V, Stk) :- color_stack(Stk).
color_map([], []).
color_map([V-_|Graph], [V-_|Coloring]) :- color_map(Graph, Coloring).
color_map([], [], [], _).
color_map([V-Ns|Graph], [C-Ns1|Graph1], [V-C|Cols], Coloring) :-
map_colors(Ns, Coloring, Ns1),
color_map(Graph, Graph1, Cols, Coloring).
map_colors([], _, []).
map_colors(Ns, Coloring, Ns1) :-
Ns = [X|_],
Coloring = [V-_|_],
compare(C, X, V),
map_colors(C, Ns, Coloring, Ns1).
map_colors(=, [_|Xs], [_-Y|Coloring], [Y|Ns1]) :-
map_colors(Xs, Coloring, Ns1).
map_colors(>, Ns, [_|Coloring], Ns1) :-
map_colors(Ns, Coloring, Ns1).