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