Skip to content
This repository has been archived by the owner on Jan 30, 2023. It is now read-only.

Commit

Permalink
Merge branch 't/20325/genericbackend__add_default_implementation_of__…
Browse files Browse the repository at this point in the history
…add_variables__and__add_linear_constraints_' into t/20600/more_failing_tests_related_to_cplex___gurobi
  • Loading branch information
Matthias Koeppe committed May 24, 2016
2 parents 95c87d1 + 987f609 commit 5447320
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 293 deletions.
35 changes: 0 additions & 35 deletions src/sage/numerical/backends/coin_backend.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -487,41 +487,6 @@ cdef class CoinBackend(GenericBackend):
self.si.deleteRows(m,rows)
sig_free(rows)

cpdef add_linear_constraints(self, int number, lower_bound, upper_bound, names = None):
"""
Add ``'number`` linear constraints.
INPUT:
- ``number`` (integer) -- the number of constraints to add.
- ``lower_bound`` - a lower bound, either a real value or ``None``
- ``upper_bound`` - an upper bound, either a real value or ``None``
- ``names`` - an optional list of names (default: ``None``)
EXAMPLE::
sage: from sage.numerical.backends.generic_backend import get_solver
sage: p = get_solver(solver = "Coin") # optional - cbc
sage: p.add_variables(5) # optional - cbc
4
sage: p.add_linear_constraints(5, None, 2) # optional - cbc
sage: p.row(4) # optional - cbc
([], [])
sage: p.row_bounds(4) # optional - cbc
(None, 2.0)
sage: p.add_linear_constraints(2, None, 2, names=['foo','bar']) # optional - cbc
sage: p.row_name(6) # optional - cbc
'bar'
"""

cdef int i
for 0<= i<number:
self.add_linear_constraint([],lower_bound, upper_bound, name = (names[i] if names else None))


cpdef add_linear_constraint(self, coefficients, lower_bound, upper_bound, name = None):
"""
Add a linear constraint.
Expand Down
15 changes: 9 additions & 6 deletions src/sage/numerical/backends/cplex_backend.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,9 @@ cdef class CPLEXBackend(GenericBackend):
elif vtype != 1:
raise ValueError("Exactly one parameter of 'binary', 'integer' and 'continuous' must be 'True'.")

cdef int numcols_before
numcols_before = CPXgetnumcols(self.env, self.lp)

cdef int status
status = CPXnewcols(self.env, self.lp, number, NULL, NULL, NULL, NULL, NULL)
check(status)
Expand All @@ -216,24 +219,24 @@ cdef class CPLEXBackend(GenericBackend):
cdef int i, j

for 0<= i < number:
j = numcols_before + i

if lower_bound != 0.0:
self.variable_lower_bound(n - i, lower_bound)
self.variable_lower_bound(j, lower_bound)
if upper_bound is not None:
self.variable_upper_bound(n - i, upper_bound)
self.variable_upper_bound(j, upper_bound)

if binary:
self.set_variable_type(n - i,0)
self.set_variable_type(j, 0)
elif integer:
self.set_variable_type(n - i,1)
self.set_variable_type(j, 1)

if names:
j = n - i
c_name = names[i]
status = CPXchgcolname(self.env, self.lp, 1, &j, &c_name)
check(status)

if c_coeff:
j = n - i
status = CPXchgobj(self.env, self.lp, 1, &j, &c_coeff)
check(status)

Expand Down
96 changes: 0 additions & 96 deletions src/sage/numerical/backends/cvxopt_backend.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -209,64 +209,6 @@ cdef class CVXOPTBackend(GenericBackend):
self.col_name_var.append(name)
return len(self.objective_function) - 1


cpdef int add_variables(self, int n, lower_bound=0.0, upper_bound=None, binary=False, continuous=True, integer=False, obj=None, names=None) except -1:
"""
Add ``n`` variables.
This amounts to adding new columns to the matrix. By default,
the variables are both positive and real.
INPUT:
- ``n`` - the number of new variables (must be > 0)
- ``lower_bound`` - the lower bound of the variable (default: 0)
- ``upper_bound`` - the upper bound of the variable (default: ``None``)
- ``binary`` - ``True`` if the variable is binary (default: ``False``).
- ``continuous`` - ``True`` if the variable is binary (default: ``True``).
- ``integer`` - ``True`` if the variable is binary (default: ``False``).
- ``obj`` - (optional) coefficient of all variables in the objective function (default: 0.0)
- ``names`` - optional list of names (default: ``None``)
OUTPUT: The index of the variable created last.
EXAMPLE::
sage: from sage.numerical.backends.generic_backend import get_solver
sage: p = get_solver(solver = "CVXOPT")
sage: p.ncols()
0
sage: p.add_variables(5)
4
sage: p.ncols()
5
sage: p.add_variables(2, lower_bound=-2.0, obj=42.0, names=['a','b'])
6
TESTS:
Check that arguments are used::
sage: p.col_bounds(5) # tol 1e-8
(-2.0, None)
sage: p.col_name(5)
'a'
sage: p.objective_coefficient(5) # tol 1e-8
42.0
"""
for i in range(n):
self.add_variable(lower_bound, upper_bound, binary, continuous, integer, obj,
None if names is None else names[i])
return len(self.objective_function) - 1;


cpdef set_variable_type(self, int variable, int vtype):
"""
Set the type of a variable.
Expand Down Expand Up @@ -464,44 +406,6 @@ cdef class CVXOPTBackend(GenericBackend):
self.row_upper_bound.append(upper_bound)
self.row_name_var.append(name)

