File: Mixed_integer_program_traits.h

package info (click to toggle)
cgal 5.5.1-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 123,536 kB
  • sloc: cpp: 763,097; ansic: 191,852; sh: 554; python: 411; makefile: 287; javascript: 180
file content (714 lines) | stat: -rw-r--r-- 29,349 bytes parent folder | download
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
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
// Copyright (c) 2018  Liangliang Nan. All rights reserved.
//
// This file is part of CGAL (www.cgal.org)
//
// $URL: https://github.com/CGAL/cgal/blob/v5.5.1/Solver_interface/include/CGAL/Mixed_integer_program_traits.h $
// $Id: Mixed_integer_program_traits.h a5b03d5 2022-04-30T14:09:18+02:00 albert-github
// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial
//
// Author(s) : Liangliang Nan

#ifndef CGAL_MIXED_INTEGER_PROGRAM_TRAITS_H
#define CGAL_MIXED_INTEGER_PROGRAM_TRAITS_H

#include <string>
#include <vector>
#include <unordered_map>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <cmath>

namespace CGAL {

        /// \cond SKIP_IN_MANUAL
        // forward declaration
        template <typename FT>
        class Mixed_integer_program_traits;

        /// The base class of solver element(e.g., Variable, Linear_constraint, and Linear_objective) in
        /// a mixed integer program

        template <typename FT>
        class Solver_entry
        {
        public:
                typedef        CGAL::Mixed_integer_program_traits<FT>        Solver;

        private:
                /// A solver element (e.g., variable, constraint, objective) cannot belong to multiple solvers.
                /// "solver" owns this entry.
                Solver_entry(
                        Solver* solver,
                        const std::string& name = "",
                        int idx = 0
                ) : solver_(solver), name_(name), index_(idx) {}

        public:
                const std::string& name() const { return name_; }
                void set_name(const std::string& n) { name_ = n; }

                int  index() const { return index_; }
                void set_index(int idx) { index_ = idx; }

                /// The solver that owns this entry
                const Solver* solver() const { return solver_; }
                Solver* solver() { return solver_; }

        private:
                Solver*                solver_; // The solver that owns this entry
                std::string        name_;
                int                        index_;

                template <typename T> friend class Variable;
                template <typename T> friend class Linear_expression;
                template <typename T> friend class Mixed_integer_program_traits;
        };


        /// The base class of solver elements that have bound constraints.
        template <typename FT>
        class Bound
        {
        private:
                Bound(FT lb = -infinity(), FT ub = +infinity());

        public:
                void set_bounds(FT lb, FT ub);
                void set_lower_bound(FT lb) { lower_bound_ = lb; }
                void set_upper_bound(FT ub) { upper_bound_ = ub; }

                void get_bounds(FT& lb, FT& ub) const;
                FT lower_bound() const { return lower_bound_; }
                FT upper_bound() const { return upper_bound_; }

                static FT infinity();

        private:
                FT                lower_bound_;
                FT                upper_bound_;

                static FT infinity_;

                template <typename T> friend class Variable;
                template <typename T> friend class Linear_constraint;
                template <typename T> friend class Mixed_integer_program_traits;
        };
        /// \endcond

        /// \ingroup PkgSolverInterfaceMIP
        ///
        /// The variable of a mixed integer program.
        ///
        /// \cgalModels `MixedIntegerProgramVariable`
        template <typename FT>
        class Variable : public Solver_entry<FT>, public Bound<FT>
        {
                /// \cond SKIP_IN_MANUAL
        public:
                enum Variable_type { CONTINUOUS, INTEGER, BINARY };

                typedef        CGAL::Bound<FT>                             Bound;
                typedef        CGAL::Solver_entry<FT>                      Solver_entry;
                typedef        CGAL::Mixed_integer_program_traits<FT>      Solver;

        private:
                /// A variable cannot belong to several solvers.
                /// "solver" owns this variable.
                Variable(
                        Solver* solver,
                        Variable_type type = CONTINUOUS,
                        FT lb = -Bound::infinity(),
                        FT ub = +Bound::infinity(),
                        const std::string& name = "",
                        int idx = 0
                );

