1# cython: c_string_type=str, c_string_encoding=ascii
2# cython: profile=True
3# cython: embedsignature=True
4
5from __future__ import print_function
6
7import inspect
8import os.path
9from itertools import product
10try:
11    from itertools import izip
12except ImportError: # Python 3 does not have izip, use zip
13    izip = zip
14import numpy as np
15cimport numpy as np
16from scipy import sparse
17cimport cpython.ref as cpy_ref
18from CyWolfePivot cimport CyWolfePivot
19from CyPEPivot cimport CyPEPivot
20from CyPivotPythonBase cimport CyPivotPythonBase
21from CyDualPivotPythonBase cimport CyDualPivotPythonBase
22from cylp.cy cimport CyClpSimplex
23from cylp.cy cimport CyCoinModel
24from cylp.py.utils.sparseUtil import sparseConcat, csc_matrixPlus
25from cylp.py.modeling.CyLPModel import CyLPVar, CyLPArray, CyLPSolution
26from cylp.py.pivots.PivotPythonBase import PivotPythonBase
27from cylp.py.pivots.DualPivotPythonBase import DualPivotPythonBase
28from cylp.py.modeling.CyLPModel import CyLPModel
29from cylp.cy cimport CyCoinMpsIO
30
31# Initialize numpy
32np.import_array()
33
34problemStatus = ['optimal', 'primal infeasible', 'dual infeasible',
35                'stopped on iterations or time',
36                'stopped due to errors',
37                'stopped by event handler (virtual int ' \
38                                    'ClpEventHandler::event())']
39
40CLP_variableStatusEnum = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05]
41StatusToInt = {'free' : 0, 'basic' : 1, 'atUpperBound' : 2,
42                             'atLowerBound' : 3, 'superBasic' : 4,'fixed' : 5}
43IntToStatus = ['free', 'basic', 'atUpperBound',
44                             'atLowerBound', 'superBasic','fixed']
45
46startFinishOptionsDic = {'x' : 1,  #do not delete work areas
47                      'f' : 2, #use old factorization
48                      's' : 4} #skip initialization of work areas
49
50cdef class CyClpSimplex:
51    '''
52    CyClpSimplex is a Cython interface to CLP.
53    Not all methods are available but they are being added gradually.
54
55    Its constructor can create an empty object if no argument is provided.
56    However, if a :class:`CyLPModel <cylp.py.modeling.CyLPModel>` object is
57    given then the resulting ``CyClpSimplex`` object will be build from it.
58    For an example of the latter case see
59    :mod:`cylp's modeling tool. <cylp.py.modeling.CyLPModel>`
60
61    .. _simple-run:
62
63    **An easy example of how to read and solve an LP**
64
65    >>> from cylp.cy.CyClpSimplex import CyClpSimplex, getMpsExample
66    >>> s = CyClpSimplex()
67    >>> f = getMpsExample()
68    >>> s.readMps(f)
69    0
70    >>> s.initialSolve()
71    'optimal'
72
73    '''
74
75    def __cinit__(self, cyLPModel=None):
76        self.CppSelf = new CppIClpSimplex(<cpy_ref.PyObject*>self,
77                                <runIsPivotAcceptable_t>RunIsPivotAcceptable,
78                                <varSelCriteria_t>RunVarSelCriteria)
79        self.vars = []
80        #self.cbcModelExists = False
81        self.coinModel = CyCoinModel()
82
83        self.cyLPModel = cyLPModel
84        if cyLPModel:
85            if isinstance(cyLPModel, CyLPModel):
86                self.loadFromCyLPModel(cyLPModel)
87            else:
88                raise TypeError('Expected a CyLPModel as an argument to ' \
89                                'cylpSimplex constructor. Got %s' %
90                                cyLPModel.__class__)
91
92    def __dealloc__(self):
93        del self.CppSelf
94
95    cdef setCppSelf(self,  CppIClpSimplex* s):
96        del self.CppSelf
97        self.CppSelf = s
98
99    #############################################
100    # Properties
101    #############################################
102
103    property basicVariables:
104        def __get__(self):
105            cdef np.ndarray[np.int32_t, ndim=1] bv = np.zeros(self.nConstraints, dtype=np.int32)
106            self.CppSelf.getBasics(<int*>bv.data)
107            return bv
108
109    property rhs:
110        def __get__(self):
111            r = np.zeros(self.nConstraints, dtype=np.double)
112            self.getRightHandSide(r)
113            #Py_INCREF(r)
114            return r
115
116    property basisInverse:
117        def __get__(self):
118            b = np.empty((self.nConstraints, self.nConstraints), dtype=np.double)
119            cdef np.ndarray[np.double_t, ndim=1] c = np.zeros(self.nConstraints, dtype=np.double)
120            for colInd in xrange(self.nConstraints):
121                self.getBInvCol(colInd, c)
122                b[:, colInd] = c
123            return b
124
125    property tableau:
126        def __get__(self):
127            nAllVars = self.nVariables + self.nConstraints
128            t = np.empty((self.nConstraints, nAllVars), dtype=np.double)
129            cdef np.ndarray[np.double_t, ndim=1] c = np.zeros(self.nConstraints, dtype=np.double)
130            for colInd in xrange(nAllVars):
131                self.getBInvACol(colInd, c)
132                t[:, colInd] = c
133            return t
134
135    property objective:
136        '''
137        Set the objective function using this property.
138        See the :ref:`modeling example <modeling-usage>`.
139        '''
140        def __set__(self, obj):
141            if self.cyLPModel:
142                self.cyLPModel.objective = obj
143                o = self.cyLPModel.objective
144
145                if not isinstance(o, (np.ndarray)):
146                    o = o.toarray()[0]
147                self.setObjectiveArray(o.astype(np.double))
148                # This old version doesn't work in some versions of Scipy
149                # For csr_matrixPlus, o[0,i] is still a matrix, not a number
150                # This does work in some versions of SciPy
151                # It would probably be OK if csr_matrixPlus didn't override
152                # __get_item__ to always cast the result back to csr_matrixPlus
153                # I'm not actually sure why the objective is stored as
154                # csr_matrixPlus anyway... seems to not always be true.
155                #
156                #if isinstance(o, (sparse.coo_matrix,
157                #                                sparse.csc_matrix,
158                #                                sparse.csr_matrix,
159                #                                sparse.lil_matrix)):
160                #    for i in xrange(self.nVariables):
161                #        self.setObjectiveCoefficient(i, o[0,i])
162                    #if not isinstance(o, sparse.coo_matrix):
163                    #    o = o.tocoo()
164                    #for i, j, v in izip(o.row, o.col, o.data):
165                    #    self.setObjectiveCoefficient(j, v)
166                #self.setObjectiveArray(
167                #       self.cyLPModel.objective.astype(np.double))
168            else:
169                raise Exception('To set the objective function of ' \
170                                'CyClpSimplex set cylpSimplex.cyLPModel ' \
171                                'first.')
172        def __get__(self):
173            return <object>self.CppSelf.getObjective()
174
175    property objectiveCoefficients:
176        '''
177        An alternative to self.objective, with a more meaningful name
178        in a more general context. Sets and gets a numpy array.
179        '''
180        def __set__(self, coef):
181            self.objective = coef
182
183        def __get__(self):
184            return self.objective
185
186    property iteration:
187        '''
188        Number of iterations.
189        '''
190        def __get__(self):
191            return self.CppSelf.numberIterations()
192
193    property nRows:
194        '''
195        Number of rows, constraints.
196        '''
197        def __get__(self):
198            return self.CppSelf.getNumRows()
199
200    property nConstraints:
201        '''
202        Number of constraints, rows.
203        '''
204        def __get__(self):
205            return self.CppSelf.getNumRows()
206
207    property nVariables:
208        '''
209        Number of variables, columns.
210        '''
211        def __get__(self):
212            return self.CppSelf.getNumCols()
213
214    property nCols:
215        '''
216        Number of columns, variables.
217        '''
218        def __get__(self):
219            return self.CppSelf.getNumCols()
220
221    property coefMatrix:
222        '''
223        The coefficient matrix. A scipy sparse matrix.
224        '''
225        def __get__(self):
226            mat = self.matrix
227            if mat.hasGaps():
228                mat.removeGaps()
229            return csc_matrixPlus((mat.elements, mat.indices, mat.vectorStarts),
230                             shape=(self.nConstraints, self.nVariables))
231
232        def __set__(self, sparseMatrix):
233            try:
234                m = sparseMatrix.tocoo()
235            except:
236                raise Exception('coefMatrix must be a scipy sparse matrix.')
237            self.matrix = CyCoinPackedMatrix(True, m.row, m.col, m.data)
238
239    property matrix:
240        '''
241        The coefficient matrix. A CyCoinPackedMatrix.
242        '''
243        def __get__(self):
244            cdef CppCoinPackedMatrix* cppMat = self.CppSelf.getMatrix()
245            mat = CyCoinPackedMatrix()
246            mat.CppSelf = cppMat
247            return mat
248
249        def __set__(self, cyCoinPackedMatrix):
250            self.replaceMatrix(cyCoinPackedMatrix, True)
251
252    property constraints:
253        '''
254        Constraints.
255        '''
256        def __get__(self):
257            if not self.cyLPModel:
258                raise Exception('No CyClpSimplex cyLPModel.')
259            else:
260                return self.cyLPModel.constraints
261
262    property variableNames:
263        '''
264        variable names
265        '''
266        def __get__(self):
267            return self.getVariableNames()
268
269    property variables:
270        '''
271        Variables.
272        '''
273        def __get__(self):
274            if not self.cyLPModel:
275                raise Exception('No CyClpSimplex cyLPModel.')
276            else:
277                return self.cyLPModel.variables
278
279#    def getNumRows(self):
280#        '''
281#        Return number of constraints
282#        '''
283#        return self.CppSelf.getNumRows()
284
285#    def getNumCols(self):
286#        return self.CppSelf.getNumCols()
287
288    property objectiveValue:
289        '''
290        The objective value. Readonly.
291        '''
292        def __get__(self):
293            return self.CppSelf.objectiveValue()
294
295    property primalVariableSolution:
296        '''
297        Solution to the primal variables.
298
299        :rtype: Numpy array
300        '''
301        def __get__(self):
302            #if self.cbcModelExists:
303            #    return <object>self.cbcModel.getPrimalVariableSolution()
304            ret = <object>self.CppSelf.getPrimalColumnSolution()
305            if self.cyLPModel:
306                m = self.cyLPModel
307                inds = m.inds
308                d = {}
309                for v in inds.varIndex.keys():
310                    d[v] = ret[inds.varIndex[v]]
311                    var = m.getVarByName(v)
312                    if var.dims:
313                        d[v] = CyLPSolution()
314                        dimRanges = [range(i) for i in var.dims]
315                        for element in product(*dimRanges):
316#                            d[v][element] = ret[var.__getitem__(element).indices[0]]
317                            d[v][element] = ret[var.fromInd+var[element].indices[0]]
318                ret = d
319            else:
320                names = self.variableNames
321                if names:
322                    d = CyLPSolution()
323                    for i in range(len(names)):
324                        d[names[i]] = ret[i]
325                    ret = d
326            return ret
327
328    property primalVariableSolutionAll:
329        '''
330        Solution to the primal variables. Including the slacks.
331
332        :rtype: Numpy array
333        '''
334        def __get__(self):
335            #if self.cbcModelExists:
336            #    return <object>self.cbcModel.getPrimalVariableSolution()
337            return <object>self.CppSelf.getPrimalColumnSolutionAll()
338
339    property solution:
340        '''
341        Return the current point.
342
343        :rtype: Numpy array
344        '''
345        def __get__(self):
346            #if self.cbcModelExists:
347            #    return <object>self.cbcModel.getPrimalVariableSolution()
348            return <object>self.CppSelf.getSolutionRegion()
349
350    property cost:
351        '''
352        Return the cost vector.
353
354        :rtype: Numpy array
355        '''
356        def __get__(self):
357            #if self.cbcModelExists:
358            #    return <object>self.cbcModel.getPrimalVariableSolution()
359            return <object>self.CppSelf.getCostRegion()
360
361    property dualVariableSolution:
362        '''
363        Variables' reduced costs
364
365        :rtype: Numpy array
366        '''
367        def __get__(self):
368            ret = <object>self.CppSelf.getDualColumnSolution()
369            if self.cyLPModel:
370                m = self.cyLPModel
371                inds = m.inds
372                d = {}
373                for v in inds.varIndex.keys():
374                    d[v] = ret[inds.varIndex[v]]
375                    var = m.getVarByName(v)
376                    if var.dims:
377                        d[v] = CyLPSolution()
378                        dimRanges = [range(i) for i in var.dims]
379                        for element in product(*dimRanges):
380                            d[v][element] = ret[var.__getitem__(element).indices[0]]
381                ret = d
382            else:
383                names = self.variableNames
384                if names:
385                    d = CyLPSolution()
386                    for i in range(len(names)):
387                        d[names[i]] = ret[i]
388                    ret = d
389            return ret
390
391    property primalConstraintSolution:
392        '''
393        Slack variables' solution
394
395        :rtype: Numpy array
396        '''
397        def __get__(self):
398            ret = <object>self.CppSelf.getPrimalRowSolution()
399            if self.cyLPModel:
400                m = self.cyLPModel
401                inds = m.inds
402                d = {}
403                for c in inds.constIndex.keys():
404                    d[c] = ret[inds.constIndex[c]]
405                ret = d
406            else:
407                pass
408                #names = self.variableNames
409                #if names:
410                #    d = CyLPSolution()
411                #    for i in range(len(names)):
412                #        d[names[i]] = ret[i]
413                #    ret = d
414            return ret
415
416
417    property dualConstraintSolution:
418        '''
419        Dual variables' solution
420
421        :rtype: Numpy array
422        '''
423        def __get__(self):
424            ret =  <object>self.CppSelf.getDualRowSolution()
425            if self.cyLPModel:
426                m = self.cyLPModel
427                inds = m.inds
428                d = {}
429                for c in inds.constIndex.keys():
430                    d[c] = ret[inds.constIndex[c]]
431                ret = d
432            else:
433                pass
434                #names = self.variableNames
435                #if names:
436                #    d = CyLPSolution()
437                #    for i in range(len(names)):
438                #        d[names[i]] = ret[i]
439                #    ret = d
440            return ret
441
442    property reducedCosts:
443        '''
444        The reduced costs. A Numpy array.
445
446        :rtype: Numpy array
447        '''
448        def __get__(self):
449            return self.getReducedCosts()
450
451        def __set__(self, np.ndarray[np.double_t, ndim=1] rc):
452            self.CppSelf.setReducedCosts(<double*> rc.data)
453
454    cpdef getReducedCosts(self):
455        return <object>self.CppSelf.getReducedCosts()
456
457    property objectiveOffset:
458        '''
459        The constant value in the objective function. A float.
460        '''
461        def __get__(self):
462            return self.CppSelf.objectiveOffset()
463
464        def __set__(self, value):
465            self.CppSelf.setObjectiveOffset(value)
466
467    property variablesUpper:
468        '''
469        Variables upper bounds
470
471        :rtype: Numpy array
472        '''
473        def __get__(self):
474            return <object>self.CppSelf.getColUpper()
475
476        def __set__(self, upperArray):
477            self.setColumnUpperFirstElements(upperArray)
478
479    property variablesLower:
480        '''
481        Variables lower bounds
482
483        :rtype: Numpy array
484        '''
485        def __get__(self):
486            return <object>self.CppSelf.getColLower()
487
488        def __set__(self, lowerArray):
489            self.setColumnLowerFirstElements(lowerArray)
490
491    property constraintsUpper:
492        '''
493        Constraints upper bounds
494
495        :rtype: Numpy array
496        '''
497        def __get__(self):
498            return <object>self.CppSelf.getRowUpper()
499
500        def __set__(self, upperArray):
501            self.setRowUpperArray(upperArray)
502
503    property constraintsLower:
504        '''
505        Constraints lower bounds
506
507        :rtype: Numpy array
508        '''
509        def __get__(self):
510            return <object>self.CppSelf.getRowLower()
511
512        def __set__(self, lowerArray):
513            self.setRowLowerArray(lowerArray)
514
515    property lower:
516        '''
517        lower bounds (CLP's lower_)
518
519        :rtype: Numpy array
520        '''
521        def __get__(self):
522            return <object>self.CppSelf.getLower()
523
524    property upper:
525        '''
526        upper bounds (CLP's upper_)
527
528        :rtype: Numpy array
529        '''
530        def __get__(self):
531            return <object>self.CppSelf.getUpper()
532
533    property variableScale:
534        '''
535        Array of variables' scale factors
536
537        :rtype: Numpy array
538        '''
539        def __get__(self):
540            return <object>self.CppSelf.getColumnScale()
541
542    property constraintScale:
543        '''
544        Array of constraints' scale factors
545
546        :rtype: Numpy array
547        '''
548        def __get__(self):
549            return <object>self.CppSelf.getRowScale()
550
551    property integerInformation:
552        '''
553        A binary list of size *nVariables* that specifies whether
554        a variable is integer or not. (ClpModel::integerInformation())
555
556        :rtype: Numpy array
557        '''
558        def __get__(self):
559            return <object>self.CppSelf.getIntegerInformation()
560
561    property status:
562        '''
563        A Numpy array of all the variables' status
564        '''
565        def __get__(self):
566            return self.getStatusArray()
567
568    cpdef getStatusArray(self):
569        return <object>self.CppSelf.getStatusArray()
570
571    property freeOrSuperBasicVarInds:
572        '''
573        The index set of variables that are *free* or *superbasic*.
574        '''
575        def __get__(self):
576            status = self.status
577            return np.where((status & 7 == 4) | (status & 7 == 0))[0]
578
579    property notBasicOrFixedOrFlaggedVarInds:
580        '''
581        The index set of variables that are not *basic* or *fixed*.
582        '''
583        def __get__(self):
584            status = self.status
585            return np.where((status & 7 != 1) &
586                            (status & 7 != 5) &
587                            (status & 64 == 0))[0]
588
589    property varIsFree:
590        '''
591        The index set of variables that are *free*.
592        '''
593        def __get__(self):
594            status = self.status
595            return (status & 7 == 0)
596
597    property varIsBasic:
598        '''
599        The index set of variables that are *basic*.
600        '''
601        def __get__(self):
602            status = self.status
603            return (status & 7 == 1)
604
605    property varIsAtUpperBound:
606        '''
607        The index set of variables that are at their upper bound.
608        '''
609        def __get__(self):
610            status = self.status
611            return (status & 7 == 2)
612
613    property varIsAtLowerBound:
614        '''
615        The index set of variables that are at their lower bound.
616        '''
617        def __get__(self):
618            status = self.status
619            return (status & 7 == 3)
620
621    property varIsSuperBasic:
622        '''
623        The index set of variables that are *superbasic*.
624        '''
625        def __get__(self):
626            status = self.status
627            return (status & 7 == 4)
628
629    property varIsFixed:
630        '''
631        The index set of variables that are *fixed*.
632        '''
633        def __get__(self):
634            status = self.status
635            return (status & 7 == 5)
636
637    property varIsFlagged:
638        '''
639        The index set of variables that are *flagged*.
640        '''
641        def __get__(self):
642            status = self.status
643            return (status & 64 != 0)
644
645    property varNotFree:
646        '''
647        The index set of variables that are NOT *free*.
648        '''
649        def __get__(self):
650            status = self.status
651            return (status & 7 != 0)
652
653    property varNotBasic:
654        '''
655        The index set of variables that are NOT *basic*.
656        '''
657        def __get__(self):
658            status = self.status
659            return (status & 7 != 1)
660
661    property varNotAtUpperBound:
662        '''
663        The index set of variables that are NOT at their upper bound.
664        '''
665        def __get__(self):
666            status = self.status
667            return (status & 7 != 2)
668
669    property varNotAtLowerBound:
670        '''
671        The index set of variables that are NOT at their lower bound.
672        '''
673        def __get__(self):
674            status = self.status
675            return (status & 7 != 3)
676
677    property varNotSuperBasic:
678        '''
679        The index set of variables that are NOT *superbasic*.
680        '''
681        def __get__(self):
682            status = self.status
683            return (status & 7 != 4)
684
685    property varNotFixed:
686        '''
687        The index set of variables that are NOT *fixed*.
688        '''
689        def __get__(self):
690            status = self.status
691            return (status & 7 != 5)
692
693    property varNotFlagged:
694        '''
695        The index set of variables that are NOT flagged.
696        '''
697        def __get__(self):
698            status = self.status
699            return (status & 64 == 0)
700
701    property Hessian:
702        def __get__(self):
703            return self._Hessian
704
705        def __set__(self, mat):
706            m = None
707            try:
708                m = mat.tocoo()
709            except:
710                raise Exception('Hessian can be set to a matrix that ' \
711                                            'implements *tocoo* method')
712            if m:
713                coinMat = CyCoinPackedMatrix(True, m.row, m.col, m.data)
714                n = self.nVariables
715                if coinMat.majorDim < n:
716                    for i in xrange(n - coinMat.majorDim):
717                        coinMat.appendCol()
718                if coinMat.minorDim < n:
719                    for i in xrange(n - coinMat.majorDim):
720                        coinMat.appendRow()
721                self._Hessian = m
722            self.loadQuadraticObjective(coinMat)
723
724    property dualTolerance:
725        def __get__(self):
726            return self.CppSelf.dualTolerance()
727
728        def __set__(self, value):
729           self.CppSelf.setDualTolerance(value)
730
731    property primalTolerance:
732        def __get__(self):
733            return self.CppSelf.primalTolerance()
734
735        def __set__(self, value):
736           self.CppSelf.setPrimalTolerance(value)
737
738    property maxNumIteration:
739        def __get__(self):
740            return self.CppSelf.maximumIterations()
741
742        def __set__(self, value):
743           self.CppSelf.setMaxNumIteration(value)
744
745    property logLevel:
746        def __get__(self):
747            return self.CppSelf.logLevel()
748
749        def __set__(self, value):
750            self.CppSelf.setLogLevel(value)
751
752    property automaticScaling:
753        def __get__(self):
754            return self.CppSelf.automaticScaling()
755
756        def __set__(self, value):
757            self.CppSelf.setAutomaticScaling(value)
758
759    property scaling:
760        def __get__(self):
761            return self.CppSelf.scalingFlag()
762        def __set__(self, mode):
763            self.CppSelf.scaling(mode)
764
765    property infeasibilityCost:
766        def __get__(self):
767            return self.CppSelf.infeasibilityCost()
768        def __set__(self, value):
769            self.CppSelf.setInfeasibilityCost(value)
770
771
772    property numberPrimalInfeasibilities:
773        def __get__(self):
774            return self.CppSelf.numberPrimalInfeasibilities()
775
776    property optimizationDirection:
777        def __get__(self):
778            return ['ignore', 'min', 'max'][int(self.CppSelf.optimizationDirection())]
779        def __set__(self, value):
780            self.CppSelf.setOptimizationDirection({'ignore':0., 'min':1., 'max':-1.}[value])
781
782    #############################################
783    # get set
784    #############################################
785
786    def getRightHandSide(self, np.ndarray[np.double_t, ndim=1] rhs):
787        '''
788        Take a spare array, ``rhs``, and store the current right-hand-side
789        in it.
790        '''
791        self.CppSelf.getRightHandSide(<double*>rhs.data)
792
793    def getStatusCode(self):
794        '''
795        Get the probelm status as defined in CLP. Return value could be:
796
797        * -1 - unknown e.g. before solve or if postSolve says not optimal
798        * 0 - optimal
799        * 1 - primal infeasible
800        * 2 - dual infeasible
801        * 3 - stopped on iterations or time
802        * 4 - stopped due to errors
803        * 5 - stopped by event handler (virtual int ClpEventHandler::event())
804
805        '''
806        return self.CppSelf.status()
807
808    def getStatusString(self):
809        '''
810        Return the problem status in string using the code from
811        :func:`getStatusCode`
812        '''
813        return problemStatus[self.getStatusCode()]
814
815    def setColumnLower(self, ind, val):
816        '''
817        Set the lower bound of variable index ``ind`` to ``val``.
818        '''
819        self.CppSelf.setColumnLower(ind, val)
820
821    def setColumnUpper(self, ind, val):
822        '''
823        Set the upper bound of variable index ``ind`` to ``val``.
824        '''
825        self.CppSelf.setColumnUpper(ind, val)
826
827    def setRowLower(self, ind, val):
828        '''
829        Set the lower bound of constraint index ``ind`` to ``val``.
830        '''
831        self.CppSelf.setRowLower(ind, val)
832
833    def setRowUpper(self, ind, val):
834        '''
835        Set the upper bound of constraint index ``ind`` to ``val``.
836        '''
837        self.CppSelf.setRowUpper(ind, val)
838
839    def useCustomPrimal(self, customPrimal):
840        '''
841        Determines if
842        :func:`cylp.python.pivot.PivotPythonBase.isPivotAcceptable`
843        should be called just before each pivot is performed (right after the
844        entering and leaving variables are obtained.
845        '''
846        self.CppSelf.useCustomPrimal(customPrimal)
847
848    def getUseCustomPrimal(self):
849        '''
850        Return the value of ``useCustomPrimal``. See :func:`useCustomPrimal`.
851
852        :rtype: int  :math:`\in \{0, 1\}`
853        '''
854        return self.CppSelf.getUseCustomPrimal()
855
856    def flagged(self, varInd):
857        '''
858        Returns ``1`` if variable index ``varInd`` is flagged.
859
860        :rtype: int  :math:`\in \{0, 1\}`
861        '''
862        return self.CppSelf.flagged(varInd)
863
864    def setFlagged(self, varInd):
865        '''
866        Set variables index ``varInd`` flagged.
867        '''
868        self.CppSelf.setFlagged(varInd)
869
870##    def currentDualTolerance(self):
871##        return self.CppSelf.currentDualTolerance()
872##
873    def largestDualError(self):
874        return self.CppSelf.largestDualError()
875
876    def pivotRow(self):
877        '''
878        Return the index of the constraint corresponding to the (basic) leaving
879        variable.
880
881        :rtype: int
882        '''
883        return self.CppSelf.pivotRow()
884
885    def setPivotRow(self, v):
886        '''
887        Set the ``v``\ 'th variable of the basis as the leaving variable.
888        '''
889        self.CppSelf.setPivotRow(v)
890
891    def sequenceIn(self):
892        '''
893        Return the index of the entering variable.
894
895        :rtype: int
896        '''
897        return self.CppSelf.sequenceIn()
898
899    def setSequenceIn(self, v):
900        '''
901        Set the variable index ``v`` as the entering variable.
902        '''
903        self.CppSelf.setSequenceIn(v)
904
905##    def dualTolerance(self):
906##        '''
907##        Return the dual tolerance.
908##
909##        :rtype: float
910##        '''
911##        return self.CppSelf.dualTolerance()
912
913    cdef double* rowLower(self):
914        '''
915        Return the lower bounds of the constraints as a double*.
916        This can be used only in Cython.
917        '''
918        return self.CppSelf.rowLower()
919
920    cdef double* rowUpper(self):
921        '''
922        Return the upper bounds of the constraints as a double*.
923        This can be used only in Cython.
924        '''
925        return self.CppSelf.rowUpper()
926
927    def getVariableNames(self):
928        '''
929        Return the variable name. (e.g. that was set in the mps file)
930        '''
931        cdef vector[string] names = self.CppSelf.getVariableNames()
932        ret = []
933        for i in range(names.size()):
934            ret.append(names[i].c_str())
935        return ret
936
937    cpdef setVariableName(self, varInd, name):
938        '''
939        Set the name of variable index ``varInd`` to ``name``.
940
941        :arg varInd: variable index
942        :type varInd: integer
943        :arg name: desired name for the variable
944        :type name: string
945
946        '''
947        self.CppSelf.setVariableName(varInd, name)
948
949    cpdef setConstraintName(self, constInd, name):
950        '''
951        Set the name of constraint index ``constInd`` to ``name``.
952
953        :arg constInd: constraint index
954        :type constInd: integer
955        :arg name: desired name for the constraint
956        :type name: string
957
958        '''
959        self.CppSelf.setConstraintName(constInd, name)
960
961    cdef int* pivotVariable(self):
962        '''
963        Return the index set of the basic variables.
964
965        :rtype: int*
966        '''
967        return self.CppSelf.pivotVariable()
968
969    cpdef  getPivotVariable(self):
970        '''
971        Return the index set of the basic variables.
972
973        :rtype: Numpy array
974        '''
975        return <object>self.CppSelf.getPivotVariable()
976
977    cpdef CLP_getVarStatus(self, int sequence):
978        '''
979        get the status of a variable
980
981        * free : 0
982        * basic : 1
983        * atUpperBound : 2
984        * atLowerBound : 3
985        * superBasic : 4
986        * fixed : 5
987
988        :rtype: int
989        '''
990        return self.CppSelf.getStatus(sequence)
991
992    cpdef CLP_setVarStatus(self, int sequence, int status):
993        '''
994        set the status of a variable
995
996        * free : 0
997        * basic : 1
998        * atUpperBound : 2
999        * atLowerBound : 3
1000        * superBasic : 4
1001        * fixed : 5
1002
1003        '''
1004        self.CppSelf.setStatus(sequence, CLP_variableStatusEnum[status])
1005
1006    def setVariableStatus(self, arg, status):
1007        '''
1008        Set the status of a variable.
1009
1010        :arg arg: Specifies the variable to change (a CyLPVar, or an index)
1011        :type status: CyLPVar, int
1012        :arg status: 'basic', 'atUpperBound', 'atLowerBound', 'superBasic', 'fixed'
1013        :type status: string
1014
1015
1016        Example:
1017
1018        >>> from cylp.cy.CyClpSimplex import CyClpSimplex
1019        >>> s = CyClpSimplex()
1020        >>> x = s.addVariable('x', 4)
1021        >>> # Using CyLPVars:
1022        >>> s.setVariableStatus(x[1:3], 'basic')
1023        >>> s.getVariableStatus(x[1])
1024        'basic'
1025        >>> # Using a variable index directly
1026        >>> s.setVariableStatus(1, 'atLowerBound')
1027        >>> s.getVariableStatus(x[1])
1028        'atLowerBound'
1029
1030        '''
1031        status = CLP_variableStatusEnum[StatusToInt[status]]
1032        if isinstance(arg, (int, long)):
1033            self.CppSelf.setStatus(arg, status)
1034        elif True:  # isinstance(arg, CyLPVar):
1035            if self.cyLPModel is None:
1036                raise Exception('The argument of setVarStatus can be ' \
1037                                'a CyLPVar only if the object is built ' \
1038                                'using a CyLPModel.')
1039            var = arg
1040            model = self.cyLPModel
1041            inds = model.inds
1042            varName = var.name
1043            if not inds.hasVar(varName):
1044                raise Exception('No such variable: %s' % varName)
1045            x = inds.varIndex[varName]
1046            if var.parent:
1047                for i in var.indices:
1048                    self.CppSelf.setStatus(x[i], status)
1049            else:
1050                for i in xrange(var.dim):
1051                    self.CppSelf.setStatus(x[i], status)
1052
1053    def getVariableStatus(self, arg):
1054        '''
1055        Get the status of a variable.
1056        '''
1057        if isinstance(arg, (int, long)):
1058            return IntToStatus[self.CppSelf.getStatus(arg)]
1059        elif True:  # isinstance(arg, CyLPVar):
1060            if self.cyLPModel is None:
1061                raise Exception('The argument of getVarStatus can be ' \
1062                                'a CyLPVar only if the object is built ' \
1063                                'using a CyLPModel.')
1064            var = arg
1065            model = self.cyLPModel
1066            inds = model.inds
1067            varName = var.name
1068            if not inds.hasVar(varName):
1069                raise Exception('No such variable: %s' % varName)
1070            x = inds.varIndex[varName]
1071            if var.parent:
1072                s = np.array([IntToStatus[
1073                            self.CppSelf.getStatus(x[i])]
1074                            for i in var.indices])
1075            else:
1076                s = np.array([IntToStatus[
1077                            self.CppSelf.getStatus(x[i])]
1078                            for i in xrange(var.dim)])
1079            if len(s) == 1:
1080                return s[0]
1081            return s
1082
1083    def setConstraintStatus(self, arg, status):
1084        '''
1085        Set the status of a constraint.
1086
1087        :arg arg: Specifies the constraint to change (name or index)
1088        :type status: string,int
1089        :arg status: 'basic', 'atUpperBound', 'atLowerBound', 'superBasic', 'fixed'
1090        :type status: string
1091
1092        >>> from cylp.cy.CyClpSimplex import CyClpSimplex
1093        >>> s = CyClpSimplex()
1094        >>> x = s.addVariable('x', 4)
1095        >>> s.addConstraint(0 <= x[0] + x[1] <= 1, 'const1')
1096        >>> # Using constraint name:
1097        >>> s.setConstraintStatus('const1', 'atUpperBound')
1098        >>> s.getConstraintStatus('const1')
1099        'atUpperBound'
1100        >>> # Using constraint index directly
1101        >>> s.setConstraintStatus(0, 'atLowerBound')
1102        >>> s.getConstraintStatus('const1')
1103        'atLowerBound'
1104        '''
1105        status = CLP_variableStatusEnum[StatusToInt[status]]
1106        if isinstance(arg, (int, long)):
1107            arg += self.nVariables
1108            self.CppSelf.setStatus(arg, status)
1109        elif True:  # isinstance(arg, CyLPVar):
1110            if self.cyLPModel is None:
1111                raise Exception('The argument of setVarStatus can be ' \
1112                                'a CyLPVar only if the object is built ' \
1113                                'using a CyLPModel.')
1114            model = self.cyLPModel
1115            inds = model.inds
1116            constName = arg
1117            if not inds.hasConst(constName):
1118                raise Exception('No such constraint: %s' % constName)
1119            c = inds.constIndex[constName]
1120            cInds = c + self.nVariables
1121            for i in xrange(len(cInds)):
1122                self.CppSelf.setStatus(cInds[i], status)
1123
1124    def getConstraintStatus(self, arg):
1125        '''
1126        Get the status of a constraint.
1127        '''
1128        if isinstance(arg, (int, long)):
1129            arg += self.nVariables
1130            return IntToStatus[self.CppSelf.getStatus(arg)]
1131        elif True:  # isinstance(arg, CyLPVar):
1132            if self.cyLPModel is None:
1133                raise Exception('The argument of setVarStatus can be ' \
1134                                'a CyLPVar only if the object is built ' \
1135                                'using a CyLPModel.')
1136            model = self.cyLPModel
1137            inds = model.inds
1138            constName = arg
1139            if not inds.hasConst(constName):
1140                raise Exception('No such constraint: %s' % constName)
1141            c = inds.constIndex[constName]
1142            cInds = c + self.nVariables
1143            s = np.array([IntToStatus[
1144                            self.CppSelf.getStatus(cInds[i])]
1145                            for i in xrange(len(cInds))])
1146            if len(s) == 1:
1147                return s[0]
1148            return s
1149
1150
1151    def setColumnUpperArray(self, np.ndarray[np.double_t, ndim=1] columnUpper):
1152        '''
1153        columnUpper should have n+m elements. The method only does
1154        a pointer assignment. If you only want to set the first n
1155        elements use setColumnUpperFirstElements().
1156        '''
1157        self.CppSelf.setColumnUpperArray(<double*>columnUpper.data)
1158
1159    def setColumnUpperFirstElements(self, np.ndarray[np.double_t, ndim=1] columnUpper):
1160        '''
1161        Run a loop in C++ and set the first n elements of variables' upperbounds
1162        '''
1163        self.CppSelf.setColumnUpperFirstElements(len(columnUpper), <double*>columnUpper.data)
1164
1165    def setColumnLowerArray(self, np.ndarray[np.double_t, ndim=1] columnLower):
1166        '''
1167        columnLower should have n+m elements. The method only does
1168        a pointer assignment. If you only want to set the first n
1169        elements use setColumnLowerFirstElements().
1170        '''
1171        self.CppSelf.setColumnLowerArray(<double*>columnLower.data)
1172
1173    def setColumnLowerFirstElements(self, np.ndarray[np.double_t, ndim=1] columnLower):
1174        '''
1175        Run a loop in C++ and set the first n elements of variables' lowerbounds
1176        '''
1177        self.CppSelf.setColumnLowerFirstElements(len(columnLower), <double*>columnLower.data)
1178
1179    def setColumnLowerSubset(self, np.ndarray[np.int32_t, ndim=1] indicesOfIndices,
1180                                   np.ndarray[np.int32_t, ndim=1] indices,
1181                                   np.ndarray[np.double_t, ndim=1] columnLower):
1182        '''
1183        This method is defined for a very specific purpose.
1184        It's only to be used to speed up self.addConstraint()
1185        '''
1186        self.CppSelf.setColumnLowerSubset(len(indicesOfIndices), <int*> indicesOfIndices.data,
1187                                          <int*> indices.data,
1188                                          <double*>columnLower.data)
1189
1190    def setColumnUpperSubset(self, np.ndarray[np.int32_t, ndim=1] indicesOfIndices,
1191                                   np.ndarray[np.int32_t, ndim=1] indices,
1192                                   np.ndarray[np.double_t, ndim=1] columnUpper):
1193        '''
1194        This method is defined for a very specific purpose.
1195        It's only to be used to speed up self.addConstraint()
1196        '''
1197        self.CppSelf.setColumnUpperSubset(len(indicesOfIndices), <int*> indicesOfIndices.data,
1198                                          <int*> indices.data,
1199                                          <double*>columnUpper.data)
1200
1201    def setRowUpperArray(self, np.ndarray[np.double_t, ndim=1] rowUpper):
1202        self.CppSelf.setRowUpperArray(<double*>rowUpper.data)
1203
1204    def setRowLowerArray(self, np.ndarray[np.double_t, ndim=1] rowLower):
1205        self.CppSelf.setRowLowerArray(<double*>rowLower.data)
1206
1207    def setObjectiveArray(self, np.ndarray[np.double_t, ndim=1] objective):
1208        self.CppSelf.setObjectiveArray(<double*>objective.data, len(objective))
1209
1210    cdef double* primalColumnSolution(self):
1211        return self.CppSelf.primalColumnSolution()
1212
1213    cdef double* dualColumnSolution(self):
1214        return self.CppSelf.dualColumnSolution()
1215
1216    cdef double* primalRowSolution(self):
1217        return self.CppSelf.primalRowSolution()
1218
1219    cdef double* dualRowSolution(self):
1220        return self.CppSelf.dualRowSolution()
1221
1222    def CLP_dualConstraintSolution(self):
1223        cdef np.npy_intp shape[1]
1224        shape[0] = <np.npy_intp> self.nConstraints
1225        ndarray = np.PyArray_SimpleNewFromData(1, shape,
1226                                               np.NPY_DOUBLE, <void*> self.dualRowSolution())
1227        return ndarray
1228
1229    #############################################
1230    # CLP Methods
1231    #############################################
1232
1233    def initialSolve(self, presolve='on'):
1234        '''
1235        Run CLP's initialSolve. It does a presolve and uses primal or dual
1236        Simplex to solve a problem.
1237
1238        **Usage example**
1239
1240        >>> from cylp.cy.CyClpSimplex import CyClpSimplex, getMpsExample
1241        >>> s = CyClpSimplex()
1242        >>> f = getMpsExample()
1243        >>> s.readMps(f)
1244        0
1245        >>> s.initialSolve()
1246        'optimal'
1247        >>> round(s.objectiveValue, 4)
1248        2520.5717
1249
1250        '''
1251        presolve = 0 if presolve == 'on' and self.Hessian is None else 1
1252        return problemStatus[self.CppSelf.initialSolve(presolve)]
1253
1254    def initialPrimalSolve(self):
1255        '''
1256        Run CLP's initalPrimalSolve. The same as :func:`initalSolve` but force
1257        the use of primal Simplex.
1258
1259        **Usage example**
1260
1261        >>> from cylp.cy.CyClpSimplex import CyClpSimplex, getMpsExample
1262        >>> s = CyClpSimplex()
1263        >>> f = getMpsExample()
1264        >>> s.readMps(f)
1265        0
1266        >>> s.initialPrimalSolve()
1267        'optimal'
1268        >>> round(s.objectiveValue, 4)
1269        2520.5717
1270
1271        '''
1272        return problemStatus[self.CppSelf.initialPrimalSolve()]
1273
1274    def initialDualSolve(self):
1275        '''
1276        Run CLP's initalPrimalSolve. The same as :func:`initalSolve` but force
1277        the use of dual Simplex.
1278
1279        **Usage example**
1280
1281        >>> from cylp.cy.CyClpSimplex import CyClpSimplex, getMpsExample
1282        >>> s = CyClpSimplex()
1283        >>> f = getMpsExample()
1284        >>> s.readMps(f)
1285        0
1286        >>> s.initialDualSolve()
1287        'optimal'
1288        >>> round(s.objectiveValue, 4)
1289        2520.5717
1290
1291        '''
1292        return problemStatus[self.CppSelf.initialDualSolve()]
1293
1294    def __iadd__(self, cons):
1295        self.addConstraint(cons)
1296        return self
1297
1298    def addConstraint(self, cons, name='', addMpsNames=True):
1299        '''
1300        Adds constraints ``cons``  to the problem. Example for the value
1301        of ``cons`` is ``0 <= A * x <= b`` where ``A`` is a Numpy matrix and
1302        b is a :py:class:`CyLPArray`.
1303        '''
1304        if self.cyLPModel:
1305            m = self.cyLPModel
1306            nVarsBefore = m.nVars
1307            nConsBefore = m.nCons
1308            c = m.addConstraint(cons, name, addMpsNames)
1309
1310            # If the dimension is changing, load from scratch
1311            if nConsBefore == 0 or m.nVars - nVarsBefore != 0:
1312                self.loadFromCyLPModel(self.cyLPModel)
1313
1314            # If the constraint to be added is just a variable range
1315            elif c.isRange:
1316                var = c.variables[0]
1317                dim = var.parentDim
1318                varinds = m.inds.varIndex[var.name]
1319
1320                lb = var.parent.lower if var.parent else var.lower
1321                ub = var.parent.upper if var.parent else var.upper
1322
1323                #if len(var.indices != 0 :
1324                self.setColumnLowerSubset(var.indices,
1325                                              varinds,
1326                                              lb)
1327                self.setColumnUpperSubset(var.indices,
1328                                              varinds,
1329                                              ub)
1330                #for i in var.indices:
1331                #    self.setColumnLower(varinds[i], lb[i])
1332                #    self.setColumnUpper(varinds[i], ub[i])
1333
1334            # If the constraint is a "real" constraint, but no
1335            # dimension changes required
1336            else:
1337                mainCoef = None
1338                for varName in m.varNames:
1339                    dim = m.pvdims[varName]
1340                    coef = sparse.coo_matrix((c.nRows, dim))
1341                    keys = [k for k in c.varCoefs.keys() if k.name == varName]
1342                    for var in keys:
1343                        coef = coef + c.varCoefs[var]
1344                    mainCoef = sparseConcat(mainCoef, coef, 'h')
1345
1346                self.addConstraints(c.nRows,
1347                        c.lower, c.upper, mainCoef.indptr,
1348                        mainCoef.indices, mainCoef.data)
1349        else:
1350            raise Exception('To add a constraint you must set ' \
1351                            'cylpSimplex.cyLPModel first.')
1352
1353    def removeConstraint(self, name):
1354        '''
1355        Removes constraint named ``name`` from the problem.
1356        '''
1357        if self.cyLPModel:
1358            indsOfRemovedConstriants = self.cyLPModel.removeConstraint(name)
1359            self.CLP_deleteConstraints(indsOfRemovedConstriants)
1360            #self.loadFromCyLPModel(self.cyLPModel)
1361        else:
1362            raise Exception('To remove a constraint you must set ' \
1363                            'cylpSimplex.cyLPModel first.')
1364
1365    def addVariable(self, varname, dim, isInt=False):
1366        '''
1367        Add variable ``var`` to the problem.
1368        '''
1369        if not self.cyLPModel:
1370            self.cyLPModel = CyLPModel()
1371        var = self.cyLPModel.addVariable(varname, dim, isInt)
1372        self.loadFromCyLPModel(self.cyLPModel)
1373        return var
1374        #else:
1375        #    raise Exception('To add a variable you must set ' \
1376        #                    'cylpSimplex.cyLPModel first.')
1377
1378    def removeVariable(self, name):
1379        '''
1380        Removes variable named ``name`` from the problem.
1381        '''
1382        if self.cyLPModel:
1383            self.cyLPModel.removeVariable(name)
1384            self.loadFromCyLPModel(self.cyLPModel)
1385        else:
1386            raise Exception('To remove a variable you must set ' \
1387                            'cylpSimplex.cyLPModel first.')
1388
1389    def getVarByName(self, name):
1390        if not self.cyLPModel:
1391            raise Exception('No cylpSimplex.cyLPModel is set.')
1392        return self.cyLPModel.getVarByName(name)
1393
1394    def getVarNameByIndex(self, ind):
1395        if not self.cyLPModel:
1396            raise Exception('No cylpSimplex.cyLPModel is set.')
1397        return self.cyLPModel.inds.reverseVarSearch(ind)
1398
1399    def CLP_addConstraint(self, numberInRow,
1400                    np.ndarray[np.int32_t, ndim=1] columns,
1401                    np.ndarray[np.double_t, ndim=1] elements,
1402                    rowLower,
1403                    rowUpper):
1404        '''
1405        Add a constraint to the problem, CLP style. See CLP documentation.
1406        Not commonly used in cylp.
1407        For cylp modeling tool see :mod:`cylp.python.modeling.CyLPModel`.
1408        '''
1409        # TODO: This makes adding a row real slower,
1410        # but it is better than a COIN EXCEPTION!
1411        if (columns >= self.nVariables).any():
1412            raise Exception('CyClpSimplex.pyx:addConstraint: Column ' \
1413                    'index out of range (number of columns: ' \
1414                                '%d)' % (self.nVariables))
1415        self.CppSelf.addRow(numberInRow, <int*>columns.data,
1416                            <double*>elements.data, rowLower, rowUpper)
1417
1418    def CLP_deleteConstraints(self, np.ndarray[np.int32_t, ndim=1] which):
1419        '''
1420        Delete constraints indexed by ``which`` from the LP.
1421        '''
1422        if (which >= self.nConstraints).any():
1423            raise Exception('CyClpSimplex.pyx:deleteConstraints: Constraint ' \
1424                    'index out of range (number of constraints: ' \
1425                                '%d)' % (self.nConstraints))
1426        self.CppSelf.deleteRows(len(which), <int*>which.data)
1427
1428    def CLP_deleteVariables(self, np.ndarray[np.int32_t, ndim=1] which):
1429        '''
1430        Delete variables indexed by ``which`` from the LP.
1431        '''
1432        if (which >= self.nVariables).any():
1433            raise Exception('CyClpSimplex.pyx:deleteVariables: variable ' \
1434                    'index out of range (number of variables: ' \
1435                                '%d)' % (self.nVariables))
1436        self.CppSelf.deleteColumns(len(which), <int*>which.data)
1437
1438    def CLP_addVariable(self, numberInColumn,
1439                        np.ndarray[np.int32_t, ndim=1] rows,
1440                        np.ndarray[np.double_t, ndim=1] elements,
1441                        columnLower,
1442                        columnUpper,
1443                        objective):
1444        '''
1445        Add a variable to the problem, CLP style. See CLP documentation.
1446        For cylp modeling tool see :mod:`cylp.python.modeling.CyLPModel`.
1447        '''
1448        # TODO: This makes adding a column real slower,
1449        # but it is better than a COIN EXCEPTION!
1450        if (rows >= self.nConstraints).any():
1451            raise Exception('CyClpSimplex.pyx:addColumn: Row '\
1452                    'index out of range (number of rows:  ' \
1453                        '%d)' % (self.nConstraints))
1454        self.CppSelf.addColumn(numberInColumn, <int*>rows.data,
1455                <double*> elements.data, columnLower,
1456                               columnUpper, objective)
1457
1458    def addVariables(self, number,
1459                        np.ndarray[np.double_t, ndim=1] columnLower,
1460                        np.ndarray[np.double_t, ndim=1] columnUpper,
1461                        np.ndarray[np.double_t, ndim=1] objective,
1462                        np.ndarray[np.int32_t, ndim=1] columnStarts,
1463                        np.ndarray[np.int32_t, ndim=1] rows,
1464                        np.ndarray[np.double_t, ndim=1] elements):
1465        '''
1466        Add ``number`` variables at once, CLP style.
1467        For cylp modeling tool see :mod:`cylp.python.modeling.CyLPModel`.
1468        '''
1469        self.CppSelf.addColumns(number, <double*>columnLower.data,
1470                                        <double*>columnUpper.data,
1471                                        <double*>objective.data,
1472                                        <int*>columnStarts.data,
1473                                        <int*>rows.data,
1474                                        <double*>elements.data)
1475
1476    def addConstraints(self, number,
1477                        np.ndarray[np.double_t, ndim=1] rowLower,
1478                        np.ndarray[np.double_t, ndim=1] rowUpper,
1479                        np.ndarray[np.int32_t, ndim=1] rowStarts,
1480                        np.ndarray[np.int32_t, ndim=1] columns,
1481                        np.ndarray[np.double_t, ndim=1] elements):
1482        '''
1483        Add ``number`` constraints at once, CLP style.
1484        For cylp modeling tool see :mod:`cylp.python.modeling.CyLPModel`.
1485        '''
1486        self.CppSelf.addRows(number, <double*>rowLower.data,
1487                                    <double*>rowUpper.data,
1488                                    <int*>rowStarts.data,
1489                                    <int*>columns.data,
1490                                    <double*>elements.data)
1491
1492    cpdef int readMps(self, filename, int keepNames=False,
1493            int ignoreErrors=False) except *:
1494        '''
1495        Read an mps file. See this :ref:`modeling example <modeling-usage>`.
1496        '''
1497        filename = filename.encode('ascii')
1498        name, ext = os.path.splitext(filename)
1499        if ext not in [b'.mps', b'.qps']:
1500            print('unrecognised extension %s' % ext)
1501            return -1
1502
1503        if ext == b'.mps':
1504            return self.CppSelf.readMps(filename, keepNames, ignoreErrors)
1505        else:
1506            m = CyCoinMpsIO.CyCoinMpsIO()
1507            ret = m.readMps(filename)
1508            self._Hessian = m.Hessian
1509
1510            # Since CyCoinMpsIO.readMps seems to be different from ClpModle.readMps
1511            # for the moment we read the problem again
1512            # FIXME: should be fixed
1513            #self.loadProblem(m.matrixByCol, m.variableLower, m.variableUpper,
1514            #                 m.objCoefficients,
1515            #                 m.constraintLower, m.constraintUpper)
1516            #return ret
1517
1518            return self.CppSelf.readMps(filename, keepNames, ignoreErrors)
1519
1520
1521    def extractCyLPModel(self, fileName, keepNames=False, ignoreErrors=False):
1522        if self.readMps(fileName, keepNames, ignoreErrors) != 0:
1523            return None
1524        m = CyLPModel()
1525
1526        x = m.addVariable('x', self.nVariables)
1527
1528        # Copy is crucial. Memory space should be different than
1529        # that of Clp. Else, a resize will ruin these.
1530        c_up = CyLPArray(self.constraintsUpper).copy()
1531        c_low = CyLPArray(self.constraintsLower).copy()
1532
1533        mat = self.matrix
1534        C = csc_matrixPlus((mat.elements, mat.indices, mat.vectorStarts),
1535                             shape=(self.nConstraints, self.nVariables))
1536
1537        m += c_low <= C * x <= c_up
1538
1539        x_up = CyLPArray(self.variablesUpper).copy()
1540        x_low = CyLPArray(self.variablesLower).copy()
1541
1542        m += x_low <= x <= x_up
1543
1544        m.objective = self.objective
1545
1546        self.cyLPModel = m
1547        return m
1548
1549    def _extractStartFinish(self, startFinishOptions):
1550        if isinstance(startFinishOptions, int):
1551            sf = startFinishOptions
1552        else:
1553            sf = 0
1554            for option in startFinishOptions:
1555                sf = sf | startFinishOptionsDic[option]
1556        return sf
1557
1558    def primal(self, ifValuesPass=0, startFinishOptions=0, presolve=False):
1559        '''
1560        Solve the problem using the primal simplex algorithm.
1561        See this :ref:`usage example <simple-run>`.
1562
1563        startFinishOptions is a string containing one or
1564        more of the following characters:
1565        'x': do not delete work areas
1566        'f': use old factorization if possible
1567        's': skip initialization of work areas
1568        So one might call ``self.primal(startFinishOptions='sx')``
1569        '''
1570        sf = self._extractStartFinish(startFinishOptions)
1571        if presolve:
1572            return self.primalWithPresolve()
1573        else:
1574            return problemStatus[self.CppSelf.primal(
1575                             ifValuesPass, sf)]
1576
1577    def dual(self, ifValuesPass=0, startFinishOptions=0, presolve=False):
1578        '''
1579        Runs CLP dual simplex.
1580
1581        **Usage Example**
1582
1583        >>> from cylp.cy.CyClpSimplex import CyClpSimplex, getMpsExample
1584        >>> s = CyClpSimplex()
1585        >>> f = getMpsExample()
1586        >>> s.readMps(f)
1587        0
1588        >>> s.dual()
1589        'optimal'
1590
1591        '''
1592        sf = self._extractStartFinish(startFinishOptions)
1593        if presolve:
1594            return self.dualWithPresolve()
1595        else:
1596            return problemStatus[self.CppSelf.dual(
1597                            ifValuesPass, sf)]
1598
1599    def setPerturbation(self, value):
1600        '''
1601        Perturb the problem by ``value``.
1602        '''
1603        self.CppSelf.setPerturbation(value)
1604
1605    cdef setPrimalColumnPivotAlgorithm(self, void* choice):
1606        '''
1607        Set primal simplex's pivot rule to ``choice``
1608        This is used when setting a pivot rule in Cython
1609        '''
1610        cdef CppClpPrimalColumnPivot* c = <CppClpPrimalColumnPivot*> choice
1611        self.CppSelf.setPrimalColumnPivotAlgorithm(c)
1612
1613    cdef setDualRowPivotAlgorithm(self, void* choice):
1614        '''
1615        Set dual simplex's pivot rule to ``choice``
1616        This is used when setting a pivot rule in Cython
1617        '''
1618        cdef CppClpDualRowPivot* c = <CppClpDualRowPivot*> choice
1619        self.CppSelf.setDualRowPivotAlgorithm(c)
1620
1621    def resize(self, newNumberRows, newNumberColumns):
1622        '''
1623        Resize the problem. After a call to ``resize`` the problem will have
1624        ``newNumberRows`` constraints and ``newNumberColumns`` variables.
1625        '''
1626        self.CppSelf.resize(newNumberRows, newNumberColumns)
1627
1628    def getBInvACol(self, col, np.ndarray[np.double_t, ndim=1] cl):
1629        '''
1630        Compute :math:`A_B^{-1}A_{col}` and store the result in ``cl``.
1631        '''
1632        self.CppSelf.getBInvACol(col, <double*>cl.data)
1633
1634    def getBInvCol(self, col, np.ndarray[np.double_t, ndim=1] cl):
1635        '''
1636        Return :math:`A_B^{-1}_{col}` and store the result in ``cl``.
1637        '''
1638        self.CppSelf.getBInvCol(col, <double*>cl.data)
1639
1640    def transposeTimes(self, scalar, CyCoinIndexedVector x,
1641                       CyCoinIndexedVector y, CyCoinIndexedVector z):
1642        '''
1643        Compute :math:`x * scalar * A + y` and store the result in ``z``.
1644        '''
1645        self.CppSelf.transposeTimes(self.CppSelf, scalar,
1646                                    x.CppSelf, y.CppSelf, z.CppSelf)
1647
1648    def transposeTimesSubset(self, number,
1649                             np.ndarray[np.int64_t, ndim=1] which,
1650                             np.ndarray[np.double_t, ndim=1] pi,
1651                             np.ndarray[np.double_t, ndim=1] y):
1652        '''
1653        Compute :math:`y_{which} - pi^{T}A_{which}` where ``which`` is a
1654        variable index set. Store the result in ``y``.
1655        '''
1656        self.CppSelf.transposeTimesSubset(number, <int*>which.data,
1657                                          <double*>pi.data, <double*>y.data)
1658
1659    def transposeTimesSubsetAll(self,
1660                             np.ndarray[np.int64_t, ndim=1] which,
1661                             np.ndarray[np.double_t, ndim=1] pi,
1662                             np.ndarray[np.double_t, ndim=1] y):
1663        '''
1664        Same as :func:`transposeTimesSubset` but here ``which``
1665        can also address slack variables.
1666        '''
1667        self.CppSelf.transposeTimesSubsetAll(len(which),
1668                                            <long long int*>which.data,
1669                                            <double*>pi.data,
1670                                            <double*>y.data)
1671
1672    def isInteger(self, ind):
1673        '''
1674        Returns True if the variable index ``ind`` is integer.
1675        '''
1676        return self.CppSelf.isInteger(ind)
1677
1678    def setInteger(self, arg):
1679        '''
1680        if ``arg`` is an integer: mark variable index ``arg`` as integer.
1681        if ``arg`` is a :class:`CyLPVar` object: mark variable
1682        ``arg`` as integer. Here is an example of the latter:
1683
1684        >>> import numpy as np
1685        >>> from cylp.cy import CyClpSimplex
1686        >>> from cylp.py.modeling.CyLPModel import CyLPModel, CyLPArray
1687        >>> model = CyLPModel()
1688        >>>
1689        >>> x = model.addVariable('x', 3)
1690        >>> y = model.addVariable('y', 2)
1691        >>>
1692        >>> A = np.matrix([[1., 2., 0],[1., 0, 1.]])
1693        >>> B = np.matrix([[1., 0, 0], [0, 0, 1.]])
1694        >>> D = np.matrix([[1., 2.],[0, 1]])
1695        >>> a = CyLPArray([5, 2.5])
1696        >>> b = CyLPArray([4.2, 3])
1697        >>> x_u= CyLPArray([2., 3.5])
1698        >>>
1699        >>> model += A*x <= a
1700        >>> model += 2 <= B * x + D * y <= b
1701        >>> model += y >= 0
1702        >>> model += 1.1 <= x[1:3] <= x_u
1703        >>>
1704        >>> c = CyLPArray([1., -2., 3.])
1705        >>> model.objective = c * x + 2 * y.sum()
1706        >>>
1707        >>>
1708        >>> s = CyClpSimplex(model)
1709        >>> s.setInteger(x[1:3])
1710        >>>
1711        >>> cbcModel = s.getCbcModel()
1712        >>> cbcModel.solve()
1713        0
1714        >>> print(cbcModel.status)
1715        'solution'
1716        >>>
1717        >>> sol_x = cbcModel.primalVariableSolution['x']
1718        >>> (abs(sol_x -
1719        ...     np.array([0.5, 2, 2]) ) <= 10**-6).all()
1720        True
1721        >>> sol_y = cbcModel.primalVariableSolution['y']
1722        >>> (abs(sol_y -
1723        ...     np.array([0, 0.75]) ) <= 10**-6).all()
1724        True
1725
1726        '''
1727
1728        if isinstance(arg, (int, long)):
1729            self.CppSelf.setInteger(arg)
1730        elif True:  # isinstance(arg, CyLPVar):
1731            if self.cyLPModel is None:
1732                raise Exception('The argument of setInteger can be ' \
1733                                'a CyLPVar only if the object is built ' \
1734                                'using a CyLPModel.')
1735            var = arg
1736            model = self.cyLPModel
1737            inds = model.inds
1738            varName = var.name
1739            if not inds.hasVar(varName):
1740                raise Exception('No such variable: %s' % varName)
1741            x = inds.varIndex[varName]
1742            if var.parent:
1743                for i in var.indices:
1744                    self.CppSelf.setInteger(x[i])
1745            else:
1746                for i in xrange(var.dim):
1747                    self.CppSelf.setInteger(x[i])
1748
1749
1750    def copyInIntegerInformation(self, np.ndarray[np.uint8_t, ndim=1] colType):
1751        '''
1752        Take in a character array containing 0-1 specifying whether or not
1753        a variable is integer
1754        '''
1755        self.CppSelf.copyInIntegerInformation(<char*>colType.data)
1756
1757    def replaceMatrix(self, CyCoinPackedMatrix matrix, deleteCurrent=False):
1758        self.CppSelf.replaceMatrix(matrix.CppSelf, deleteCurrent)
1759
1760    def loadQuadraticObjective(self, CyCoinPackedMatrix matrix):
1761        self.CppSelf.loadQuadraticObjective(matrix.CppSelf)
1762
1763    def preSolve(self, feasibilityTolerance=0.0,
1764                 keepIntegers=0, numberPasses=5,
1765                 dropNames=0, doRowObjective=0):
1766        cdef CppIClpSimplex* model = self.CppSelf.preSolve(self.CppSelf,
1767                                feasibilityTolerance, keepIntegers,
1768                                numberPasses, dropNames, doRowObjective)
1769        s = CyClpSimplex()
1770        if model == NULL:
1771            print("Presolve says problem infeasible.")
1772            return s
1773
1774        s.setCppSelf(model)
1775        return s
1776        #self.setCppSelf(model)
1777
1778    def postSolve(self, updateStatus=True):
1779        self.CppSelf.postSolve(updateStatus)
1780
1781    def dualWithPresolve(self, feasibilityTolerance=0.0,
1782                 keepIntegers=0, numberPasses=5,
1783                 dropNames=0, doRowObjective=0):
1784        ret = self.CppSelf.dualWithPresolve(self.CppSelf,
1785                                feasibilityTolerance, keepIntegers,
1786                                numberPasses, dropNames, doRowObjective)
1787        if ret == -2000:
1788            print("Presolve says problem infeasible.")
1789            return -2000
1790
1791        return problemStatus[ret]
1792
1793    def primalWithPresolve(self, feasibilityTolerance=0.0,
1794                 keepIntegers=0, numberPasses=5,
1795                 dropNames=0, doRowObjective=0):
1796        ret = self.CppSelf.primalWithPresolve(self.CppSelf,
1797                                feasibilityTolerance, keepIntegers,
1798                                numberPasses, dropNames, doRowObjective)
1799        if ret == -2000:
1800            print("Presolve says problem infeasible.")
1801            return -2000
1802
1803        return problemStatus[ret]
1804
1805    def writeMps(self, filename, formatType=0, numberAcross=2, objSense=0):
1806        try:
1807            f = open(filename, 'w')
1808            f.close()
1809        except:
1810            raise Exception('No write access for %s or an intermediate \
1811                            directory does not exist.' % filename)
1812
1813        m = self.cyLPModel
1814        if m:
1815            inds = m.inds
1816            for var in m.variables:
1817                varinds = inds.varIndex[var.name]
1818                for i in xrange(var.dim):
1819                    self.setVariableName(varinds[i], var.mpsNames[i])
1820
1821            for con in m.constraints:
1822                coninds = inds.constIndex[con.name]
1823                for i in xrange(con.nRows):
1824                    self.setConstraintName(coninds[i], con.mpsNames[i])
1825        return self.CppSelf.writeMps(filename, formatType, numberAcross,
1826                                     objSense)
1827
1828    def writeLp(self, filename, extension="", epsilon=10**-5, numberAcross=10,
1829                        decimals=5, objSense=0.0, useRowNames=1):
1830        try:
1831            f = open(filename, 'w')
1832            f.close()
1833        except:
1834            raise Exception('No write access for %s or an intermediate \
1835                            directory does not exist.' % filename)
1836
1837        m = self.cyLPModel
1838        if m:
1839            inds = m.inds
1840            for var in m.variables:
1841                varinds = inds.varIndex[var.name]
1842                for i in xrange(var.dim):
1843                    self.setVariableName(varinds[i], var.mpsNames[i])
1844
1845            for con in m.constraints:
1846                coninds = inds.constIndex[con.name]
1847                for i in xrange(con.nRows):
1848                    self.setConstraintName(coninds[i], con.mpsNames[i])
1849        self.CppSelf.writeLp(filename, extension, epsilon, numberAcross, decimals, objSense, useRowNames)
1850
1851    def readLp(self, char *filename, epsilon=10**-5):
1852        return self.CppSelf.readLp(filename, epsilon)
1853
1854    def updateColumnFT(self, CyCoinIndexedVector spare, CyCoinIndexedVector updatedColumn):
1855        return self.CppSelf.updateColumnFT(spare.CppSelf, updatedColumn.CppSelf)
1856
1857    def updateColumnTranspose(self, CyCoinIndexedVector regionSparse1,
1858                                    CyCoinIndexedVector regionSparse2):
1859        return self.CppSelf.updateColumnTranspose(regionSparse1.CppSelf, regionSparse2.CppSelf)
1860
1861    #############################################
1862    # Modeling
1863    #############################################
1864
1865    def loadFromCyLPModel(self, cyLPModel):
1866        '''
1867        Set the coefficient matrix, constraint bounds, and variable
1868        bounds based on the data in *cyLPModel* which should be and object
1869        of *CyLPModel* class.
1870
1871        This method is usually called from CyClpSimplex's constructor.
1872        But in a case that the CyClpSimplex instance is created before
1873        we have the CyLPModel we use this method to load the LP,
1874        for example:
1875
1876        >>> import numpy as np
1877        >>> from cylp.cy.CyClpSimplex import CyClpSimplex, getModelExample
1878        >>>
1879        >>> s = CyClpSimplex()
1880        >>> model = getModelExample()
1881        >>> s.loadFromCyLPModel(model)
1882        >>>
1883        >>> s.primal()
1884        'optimal'
1885        >>> sol_x = s.primalVariableSolution['x']
1886        >>> (abs(sol_x -
1887        ...     np.array([0.2, 2, 1.1]) ) <= 10**-6).all()
1888        True
1889
1890        '''
1891        self.cyLPModel = cyLPModel
1892        (mat, constraintLower, constraintUpper,
1893                    variableLower, variableUpper) = cyLPModel.makeMatrices()
1894
1895        n = len(variableLower)
1896        m = len(constraintLower)
1897        if n == 0:# or m == 0:
1898            return
1899
1900        self.resize(m, n)
1901        if mat is not None:
1902            if not isinstance(mat, sparse.coo_matrix):
1903                mat = mat.tocoo()
1904
1905            coinMat = CyCoinPackedMatrix(True, np.array(mat.row, np.int32),
1906                                        np.array(mat.col, np.int32),
1907                                        np.array(mat.data, np.double))
1908        else:
1909            coinMat = CyCoinPackedMatrix(True, np.array([], np.int32),
1910                                        np.array([], np.int32),
1911                                        np.array([], np.double))
1912        self.replaceMatrix(coinMat, True)
1913
1914        #start adding the arrays and the matrix to the problem
1915
1916        for i in xrange(n):
1917            self.setColumnLower(i, variableLower[i])
1918            self.setColumnUpper(i, variableUpper[i])
1919
1920        for i in xrange(m):
1921            self.setRowLower(i, constraintLower[i])
1922            self.setRowUpper(i, constraintUpper[i])
1923
1924        #setting integer informations
1925        variables = cyLPModel.variables
1926        curVarInd = 0
1927        for var in variables:
1928            if var.isInt:
1929                for i in xrange(curVarInd, curVarInd + var.dim):
1930                    self.setInteger(i)
1931            curVarInd += var.dim
1932
1933
1934        if cyLPModel.objective is not None:
1935            self.objective = cyLPModel.objective
1936
1937    def evaluateAt(self, x0):
1938        '''
1939        Evaluate the objective function at x0
1940        '''
1941        if self.Hessian is not None:
1942            return (np.dot(self.objectiveCoefficients, x0) +
1943                    0.5 * np.dot(x0, self.Hessian.dot(x0)) - self.objectiveOffset)
1944        else:
1945            return np.dot(self.objectiveCoefficients, x0) - self.objectiveOffset
1946
1947    def gradientAt(self, x0):
1948        if self.Hessian is not None:
1949            return self.objectiveCoefficients + self.Hessian * x0
1950        else:
1951            return self.objectiveCoefficients
1952
1953
1954    #############################################
1955    # Integer Programming
1956    #############################################
1957
1958    def getCbcModel(self):
1959        '''
1960        Run initialSolve, return a :class:`CyCbcModel` object that can be
1961        used to add cuts, run B&B and ...
1962        '''
1963        cdef CppICbcModel* model = self.CppSelf.getICbcModel()
1964        cm =  CyCbcModel()
1965        cm.setCppSelf(model)
1966        cm.setClpModel(self)
1967        if self.cyLPModel:
1968            cm.cyLPModel = self.cyLPModel
1969        return cm
1970
1971    #############################################
1972    # cylp and Pivoting
1973    #############################################
1974
1975    def isPivotAcceptable(self):
1976        return (<CyPivotPythonBase>
1977                self.cyPivot).pivotMethodObject.isPivotAcceptable()
1978
1979    def checkVar(self, i):
1980        (<CyPivotPythonBase>self.cyPivot).pivotMethodObject.checkVar(i)
1981        return (<CyPivotPythonBase>self.cyPivot).pivotMethodObject.checkVar(i)
1982
1983    def setPrimalColumnPivotAlgorithmToWolfe(self):
1984        '''
1985        Set primal simplex's pivot rule to the Cython implementation of
1986        Wolfe's rule used to solve QPs.
1987        '''
1988        cdef CyWolfePivot wp = CyWolfePivot()
1989        self.setPrimalColumnPivotAlgorithm(wp.CppSelf)
1990
1991    def setPrimalColumnPivotAlgorithmToPE(self):
1992        '''
1993        Set primal simplex's pivot rule to the Cython
1994        implementation of *positive edge*
1995        '''
1996        cdef CyPEPivot pe = CyPEPivot()
1997        self.setPrimalColumnPivotAlgorithm(pe.CppSelf)
1998
1999    def setPivotMethod(self, pivotMethodObject):
2000        '''
2001        Takes a python object and sets it as the primal
2002        simplex pivot rule. ``pivotObjectMethod`` should
2003        implement :py:class:`PivotPythonBase`.
2004        See :ref:`how to use custom Python pivots
2005        to solve LPs <custom-pivot-usage>`.
2006        '''
2007        if not issubclass(pivotMethodObject.__class__, PivotPythonBase):
2008            raise TypeError('pivotMethodObject should be of a \
2009                            class derived from PivotPythonBase')
2010
2011        cdef CyPivotPythonBase p = CyPivotPythonBase(pivotMethodObject)
2012        self.cyPivot = p
2013        p.cyModel = self
2014        self.setPrimalColumnPivotAlgorithm(p.CppSelf)
2015
2016    def setDualPivotMethod(self, dualPivotMethodObject):
2017        '''
2018        Takes a python object and sets it as the dual
2019        pivot rule. ``dualPivotObjectMethod`` should
2020        implement :py:class:`DualPivotPythonBase`.
2021        See :ref:`how to use custom dual Python pivots
2022        to solve LPs <custom-dual-pivot-usage>`.       '''
2023        if not issubclass(dualPivotMethodObject.__class__, DualPivotPythonBase):
2024            raise TypeError('dualPivotMethodObject should be of a \
2025                            class derived from DualPivotPythonBase')
2026
2027        cdef CyDualPivotPythonBase p = CyDualPivotPythonBase(dualPivotMethodObject)
2028        self.cyDualPivot = p
2029        p.cyModel = self
2030        self.setDualRowPivotAlgorithm(p.CppSelf)
2031
2032
2033    cpdef filterVars(self,  inds):
2034        return <object>self.CppSelf.filterVars(<PyObject*>inds)
2035
2036    def setObjectiveCoefficient(self, elementIndex, elementValue):
2037        '''
2038        Set the objective coefficients using sparse vector elements
2039        ``elementIndex`` and ``elementValue``.
2040        '''
2041        self.CppSelf.setObjectiveCoefficient(elementIndex, elementValue)
2042
2043    def partialPricing(self, start, end,
2044                      np.ndarray[np.int32_t, ndim=1] numberWanted):
2045        '''
2046        Perform partial pricing from variable ``start`` to variable ``end``.
2047        Stop when ``numberWanted`` variables good variable checked.
2048        '''
2049        return self.CppSelf.partialPrice(start, end, <int*>numberWanted.data)
2050
2051    def setComplementarityList(self, np.ndarray[np.int32_t, ndim=1] cl):
2052        self.CppSelf.setComplementarityList(<int*>cl.data)
2053
2054    cpdef getACol(self, int ncol, CyCoinIndexedVector colArray):
2055        '''
2056        Gets column ``ncol`` of ``A`` and store it in ``colArray``.
2057        '''
2058        self.CppSelf.getACol(ncol, colArray.CppSelf)
2059
2060    cpdef vectorTimesB_1(self, CyCoinIndexedVector vec):
2061        '''
2062        Compute :math:`vec A_B^{-1}` and store it in ``vec``.
2063        '''
2064        self.CppSelf.vectorTimesB_1(vec.CppSelf)
2065
2066    cdef primalRow(self, CppCoinIndexedVector * rowArray,
2067                                       CppCoinIndexedVector * rhsArray,
2068                                       CppCoinIndexedVector * spareArray,
2069                                       CppCoinIndexedVector * spareArray2,
2070                                       int valuesPass):
2071        raise Exception('CyClpPrimalColumnPivotBase.pyx: pivot column ' \
2072                        'should be implemented.')
2073
2074    def argWeightedMax(self, arr, arr_ind, w, w_ind):
2075        return self.CppSelf.argWeightedMax(<PyObject*>arr, <PyObject*>arr_ind,
2076                                            <PyObject*>w, <PyObject*>w_ind)
2077
2078#    def getnff(self):
2079#        status = self.status
2080#        return np.where((status & 7 != 5) & (status & 64 == 0))[0]
2081#
2082#    def getfs(self):
2083#        status = self.status
2084#        return np.where((status & 7 == 4) | (status & 7 == 0))[0]
2085
2086    cdef int* ComplementarityList(self):
2087        return self.CppSelf.ComplementarityList()
2088
2089    cpdef getComplementarityList(self):
2090        return <object>self.CppSelf.getComplementarityList()
2091
2092    def setComplement(self, var1, var2):
2093        '''
2094        Set ``var1`` as the complementary variable of ``var2``. These
2095        arguments may be integers signifying indices, or CyLPVars.
2096        '''
2097
2098        if isinstance(var1, (int, long)) and isinstance(var2, (int, long)) :
2099           self.CppSelf.setComplement(var1, var2)
2100        elif True:  # isinstance(arg, CyLPVar):
2101            if self.cyLPModel is None:
2102                raise Exception('The argument of setInteger can be ' \
2103                                'a CyLPVar only if the object is built ' \
2104                                'using a CyLPModel.')
2105            if var1.dim != var2.dim:
2106                raise Exception('Variables should have the same  ' \
2107                                'dimensions to be complements.' \
2108                                ' Got %s: %g and %s: %g' %
2109                                (var1.name, var1.dim, var2.name, var2.dim))
2110
2111            model = self.cyLPModel
2112            inds = model.inds
2113            vn1 = var1.name
2114            vn2 = var2.name
2115
2116            if not inds.hasVar(vn1):
2117                raise Exception('No such variable: %s' % vn1)
2118            x1 = inds.varIndex[vn1]
2119            if not inds.hasVar(vn2):
2120                raise Exception('No such variable: %s' % vn2)
2121            x2 = inds.varIndex[vn2]
2122
2123            for i in xrange(var1.dim):
2124                self.CppSelf.setComplement(x1[i], x2[i])
2125
2126#    def setComplement(self, var1, var2):
2127#        'sets var1 and var2 to be complements'
2128#        #When you create LP using CoinModel getComplementarityList
2129#        #cannot return with the right size
2130#        #cl = self.getComplementarityList()
2131#        #print(var1, var2, len(cl))
2132#        #cl[var1], cl[var2] = var2, var1
2133#        self.CppSelf.setComplement(var1, var2)
2134
2135    def loadProblemFromCyCoinModel(self, CyCoinModel modelObject, int
2136                                        tryPlusMinusOne=False):
2137        return self.CppSelf.loadProblem(modelObject.CppSelf, tryPlusMinusOne)
2138
2139    def loadProblem(self, CyCoinPackedMatrix matrix,
2140                 np.ndarray[np.double_t, ndim=1] collb,
2141                 np.ndarray[np.double_t, ndim=1] colub,
2142                 np.ndarray[np.double_t, ndim=1] obj,
2143                 np.ndarray[np.double_t, ndim=1] rowlb,
2144                 np.ndarray[np.double_t, ndim=1] rowub,
2145                 np.ndarray[np.double_t, ndim=1] rowObjective=np.array([])):
2146        cdef double* rd
2147        if len(rowObjective) == 0:
2148            rd = NULL
2149        else:
2150            rd = <double*> rowObjective.data
2151        self.CppSelf.loadProblem(matrix.CppSelf, <double*> collb.data,
2152                                         <double*> colub.data,
2153                                         <double*> obj.data,
2154                                         <double*> rowlb.data,
2155                                         <double*> rowub.data,
2156                                         <double*> rd)
2157
2158    def getCoinInfinity(self):
2159        return self.CppSelf.getCoinInfinity()
2160
2161    #############################################
2162    # Osi
2163    #############################################
2164
2165    def setBasisStatus(self, np.ndarray[np.int32_t, ndim=1] cstat,
2166                             np.ndarray[np.int32_t, ndim=1] rstat):
2167        self.CppSelf.setBasisStatus(<int*>cstat.data, <int*>rstat.data)
2168
2169    def getBasisStatus(self):
2170        cdef np.ndarray[np.int32_t, ndim=1] cstat = \
2171                                np.zeros(self.nVariables, dtype='int32')
2172        cdef np.ndarray[np.int32_t, ndim=1] rstat = \
2173                                np.zeros(self.nConstraints, dtype='int32')
2174        self.CppSelf.getBasisStatus(<int*>cstat.data, <int*>rstat.data)
2175        return cstat, rstat
2176
2177
2178def getModelExample():
2179    '''
2180    Return a model example to be used in doctests.
2181    '''
2182    import numpy as np
2183    from cylp.py.modeling.CyLPModel import CyLPModel, CyLPArray
2184    from cylp.cy import CyClpSimplex
2185
2186    model = CyLPModel()
2187    x = model.addVariable('x', 3)
2188    y = model.addVariable('y', 2)
2189
2190    A = np.matrix([[1., 2., 0], [1., 0, 1.]])
2191    B = np.matrix([[1., 0, 0], [0, 0, 1.]])
2192    D = np.matrix([[1., 2.], [0, 1]])
2193    a = CyLPArray([5, 2.5])
2194    b = CyLPArray([4.2, 3])
2195    x_u= CyLPArray([2., 3.5])
2196
2197    model += A * x <= a
2198    model += 2 <= B * x + D * y <= b
2199    model += y >= 0
2200    model += 1.1 <= x[1:3] <= x_u
2201
2202    c = CyLPArray([1., -2., 3.])
2203    model.objective = c * x + 2 * y.sum()
2204
2205    return model
2206
2207
2208cpdef cydot(CyCoinIndexedVector v1, CyCoinIndexedVector v2):
2209    return cdot(v1.CppSelf, v2.CppSelf)
2210
2211
2212def getMpsExample():
2213    '''
2214    Return full path to an MPS example file for doctests
2215    '''
2216    import os
2217    import inspect
2218    curpath = os.path.dirname(inspect.getfile(inspect.currentframe()))
2219    return os.path.join(curpath, '../input/p0033.mps')
2220
2221
2222cdef int RunIsPivotAcceptable(void * ptr):
2223    cdef CyClpSimplex CyWrapper = <CyClpSimplex>(ptr)
2224    return CyWrapper.isPivotAcceptable()
2225
2226
2227cdef int RunVarSelCriteria(void * ptr, int varInd):
2228    cdef CyClpSimplex CyWrapper = <CyClpSimplex>(ptr)
2229    return CyWrapper.checkVar(varInd)
2230
2231
2232cdef class VarStatus:
2233    free = 0
2234    basic = 1
2235    atUpperBound = 2
2236    atLowerBound = 3
2237    superBasic = 4
2238    fixed = 5
2239    status_ = np.array([free,
2240                        basic,
2241                        atUpperBound,
2242                        atLowerBound,
2243                        superBasic,
2244                        fixed])
2245