-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathintvar.cpp
More file actions
259 lines (236 loc) · 7.85 KB
/
intvar.cpp
File metadata and controls
259 lines (236 loc) · 7.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
/*
* mini-cp is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License v3
* as published by the Free Software Foundation.
*
* mini-cp is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with mini-cp. If not, see http://www.gnu.org/licenses/lgpl-3.0.en.html
*
* Copyright (c) 2018. by Laurent Michel, Pierre Schaus, Pascal Van Hentenryck
*/
#include <utils.hpp>
#include "intvar.hpp"
#include "store.hpp"
#include <algorithm>
void printVar(var<int>* x) {
x->print(std::cout) << std::endl;
}
void printVar(var<int>::Ptr x) {
x->print(std::cout) << std::endl;
}
IntVarImpl::IntVarImpl(CPSolver::Ptr& cps,int min,int max)
: _solver(cps),
_dom(new (cps) BitDomain(cps->getStateManager(),cps->getStore(),min,max)), // allocate domain on stack allocator
_onBindList(cps->getStateManager(),cps->getStore()),
_onBoundsList(cps->getStateManager(),cps->getStore()),
_onDomList(cps->getStateManager(),cps->getStore()),
_domListener(new (cps) DomainListener(this))
{}
class ClosureConstraint : public Constraint {
std::function<void(void)> _f;
public:
ClosureConstraint(CPSolver::Ptr cp,std::function<void(void)>&& f)
: Constraint(cp),
_f(std::move(f)) {}
void post() {}
void propagate() {
_f();
}
};
TLCNode* IntVarImpl::whenBind(std::function<void(void)>&& f)
{
return propagateOnBind(new (getSolver()) ClosureConstraint(_solver,std::move(f)));
}
TLCNode* IntVarImpl::whenBoundsChange(std::function<void(void)>&& f)
{
return propagateOnBoundChange(new (getSolver()) ClosureConstraint(_solver,std::move(f)));
}
TLCNode* IntVarImpl::whenDomainChange(std::function<void(void)>&& f)
{
return propagateOnDomainChange(new (getSolver()) ClosureConstraint(_solver,std::move(f)));
}
void IntVarImpl::assign(int v)
{
TRACE
(
if(not (isBound() and contains(v)))
{
printf("[DEBUG] Setting %d to ", v);
printVar(this);
}
)
_dom->assign(v,*_domListener);
}
void IntVarImpl::remove(int v)
{
TRACE
(
if (contains(v))
{
printf("[DEBUG] Removing %d from ", v);
printVar(this);
}
)
_dom->remove(v,*_domListener);
}
void IntVarImpl::removeBelow(int newMin)
{
TRACE
(
if (newMin > min())
{
printf("[DEBUG] Increasing min to %d of ", newMin);
printVar(this);
}
)
_dom->removeBelow(newMin,*_domListener);
}
void IntVarImpl::removeAbove(int newMax)
{
TRACE
(
if (newMax < max())
{
printf("[DEBUG] Decreasing max to %d of ", newMax);
printVar(this);
}
)
_dom->removeAbove(newMax,*_domListener);
}
void IntVarImpl::updateBounds(int newMin,int newMax)
{
//_dom->removeBelow(newMin,*_domListener);
//_dom->removeAbove(newMax,*_domListener);
removeBelow(newMin);
removeAbove(newMax);
}
void IntVarImpl::DomainListener::empty()
{
failNow();
}
void IntVarImpl::DomainListener::bind()
{
for(auto& f : theVar->_onBindList)
theVar->_solver->schedule(f);
}
void IntVarImpl::DomainListener::change()
{
for(auto& f : theVar->_onDomList)
theVar->_solver->schedule(f);
}
void IntVarImpl::DomainListener::changeMin()
{
for(auto& f : theVar->_onBoundsList)
theVar->_solver->schedule(f);
}
void IntVarImpl::DomainListener::changeMax()
{
for(auto& f : theVar->_onBoundsList)
theVar->_solver->schedule(f);
}
namespace Factory {
var<int>::Ptr makeIntVar(CPSolver::Ptr cps,int min,int max) {
var<int>::Ptr rv = new (cps) IntVarImpl(cps,min,max); // allocate var on stack allocator
cps->registerVar(rv);
return rv;
}
var<int>::Ptr makeIntVar(CPSolver::Ptr cps,int n) {
var<int>::Ptr rv = new (cps) IntVarImpl(cps,n); // allocate var on stack allocator
cps->registerVar(rv);
return rv;
}
var<int>::Ptr makeIntVar(CPSolver::Ptr cps,std::initializer_list<int> vals) {
auto minVal = std::min(vals);
auto maxVal = std::max(vals);
auto var = makeIntVar(cps,minVal,maxVal);
for(int k=minVal;k <= maxVal;k++) {
if (std::find(vals.begin(),vals.end(),k) == vals.end())
var->remove(k);
}
return var;
}
var<int>::Ptr makeIntVar(CPSolver::Ptr cps, std::vector<int> const & values)
{
// Values are sorted
int minValue = values.front();
int maxValue = values.back();
auto var = makeIntVar(cps, minValue, maxValue);
int idx = 0;
for(int value = minValue; value <= maxValue; value += 1)
{
if (value == values[idx])
{
idx += 1;
}
else
{
var->remove(value);
}
}
return var;
}
var<bool>::Ptr makeBoolVar(CPSolver::Ptr cps)
{
var<bool>::Ptr rv = new (cps) var<bool>(cps);
cps->registerVar(rv);
return rv;
}
var<bool>::Ptr makeBoolVar(CPSolver::Ptr cps, bool value)
{
var<bool>::Ptr rv = new (cps) var<bool>(cps);
rv->assign(value);
cps->registerVar(rv);
return rv;
}
/**
* ldm : This factory method for a vector of var<int> is meant to not only allocate the vector
* and the elements, but, more importantly, to allocate on the library Store (Storage type).
* To Make STL work peacefully here, we need an _adapter_ type that wraps our own allocator
* and passes it to the vector constructor. Note that this is a stateful allocator and its
* type is also part of the STL vector template. So this is no longer a vector<var<int>::Ptr>
* Rather it is now a vector<var<int>::Ptr,alloc> where alloc is the type of the allocator
* adapter (see the .hpp file for its definition!). STL allocators are _typed_ for
* what type of value they can allocate. We would need one using clause per type of allocator
* we might ever need (ugly, but that's STL's constraint).
* With the 'auto' keyword, this is invisible to the modeler. Clearly, vector<var<int>::Ptr> and
* vector<var<int>::Ptr,alloc> are two distinct and incompatible types. Either use auto, or
* rely on C++ decltype primitive.
* The mechanism for allocating STL objects fully on the system stack is the same. Only caveat
* You first need to create an stl::CoreAlloc (a class of mine) to grab space on the stack and
* create an adapter from it again. Observe how CoreAlloc and Storage both have the same API. They
* are both stack-allocator (meaning FIFO allocation, no free).
*/
Veci intVarArray(CPSolver::Ptr cps,int sz,int min,int max) {
Veci a(sz,(alloci(cps->getStore())));
for(int i=0;i<sz;i++)
a[i] = Factory::makeIntVar(cps,min,max);
return a;
}
Veci intVarArray(CPSolver::Ptr cps,int sz,int n)
{
Veci a(sz,(alloci(cps->getStore())));
for(int i=0;i<sz;i++)
a[i] = Factory::makeIntVar(cps,n);
return a;
}
Veci intVarArray(CPSolver::Ptr cps,int sz) {
return Veci(sz,(alloci(cps->getStore())));
}
Vecb boolVarArray(CPSolver::Ptr cps,int sz,bool createVar) {
Vecb a(sz,(allocb(cps->getStore())));
if (createVar)
for(int i =0;i < sz;i++)
a[i] = Factory::makeBoolVar(cps);
return a;
}
std::vector<var<int>::Ptr> makeIntVars(CPSolver::Ptr cps, int sz, int min, int max) {
std::vector<var<int>::Ptr> a(sz);
for(int i=0;i<sz;i++)
a[i] = Factory::makeIntVar(cps,min,max);
return a;
}
};