        public:
                Variable_type variable_type() const { return variable_type_; }
                void set_variable_type(Variable_type t);

                /// Returns the value of the variable in the current solution.
                /// \note (1) Valid only if the program was successfully solved.
                ///       (2) If the variable is integer and rounded == true, then the
                ///           value will be rounded to the nearest integer.
                FT solution_value(bool rounded = false) const;

                void set_solution_value(FT value) { solution_value_ = value; }

        private:
                Variable_type        variable_type_;
                FT                solution_value_;

                template <typename T> friend class Mixed_integer_program_traits;
                /// \endcond
        };


        /// \cond SKIP_IN_MANUAL
        /// The base class of Linear_constraint and Linear_objective.
        template <typename FT>
        class Linear_expression : public Solver_entry<FT>
        {
        public:
                typedef CGAL::Solver_entry<FT>                  Solver_entry;
                typedef CGAL::Variable<FT>                        Variable;
                typedef        CGAL::Mixed_integer_program_traits<FT>        Solver;

        private:
                /// An expression cannot belong to several solvers.
                /// "solver" owns this expression.
                Linear_expression(
                        Solver* solver,
                        const std::string& name = "",
                        int idx = 0
                );

        public:
                /// Adds a coefficient to a variable.
                void  add_coefficient(const Variable* var, FT coeff);

                const std::unordered_map<const Variable*, FT>& coefficients() const { return coefficients_; }
                void  set_coefficients(const std::unordered_map<const Variable*, FT>& coeffs) { coefficients_ = coeffs; }

                FT get_coefficient(const Variable* var) const;

                // The constant term
                void set_offset(FT value) { offset_ = value; }
                FT offset() const { return offset_; }

                /// Evaluates the value of this expression at the solution found.
                /// \note (1) valid only if the problem was successfully solved.
                ///       (2) if a variable is integer and rounded == true, then the
                ///           variable value will be rounded to the nearest integer.
                FT solution_value(bool rounded = false) const;

                virtual void clear() { coefficients_.clear(); offset_ = 0.0; }

        private:
                std::unordered_map<const Variable*, FT>        coefficients_;
                FT        offset_;

                template <typename T> friend class Linear_constraint;
                template <typename T> friend class Linear_objective;
                template <typename T> friend class Mixed_integer_program_traits;
        };
        /// \endcond

        /// \ingroup PkgSolverInterfaceMIP
        ///
        /// The linear constraint of a mixed integer program.
        ///
        /// \cgalModels `MixedIntegerProgramLinearConstraint`
        template <typename FT>
        class Linear_constraint : public Linear_expression<FT>, public Bound<FT>
        {
                /// \cond SKIP_IN_MANUAL
        public:
                typedef        CGAL::Bound<FT>                         Bound;
                typedef        CGAL::Linear_expression<FT>             Linear_expression;
                typedef        CGAL::Mixed_integer_program_traits<FT>        Solver;

        private:
                /// A constraint cannot belong to several solvers.
                /// The "solver" owns this constraint.
                Linear_constraint(
                        Solver* solver,
                        FT lb = -Bound::infinity(),
                        FT ub = +Bound::infinity(),
                        const std::string& name = "",
                        int idx = 0
                );

                virtual ~Linear_constraint() {}

                template <typename T> friend class Mixed_integer_program_traits;
                /// \endcond
        };


        /// \ingroup PkgSolverInterfaceMIP
        ///
        /// The linear objective of a mixed integer program.
        ///
        /// \cgalModels `MixedIntegerProgramLinearObjective`
        ///
        template <typename FT>
        class Linear_objective : public Linear_expression<FT>
        {
                /// \cond SKIP_IN_MANUAL
        public:
                typedef        CGAL::Mixed_integer_program_traits<FT>      Solver;
                typedef CGAL::Linear_expression<FT>                 Linear_expression;
                typedef typename Linear_expression::Solver_entry    Solver_entry;