cpdef add_linear_constraints(self, int number, lower_bound, upper_bound, names=None):
"""
Add constraints.
INPUT:
- ``number`` (integer) -- the number of constraints to add.
- ``lower_bound`` - a lower bound, either a real value or ``None``
- ``upper_bound`` - an upper bound, either a real value or ``None``
- ``names`` - an optional list of names (default: ``None``)
EXAMPLE::
sage: from sage.numerical.backends.generic_backend import get_solver
sage: p = get_solver(solver = "CVXOPT")
sage: p.add_variables(5)
4
sage: p.add_linear_constraints(5, None, 2)
sage: p.row(4)
([], [])
sage: p.row_bounds(4)
(None, 2)
TESTS:
It does not add mysterious new variables::
sage: p.ncols()
5
"""
for i in range(number):
self.add_linear_constraint([], lower_bound, upper_bound,
name=None if names is None else names[i])

cpdef int solve(self) except -1:
"""
Solve the problem.
Expand Down
74 changes: 64 additions & 10 deletions src/sage/numerical/backends/generic_backend.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,12 @@ cdef class GenericBackend:
"""
raise NotImplementedError()

cpdef int add_variables(self, int n, lower_bound=0, upper_bound=None, binary=False, continuous=True, integer=False, obj=None, names=None) except -1:
cpdef int add_variables(self, int n, lower_bound=False, upper_bound=None, binary=False, continuous=True, integer=False, obj=None, names=None) except -1:
"""
Add ``n`` variables.
This amounts to adding new columns to the matrix. By default,
the variables are both positive and real.
the variables are both nonnegative and real.
INPUT:
Expand Down Expand Up @@ -135,8 +135,35 @@ cdef class GenericBackend:
5
sage: p.add_variables(2, lower_bound=-2.0, integer=True, names=['a','b']) # optional - Nonexistent_LP_solver
6
TESTS:
Check that arguments are used::
sage: p.col_bounds(5) # tol 1e-8, optional - Nonexistent_LP_solver
(-2.0, None)
sage: p.is_variable_integer(5) # optional - Nonexistent_LP_solver
True
sage: p.col_name(5) # optional - Nonexistent_LP_solver
'a'
sage: p.objective_coefficient(5) # tol 1e-8, optional - Nonexistent_LP_solver
42.0
"""
raise NotImplementedError()
cdef int i
cdef int value
if lower_bound is False:
lower_bound = self.zero()
if obj is None:
obj = self.zero()
for i in range(n):
value = self.add_variable(lower_bound = lower_bound,
upper_bound = upper_bound,
binary = binary,
continuous = continuous,
integer = integer,
obj = obj,
name = None if names is None else names[i])
return value

