1/* BEGIN LICENSE BLOCK
2 * Version: CMPL 1.1
3 *
4 * The contents of this file are subject to the Cisco-style Mozilla Public
5 * License Version 1.1 (the "License"); you may not use this file except
6 * in compliance with the License.  You may obtain a copy of the License
7 * at www.eclipse-clp.org/license.
8 *
9 * Software distributed under the License is distributed on an "AS IS"
10 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See
11 * the License for the specific language governing rights and limitations
12 * under the License.
13 *
14 * The Original Code is  The ECLiPSe Constraint Logic Programming System.
15 * The Initial Developer of the Original Code is  Cisco Systems, Inc.
16 * Portions created by the Initial Developer are
17 * Copyright (C) 2006 Cisco Systems, Inc.  All Rights Reserved.
18 *
19 * Contributor(s): Pascal Brisset
20 *
21 * END LICENSE BLOCK */
22// $Id: ilog.cc,v 1.1 2006/09/23 01:54:04 snovello Exp $
23
24// External predicates for the ilog.pl module
25
26#include "classes.h"
27#include "ec2il.h"
28
29// Positions in the term attached to an Ilog Variable (object of EC_IlcIntVar)
30//  Must be COHERENT with ilog_structure in ilog.cc
31#define VARIABLE_INDEX 2
32#define SUSPENSIONS_MIN_INDEX 3
33#define SUSPENSIONS_MAX_INDEX 4
34#define SUSPENSIONS_ANY_INDEX 5
35
36#define ILOG_ALREADY_INITIALIZED PERROR
37#define ILOG_NOT_INITIALIZED PERROR
38#define CheckInit() if (!ilog_initialized) {return ILOG_NOT_INITIALIZED;}
39
40static ilog_initialized = IlcFalse;
41
42
43t_ext_type ilog_method = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
44};
45
46
47extern "C"
48int
49c_ilog_init()
50{
51  if (ilog_initialized) { m.end();}
52
53  IlcInitFloat();
54  m = IlcManager(IlcNoEdit);
55  m.useExceptions();
56  zero = IlcIntVar(m, 0, 0); zero.setValue(0);
57  ilog_initialized = IlcTrue;
58  return unify(EC_arg(1), handle(&ilog_method, m.getImpl()));
59}
60
61int
62get_handle_from_arg(int arg, t_ext_type *method, void **obj)
63{
64  return ((EC_succeed == EC_arg(arg).is_handle(method, obj)));
65}
66
67extern "C"
68c_ilog_is_intvar()
69{
70  void **obj = NULL;
71  return EC_arg(1).is_handle(intvar_method, obj);
72}
73extern "C"
74int
75c_ilog_print_info()
76{
77  CheckInit();
78  m.printInformation();
79  return(EC_succeed);
80}
81
82void
83instantiate_ecvar(EC_IlcIntVar v)
84{
85  EC_word ec_term = *v.getEC_term();
86  EC_word ec_var = EC_argument(ec_term, VARIABLE_INDEX);
87
88  if (unify(ec_var, EC_word(v.getValue())) != EC_succeed) {
89    throw IlcFailException();
90  }
91}
92
93void
94wake_range_suspensions(EC_IlcIntVar v)
95{
96  EC_word ec_term = *v.getEC_term();
97
98  ec_term.schedule_suspensions(SUSPENSIONS_MIN_INDEX);
99  ec_term.schedule_suspensions(SUSPENSIONS_MAX_INDEX);
100  ec_term.schedule_suspensions(SUSPENSIONS_ANY_INDEX);
101}
102
103void
104wake_domain_suspensions(EC_IlcIntVar v)
105{
106  EC_word ec_term = *v.getEC_term();
107
108  ec_term.schedule_suspensions(SUSPENSIONS_ANY_INDEX);
109}
110
111int
112suspend_and_unify_intvar(EC_IlcIntVar v, int arg)
113{
114  v.whenCondition(instantiate_ecvar, IlcWhenValue);
115  v.whenCondition(wake_range_suspensions, IlcWhenRange);
116  v.whenCondition(wake_domain_suspensions, IlcWhenDomain);
117  return unify(EC_arg(arg), handle(intvar_method, v.getImpl()));
118}
119
120extern "C"
121int
122c_ilog_intvar() // ilog_intvar(Term, Id, Min, Max)
123{
124  CheckInit();
125  IlcInt min = ec_arg(3).val.nint;
126  IlcInt max = ec_arg(4).val.nint;
127
128  EC_IlcIntVar v(m, min, max, EC_arg(1));
129  return suspend_and_unify_intvar(v, 2);
130}
131
132extern "C"
133int
134c_ilog_enum_var() // ilog_intvar(Term, Id, Values)
135{
136  CheckInit();
137  try {
138    IlcIntArray values = int_array_of_list(EC_arg(3));
139
140    EC_IlcIntVar v(m, values, EC_arg(1));
141
142    return suspend_and_unify_intvar(v, 2);
143  }
144  catch (Ec2ilException) {
145    // It's not a list
146    return INSTANTIATION_FAULT;
147  }
148  catch (IsLongException) {
149    // It's not a list of integers
150    return INSTANTIATION_FAULT;
151  }
152}
153
154extern "C"
155int
156c_ilog_copy_var() // ilog_copy_var(Term, Copy, Original)
157{
158  CheckInit();
159
160  IlcIntVar original;
161
162  if (get_handle_from_arg(3, intvar_method, (void**)&original)) {
163    IlcIntVar copy = original.getCopy(m);
164
165    EC_IlcIntVar v(m, copy, EC_arg(1));
166
167    return suspend_and_unify_intvar(v, 2);
168  } else {
169    return INSTANTIATION_FAULT;
170  }
171}
172
173extern "C"
174int
175c_ilog_get_range() // ilog_get_range(Var, Min, Max)
176{
177  CheckInit();
178  IlcIntVar v;
179
180  if (get_handle_from_arg(1, intvar_method, (void**)&v)) {
181    if (v.isBound()) {ec_panic("Bound variable", "ilog_get_range");}
182
183    return (unify(EC_arg(3), EC_word(v.getMax())) ||
184	    unify(EC_arg(2), EC_word(v.getMin())));
185  } else {
186    Error(INSTANTIATION_FAULT);
187  }
188}
189
190
191extern "C"
192int
193c_ilog_get_size() // ilog_get_size(Var, Size)
194{
195  CheckInit();
196  IlcIntVar v;
197
198  if (get_handle_from_arg(1, intvar_method, (void**)&v)) {
199    return (unify(EC_arg(2), EC_word(v.getSize())));
200  } else {
201    Error(INSTANTIATION_FAULT);
202  }
203}
204
205
206EC_word
207make_interval(IlcInt last, IlcInt max, EC_word l, EC_functor dotdot)
208{
209  if (last == max) { // Single number
210    return list(EC_word(max), l);
211  } else if (last == max - 1) { // 2-value interval
212    return list(EC_word(max-1), list(EC_word(max), l));
213  } else { // Interval
214    return list(term(dotdot, EC_word(last), EC_word(max)), l);
215  }
216
217}
218
219extern "C"
220c_ilog_get_domain() // ilog_get_domain(Var, List of integers and intervals)
221{
222  CheckInit();
223  IlcIntVar v;
224
225  if (get_handle_from_arg(1, intvar_method, (void**)&v)) {
226    if (v.isBound()) {ec_panic("Bound variable", "ilog_get_domain");}
227
228    IlcInt max = v.getMax();
229    EC_word l = nil();
230      EC_functor dotdot("..", 2);
231
232    if (max - v.getMin() > 100000) {
233      // Too long to return the actual domain
234      return unify(EC_arg(2), make_interval(v.getMin(), max, l, dotdot));
235    } else {
236      // Let's fetch all the values starting from the max
237      IlcInt last = max;
238
239      while (v.getNextLower(last) != last) {
240	IlcInt lower = v.getNextLower(last);
241	if (lower == last - 1) {
242	  last = lower;
243	} else {
244	  l = make_interval(last, max, l, dotdot);
245	  max = lower; last = lower;
246	}
247      }
248      l = make_interval(last, max, l, dotdot);
249      return (unify(EC_arg(2), l));
250    }
251  } else {
252    Error(INSTANTIATION_FAULT);
253  }
254}
255
256
257int
258ilog_call(IlcConstraint g, pword *handle)
259{
260  ReturnTryPushTrailCatchPop(m.add(g), handle);
261}
262
263extern "C"
264int
265c_ilog_set_value() // ilog_set_value(H, Var, IntValue)
266{
267  CheckInit();
268  IlcIntVar v;
269
270  if (get_handle_from_arg(2, intvar_method, (void**)&v)) {
271    if (v.isBound()) {
272      Assert(v.getValue() == ec_arg(3).val.nint, "c_ilog_set_value");
273      return EC_succeed;
274    } else {
275      return ilog_call(v == ec_arg(3).val.nint, ec_arg(1).val.ptr);
276    }
277  } else {
278    Error(INSTANTIATION_FAULT);
279  }
280}
281
282
283extern "C"
284int
285c_ilog_eq_vars() // ilog_eq_vars(H, X, Y)
286{
287  CheckInit();
288  IlcIntVar x, y;
289
290  if (get_handle_from_arg(2, intvar_method, (void**)&x)
291      && get_handle_from_arg(3, intvar_method, (void**)&y)) {
292    return ilog_call(x == y, ec_arg(1).val.ptr);
293  } else {
294    Error(INSTANTIATION_FAULT);
295  }
296}
297
298
299extern "C" int
300c_ilog_add() // ilog_add(SolverHandle, Constraint)
301{
302  CheckInit();
303  try {
304    return ilog_call(ec2il_cstr(EC_arg(2)), ec_arg(1).val.ptr);
305  }
306  catch (Ec2ilException) {
307    Error(INSTANTIATION_FAULT);
308  }
309  catch(IlcFailException) { // ec2il_cstr may raise this exception (element/3)
310    return EC_fail;
311  }
312}
313
314
315extern "C"
316int
317c_ilog_setmin()
318{
319  CheckInit();
320  IlcIntVar v;
321
322  if (get_handle_from_arg(2, intvar_method, (void**)&v)) {
323    ReturnTryPushTrailCatchPop(v.setValue(v.getMin()), ec_arg(1).val.ptr);
324  } else {
325    Error(INSTANTIATION_FAULT);
326  }
327}
328
329extern "C"
330int
331c_ilog_removemin()
332{
333  CheckInit();
334  IlcIntVar v;
335
336  if (get_handle_from_arg(2, intvar_method, (void**)&v)) {
337    ReturnTryPushTrailCatchPop(v.setMin(v.getMin()+1), ec_arg(1).val.ptr);
338  } else {
339    Error(INSTANTIATION_FAULT);
340  }
341}
342