                enum Sense { MINIMIZE, MAXIMIZE, UNDEFINED };

        private:
                /// An objective cannot belong to several solvers.
                /// "solver" owns this objective.
                Linear_objective(Solver* solver, Sense sense);
                virtual ~Linear_objective() {}

        public:
                void  set_sense(Sense sense) { sense_ = sense; }
                Sense sense() const { return sense_; }

                void clear();

        private:
                Sense sense_;

                template <typename T> friend class Mixed_integer_program_traits;
                /// \endcond
        };

        /// \ingroup PkgSolverInterfaceMIP
        ///
        /// The class `CGAL::Mixed_integer_program_traits` provides an interface for
        /// formulating and solving (constrained or unconstrained) mixed integer
        /// programs. It can also be used for general linear programs.
        /// \note The solve() function is virtual and thus this class cannot be
        ///                  instantiated directly. Client code should use the inherited
        ///       classes, i.e., `CGAL::GLPK_mixed_integer_program_traits` or
        ///                  `CGAL::SCIP_mixed_integer_program_traits`. Alternatively, use
        ///       `CGAL::Mixed_integer_program_traits` as a base to derive a new model
        ///       (using e.g., <a href = "https://github.com/coin-or/Cbc"> CBC </a>,
        ///       <a href = "https://www.gurobi.com/"> Gurobi </a> for better
        ///       performance).
        ///
        /// \cond SKIP_IN_MANUAL
        /// \tparam FT Number type
        /// \endcond
        ///
        /// \cgalModels `MixedIntegerProgramTraits`
        template <typename FT>
        class Mixed_integer_program_traits
        {
                /// \cond SKIP_IN_MANUAL
        public:
                typedef CGAL::Variable<FT>                                Variable;
                typedef CGAL::Linear_constraint<FT>                        Linear_constraint;
                typedef CGAL::Linear_objective<FT>                        Linear_objective;
                typedef typename Linear_objective::Sense                Sense;
                typedef typename Variable::Variable_type                Variable_type;

        public:
                Mixed_integer_program_traits();
                ~Mixed_integer_program_traits();

                /// Creates a single variable, add it to the solver, and returns its pointer.
                /// \note (1) If name is empty or not provided, a default name (e.g., x0, x1...)
                ///                  will be given.
                ///                  (2) Memory is managed by the solver and will be automatically released
                ///                  when the solver is destroyed.
                Variable* create_variable(
                        Variable_type type = Variable::CONTINUOUS,
                        FT lb = -Variable::infinity(),
                        FT ub = +Variable::infinity(),
                        const std::string& name = ""
                );

                /// Creates a set of variables and add them to the solver.
                /// \note (1) Variables will be given default names, e.g., x0, x1...
                ///                  (2) Memory is managed by the solver and will be automatically released
                ///                  when the solver is destroyed.
                std::vector<Variable*> create_variables(std::size_t n);

                /// Creates a single linear constraint, add it to the solver, and returns the pointer.
                /// \note (1) If 'name' is empty or not provided, a default name (e.g., c0, c1...) will be given.
                ///                  (2) Memory is managed by the solver and will be automatically released when the
                ///                  solver is destroyed.
                Linear_constraint* create_constraint(
                        FT lb = -Variable::infinity(),
                        FT ub = +Variable::infinity(),
                        const std::string& name = ""
                );

                /// Creates a set of linear constraints and add them to the solver.
                /// \note (1) Constraints with be given default names, e.g., c0, c1...
                ///                  (2) Memory is managed by the solver and will be automatically released
                ///                  when the solver is destroyed.
                std::vector<Linear_constraint*> create_constraints(std::size_t n);

                /// Creates the objective function and returns the pointer.
                /// \note Memory is managed by the solver and will be automatically released
                ///                  when the solver is destroyed.
                Linear_objective* create_objective(Sense sense = Linear_objective::MINIMIZE);

                std::size_t number_of_variables() const { return variables_.size(); }
                const std::vector<Variable*>& variables() const { return variables_; }
                std::vector<Variable*>& variables() { return variables_; }

