Ticket #7740: trac_7740.patch

File trac_7740.patch, 11.8 KB (added by ncohen, 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  
    11cdef 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  
    44
    55include "../ext/stdsage.pxi"
    66include "../ext/interrupt.pxi"
     7from copy import copy
    78
    89class MixedIntegerLinearProgram:
    910    r"""
     
    4243         sage: p.solve(objective_only=True)     # optional - requires Glpk or COIN-OR/CBC
    4344         4.0
    4445    """
    45 
     46   
    4647    def __init__(self, maximization=True):
    4748        r"""
    4849        Constructor for the ``MixedIntegerLinearProgram`` class.
     
    210211            sage: p = MixedIntegerLinearProgram()
    211212            sage: p.set_objective(p['x'] + p['z'])
    212213            sage: p['x']
    213             x0
     214            x_0
    214215        """
    215216
    216217        try:
     
    266267            sage: p=MixedIntegerLinearProgram()
    267268            sage: v=p.new_variable(name="Test")
    268269            sage: v[5]+v[99]
    269             x0 + x1
     270            x_0 +x_1
    270271            sage: p._update_variables_name()
    271272        """
    272273
     
    337338            sage: p.add_constraint(x[1] + 2/10*x[2], max=4)
    338339            sage: p.add_constraint(15/10*x[1]+3*x[2], max=4)
    339340            sage: p.constraints()
    340             [(x0 + 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)]
    341342        """
    342343       
    343344        d = [0]*len(self._variables)
     
    363364            sage: p.add_constraint(-3*x[1] + 2*x[2], max=2)
    364365            sage: p.show()
    365366            Maximization:
    366               x0 + x1
     367              x_0 +x_1
    367368            Constraints:
    368               -3*x0 + 2*x1 <= 2
     369              -3 x_0 +2 x_1 <= 2
    369370            Variables:
    370               x0 is a real variable (min=0.0, max=+oo)
    371               x1 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)
    372373        """
    373374
    374375        inv_variables = [0]*len(self._variables)
     
    597598        # forget it ). In some LP problems, you just want a feasible solution
    598599        # and do not care about any function being optimal.
    599600
    600         try:
    601             f = self._NormalForm(obj)
    602         except:
     601        if obj != None:
     602            f = obj.f
     603        else:
    603604            return None
    604605       
    605         f.pop(0,0)
     606        f.pop(-1,0)
    606607
    607608        for (v,coeff) in f.iteritems():
    608             self._objective_i.append(self._variables[v])
     609            self._objective_i.append(v)
    609610            self._objective_values.append(coeff)
    610611
    611612    def add_constraint(self, linear_function, max=None, min=None, name=None):
     
    653654        if linear_function==0:
    654655            return None
    655656
    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
    661658
    662659        self._constraints_name.append(name)
    663660
    664         constant_coefficient = f.pop(0,0)
     661        constant_coefficient = f.pop(-1,0)
    665662
    666663        # We do not want to ignore the constant coefficient
    667664        max = (max-constant_coefficient) if max != None else None
     
    672669
    673670        for (v,coeff) in f.iteritems():
    674671            self._constraints_matrix_i.append(c)
    675             self._constraints_matrix_j.append(self._variables[v])
     672            self._constraints_matrix_j.append(v)
    676673            self._constraints_matrix_values.append(coeff)
    677674
    678675        self._constraints_bounds_max.append(max)
     
    959956            sage: p.solve(solver='GLPK', objective_only=True) # optional - requires GLPK
    960957            Traceback (most recent call last):
    961958            ...
    962             NotImplementedError: ...
     959            RuntimeError
    963960        """
    964961        if self._objective_i == None:
    965962            raise ValueError("No objective function has been defined.")
     
    992989        else:
    993990            raise NotImplementedError("'solver' should be set to 'GLPK', 'Coin', 'CPLEX' or None (in which case the default one is used).")
    994991
    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 whose
    1006         values are their coefficients. The value corresponding to key
    1007         `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] = exp-sum([c*v for (v,c) in d2.iteritems()])
    1024 
    1025         return d2           
    1026        
    1027992    def _add_element_to_ring(self, vtype):
    1028993        r"""
    1029         Creates a new variable from the main ``InfinitePolynomialRing``.
     994        Creates a new variable in the Linear Program.
    1030995
    1031996        INPUT:
    1032997
     
    10441009            sage: len(p._variables_type)
    10451010            0
    10461011            sage: p._add_element_to_ring(p.__REAL)
    1047             x0
     1012            x_0
    10481013            sage: len(p._variables_type)
    10491014            1
    10501015        """
    10511016
    1052         from sage.calculus.calculus import var
    1053         v = var('x'+str(len(self._variables)))
     1017        v = LinearFunction({len(self._variables) : 1})
    10541018
    10551019        self._variables[v] = len(self._variables)
    10561020        self._variables_type.append(vtype)
     
    12721236            sage: v = p.new_variable()
    12731237            sage: p.set_objective(v[0] + v[1])
    12741238            sage: v[0]
    1275             x0
     1239            x_0
    12761240        """
    12771241        if self._dict.has_key(i):
    12781242            return self._dict[i]
     
    12941258            sage: p=MixedIntegerLinearProgram()
    12951259            sage: v=p.new_variable(name="Test")
    12961260            sage: v[5]+v[99]
    1297             x0 + x1
     1261            x_0 +x_1
    12981262            sage: p._variables_name=['']*2
    12991263            sage: v._update_variables_name()
    13001264        """
     
    13221286            sage: v
    13231287            MIPVariable of dimension 3.
    13241288            sage: v[2][5][9]
    1325             x0
     1289            x_0
    13261290            sage: v
    13271291            MIPVariable of dimension 3.
    13281292        """
     
    13521316            sage: v = p.new_variable()
    13531317            sage: p.set_objective(v[0] + v[1])
    13541318            sage: v.items()
    1355             [(0, x0), (1, x1)]
     1319            [(0, x_0), (1, x_1)]
    13561320        """
    13571321        return self._dict.items()
    13581322
     
    13801344            sage: v = p.new_variable()
    13811345            sage: p.set_objective(v[0] + v[1])
    13821346            sage: v.values()
    1383             [x0, x1]
     1347            [x_0, x_1]
    13841348        """
    13851349        return self._dict.values()
     1350
     1351
     1352class 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