Ticket #7740: trac_7740.patch
File trac_7740.patch, 11.8 KB (added by , 11 years ago) 


sage/numerical/mip.pxd
# HG changeset patch # User Nathann Cohen <nathann.cohen@gmail.com> # Date 1261830041 3600 # Node ID 5733a20b53dc569fc888cc04d66c8484f2b82973 # Parent 21efb0b3fc474972b5c7f617d99173536a3d79d0 Symbolic algebra embedded in sage.numerical.mip diff r 21efb0b3fc47 r 5733a20b53dc sage/numerical/mip.pxd
a b 1 1 cdef extern from *: 2 ctypedef double* const_double_ptr "const double*" 3 No newline at end of file 2 ctypedef double* const_double_ptr "const double*" 
sage/numerical/mip.pyx
diff r 21efb0b3fc47 r 5733a20b53dc sage/numerical/mip.pyx
a b 4 4 5 5 include "../ext/stdsage.pxi" 6 6 include "../ext/interrupt.pxi" 7 from copy import copy 7 8 8 9 class MixedIntegerLinearProgram: 9 10 r""" … … 42 43 sage: p.solve(objective_only=True) # optional  requires Glpk or COINOR/CBC 43 44 4.0 44 45 """ 45 46 46 47 def __init__(self, maximization=True): 47 48 r""" 48 49 Constructor for the ``MixedIntegerLinearProgram`` class. … … 210 211 sage: p = MixedIntegerLinearProgram() 211 212 sage: p.set_objective(p['x'] + p['z']) 212 213 sage: p['x'] 213 x 0214 x_0 214 215 """ 215 216 216 217 try: … … 266 267 sage: p=MixedIntegerLinearProgram() 267 268 sage: v=p.new_variable(name="Test") 268 269 sage: v[5]+v[99] 269 x 0 + x1270 x_0 +x_1 270 271 sage: p._update_variables_name() 271 272 """ 272 273 … … 337 338 sage: p.add_constraint(x[1] + 2/10*x[2], max=4) 338 339 sage: p.add_constraint(15/10*x[1]+3*x[2], max=4) 339 340 sage: p.constraints() 340 [(x 0 + 1/5*x1, None, 4), (3/2*x0 + 3*x1, None, 4)]341 [(x_0 +1/5 x_1, None, 4), (3/2 x_0 +3 x_1, None, 4)] 341 342 """ 342 343 343 344 d = [0]*len(self._variables) … … 363 364 sage: p.add_constraint(3*x[1] + 2*x[2], max=2) 364 365 sage: p.show() 365 366 Maximization: 366 x 0 + x1367 x_0 +x_1 367 368 Constraints: 368 3 *x0 + 2*x1 <= 2369 3 x_0 +2 x_1 <= 2 369 370 Variables: 370 x 0 is a real variable (min=0.0, max=+oo)371 x 1 is a real variable (min=0.0, max=+oo)371 x_0 is a real variable (min=0.0, max=+oo) 372 x_1 is a real variable (min=0.0, max=+oo) 372 373 """ 373 374 374 375 inv_variables = [0]*len(self._variables) … … 597 598 # forget it ). In some LP problems, you just want a feasible solution 598 599 # and do not care about any function being optimal. 599 600 600 try:601 f = self._NormalForm(obj)602 e xcept:601 if obj != None: 602 f = obj.f 603 else: 603 604 return None 604 605 605 f.pop( 0,0)606 f.pop(1,0) 606 607 607 608 for (v,coeff) in f.iteritems(): 608 self._objective_i.append( self._variables[v])609 self._objective_i.append(v) 609 610 self._objective_values.append(coeff) 610 611 611 612 def add_constraint(self, linear_function, max=None, min=None, name=None): … … 653 654 if linear_function==0: 654 655 return None 655 656 656 # In case a null constraint is given ( see tests ) 657 try: 658 f = self._NormalForm(linear_function) 659 except: 660 return None 657 f = linear_function.f 661 658 662 659 self._constraints_name.append(name) 663 660 664 constant_coefficient = f.pop( 0,0)661 constant_coefficient = f.pop(1,0) 665 662 666 663 # We do not want to ignore the constant coefficient 667 664 max = (maxconstant_coefficient) if max != None else None … … 672 669 673 670 for (v,coeff) in f.iteritems(): 674 671 self._constraints_matrix_i.append(c) 675 self._constraints_matrix_j.append( self._variables[v])672 self._constraints_matrix_j.append(v) 676 673 self._constraints_matrix_values.append(coeff) 677 674 678 675 self._constraints_bounds_max.append(max) … … 959 956 sage: p.solve(solver='GLPK', objective_only=True) # optional  requires GLPK 960 957 Traceback (most recent call last): 961 958 ... 962 NotImplementedError: ...959 RuntimeError 963 960 """ 964 961 if self._objective_i == None: 965 962 raise ValueError("No objective function has been defined.") … … 992 989 else: 993 990 raise NotImplementedError("'solver' should be set to 'GLPK', 'Coin', 'CPLEX' or None (in which case the default one is used).") 994 991 995 def _NormalForm(self, exp):996 r"""997 Returns a dictionary built from the linear function.998 999 INPUT:1000 1001  ``exp``  The expression representing a linear function.1002 1003 OUTPUT:1004 1005 A dictionary whose keys are the variables and whose1006 values are their coefficients. The value corresponding to key1007 `0` is the constant coefficient.1008 1009 EXAMPLE::1010 1011 sage: p = MixedIntegerLinearProgram()1012 sage: v = p.new_variable()1013 sage: nf = p._NormalForm(v[0] + v[1])1014 sage: nf[0], nf[v[0]], nf[v[1]]1015 (0, 1, 1)1016 """1017 1018 d2={}1019 1020 for v in exp.variables():1021 d2[v]=exp.coefficient(v)1022 1023 d2[0] = expsum([c*v for (v,c) in d2.iteritems()])1024 1025 return d21026 1027 992 def _add_element_to_ring(self, vtype): 1028 993 r""" 1029 Creates a new variable from the main ``InfinitePolynomialRing``.994 Creates a new variable in the Linear Program. 1030 995 1031 996 INPUT: 1032 997 … … 1044 1009 sage: len(p._variables_type) 1045 1010 0 1046 1011 sage: p._add_element_to_ring(p.__REAL) 1047 x 01012 x_0 1048 1013 sage: len(p._variables_type) 1049 1014 1 1050 1015 """ 1051 1016 1052 from sage.calculus.calculus import var 1053 v = var('x'+str(len(self._variables))) 1017 v = LinearFunction({len(self._variables) : 1}) 1054 1018 1055 1019 self._variables[v] = len(self._variables) 1056 1020 self._variables_type.append(vtype) … … 1272 1236 sage: v = p.new_variable() 1273 1237 sage: p.set_objective(v[0] + v[1]) 1274 1238 sage: v[0] 1275 x 01239 x_0 1276 1240 """ 1277 1241 if self._dict.has_key(i): 1278 1242 return self._dict[i] … … 1294 1258 sage: p=MixedIntegerLinearProgram() 1295 1259 sage: v=p.new_variable(name="Test") 1296 1260 sage: v[5]+v[99] 1297 x 0 + x11261 x_0 +x_1 1298 1262 sage: p._variables_name=['']*2 1299 1263 sage: v._update_variables_name() 1300 1264 """ … … 1322 1286 sage: v 1323 1287 MIPVariable of dimension 3. 1324 1288 sage: v[2][5][9] 1325 x 01289 x_0 1326 1290 sage: v 1327 1291 MIPVariable of dimension 3. 1328 1292 """ … … 1352 1316 sage: v = p.new_variable() 1353 1317 sage: p.set_objective(v[0] + v[1]) 1354 1318 sage: v.items() 1355 [(0, x 0), (1, x1)]1319 [(0, x_0), (1, x_1)] 1356 1320 """ 1357 1321 return self._dict.items() 1358 1322 … … 1380 1344 sage: v = p.new_variable() 1381 1345 sage: p.set_objective(v[0] + v[1]) 1382 1346 sage: v.values() 1383 [x 0, x1]1347 [x_0, x_1] 1384 1348 """ 1385 1349 return self._dict.values() 1350 1351 1352 class LinearFunction: 1353 r""" 1354 An elementary algebra to represent symbolic linear functions. 1355 """ 1356 1357 def __init__(self,f): 1358 r""" 1359 Constructor taking a dictionary as its argument. 1360 1361 A linear function is represented as a dictionary. The 1362 value are the coefficient of the variable represented 1363 by the keys ( which are integers ). 1364 1365 EXAMPLE:: 1366 1367 sage: from sage.numerical.mip import LinearFunction 1368 sage: LinearFunction({0 : 1, 3 : 8}) 1369 x_0 8 x_3 1370 """ 1371 self.f = f 1372 1373 def __add__(self,b): 1374 r""" 1375 Defining the + operator 1376 1377 EXAMPLE:: 1378 1379 sage: from sage.numerical.mip import LinearFunction 1380 sage: LinearFunction({0 : 1, 3 : 8}) + LinearFunction({2 : 5, 3 : 2})  16 1381 16 +x_0 +5 x_2 6 x_3 1382 """ 1383 if isinstance(b,LinearFunction): 1384 e = copy(self.f) 1385 for (id,coeff) in b.f.iteritems(): 1386 e[id] = self.f.get(id,0) + coeff 1387 return LinearFunction(e) 1388 else: 1389 el = copy(self) 1390 el.f[1] = el.f.get(1,0) + b 1391 return el 1392 1393 def __neg__(self): 1394 r""" 1395 Defining the  operator (opposite). 1396 1397 EXAMPLE:: 1398 1399 sage: from sage.numerical.mip import LinearFunction 1400 sage: LinearFunction({0 : 1, 3 : 8}) 1401 1 x_0 +8 x_3 1402 """ 1403 return LinearFunction(dict([(id,coeff) for (id, coeff) in self.f.iteritems()])) 1404 1405 def __sub__(self,b): 1406 r""" 1407 Defining the  operator (substraction). 1408 1409 EXAMPLE:: 1410 1411 sage: from sage.numerical.mip import LinearFunction 1412 sage: LinearFunction({2 : 5, 3 : 2})  3 1413 3 +5 x_2 +2 x_3 1414 sage: LinearFunction({0 : 1, 3 : 8})  LinearFunction({2 : 5, 3 : 2})  16 1415 16 +x_0 5 x_2 10 x_3 1416 """ 1417 if isinstance(b,LinearFunction): 1418 e = copy(self.f) 1419 for (id,coeff) in b.f.iteritems(): 1420 e[id] = self.f.get(id,0)  coeff 1421 return LinearFunction(e) 1422 else: 1423 el = copy(self) 1424 el.f[1] = self.f.get(1,0)  b 1425 return el 1426 1427 def __radd__(self,b): 1428 r""" 1429 Defining the + operator (right side). 1430 1431 EXAMPLE:: 1432 1433 sage: from sage.numerical.mip import LinearFunction 1434 sage: 3 + LinearFunction({2 : 5, 3 : 2}) 1435 3 +5 x_2 +2 x_3 1436 """ 1437 if isinstance(self,LinearFunction): 1438 return self.__add__(b) 1439 else: 1440 return b.__add__(self) 1441 1442 def __rsub__(self,b): 1443 r""" 1444 Defining the  operator (right side). 1445 1446 EXAMPLE:: 1447 1448 sage: from sage.numerical.mip import LinearFunction 1449 sage: 3  LinearFunction({2 : 5, 3 : 2}) 1450 3 5 x_2 2 x_3 1451 """ 1452 if isinstance(self,LinearFunction): 1453 return (self).__add__(b) 1454 else: 1455 return b.__sub__(self) 1456 1457 def __mul__(self,b): 1458 r""" 1459 Defining the * operator. 1460 1461 EXAMPLE:: 1462 1463 sage: from sage.numerical.mip import LinearFunction 1464 sage: LinearFunction({2 : 5, 3 : 2}) * 3 1465 15 x_2 +6 x_3 1466 """ 1467 return LinearFunction(dict([(id,b*coeff) for (id, coeff) in self.f.iteritems()])) 1468 1469 def __rmul__(self,b): 1470 r""" 1471 Defining the * operator (right side). 1472 1473 EXAMPLE:: 1474 1475 sage: from sage.numerical.mip import LinearFunction 1476 sage: 3 * LinearFunction({2 : 5, 3 : 2}) 1477 15 x_2 +6 x_3 1478 """ 1479 1480 return self.__mul__(b) 1481 1482 def __repr__(self): 1483 r""" 1484 Returns a string version of the linear function. 1485 1486 EXAMPLE:: 1487 1488 sage: from sage.numerical.mip import LinearFunction 1489 sage: LinearFunction({2 : 5, 3 : 2}) 1490 5 x_2 +2 x_3 1491 """ 1492 1493 cdef dict d = copy(self.f) 1494 cdef bool first = True 1495 t = "" 1496 1497 if d.has_key(1): 1498 coeff = d.pop(1) 1499 if coeff!=0: 1500 t = str(coeff) 1501 first = False 1502 1503 cdef list l = sorted(d.items()) 1504 for id,coeff in l: 1505 if coeff!=0: 1506 if not first: 1507 t+=" " 1508 t += ("+" if (not first and coeff>=0) else "")+(str(coeff)+" " if coeff!=1 else "")+"x_"+str(id) 1509 first = False 1510 return t