                std::size_t number_of_constraints() const { return constraints_.size(); }
                const std::vector<Linear_constraint*>& constraints() const { return constraints_; }
                std::vector<Linear_constraint*>& constraints() { return constraints_; }

                const Linear_objective* objective() const;
                Linear_objective* objective();

                std::size_t number_of_continuous_variables() const;
                std::size_t number_of_integer_variables() const;
                std::size_t number_of_binary_variables() const;

                bool is_continuous() const;                                // Returns true if all variables are continuous
                bool is_mixed_integer_program() const;        // Returns true if mixed integer program
                bool is_integer_program() const;                // Returns true if integer program
                bool is_binary_program() const;                        // Returns true if binary program

                /// Clears all variables, constraints, and the objective.
                void clear();

                /// Solves the program. Returns false if fails.
                virtual bool solve() = 0;

                /// Returns the result.
                /// The result can also be retrieved using Variable::solution_value().
                /// \note (1) Result is valid only if the solver succeeded.
                ///       (2) Each entry in the result corresponds to the variable with the
                ///                         same index in the program.
                const std::vector<FT>& solution() const { return result_; }

                /// Returns the error message.
                /// \note This function should be called after call to solve().
                const std::string& error_message() const { return error_message_; }

        protected:
                Linear_objective*                                objective_;
                std::vector<Variable*>                        variables_;
                std::vector<Linear_constraint*>        constraints_;

                std::vector<FT>                result_;
                std::string                        error_message_;
                /// \endcond
        };

        //////////////////////////////////////////////////////////////////////////

        // implementation
#ifndef DOXYGEN_RUNNING
        template<typename FT>
        FT Bound<FT>::infinity_ = 1e20;                // values larger than this value are considered infinity

        template<typename FT>
        Bound<FT>::Bound(FT lb /* = -infinity() */, FT ub /* = +infinity() */)
                : lower_bound_(lb)
                , upper_bound_(ub)
        {
        }

        template<typename FT>
        FT Bound<FT>::infinity() {
                return infinity_;
        }

        template<typename FT>
        void Bound<FT>::set_bounds(FT lb, FT ub) {
                lower_bound_ = lb;
                upper_bound_ = ub;
        }

        template<typename FT>
        void Bound<FT>::get_bounds(FT& lb, FT& ub) const {
                lb = lower_bound_;
                ub = upper_bound_;
        }


        template<typename FT>
        Variable<FT>::Variable(
                Solver* solver,
                Variable_type type /* = CONTINUOUS */,
                FT lb /* = -infinity() */,
                FT ub /* = +infinity() */,
                const std::string& name /* = "" */,
                int idx /* = 0*/
        )
                : Solver_entry(solver, name, idx)
                , Bound(lb, ub)
                , variable_type_(type)
                , solution_value_(0.0)
        {
                if (type == BINARY)
                        Bound::set_bounds(0.0, 1.0);
        }


        template<typename FT>
        void Variable<FT>::set_variable_type(Variable_type type) {
                variable_type_ = type;
                if (type == BINARY)
                        Bound::set_bounds(0.0, 1.0);
        }


        template<typename FT>
        FT Variable<FT>::solution_value(bool rounded /* = false*/) const {
                if (rounded && variable_type_ != CONTINUOUS)
                        return std::round(solution_value_);
                else
                        return solution_value_;
        }

        //////////////////////////////////////////////////////////////////////////

        template<typename FT>
        Linear_expression<FT>::Linear_expression(Solver* solver, const std::string& name, int idx)
                : Solver_entry(solver, name, idx)
                , offset_(0.0)
        {
        }


        template<typename FT>
        void Linear_expression<FT>::add_coefficient(const Variable* var, FT coeff) {
                if (coefficients_.find(var) == coefficients_.end())
                        coefficients_[var] = coeff;
                else
                        coefficients_[var] += coeff;
        }