@classmethod
def _test_add_variables(cls, tester=None, **options):
Expand All @@ -155,12 +182,27 @@ cdef class GenericBackend:
p = cls() # fresh instance of the backend
if tester is None:
tester = p._tester(**options)
# Test from CVXOPT interface (part 1):
# Test from CVXOPT interface:
ncols_added = 5
ncols_before = p.ncols()
add_variables_result = p.add_variables(ncols_added)
ncols_after = p.ncols()
tester.assertEqual(ncols_after, ncols_before+ncols_added, "Added the wrong number of columns")
# Test from CVXOPT interface, continued; edited to support InteractiveLPBackend
ncols_before = p.ncols()
try:
col_bounds = (-2.0, None)
add_variables_result = p.add_variables(2, lower_bound=col_bounds[0], upper_bound=col_bounds[1],
obj=42.0, names=['a','b'])
except NotImplementedError:
# The InteractiveLPBackend does not allow general variable bounds.
col_bounds = (0.0, None)
add_variables_result = p.add_variables(2, lower_bound=col_bounds[0], upper_bound=col_bounds[1],
obj=42.0, names=['a','b'])
ncols_after = p.ncols()
tester.assertAlmostEqual(p.col_bounds(ncols_before), col_bounds)
tester.assertEqual(p.col_name(ncols_before), 'a')
tester.assertAlmostEqual(p.objective_coefficient(ncols_before), 42.0)

cpdef set_variable_type(self, int variable, int vtype):
"""
Expand Down Expand Up @@ -467,7 +509,13 @@ cdef class GenericBackend:
p.add_variables(2)
coeffs = ([0, vector([1, 2])], [1, vector([2, 3])])
upper = vector([5, 5])
p.add_linear_constraint_vector(2, coeffs, None, upper, 'foo')
lower = vector([0, 0])
try:
p.add_linear_constraint_vector(2, coeffs, lower, upper, 'foo')
except NotImplementedError:
# Ranged constraints are not supported by InteractiveLPBackend
lower = None
p.add_linear_constraint_vector(2, coeffs, lower, upper, 'foo')
# FIXME: Tests here. Careful what we expect regarding ranged constraints with some solvers.

cpdef add_col(self, list indices, list coeffs):
Expand Down Expand Up @@ -508,7 +556,7 @@ cdef class GenericBackend:

cpdef add_linear_constraints(self, int number, lower_bound, upper_bound, names=None):
"""
Add constraints.
Add ``'number`` linear constraints.
INPUT:
Expand All @@ -532,7 +580,9 @@ cdef class GenericBackend:
sage: p.row_bounds(4) # optional - Nonexistent_LP_solver
(None, 2.0)
"""
raise NotImplementedError()
cdef int i
for 0<= i<number:
self.add_linear_constraint([],lower_bound, upper_bound, name = (names[i] if names else None))

@classmethod
def _test_add_linear_constraints(cls, tester=None, **options):
Expand All @@ -544,9 +594,10 @@ cdef class GenericBackend:
sage: from sage.numerical.backends.generic_backend import GenericBackend
sage: p = GenericBackend()
sage: p._test_add_linear_constraints()
...
Traceback (most recent call last):
...
NotImplementedError
NotImplementedError...
"""
p = cls() # fresh instance of the backend
if tester is None:
Expand All @@ -561,8 +612,11 @@ cdef class GenericBackend:
for i in range(nrows_before, nrows_after):
tester.assertEqual(p.row(i), ([], []))
tester.assertEqual(p.row_bounds(i), (None, 2.0))
# FIXME: Not sure if we should test that no new variables were added.
# Perhaps some backend may need to introduce explicit slack variables?
# Test from COINBackend.add_linear_constraints:
tester.assertIsNone(p.add_linear_constraints(2, None, 2, names=['foo', 'bar']))
tester.assertEqual(p.row_name(6), 'bar')
# Test that it did not add mysterious new variables:
tester.assertEqual(p.ncols(), 0)

cpdef int solve(self) except -1:
"""
Expand Down
Loading

0 comments on commit 5447320

Please sign in to comment.