Aleph-w  1.9
General library for algorithms and data structures
Simplex.H
1 
2 /* Aleph-w
3 
4  / \ | | ___ _ __ | |__ __ __
5  / _ \ | |/ _ \ '_ \| '_ \ ____\ \ /\ / / Data structures & Algorithms
6  / ___ \| | __/ |_) | | | |_____\ V V / version 1.9b
7  /_/ \_\_|\___| .__/|_| |_| \_/\_/ https://github.com/lrleon/Aleph-w
8  |_|
9 
10  This file is part of Aleph-w library
11 
12  Copyright (c) 2002-2018 Leandro Rabindranath Leon & Alejandro Mujica
13 
14  This program is free software: you can redistribute it and/or modify
15  it under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  This program is distributed in the hope that it will be useful, but
20  WITHOUT ANY WARRANTY; without even the implied warranty of
21  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22  General Public License for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with this program. If not, see <https://www.gnu.org/licenses/>.
26 */
27 
28 # ifndef SIMPLEX_H
29 # define SIMPLEX_H
30 
31 # include <limits>
32 # include <fstream>
33 # include <tpl_dynMat.H>
34 # include <tpl_dynDlist.H>
35 # include <format.H>
36 
37 namespace Aleph {
38 
39 
62 template <typename T> class Simplex
63 {
64 public:
65 
67  enum State { Not_Solved, Solving, Unbounded, Solved, Unfeasible };
68 
69 private:
70 
71 
72  // selecciona la celda de la función objetivo con menor
73  // valor. Retorna -1 si todas las celdas son negativas
74 
75  int compute_pivot_col() const noexcept
76  {
77  T minimum = numeric_limits<T>::max();
78  int p = -1;
79  for (int i = 0, M = num_var + num_rest; i < M; i++)
80  {
81  const T & c = m->read(0, i);
82  if (c < minimum)
83  {
84  p = i;
85  minimum = c;
86  }
87  }
88  return minimum >= 0 ? -1 : p;
89  }
90 
91  // selecciona entre los elementos B el menor valor de división
92  // entre el col_idx coeficiente de la función objetivo que
93  // sea positivo
94  int compute_pivot_row(int p) const noexcept
95  {
96  assert(p >= 0 and p < num_var + num_rest);
97 
98  int q = -1;
99  T min_ratio = numeric_limits<T>::max();
100  for (int i = q + 1, M = num_var + num_rest; i <= num_rest; i++)
101  {
102  const T val = m->read(i, M);
103  if (val < 0)
104  continue;
105 
106  const T den = m->read(i, p);
107  if (den <= 0)
108  continue;
109 
110  const T ratio = val / den;
111  if (ratio < min_ratio)
112  {
113  q = i;
114  min_ratio = ratio;
115  }
116  }
117  return q;
118  }
119 
120  State select_pivot(int & p, int & q) noexcept
121  {
122  assert(state == Not_Solved or state == Solving);
123 
124  const int col = compute_pivot_col();
125  if (col == -1)
126  return state = Solved;
127 
128  const int row = compute_pivot_row(col);
129  if (row == -1)
130  return state = Unbounded;
131 
132  p = row;
133  q = col;
134 
135  return state = Solving;
136  }
137 
138  void to_pivot(size_t p, size_t q)
139  {
140  assert(p <= num_rest and q <= num_var + num_rest);
141 
142  const int M = num_var + num_rest; // cantidad de columnas
143  const T pivot = m->read(p, q);
144  for (int j = 0; j <= M; j++) // fila del pivote
145  if (j != q)
146  m->write(p, j, m->read(p, j) / pivot);
147 
148  m->write(p, q, 1);
149 
150  for (int i = 0; i <= num_rest; i++) // resto de las filas
151  for (int j = 0; j <= M; j++)
152  if (i != p and j != q)
153  m->write(i, j, m->read(i,j) - m->read(i,q)*m->read(p,j));
154 
155  for (int i = 0; i <= num_rest; i++) // col de pivote en 0 salvo q
156  if (i != p)
157  m->write(i, q, 0);
158  }
159 
160  T find_value(const size_t j) const noexcept
161  {
162  assert(j < num_var);
163 
164  T ret_val = 0.0;
165  for (int i = 1, count = 0; i < num_rest; i++)
166  {
167  const T & value = m->read(i, j);
168  if (value == 0.0)
169  continue;
170 
171  if (value == 1.0)
172  if (count++ == 0)
173  ret_val = m->read(i, num_var + num_rest);
174  else
175  return 0.0;
176  else
177  return ret_val;
178  }
179  return ret_val;
180  }
181 
182  unique_ptr<DynMatrix<T>> m;
183 
184  unique_ptr<T[]> objetive;
185 
186  DynDlist<T*> rest_list;
187 
188  size_t num_var;
189  size_t num_rest;
190 
191  unique_ptr<T[]> solution;
192 
193  public:
194 
195  private:
196 
197  State state;
198 
199  void verify_var_index(int i)
200  {
201  if (i >= num_var)
202  throw std::out_of_range("index " + to_string(i) + " out of range (" +
203  to_string(num_var - 1) + "");
204  }
205 
206  T * create_restriction()
207  {
208  T * ptr = new T [num_var + 1];
209  rest_list.append(ptr);
210  num_rest++;
211  for (int i = 0; i <= num_var; i++)
212  ptr[i] = 0;
213  return ptr;
214  }
215 
216  void create_matrix()
217  {
218  m = unique_ptr<DynMatrix<T>>(new DynMatrix<T> (num_rest + 1,
219  num_var + num_rest + 1));
220 
221  int i = 0; // llena los num_var coeficientes de la función objetivo
222  for (; i < num_var; i++)
223  m->write(0, i, -objetive[i]);
224 
225  // llena los num_var coeficientes de las restricciones
226  i = 1;
227  for (auto it = rest_list.get_it(); it.has_curr(); it.next_ne(), i++)
228  {
229  T * rest = it.get_curr_ne();
230 
231  for (int j = 0; j < num_var; j++)
232  m->write(i, j, rest[j]);
233 
234  m->write(i, num_var + i - 1, 1); // coef 1 i-esima variable slack
235 
236  m->write(i, num_var + num_rest, rest[num_var]);
237  }
238  }
239 
240 public:
241 
251  Simplex(int n)
252  : m(nullptr), objetive(new T [n]), num_var(n), num_rest(0),
253  solution(new T [num_var]), state(Not_Solved) {}
254 
255  ~Simplex()
256  {
257  rest_list.for_each([] (auto ptr) { delete [] ptr; });
258  }
259 
262  void put_objetive_function_coef(int i, const T & coef)
263  {
264  verify_var_index(i);
265  objetive[i] = coef;
266  }
267 
270  void put_objetive_function(DynArray<T> & coefs) noexcept
271  {
272  for (int i = 0; i < num_var; i++)
273  objetive[i] = coefs;
274  }
275 
278  void put_objetive_function(T coefs[]) noexcept
279  {
280  for (int i = 0; i < num_var; i++)
281  objetive[i] = coefs;
282  }
296  T * put_restriction(T * coefs = nullptr)
297  {
298  T * rest = create_restriction();
299 
300  if (coefs == nullptr)
301  return rest;
302 
303  for (int i = 0; i <= num_var; ++i)
304  rest[i] = coefs[i];
305 
306  return rest;
307  }
308 
310  T * get_restriction(int rest_num)
311  {
312  if (rest_num >= num_rest)
313  throw std::out_of_range("index " + to_string(rest_num) +
314  "out of range (" + to_string(num_rest - 1) + ")");
315 
316  int i = 1;
317  for (auto it = rest_list.get_it(); it.has_curr(); it.next_ne())
318  if (i == rest_num)
319  return it.get_curr_ne();
320  }
321 
335  {
336  T * rest = create_restriction();
337 
338  for (int i = 0; i <= num_var; ++i)
339  rest[i] = coefs[i];
340 
341  return rest;
342  }
343 
344  State latex_solve(char * name = nullptr)
345  {
346  latex_matrix(string(name) + "-0.tex");
347  for (int i, j, k = 1; true; k++)
348  {
349  const Simplex<T>::State state = select_pivot(i, j);
350 
351  string str = string(name) + "-" + to_string(k) + ".tex";
352  if (state == Simplex<T>::Unbounded or state == Simplex<T>::Solved)
353  {
354  latex_matrix(str.c_str());
355  return state;
356  }
357 
358  latex_matrix(str.c_str(), 2, i, j);
359  to_pivot(i, j);
360 
361  latex_matrix(name, i, j);
362  }
363  }
364 
379  {
380  if (state != Not_Solved)
381  throw std::logic_error("solve() has already been called");
382  if (num_rest == 0)
383  throw std::logic_error("linear program without restrictions");
384 
385  for (int i, j; true;)
386  {
387  const Simplex<T>::State state = select_pivot(i, j);
388  if (state == Simplex<T>::Unbounded or state == Simplex<T>::Solved)
389  return state;
390 
391  to_pivot(i, j);
392  }
393  }
394 
396  void load_solution() noexcept
397  {
398  for (int j = 0; j < num_var; j++)
399  solution[j] = find_value(j);
400  }
401 
404  const T & get_solution(size_t i) const noexcept
405  {
406  assert(i < num_var);
407  return solution[i];
408  }
409 
411  T objetive_value() const noexcept
412  {
413  T sum = 0;
414  for (int i = 0; i < num_var; i++)
415  sum += solution[i]*objetive[i];
416  return sum;
417  }
418 
421  bool verify_solution() const
422  {
423  for (auto it = rest_list.get_it(); it.has_curr(); it.next_ne())
424  {
425  T * rest = it.get_curr_ne();
426  T sum = 0;
427  for (int j = 0; j < num_var; j++)
428  sum += rest[j]*solution[j];
429 
430  if (sum > rest[num_var])
431  return false;
432  }
433  return true;
434  }
435 
436  void print_matrix()
437  {
438  for (int i = 0; i <= num_rest; ++i)
439  {
440  for (int j = 0; j <= num_var + num_rest; j++)
441  cout << float_f(m->read(i, j), 2) << " ";
442 
443  cout << endl;
444  }
445  }
446 
447  void latex_matrix(const string & name, int d = 2, int p = -1, int q = -1)
448  {
449  ofstream out(name, ios::out);
450 
451  const int cols = num_var + num_rest;
452 
453  out << "$\\left(\\begin{array}{c";
454  for (int i = 0; i < cols; i++)
455  out << "c";
456  out << "}" << endl;
457 
458  for (int i = 0; i <= num_rest; ++i)
459  {
460  for (int j = 0; j <= cols; j++)
461  {
462  if (i == p and j == q)
463  out << "\\circled{" << float_f(m->read(i, j), d) << "}" << " ";
464  else
465  out << float_f(m->read(i, j), d) << " ";
466  if (j != cols)
467  out << "& ";
468  }
469 
470  if (i != num_rest)
471  out << "\\\\";
472 
473  out << endl;
474  }
475  out << "\\end{array}\\right)$" << endl;
476  }
477 
478  void latex_linear_program(const string & name)
479  {
480  ofstream out(name, ios::out);
481  out << "\\begin{equation*}" << endl
482  << "Z = " ;
483  for (int i = 0; i < num_var; i++)
484  {
485  if (objetive[i] == 0.0)
486  continue;
487 
488  if (i > 0)
489  out << " + ";
490 
491  if (objetive[i] != 1.0)
492  out << objetive[i];
493  out << "x_" << i;
494  }
495  out << endl
496  << "\\end{equation*}" << endl
497  << "Sujeto a:" << endl
498  << "\\begin{eqnarray*}" << endl;
499 
500  for (auto it = rest_list.get_it(); it.has_curr(); it.next_ne())
501  {
502  T * rest = it.get_curr_ne();
503 
504  for (int i = 0; i < num_rest; i++)
505  {
506  if (rest[i] == 0.0)
507  continue;
508 
509  if (i > 0)
510  out << " + ";
511 
512  if (rest[i] != 1.0)
513  out << rest[i];
514  out << " x_" << i;
515  }
516 
517  out << " & \\leq & " << rest[num_rest];
518 
519  if (not it.is_in_last())
520  out << " \\\\";
521 
522  out << endl;
523  }
524  out << "\\end{eqnarray*}" << endl;
525  }
526 
527  size_t get_num_restrictions() const noexcept { return num_rest; }
528 
529  size_t get_num_vars() const noexcept { return num_var; }
530 
531  T * get_objetive_function() noexcept
532  {
533  return objetive;
534  }
535 
537  T & get_restriction_coef(int rest_num, int idx)
538  {
539  verify_var_index(idx);
540 
541  return get_restriction(rest_num)[idx];
542  }
543 
544  void put_restriction_coef(int rest_num, int idx, const T & coef)
545  {
546  get_restriction_coef(rest_num, idx) = coef;
547  }
548 
549  void prepare_linear_program()
550  {
551  create_matrix();
552  }
553 };
554 
555 
556 } // end namespace Aleph
557 
558 # endif // SIMPLEX_H
559 
T * put_restriction(DynArray< T > &coefs)
Definition: Simplex.H:334
Definition: Simplex.H:62
T * put_restriction(T *coefs=nullptr)
Definition: Simplex.H:296
T & get_restriction_coef(int rest_num, int idx)
retorna el coeficiente idx de la restricci{on rest_num
Definition: Simplex.H:537
auto get_it() const
Definition: htlist.H:151
Definition: tpl_dynDlist.H:51
void for_each(Operation &operation) noexcept(noexcept(operation))
Definition: htlist.H:589
T objetive_value() const noexcept
Retorna el valor de la función objetivo.
Definition: Simplex.H:411
Definition: tpl_dynMat.H:46
State solve()
Definition: Simplex.H:378
const T & get_solution(size_t i) const noexcept
Definition: Simplex.H:404
void put_objetive_function(T coefs[]) noexcept
Definition: Simplex.H:278
T * get_restriction(int rest_num)
Retorna un punero al arreglo restricción num_rest.
Definition: Simplex.H:310
Definition: ah-comb.H:35
bool verify_solution() const
Definition: Simplex.H:421
void put_objetive_function_coef(int i, const T &coef)
Definition: Simplex.H:262
State
Estados del sistema.
Definition: Simplex.H:67
Simplex(int n)
Definition: Simplex.H:251
void put_objetive_function(DynArray< T > &coefs) noexcept
Definition: Simplex.H:270
Definition: tpl_dynArray.H:159
T & append(const T &item)
Definition: tpl_dynDlist.H:149
void load_solution() noexcept
Carga los valores de las variables solución.
Definition: Simplex.H:396

Leandro Rabindranath León