        template<typename FT>
        FT Linear_expression<FT>::get_coefficient(const Variable* var) const {
                typename std::unordered_map<const Variable*, FT>::const_iterator pos = coefficients_.find(var);
                if (pos != coefficients_.end())
                        return pos->second;
                else {
                        std::cerr << "linear expression does not own variable " << var->name() << " (" << var->index() << ")" << std::endl;
                        return 0.0;
                }
        }


        template<typename FT>
        FT Linear_expression<FT>::solution_value(bool rounded /* = false*/) const {
                FT solution = offset_;

                typename std::unordered_map<const Variable*, FT>::const_iterator it = coefficients_.begin();
                for (; it != coefficients_.end(); ++it) {
                        const Variable* var = it->first;
                        FT coeff = it->second;
                        solution += var->solution_value(rounded) * coeff;
                }
                return solution;
        }


        template<typename FT>
        void Linear_objective<FT>::clear() {
                Linear_expression::clear();
                Solver_entry::set_name("");
                Solver_entry::set_index(0);
        }


        template<typename FT>
        Linear_constraint<FT>::Linear_constraint(
                Solver* solver,
                FT lb /* = -infinity() */,
                FT ub /* = +infinity() */,
                const std::string& name/* = "" */,
                int idx /* = 0*/
        )
                : Linear_expression(solver, name, idx)
                , Bound(lb, ub)
        {
        }

        template<typename FT>
        Linear_objective<FT>::Linear_objective(Solver* solver, Sense sense)
                : Linear_expression(solver)
                , sense_(sense)
        {
        }

        template<typename FT>
        Mixed_integer_program_traits<FT>::Mixed_integer_program_traits() {
                // Intentionally set the objective to UNDEFINED, so it will allow me to warn
                // the user if he/she forgot to set the objective sense.
                objective_ = new Linear_objective(this, Linear_objective::UNDEFINED);
        }

        template<typename FT>
        Mixed_integer_program_traits<FT>::~Mixed_integer_program_traits() {
                clear();
                delete objective_;
        }

        template<typename FT>
        void Mixed_integer_program_traits<FT>::clear() {
                for (std::size_t i = 0; i < variables_.size(); ++i)
                        delete variables_[i];
                variables_.clear();

                for (std::size_t i = 0; i < constraints_.size(); ++i)
                        delete constraints_[i];
                constraints_.clear();

                objective_->clear();
        }

        namespace internal {
                /**
                * Converts an integer v to a string of specified 'width' by
                * filling with character 'fill'
                */
                template <class Int>
                inline std::string from_integer(Int v, int width, char fill) {
                        std::ostringstream string_stream;
                        string_stream << std::setfill(fill) << std::setw(width) << v;
                        return string_stream.str();
                }
        }

        template<typename FT>
        typename Mixed_integer_program_traits<FT>::Variable* Mixed_integer_program_traits<FT>::create_variable(
                Variable_type type /* = Variable::CONTINUOUS */,
                FT lb /* = -Variable::infinity() */,
                FT ub /* = +Variable::infinity() */,
                const std::string& name /* = "" */)
        {
                Variable* v = new Variable(this, type, lb, ub);

                std::size_t idx = variables_.size();
                v->set_index(static_cast<int>(idx));

                const std::string& fixed_name = name.empty() ? "x" + internal::from_integer(idx, 9, '0') : name;
                v->set_name(fixed_name);

                variables_.push_back(v);
                return v;
        }

        template<typename FT>
        std::vector<typename Mixed_integer_program_traits<FT>::Variable*> Mixed_integer_program_traits<FT>::create_variables(std::size_t n) {
                std::vector<Variable*> variables;
                for (std::size_t i = 0; i < n; ++i) {
                        Variable* v = create_variable();
                        variables.push_back(v);
                }
                return variables;
        }

