1 /*
2 4ti2 -- A software package for algebraic, geometric and combinatorial
3 problems on linear spaces.
4 
5 Copyright (C) 2006 4ti2 team.
6 Main author(s): Peter Malkin.
7 
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
12 
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 */
22 
23 #include "BinomialFactory.h"
24 #include "WeightAlgorithm.h"
25 #include <iostream>
26 #include "BitSetStream.h"
27 #include "VectorArrayStream.h"
28 #include "VectorStream.h"
29 #include "Globals.h"
30 
31 #include "Debug.h"
32 
33 #include <cstdlib>
34 
35 using namespace _4ti2_;
36 
BinomialFactory(Feasible & _feasible,const VectorArray & cost)37 BinomialFactory::BinomialFactory(
38                 Feasible& _feasible,
39                 const VectorArray& cost)
40 {
41     permutation = 0;
42     costs = 0;
43     orig_bnd = 0;
44 
45     VectorArray tmp_cost(cost);
46     check_cost(_feasible, tmp_cost);
47 
48     initialise( _feasible.get_dimension(),
49                 _feasible.get_basis(),
50                 tmp_cost,
51                 _feasible.get_urs(),
52                 _feasible.get_bnd(),
53                 _feasible.get_unbnd(),
54                 _feasible.get_grading(),
55                 _feasible.get_weights(),
56                 _feasible.get_max_weights(),
57                 _feasible.get_rhs());
58 }
59 
BinomialFactory(Feasible & _feasible,const VectorArray & cost,const BitSet & sat)60 BinomialFactory::BinomialFactory(
61                 Feasible& _feasible,
62                 const VectorArray& cost,
63                 const BitSet& sat)
64 {
65     permutation = 0;
66     costs = 0;
67     orig_bnd = 0;
68 
69     VectorArray tmp_cost(cost);
70     check_cost(_feasible, tmp_cost);
71 
72     initialise( _feasible.get_dimension(),
73                 _feasible.get_basis(),
74                 tmp_cost,
75                 _feasible.get_urs(),
76                 sat,
77                 _feasible.get_unbnd(),
78                 _feasible.get_grading(),
79                 _feasible.get_weights(),
80                 _feasible.get_max_weights(),
81                 _feasible.get_rhs());
82 }
83 
84 // Checks whether the cost function is bounded.
85 // It adds a vector to cost if needed to ensure that it is bounded.
86 void
check_cost(Feasible feasible,VectorArray & cost)87 BinomialFactory::check_cost(Feasible feasible, VectorArray& cost)
88 {
89     BitSet cost_unbnd(feasible.get_dimension());
90     bool is_bounded = feasible.bounded(cost, cost_unbnd);
91     if (!is_bounded)
92     {
93         std::cerr << "Cost function is not bounded.\n";
94         exit(1);
95     }
96     else if (!cost_unbnd.empty())
97     {
98         // If there are unbounded components, then we must insert another cost
99         // vector to ensure that the miniumum is bounded.
100         Vector tmp(cost.get_size(),0);
101         for (int i = 0; i < cost.get_size(); ++i)
102         {   if (cost_unbnd[i]) { tmp[i] = 1; } }
103         cost.insert(tmp);
104     }
105 }
106 
~BinomialFactory()107 BinomialFactory::~BinomialFactory()
108 {
109     delete permutation;
110     delete costs;
111     delete orig_bnd;
112 }
113 
114 void
initialise(int dim,const VectorArray & _lattice,const VectorArray & cost,const BitSet & urs,const BitSet & bnd,const BitSet & unbnd,const Vector & _grading,const VectorArray * _weights,const Vector * _max_weights,const Vector * _rhs)115 BinomialFactory::initialise(
116                 int dim,
117                 const VectorArray& _lattice,
118                 const VectorArray& cost,
119                 const BitSet& urs,
120                 const BitSet& bnd,
121                 const BitSet& unbnd,
122                 const Vector& _grading,
123                 const VectorArray* _weights,
124                 const Vector* _max_weights,
125                 const Vector* _rhs)
126 {
127     assert(urs.get_size() == dim);
128     assert(bnd.get_size() == dim);
129     assert(_grading.get_size() == dim);
130     assert(cost.get_size() == dim);
131 
132     delete orig_bnd;
133     orig_bnd = new BitSet(bnd);
134 
135     delete costs;
136     costs = new VectorArray(cost);
137 
138     Binomial::bnd_end = bnd.count();
139     Binomial::rs_end = dim - urs.count();
140     Binomial::size = dim + costs->get_number();
141     Binomial::urs_end = dim;
142     Binomial::cost_start = dim;
143     Binomial::cost_end = Binomial::size;
144 
145     delete permutation;
146     initialise_permutation(bnd, urs);
147 
148     delete Binomial::grading;
149     Binomial::grading = new Grading(_grading);
150     Binomial::grading->permute(*permutation);
151     DEBUG_4ti2(std::cout << "Grading:\n" << *Binomial::grading << "\n";)
152 
153     set_weights(_weights, _max_weights);
154     set_truncated(_lattice, _rhs);
155 }
156 
157 void
set_truncated(const VectorArray & _lattice,const Vector * _rhs)158 BinomialFactory::set_truncated(
159                 const VectorArray& _lattice,
160                 const Vector* _rhs)
161 {
162     delete Binomial::rhs; Binomial::rhs = 0;
163     delete Binomial::lattice; Binomial::lattice = 0;
164     if (Globals::truncation == Globals::NONE) { return; }
165     if (_rhs != 0 && orig_bnd->count() != 0)
166     {
167         if (Globals::truncation != Globals::WEIGHT)
168         {
169             assert(_rhs->get_size() == _lattice.get_size());
170             assert(_rhs->get_size() == Binomial::urs_end);
171             Binomial::rhs = new Vector(orig_bnd->count());
172             Vector::project(*_rhs, *orig_bnd, *Binomial::rhs);
173             Binomial::lattice = new VectorArray(_lattice.get_number(),
174                             orig_bnd->count());
175             VectorArray::project(_lattice, *orig_bnd, *Binomial::lattice);
176             DEBUG_4ti2(*out<<"Truncation Lattice:\n"<<*Binomial::lattice<<"\n";)
177             DEBUG_4ti2(*out<<"Truncation RHS:\n"<<*Binomial::rhs<<"\n";)
178         }
179 
180         BitSet unbnd(*orig_bnd);
181         unbnd.set_complement();
182         Vector weight(_lattice.get_size(),0);
183         Vector zero(_lattice.get_size(),0);
184         if (Globals::norm == 2)
185         {
186             lp_weight_l2(_lattice, unbnd, *_rhs, weight);
187         }
188         else
189         {
190             lp_weight_l1(_lattice, unbnd, *_rhs, weight);
191         }
192         IntegerType max = Vector::dot(*_rhs, weight);
193         DEBUG_4ti2(*out<<"Weight:\n"<<weight<<"\n";)
194         if (weight != zero) { add_weight(weight, max); }
195     }
196 }
197 
198 void
set_weights(const VectorArray * _weights,const Vector * _max_weights)199 BinomialFactory::set_weights(
200                 const VectorArray* _weights,
201                 const Vector* _max_weights)
202 {
203     delete Binomial::weights; Binomial::weights = 0;
204     delete Binomial::max_weights; Binomial::max_weights = 0;
205     if (_weights != 0 && _max_weights != 0)
206     {
207         assert(_weights->get_number() == _max_weights->get_size());
208         assert(_weights->get_size() == Binomial::urs_end);
209         Binomial::weights = new VectorArray(*_weights);
210         Binomial::max_weights = new Weight(*_max_weights);
211         BitSet unbnd(*orig_bnd);
212         unbnd.set_complement();
213         WeightAlgorithm::strip_weights(Binomial::weights, Binomial::max_weights, unbnd);
214         Binomial::weights->permute(*permutation);
215         DEBUG_4ti2(*out<<"Weights:\n"<<*Binomial::weights<<"\n";)
216         DEBUG_4ti2(*out<<"RHS:\n"<<*Binomial::max_weights<<"\n";)
217     }
218 }
219 
220 void
add_weight(const Vector & _weight,IntegerType _max_weight)221 BinomialFactory::add_weight(
222                 const Vector& _weight,
223                 IntegerType _max_weight)
224 {
225     Vector tmp(_weight);
226     tmp.permute(*permutation);
227     DEBUG_4ti2(*out<<"Weight:\n"<<tmp<<"\n";)
228     if (Binomial::weights == 0 || Binomial::max_weights == 0)
229     {
230         Binomial::weights = new VectorArray(0, _weight.get_size());
231         Binomial::weights->insert(tmp);
232         Binomial::max_weights = new Vector(1, _max_weight);
233     }
234     else
235     {
236         Binomial::weights->insert(tmp);
237         Vector tmp_max(1, _max_weight);
238         Vector* new_max_weights = new Vector(Binomial::max_weights->get_size()+1);
239         Vector::concat(*Binomial::max_weights, tmp_max, *new_max_weights);
240         delete Binomial::max_weights;
241         Binomial::max_weights = new_max_weights;
242     }
243 }
244 
245 void
initialise_permutation(const BitSet & bnd_mask,const BitSet & urs_mask)246 BinomialFactory::initialise_permutation(
247                 const BitSet& bnd_mask,
248                 const BitSet& urs_mask)
249 {
250     // Check that no variable is both urs and bounded.
251     assert(BitSet::set_disjoint(bnd_mask,urs_mask));
252 
253     int num_bnd = bnd_mask.count();
254     int num_urs = urs_mask.count();
255 
256     permutation = new Permutation(bnd_mask.get_size());
257 
258     int bnd_count = 0;
259     int urs_count = 0;
260     int nothing_count = 0;
261     // TODO: Change name of locals.
262     int bnd_index = 0;
263     int urs_index = bnd_mask.get_size() - num_urs;
264     int nothing_index = num_bnd;
265     for (Index i = 0; i < bnd_mask.get_size(); ++i)
266     {
267         if (urs_mask[i] == 1)
268         {
269             (*permutation)[urs_index + urs_count] = i;
270             ++urs_count;
271         }
272         else if (bnd_mask[i] == 1)
273         {
274             (*permutation)[bnd_index + bnd_count] = i;
275             ++bnd_count;
276         }
277         else
278         {
279             (*permutation)[nothing_index + nothing_count] = i;
280             ++nothing_count;
281         }
282     }
283 
284     // TODO: Check to see if a permutation is necessary.
285     // i.e. Is the permutation trivial?
286 }
287 
288 void
convert(const Vector & v,Binomial & b) const289 BinomialFactory::convert(const Vector& v, Binomial& b) const
290 {
291     assert(b.size == v.get_size() + costs->get_number());
292     assert(v.get_size() == costs->get_size());
293 
294     for (Index i = 0; i < v.get_size(); ++i)
295     {
296         b[i] = v[(*permutation)[i]];
297     }
298     const VectorArray& cost_matrix = *costs;
299     for (Index i = 0; i < cost_matrix.get_number(); ++i)
300     {
301         b[i+Binomial::cost_start] = Vector::dot(v,cost_matrix[i]);
302     }
303 }
304 
305 void
convert(const Binomial & b,Vector & v) const306 BinomialFactory::convert(const Binomial& b, Vector& v) const
307 {
308     assert(v.get_size() == b.urs_end);
309     for (Index i = 0; i < v.get_size(); ++i)
310     {
311         v[(*permutation)[i]] = b[i];
312     }
313 }
314 
315 void
convert(const VectorArray & vs,BinomialCollection & bc,bool orientate) const316 BinomialFactory::convert(const VectorArray& vs, BinomialCollection& bc, bool orientate) const
317 {
318     Binomial b;
319     for (int i = 0; i < vs.get_number(); ++i)
320     {
321         convert(vs[i], b);
322         if (!Binomial::overweight(b) && !Binomial::truncated(b))
323         {
324             if (orientate) { if (b.orientate()) { bc.add(b); } }
325             else { bc.add(b); }
326             assert(!b.is_non_positive());
327         }
328     }
329 }
330 
331 void
convert(const BinomialArray & bs,VectorArray & vs) const332 BinomialFactory::convert(const BinomialArray& bs, VectorArray& vs) const
333 {
334     assert(vs.get_size() == Binomial::urs_end);
335     vs.renumber(bs.get_number());
336     for (int i = 0; i < bs.get_number(); ++i) { convert(bs[i], vs[i]); }
337 }
338 
339 void
convert(const BinomialSet & bs,VectorArray & vs) const340 BinomialFactory::convert(const BinomialSet& bs, VectorArray& vs) const
341 {
342     assert(vs.get_size() == Binomial::urs_end);
343     vs.renumber(bs.get_number());
344     for (int i = 0; i < bs.get_number(); ++i) { convert(bs[i], vs[i]); }
345 }
346