FAQ Revised: Tuesday 01 April 2008 18:38:31
param
work?for
loop failing?;
?
Programming in the ECLiPSe Constraint Logic Programming System
ECLiPSe is a software system for the development and deployment of
constraint programming and Constraint logic programming applications.
It contains several constraint solver libraries, a high-level
modelling and control language, interfaces to third-party solvers, a
development environment and interfaces for embedding into host environments.
No, that's the open-source ECLiPSe CLP system; originated from
ECRC in Germany; there is no link between the two. [note however that
Saros, a plug-in for the Eclipse development platform, provides an IDE for
ECLiPSe CLP platform, is now available]
ECLiPSe programmers who have some experience of Prolog and constraint
logic programming. For background, see the book
"Programming with Constraints: An Introduction"
by K. Marriott and P. J. Stuckey (MIT Press, 1998),
and the book
"Constraint Logic Programming using ECLiPSe"
by K. P. Apt and M. Wallace (Cambridge University Press, 2006).
This FAQ was started and originally maintained by Karen E. Petrie and Neil
Yorke-Smith, with contributions from Christian Cleber Masdeval Braz,
Warwick Harvey, Joachim Schimpf, Kish Shen, before ECLiPSe was made open-source.
We welcome submission of FAQ items that should be included.
ECLiPSe is licensed under the Cisco-style Mozilla Public License 1.1.
This license is based on the Mozilla Public License 1.1. The main change is that "Cisco" replaces "Mozilla" and "Netscape".
This is an open-source license, meaning that the source, as well as the
binaries, is available for download without cost. There is also no
restrictions on use.
No, unless you already have a license for these older versions of ECLiPSe.
Before ECLiPSe was open-sourced (version 5.9 and earlier), it was
available in binary form under the ECLiPSe academic license, issued by
IC-Parc. The terms of this license still applies, but as IC-Parc no longer
exists, new licenses under these terms can no longer be issued. Note also that
sources for ECLiPSe are not available under this license.
ECLiPSe is open-source, and can be downloaded in source and
binary forms from ECLiPSe's Source Forge project page
(http://sourceforge.net/projects/eclipse-clp),
and from ECLiPSe's web site (http://www.eclipse-clp.org).
The current version of ECLiPSe is regularly built and tested on x86 Linux, Sparc Solaris, 32-bit x86 Windows, and x86-64 (also known as AMD64 and Intel 64) Linux; it is also built less frequently on MacOS X (Intel and PPC), and the binaries can be downloaded from Source Forge.
You can also compile the source yourself. In addition to the distributed
binaries, the ECLiPSe source should compile `out-of-the-box' for several
platforms that it was built on in the recent past, e.g. x86 Solaris and
Alpha Linux. In addition, it should be possible to compile ECLiPSe on most
Unix(like) platforms (32 and 64 bits) with a little effort, although you
would probably need some knowledge about Unix application development to do
this. More details for compiling ECLiPSe can be found in the Setup guide,
which is included in the source distribution (in documents/internals
subdirectory).
If you have ECLiPSe installed, start tkeclipse, and from the Help menu
select Full Documentation (in command line eclipse, type "help."). You
can also access online versions of the documentation.
[ECLiPSeDir]/doc/examples
(general examples),
and in [ECLiPSeDir]/lib_tcl
(various examples of using the Tcl embedding).You need to use an editor to write your programs. You can either use your own favourite text editor, or you can use the Saros IDE for ECLiPSe, which comes with an editor.
You can use any editor that can save plain text files. However, special support for ECLiPSe (e.g. syntax highlighting) is provided for some editors, e.g. emacs and vi. Save your program as a plain text file, and you can then compile the program into ECLiPSe and run it.
For more instructions on how to get started with ECLiPSe, including how to run programs, please see the first chapters of the User Manual.
With tkeclipse, you can specify the editor you want to use, and this editor will be started by tkeclipse, e.g. when you select a file in the "Edit" option under the File menu. The default values are the value of the VISUAL environment variable under Unix, or Wordpad under Windows. This can be changed with the Preference Editor under the Tools menu.
In tkeclipse, if you just want to test out some small amount of code,
you can use the `Compile scratch-pad' tool, instead of an editor. In
eclipse, you can type in "[user]." as a query, and eclipse will compile what
you type next as ECLiPSe code. In both cases, however, you cannot save your
code.
Yes, Saros, a plug-in for the Eclipse development platform originally from IBM, that provides an IDE for ECLiPSe, is now available as a prototype, and can be downloaded.
In addition. tkeclipse provides some of the features of an IDE, but a separate programming editor is recommended; for instance, emacs.
A package containing extra support for several text editors is
available on ECLiPSe's SourceForge download page.
Yes, ECLiPSe is largely compatible with standard Prolog, and in addition,
has libraries which provide almost full compliance with ISO Prolog and other
Prolog dialects, such as SICStus Prolog, on a per-module basis. ECLiPSe
implements some extensions (primarily to support constraints and
program-in-the-large, but also others too), which are documented in chapter 5
of the User Manual.
There are three ways of finding out:
In the reference manual. If you open the HTML documentation installed
with ECLiPSe, you will find a link to "Alphabetical Predicate Index".
It does happen! First, though, check your code carefully. If it is a
genuine bug, second, download the latest patch release of ECLiPSe to see if
the problem has been fixed. If not, third, isolate a code fragment that
reproduces the problem. Fourth, submit a bug report.
The concept of "standalone executable" doesn't really exist anymore these days. Almost every application now needs to be installed in some way, because of the dependencies on other resources, in particular shared libraries. The way to deploy an ECLiPSe application is to provide three components:
eclipse_rt.tgz
)library(fcompile)
)eclipse -b my_application.eco -e my_top_goal
tkeclipse is a graphical front-end for ECLiPSe. It provides easy access
to the system, and many additional tools, including visualisation.
In this FAQ, we write "ECLiPSe" for the overall system, "eclipse" for the
command line version, and "tkeclipse" for the graphical version.
Like eclipse, tkeclipse itself is designed for interactive use, i.e. you
load your ECLiPSe program into it and run it. However, the graphical tool
set, e.g. the tracer, can be linked with an ECLiPSe application that is
embedded into a host language, e.g. C, Java. To use the tools, you need to
attach tktools to your application. See the manual description of tktools
for more details. In fact, tktools can be attached to and use by any
ECLiPSe code, as long as you are running in an environment that can display
graphics. For example, you can use tktools when you are running ECLiPSe
from within emacs using the ECLiPSe mode, which provides support to make
this easier - you can start tktools from the ECLiPSe-Process menu.
tkeclipse is written in Tcl/Tk, and should run on any platform that
supports Tcl/Tk. Do you have the required version installed? Do you
have the paths set correctly? Under Windows, did you follow the
platform-specific ECLiPSe installation instructions?
When you change your program and save it, you must click "Make"
in tkeclipse (in eclipse, type "make."). Then re-run your query.
First, left-click in the "Results" window to move the focus
there. In ECLiPSe 5.7 and later, right click to bring up the context menu, and
select "Clear this window". Do the same for the "Output and Error Messages"
window. In earlier versions, instead select the text you want
to remove from the "Results" window using the right mouse button
(triple-click to select everything), and press delete on your keyboard.
First, left-click in the "Output and Error Messages" window and select
the text you want with the left mouse button. In ECLiPSe 5.7 and later,
right click to bring up the context menu, and select "Copy selection to
clipboard".
If your program is running, tkeclipse may respond slowly during heavy
computation. However, the "interrupt" button always works: you can then
choose to continue or abort execution. A second reason tkeclipse may not
respond is if you have the Tracer open. In that case, during execution, the
Tracer has focus; the main tkeclipse window will not respond (apart from
"interrupt"). Finally, if tkeclipse really has locked up, under Linux hold
down Control and Shift and click "interrupt" to kill tkeclipse.
Information about how to use tkeclipse is found in the User Manual, and
also from the Help menu in tkeclipse. Information about ECLiPSe is
available using the "ECLiPSe Library Browser and Help" from the Tools
menu. Finally, the ECLiPSe Tutorial has a chapter on debugging with
tkeclipse.
General advice is to decompose your program into model, search, and
results-reporting sections. Keep separate predicates for the modelling
section, constraints (i.e. where you define any new constraints), and
search sections; with a control section to link all the predicates
together. This will help with debugging your programs and understanding
them at a later date. See the example codes on the ECLiPSe web site for
examples.
=
, ==
, =:=
and #=
?The semantics (meaning) of these operators are different:
=
is unification ==
is syntactic term equality =:=
is arithmetic equality #=
is a constraint (integer-valued equality constraint) See the pages in the Reference Manual for examples. Specific libraries
introduce other forms of equality: for example ic
introduces real-valued constraint equality $=
.
Integer is fix(Real)
Often you'll want to round the real number appropriately first (round/2,
floor/2, ceiling/2) rather than relying on fix's truncation. See the
documentation for is/2 and fix/2.
This is a large topic! The best way is to consider the data structures and algorithms you are using. However, there are some ECLiPSe-specific performance considerations: see section 6.9 of the User Manual. You can use ECLiPSe's debugging and profiling tools to find where your program is spending its time. Finally, you can remove debugging code.
For a constraints program, you can try improve your labelling heuristic to
reduce the amount of search to find the solution, and visualising how the
existing search is behaving may help guide you in this. You can also try
adding more powerful constraints to your problem (e.g. global constraints),
which you may need to write yourself.
eclipse -b my_file.pl -e 'my_predicate(X,Y)'
Logical loops are a compact way of writing iteration in ECLiPSe. The simulate the loop facilities of an imperative language (such as Java) in a declarative language. For example, you can write
( for(I, 1, N) do writeln(I) ),
Loops let you write more compact ECLiPSe code. Without them, you would
have to code the loop explicitly as a recursive predicate, in standard
Prolog fashion. Internally, ECLiPSe rewrites your loop statement
automatically in this way; this is why loops appear as calls to a
predicate do_n
in the Tracer. To find out what kind of
loops are possible in ECLiPSe see section 5.2 of the User Manual.
Put them outside the loop, like this:
( loop declaration, param(...) do loop statements ),Note that no brackets are needed about the loop declarations (for example,
for(I, 1, N)
) themselves. Note also that the last line
of the loop statements
should not end in a comma (nor a full-stop),
because the whole loop statement is seen by ECLiPSe as one unit:
(... do ... )
. The usual rules for comma/full-stop apply to the
whole loop statement.param
work?
The param
term of a logical loop links variables outside a
loop with variables inside. Without param(X)
, variable X is
not visible inside the loop; X inside the loop is a new variable, unrelated
with X outside. With param(X)
, variable X is visible inside
the loop; X inside the loop is the same as X outside. Note that variables
in the loop declaration (for example, N in for(I, 1, N)
) are
automatically those visible outside the loop; you don't need a param
for these variables.
for
loop failing?
The target value in a for statement cannot be an unbound variable: it
must be a known, ground value at execution time. If TotalIterations
is unbound, you cannot write for(I,1,TotalIterations)
; use a
count
loop if you want to do this.
ECLiPSe translates loop statements into predicates called do__n
,
where n is a unique integer. There is no general way of
determining which number each loop statement corresponds with: use the
Tracer. However, when the do statement number has been determined it can
be traced with spy do__n
.
In ECLiPSe 5.6 and later, you can choose a name for a loop, which will then be used instead of the generated name, for instance:
( loop_name(first_write_loop), for(I, 1, N) do writeln(I) ),
In ECLiPSe 5.11 and later, code compiled by the new compiler can be
source-traced, and the execution of the loop can be seen directly via
the source-tracing.
Put them outside the conditional statement, like this:
( condition -> if_true_do_this ; if_false_do_this ),Note that no brackets are needed (in general) about the condition itself. Note also that the last line of the
if_true_do_this
and if_false_do_this
statements should not end in a comma (nor a full-stop), because the whole
conditional statement is seen by ECLiPSe as one unit:
( ... ->; ... ; ... )
. The usual rules for comma/full-stop
apply to the whole conditional statement.In ECLiPSe, every conditional should have an else clause. If you only want to execute something if a condition holds (and do nothing otherwise), you must code this explicitly:
( condition -> ... ; true )
The conditional must have a truth value known at modelling time
(i.e. when you compile your program): it can not be a constraint. For
example #=
should not be used in the condition.
;
?
When you want to express a logical disjunction, such as between two
truth-known terms in a condition. Do not use ;
to express
search choices; instead use constraints and generic search routines. See
section 12.2.1 of the ECLiPSe tutorial.
The simplest way to remove a posted constraint is to backtrack over the posting of the constraint. This is the logical way of removing the constraint.
There is no logical way of selectively `removing' a constraint,
i.e. `undo' the effect of one posted constraint but not others that are
posted after it. However, if you use lib(tentative)<\code>, you can post
constraints which are only monitored for violation, so you can just ignore
ignore them if they are violated. Note that in this case the constraint is
only monitored, and no propagation is done by posting it, and that
resources are still consumed until it is backtracked over.
Constraint propagation is in general not enough to find solutions. This
is one reason you might see delayed goals.
Extensive search algorithms are provided in the ic
(search/6)
and branch_and_bound
libraries.
The simplest search predicate tries to allocate variables to
values in chronological order. This can be done using the build in labeling
predicate and search/6
. If you want to implement your own
variable or value ordering heuristics, the simplest way is to write
your own search predicates based on the labeling
. More
complex search predicates can also be implemented. See section 12 and
13 of the ECLiPSe Tutorial for more details.
The documentation for minimize(Goal, Cost)
refers
you to bb_min/2
, and the second sentence in the description
for that predicate says:
"Cost should be a variable that is affected, and eventually instantiated, by Goal."
That is, Goal is expected to completely solve the problem, and once the
problem is solved, Cost should be known (fixed, and not a variable). The
error message indicates that Cost had not been fixed when Goal completed;
you should find out why Goal did not instantiate the cost, and modify
it appropriately to correct the problem.
Increase the print depth. In tkeclipse, choose "Global Settings"
from the Tools menu; in the Tracer, choose "Change print options"
from the Options menu. You can also print individual items at their full
depth by using the "D" modifier in printf. For example, printf("%Dw",[Term])
.
Finally, you can query the print depth for all output in your program using
get_flag(print_depth,Depth)
and change it using
set_flag(print_depth, Depth)
.
With the Tracer, consider using the Inspector tool instead of printing
out more of the term; the Inspector makes it easier to visually parse a
long term, and enables you to explore its structure.
Are you sure execution reaches your write/printf statement? If so, it
might be that a failure occurs afterwards, before the stream is flushed,
and so your output never appears. A stream is flushed when a newline is
printed, but you can also ask for it explicitly. For example,
printf("%w%b",[Term])
.
write
and printf
differ in buffering?
Especially if you've used different modules, ECLiPSe might need a clean
start. In tkeclipse, choose "Clear toplevel module" from the File menu.
Now reload your program.
The most likely cause is that you've misplaced a comma (,) or full-stop
(.) at the end of a line. As a rough guide, each line must end in a comma,
expect the last line of a clause, which must end in a full-stop.
If you were not meaning to redefine a built-in predicate, most likely you put a full-stop where you meant to put a comma. When you have a full-stop instead of a comma, the above message appears because the rest of the clause is taken as a fact for ,/2.
Alternatively, you may get the messages "trying to redefine a built-in
predicate: ..." for some other built-in you have used, or "WARNING: Hiding
imported predicate ..." for some library predicate you have used.
In the unlikely case that you really did want to redefine a built-in, read
the documentation for the module system and the local/1 declaration.
Perhaps you do need brackets, but perhaps you just omitted a
full-stop at the end of a clause.
A singleton variable is a variable you have referred to only once. This
warning often indicates a programming error, especially in loops. Even
if your code does what you intended, singleton variables are considered
bad form: replace them with _
.
Almost certainly, you forgot a param(...)
in your loop.
You may have a spurious closing bracket where indicated. However,
another possible cause is that the line finishes with a comma when it
should not. For example, the last statement before a closing bracket of a
loop should not be followed with a comma.
The best way is to change what is causing the warning so that you don't get
the warning. However, warning output during program execution is not always
helpful. To remove it: set_stream(warning_output,null)
.
Warning: this will remove all warnings, including ones that might alert you
to real problems with your code.
Memory-intensive computation can exhaust ECLiPSe's working space, typically the global stack. The default limit is 128MB, but this can be set to a larger amount before ECLiPSe is started. In both command-line eclipse and tkeclipse, use for example the command line option -g 512M for a 512MB stack.
The absolute limit on a 32 bit machine is between 2GB and almost 4GB, depending on the operating system. The maximum global stack you can request for ECLiPSe on 32-bit Linux is about 1900M; on Solaris you can allocate close to 4GB. On 64-bit, of course this limit doesn't exist.
It is inadvisable to choose a value larger than the physical memory on your machine, because your program will spend most of the time swapping pages.
In tkeclipse, the preference editor tool allows you to set the default
sizes of the various stacks. After you enter the new size, save it using the `Save
Preferences' button, and restart tkeclipse.
Use the Tracer. In tkeclipse, choose "Tracer" from the Tools menu. See
the chapter on "Debugging" in the User Manual; and the worked example
in chapter 5 of the ECLiPSe Tutorial.
The Tracer is designed to let you step through the execution of your
program. The visualisation tools are designed to let you see the effects on
constraints on your variables's domains. The two can be used together.
Use the profiling tools in libraries profile
, port_profile
,
instprofile
, and coverage
. In tkeclipse 5.7 and later, "Time Profile"
and "Port Profile" can be invoked from the Run menu.
By default, ECLiPSe produces debuggable (traceable) code. Because it
includes tracing information, this code is slower. You can ask instead
for optimised (non-traceable) code with the directive: :-
pragma(nodebug)
.
The visualisation client does not start automatically: you must invoke
it from the Tools menu in tkeclipse. The most common reason it won't
start is a problem with Java on your computer. Check the Java version
and installation (Java should be installed before ECLiPSe). Check the
CLASSPATH environment variable. Check paths and access permissions.
Consult your local ECLiPSe expert and the Visualisation Tools manual.
In the visualisation client, right-click on the variable that
you are interested in and choose "Hold on updates".
Use the "Auto resume" option:
ic
?
ic does not directly support using symbols as the domain values.
This support is provided by the ic_symbolic
library.
Delayed goals correspond to unresolved constraints. If ECLiPSe has
delayed goals at the end of computation, it reflects the fact that the
variable's ranges could possibly be further reduced in the future.
Delayed goals also reflect the fact that ic
does not guarantee
the existence of solutions in the computed ranges (in interval computation
terminology, it is not sound). However, it guarantees that there are no
solutions outside these ranges (it is complete).
If delayed goals occur, you should check that all decision variables
have been labelled, and that the constraints have assigned values to all
other variables. If so, then the existence of a few delayed goals is
probably not significant: they likely occur because of interval arithmetic
(see next question).
Interval arithmetic is not like arithmetic with integers or reals.
A major reason why ic gives delayed goals (beyond unresolved
constraints you have posted) is because some arithmetic operations
cannot be resolved: for example, is 1.0__2.0 > 1.5__2.5? In tkeclipse,
select "Delayed Goals" from the Tools menu to see all delayed goals. You
can then examine them to see whether they are significant for you.
;
and #\/?
;
is Prolog disjunction; #\/
is a constraint
(disjunctive constraint). ;
introduces a choice point in your
code, which you might use to write a search procedure; #\/
imposes a constraint, which you might use to model a problem.
ic
and ic_global
?
The constraints have the same declarative semantics (what they do,
conceptually), but different operational semantics (how they do it, in
practice). Those in ic_global
perform more computation, but
achieve more propagation. In
simple terms, the prpagation in the ic_global
takes a more
"global" view of the constraint by reasoning over several variables at the
same time, rather than just pairs of variables. For example,
all_different
in ic
is decomposed into
#\=
constraints between all possible pairs of variables, where
as the
ic
considers the variables in the constraint together.
ECLiPSe is able to interface with the open-source Coin-OR project's solvers via their Open Solver Interface (OSI); currently this is mainly interfaced to the CLP/CBC solvers, with a prototype to SYMPHONY/CLP solvers. It is also able to interface to the commercial solvers ILOG's CPLEX and Dash Optimization's Xpress-MP, but no license for either is included with ECLiPSe 5.8 or later. Both companies offer academic licences at discounted rates. Dash offers free academic licenses to Universities through their Academic Partner Program.
The interface to Xpress-MP is only up to versions of Xpress-MP
developed in 2005, because the developers does not have access to later
versions of the solvers. If anyone wants to continue the development of
the interface, or provide access to Xpress-MP solver for development,
please contact the developers via the mail list.
To use eplex with CPLEX with a normal license file, you need to have
the environment variable ILOG_LICENSE_FILE setup to point to the location
of your license file (access.ilm
). Note that we do not
distribute a binary package for the eplex CPLEX interface, because this
requires the commercial binaries from ILOG to be included in the
distribution. Instead, you need to compile ECLiPSe from the source to
use it. See the Setup Guide included in the source distribution for
more details.
The exact types of problems that can be solved depend on the solver that
eplex is interfaced to. At the minimum, eplex should be able to solve
linear problems (LP), and probably also mixed integer linear problems
(MILP). In addition, eplex supports the specification of a quadratic
objective function, so if supported by the solver, it can also solve
quadratic problems (QP) and mixed integer quadratic problems (MIQP). Note
that if you are using a commercial solver, your license may not permit you
to solve all problem types, even if the solver supports it.
The exact method used to solve the problem is determined by the solver. The
eplex library does provide options to specify the solving method that
should be used, but this will only be meaningful if the solver supports the
specified method. The common solving methods are: Simplex (primal and
dual), and interior point (barrier) methods. Note that some solvers places
restrictions on the problem types that can be solved by a particular
method. In addition, for commercial solvers, your license may limit the
solving methods you can use.
A library for symmetry breaking during search.
Both are possible. See "Embedding and Interfacing Manual".
Call the ECLiPSe compile/1
predicate using the ECLiPSe
external interface, from your external program. For example, from C++,
any of the following (which are all equivalent):
post_goal(term(EC_functor("compile",1),"predicate"));
post_goal("compile(\"predicate\")");
post_goal("compile('predicate')");
ECLiPSe expects the file with the predicate called to be in the running process's "current directory". When the predicate is invoked from an external program, the current directory is not under ECLiPSe's control.
Specify an absolute pathname to your ecl file by:
post_goal(term(EC_functor("compile",1),"//C/foo/bar/predicate"));
(but note the generic ECLiPSe pathname syntax, see os_file_name/2
).
You probably initialise ECLiPSe repeatedly. You are supposed
to call ec_init()
just once, and then post goals repeatedly.
Do not call ec_cleanup()
and do not try to re-init ECLiPSe.