        template<typename FT>
        typename Mixed_integer_program_traits<FT>::Linear_constraint* Mixed_integer_program_traits<FT>::create_constraint(
                FT lb /* = -Variable::infinity() */,
                FT ub /* = +Variable::infinity() */,
                const std::string& name /* = "" */)
        {
                Linear_constraint* c = new Linear_constraint(this, lb, ub);

                std::size_t idx = constraints_.size();
                c->set_index(static_cast<int>(idx));

                const std::string& fixed_name = name.empty() ? "c" + internal::from_integer(idx, 9, '0') : name;
                c->set_name(fixed_name);

                constraints_.push_back(c);
                return c;
        }

        template<typename FT>
        std::vector<typename Mixed_integer_program_traits<FT>::Linear_constraint*> Mixed_integer_program_traits<FT>::create_constraints(std::size_t n) {
                std::vector<Linear_constraint*> constraints;
                for (std::size_t i = 0; i < n; ++i) {
                        Linear_constraint* v = create_constraint();
                        constraints.push_back(v);
                }
                return constraints;
        }

        template<typename FT>
        typename Mixed_integer_program_traits<FT>::Linear_objective * Mixed_integer_program_traits<FT>::create_objective(Sense sense /* = Linear_objective ::MINIMIZE*/) {
                if (objective_)
                        delete objective_;

                objective_ = new Linear_objective(this, sense);
                return objective_;
        }


        template<typename FT>
        const typename Mixed_integer_program_traits<FT>::Linear_objective * Mixed_integer_program_traits<FT>::objective() const {
                if (!objective_)
                        std::cerr << "please call \'create_objective()\' to create an objective first" << std::endl;

                return objective_;
        }

        template<typename FT>
        typename Mixed_integer_program_traits<FT>::Linear_objective * Mixed_integer_program_traits<FT>::objective() {
                if (!objective_)
                        std::cerr << "please call \'create_objective()\' to create an objective first" << std::endl;

                return objective_;
        }

        template<typename FT>
        std::size_t Mixed_integer_program_traits<FT>::number_of_continuous_variables() const {
                std::size_t num_continuous_var = 0;
                for (std::size_t i = 0; i < variables_.size(); ++i) {
                        const Variable* v = variables_[i];
                        if (v->variable_type() == Variable::CONTINUOUS)
                                ++num_continuous_var;
                }
                return num_continuous_var;
        }

        template<typename FT>
        std::size_t Mixed_integer_program_traits<FT>::number_of_integer_variables() const {
                std::size_t num_iteger_var = 0;
                for (std::size_t i = 0; i < variables_.size(); ++i) {
                        const Variable* v = variables_[i];
                        if (v->variable_type() == Variable::INTEGER)
                                ++num_iteger_var;
                }
                return num_iteger_var;
        }

        template<typename FT>
        std::size_t Mixed_integer_program_traits<FT>::number_of_binary_variables() const {
                std::size_t num_binary_var = 0;
                for (std::size_t i = 0; i < variables_.size(); ++i) {
                        const Variable* v = variables_[i];
                        if (v->variable_type() == Variable::BINARY)
                                ++num_binary_var;
                }
                return num_binary_var;
        }

        // Returns true if all variables are continuous
        template<typename FT>
        bool Mixed_integer_program_traits<FT>::is_continuous() const {
                std::size_t num = number_of_continuous_variables();
                return (num > 0) && (num == variables_.size());
        }


        // Returns true if this is a mixed integer program
        template<typename FT>
        bool Mixed_integer_program_traits<FT>::is_mixed_integer_program() const {
                std::size_t num = number_of_continuous_variables();
                return (num > 0) && (num < variables_.size());
        }


        // Returns true if inter program
        template<typename FT>
        bool Mixed_integer_program_traits<FT>::is_integer_program() const {
                std::size_t num = number_of_integer_variables();
                return (num > 0) && (num == variables_.size());
        }


        // Returns true if binary program
        template<typename FT>
        bool Mixed_integer_program_traits<FT>::is_binary_program() const {
                std::size_t num = number_of_binary_variables();
                return (num > 0) && (num == variables_.size());
        }
#endif
} // namespace CGAL

#endif // CGAL_MIXED_INTEGER_PROGRAM_TRAITS_H