forked from coin-or/Clp
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ClpMatrixBase.cpp
594 lines (578 loc) · 18.9 KB
/
ClpMatrixBase.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
// Copyright (C) 2002, International Business Machines
// Corporation and others. All Rights Reserved.
// This code is licensed under the terms of the Eclipse Public License (EPL).
#include "CoinPragma.hpp"
#include <iostream>
#include "CoinIndexedVector.hpp"
#include "CoinHelperFunctions.hpp"
#include "ClpMatrixBase.hpp"
#include "ClpSimplex.hpp"
//#############################################################################
// Constructors / Destructor / Assignment
//#############################################################################
//-------------------------------------------------------------------
// Default Constructor
//-------------------------------------------------------------------
ClpMatrixBase::ClpMatrixBase()
: rhsOffset_(NULL)
, startFraction_(0.0)
, endFraction_(1.0)
, savedBestDj_(0.0)
, originalWanted_(0)
, currentWanted_(0)
, savedBestSequence_(-1)
, type_(-1)
, lastRefresh_(-1)
, refreshFrequency_(0)
, minimumObjectsScan_(-1)
, minimumGoodReducedCosts_(-1)
, trueSequenceIn_(-1)
, trueSequenceOut_(-1)
, skipDualCheck_(false)
{
}
//-------------------------------------------------------------------
// Copy constructor
//-------------------------------------------------------------------
ClpMatrixBase::ClpMatrixBase(const ClpMatrixBase &rhs)
: type_(rhs.type_)
, skipDualCheck_(rhs.skipDualCheck_)
{
startFraction_ = rhs.startFraction_;
endFraction_ = rhs.endFraction_;
savedBestDj_ = rhs.savedBestDj_;
originalWanted_ = rhs.originalWanted_;
currentWanted_ = rhs.currentWanted_;
savedBestSequence_ = rhs.savedBestSequence_;
lastRefresh_ = rhs.lastRefresh_;
refreshFrequency_ = rhs.refreshFrequency_;
minimumObjectsScan_ = rhs.minimumObjectsScan_;
minimumGoodReducedCosts_ = rhs.minimumGoodReducedCosts_;
trueSequenceIn_ = rhs.trueSequenceIn_;
trueSequenceOut_ = rhs.trueSequenceOut_;
skipDualCheck_ = rhs.skipDualCheck_;
int numberRows = rhs.getNumRows();
if (rhs.rhsOffset_ && numberRows) {
rhsOffset_ = ClpCopyOfArray(rhs.rhsOffset_, numberRows);
} else {
rhsOffset_ = NULL;
}
}
//-------------------------------------------------------------------
// Destructor
//-------------------------------------------------------------------
ClpMatrixBase::~ClpMatrixBase()
{
delete[] rhsOffset_;
}
//----------------------------------------------------------------
// Assignment operator
//-------------------------------------------------------------------
ClpMatrixBase &
ClpMatrixBase::operator=(const ClpMatrixBase &rhs)
{
if (this != &rhs) {
type_ = rhs.type_;
delete[] rhsOffset_;
int numberRows = rhs.getNumRows();
if (rhs.rhsOffset_ && numberRows) {
rhsOffset_ = ClpCopyOfArray(rhs.rhsOffset_, numberRows);
} else {
rhsOffset_ = NULL;
}
startFraction_ = rhs.startFraction_;
endFraction_ = rhs.endFraction_;
savedBestDj_ = rhs.savedBestDj_;
originalWanted_ = rhs.originalWanted_;
currentWanted_ = rhs.currentWanted_;
savedBestSequence_ = rhs.savedBestSequence_;
lastRefresh_ = rhs.lastRefresh_;
refreshFrequency_ = rhs.refreshFrequency_;
minimumObjectsScan_ = rhs.minimumObjectsScan_;
minimumGoodReducedCosts_ = rhs.minimumGoodReducedCosts_;
trueSequenceIn_ = rhs.trueSequenceIn_;
trueSequenceOut_ = rhs.trueSequenceOut_;
skipDualCheck_ = rhs.skipDualCheck_;
}
return *this;
}
// And for scaling - default aborts for when scaling not supported
void ClpMatrixBase::times(double scalar,
const double *x, double *y,
const double *rowScale,
const double * /*columnScale*/) const
{
if (rowScale) {
std::cerr << "Scaling not supported - ClpMatrixBase" << std::endl;
abort();
} else {
times(scalar, x, y);
}
}
// And for scaling - default aborts for when scaling not supported
void ClpMatrixBase::transposeTimes(double scalar,
const double *x, double *y,
const double *rowScale,
const double * /*columnScale*/,
double * /*spare*/) const
{
if (rowScale) {
std::cerr << "Scaling not supported - ClpMatrixBase" << std::endl;
abort();
} else {
transposeTimes(scalar, x, y);
}
}
/* Subset clone (without gaps). Duplicates are allowed
and order is as given.
Derived classes need not provide this as it may not always make
sense */
ClpMatrixBase *
ClpMatrixBase::subsetClone(
int /*numberRows*/, const int * /*whichRows*/,
int /*numberColumns*/, const int * /*whichColumns*/) const
{
std::cerr << "subsetClone not supported - ClpMatrixBase" << std::endl;
abort();
return NULL;
}
/* Given positive integer weights for each row fills in sum of weights
for each column (and slack).
Returns weights vector
Default returns vector of ones
*/
CoinBigIndex *
ClpMatrixBase::dubiousWeights(const ClpSimplex *model, int * /*inputWeights*/) const
{
int number = model->numberRows() + model->numberColumns();
CoinBigIndex *weights = new CoinBigIndex[number];
int i;
for (i = 0; i < number; i++)
weights[i] = 1;
return weights;
}
#ifndef CLP_NO_VECTOR
// Append Columns
void ClpMatrixBase::appendCols(int /*number*/,
const CoinPackedVectorBase *const * /*columns*/)
{
std::cerr << "appendCols not supported - ClpMatrixBase" << std::endl;
abort();
}
// Append Rows
void ClpMatrixBase::appendRows(int /*number*/,
const CoinPackedVectorBase *const * /*rows*/)
{
std::cerr << "appendRows not supported - ClpMatrixBase" << std::endl;
abort();
}
#endif
/* Returns largest and smallest elements of both signs.
Largest refers to largest absolute value.
*/
void ClpMatrixBase::rangeOfElements(double &smallestNegative, double &largestNegative,
double &smallestPositive, double &largestPositive)
{
smallestNegative = 0.0;
largestNegative = 0.0;
smallestPositive = 0.0;
largestPositive = 0.0;
}
/* The length of a major-dimension vector. */
int ClpMatrixBase::getVectorLength(int index) const
{
return getVectorLengths()[index];
}
// Says whether it can do partial pricing
bool ClpMatrixBase::canDoPartialPricing() const
{
return false; // default is no
}
/* Return <code>x *A</code> in <code>z</code> but
just for number indices in y.
Default cheats with fake CoinIndexedVector and
then calls subsetTransposeTimes */
void ClpMatrixBase::listTransposeTimes(const ClpSimplex *model,
double *x,
int *y,
int number,
double *z) const
{
CoinIndexedVector pi;
CoinIndexedVector list;
CoinIndexedVector output;
int *saveIndices = list.getIndices();
list.setNumElements(number);
list.setIndexVector(y);
double *savePi = pi.denseVector();
pi.setDenseVector(x);
double *saveOutput = output.denseVector();
output.setDenseVector(z);
output.setPacked();
subsetTransposeTimes(model, &pi, &list, &output);
// restore settings
list.setIndexVector(saveIndices);
pi.setDenseVector(savePi);
output.setDenseVector(saveOutput);
}
// Partial pricing
void ClpMatrixBase::partialPricing(ClpSimplex *, double, double,
int &, int &)
{
std::cerr << "partialPricing not supported - ClpMatrixBase" << std::endl;
abort();
}
/* expands an updated column to allow for extra rows which the main
solver does not know about and returns number added. If the arrays are NULL
then returns number of extra entries needed.
This will normally be a no-op - it is in for GUB!
*/
int ClpMatrixBase::extendUpdated(ClpSimplex *, CoinIndexedVector *, int)
{
return 0;
}
/*
utility primal function for dealing with dynamic constraints
mode=n see ClpGubMatrix.hpp for definition
Remember to update here when settled down
*/
void ClpMatrixBase::primalExpanded(ClpSimplex *, int)
{
}
/*
utility dual function for dealing with dynamic constraints
mode=n see ClpGubMatrix.hpp for definition
Remember to update here when settled down
*/
void ClpMatrixBase::dualExpanded(ClpSimplex *,
CoinIndexedVector *,
double *, int)
{
}
/*
general utility function for dealing with dynamic constraints
mode=n see ClpGubMatrix.hpp for definition
Remember to update here when settled down
*/
int ClpMatrixBase::generalExpanded(ClpSimplex *model, int mode, int &number)
{
int returnCode = 0;
switch (mode) {
// Fill in pivotVariable but not for key variables
case 0: {
int i;
int numberBasic = number;
int numberColumns = model->numberColumns();
// Use different array so can build from true pivotVariable_
//int * pivotVariable = model->pivotVariable();
int *pivotVariable = model->rowArray(0)->getIndices();
for (i = 0; i < numberColumns; i++) {
if (model->getColumnStatus(i) == ClpSimplex::basic)
pivotVariable[numberBasic++] = i;
}
number = numberBasic;
} break;
// Do initial extra rows + maximum basic
case 2: {
number = model->numberRows();
} break;
// To see if can dual or primal
case 4: {
returnCode = 3;
} break;
default:
break;
}
return returnCode;
}
// Sets up an effective RHS
void ClpMatrixBase::useEffectiveRhs(ClpSimplex *)
{
std::cerr << "useEffectiveRhs not supported - ClpMatrixBase" << std::endl;
abort();
}
/* Returns effective RHS if it is being used. This is used for long problems
or big gub or anywhere where going through full columns is
expensive. This may re-compute */
double *
ClpMatrixBase::rhsOffset(ClpSimplex *model, bool forceRefresh, bool
#ifdef CLP_DEBUG
check
#endif
)
{
if (rhsOffset_) {
#ifdef CLP_DEBUG
if (check) {
// no need - but check anyway
// zero out basic
int numberRows = model->numberRows();
int numberColumns = model->numberColumns();
double *solution = new double[numberColumns];
double *rhs = new double[numberRows];
const double *solutionSlack = model->solutionRegion(0);
CoinMemcpyN(model->solutionRegion(), numberColumns, solution);
int iRow;
for (iRow = 0; iRow < numberRows; iRow++) {
if (model->getRowStatus(iRow) != ClpSimplex::basic)
rhs[iRow] = solutionSlack[iRow];
else
rhs[iRow] = 0.0;
}
for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
if (model->getColumnStatus(iColumn) == ClpSimplex::basic)
solution[iColumn] = 0.0;
}
times(-1.0, solution, rhs);
delete[] solution;
for (iRow = 0; iRow < numberRows; iRow++) {
if (fabs(rhs[iRow] - rhsOffset_[iRow]) > 1.0e-3)
printf("** bad effective %d - true %g old %g\n", iRow, rhs[iRow], rhsOffset_[iRow]);
}
}
#endif
if (forceRefresh || (refreshFrequency_ && model->numberIterations() >= lastRefresh_ + refreshFrequency_)) {
// zero out basic
int numberRows = model->numberRows();
int numberColumns = model->numberColumns();
double *solution = new double[numberColumns];
const double *solutionSlack = model->solutionRegion(0);
CoinMemcpyN(model->solutionRegion(), numberColumns, solution);
for (int iRow = 0; iRow < numberRows; iRow++) {
if (model->getRowStatus(iRow) != ClpSimplex::basic)
rhsOffset_[iRow] = solutionSlack[iRow];
else
rhsOffset_[iRow] = 0.0;
}
for (int iColumn = 0; iColumn < numberColumns; iColumn++) {
if (model->getColumnStatus(iColumn) == ClpSimplex::basic)
solution[iColumn] = 0.0;
}
times(-1.0, solution, rhsOffset_);
delete[] solution;
lastRefresh_ = model->numberIterations();
}
}
return rhsOffset_;
}
/*
update information for a pivot (and effective rhs)
*/
int ClpMatrixBase::updatePivot(ClpSimplex *model, double oldInValue, double)
{
if (rhsOffset_) {
// update effective rhs
int sequenceIn = model->sequenceIn();
int sequenceOut = model->sequenceOut();
double *solution = model->solutionRegion();
int numberColumns = model->numberColumns();
if (sequenceIn == sequenceOut) {
if (sequenceIn < numberColumns)
add(model, rhsOffset_, sequenceIn, oldInValue - solution[sequenceIn]);
} else {
if (sequenceIn < numberColumns)
add(model, rhsOffset_, sequenceIn, oldInValue);
if (sequenceOut < numberColumns)
add(model, rhsOffset_, sequenceOut, -solution[sequenceOut]);
}
}
return 0;
}
int ClpMatrixBase::hiddenRows() const
{
return 0;
}
/* Creates a variable. This is called after partial pricing and may modify matrix.
May update bestSequence.
*/
void ClpMatrixBase::createVariable(ClpSimplex *, int &)
{
}
// Returns reduced cost of a variable
double
ClpMatrixBase::reducedCost(ClpSimplex *model, int sequence) const
{
int numberRows = model->numberRows();
int numberColumns = model->numberColumns();
if (sequence < numberRows + numberColumns)
return model->djRegion()[sequence];
else
return savedBestDj_;
}
/* Just for debug if odd type matrix.
Returns number and sum of primal infeasibilities.
*/
int ClpMatrixBase::checkFeasible(ClpSimplex *model, double &sum) const
{
int numberRows = model->numberRows();
double *rhs = new double[numberRows];
int numberColumns = model->numberColumns();
int iRow;
CoinZeroN(rhs, numberRows);
times(1.0, model->solutionRegion(), rhs, model->rowScale(), model->columnScale());
int iColumn;
int logLevel = model->messageHandler()->logLevel();
int numberInfeasible = 0;
const double *rowLower = model->lowerRegion(0);
const double *rowUpper = model->upperRegion(0);
const double *solution;
solution = model->solutionRegion(0);
double tolerance = model->primalTolerance() * 1.01;
sum = 0.0;
for (iRow = 0; iRow < numberRows; iRow++) {
double value = rhs[iRow];
double value2 = solution[iRow];
if (logLevel > 3) {
if (fabs(value - value2) > 1.0e-8)
printf("Row %d stored %g, computed %g\n", iRow, value2, value);
}
if (value < rowLower[iRow] - tolerance || value > rowUpper[iRow] + tolerance) {
numberInfeasible++;
sum += CoinMax(rowLower[iRow] - value, value - rowUpper[iRow]);
}
if (value2 > rowLower[iRow] + tolerance && value2 < rowUpper[iRow] - tolerance && model->getRowStatus(iRow) != ClpSimplex::basic) {
assert(model->getRowStatus(iRow) == ClpSimplex::superBasic);
}
}
const double *columnLower = model->lowerRegion(1);
const double *columnUpper = model->upperRegion(1);
solution = model->solutionRegion(1);
for (iColumn = 0; iColumn < numberColumns; iColumn++) {
double value = solution[iColumn];
if (value < columnLower[iColumn] - tolerance || value > columnUpper[iColumn] + tolerance) {
numberInfeasible++;
sum += CoinMax(columnLower[iColumn] - value, value - columnUpper[iColumn]);
}
if (value > columnLower[iColumn] + tolerance && value < columnUpper[iColumn] - tolerance && model->getColumnStatus(iColumn) != ClpSimplex::basic) {
assert(model->getColumnStatus(iColumn) == ClpSimplex::superBasic);
}
}
delete[] rhs;
return numberInfeasible;
}
// These have to match ClpPrimalColumnSteepest version
#define reference(i) (((reference[i >> 5] >> (i & 31)) & 1) != 0)
// Updates second array for steepest and does devex weights (need not be coded)
void ClpMatrixBase::subsetTimes2(const ClpSimplex *model,
CoinIndexedVector *dj1,
const CoinIndexedVector *pi2, CoinIndexedVector *dj2,
double referenceIn, double devex,
// Array for exact devex to say what is in reference framework
unsigned int *reference,
double *weights, double scaleFactor)
{
// get subset which have nonzero tableau elements
subsetTransposeTimes(model, pi2, dj1, dj2);
bool killDjs = (scaleFactor == 0.0);
if (!scaleFactor)
scaleFactor = 1.0;
// columns
int number = dj1->getNumElements();
const int *index = dj1->getIndices();
double *updateBy = dj1->denseVector();
double *updateBy2 = dj2->denseVector();
for (int j = 0; j < number; j++) {
double thisWeight;
double pivot;
double pivotSquared;
int iSequence = index[j];
double value2 = updateBy[j];
if (killDjs)
updateBy[j] = 0.0;
double modification = updateBy2[j];
updateBy2[j] = 0.0;
ClpSimplex::Status status = model->getStatus(iSequence);
if (status != ClpSimplex::basic && status != ClpSimplex::isFixed) {
thisWeight = weights[iSequence];
pivot = value2 * scaleFactor;
pivotSquared = pivot * pivot;
thisWeight += pivotSquared * devex + pivot * modification;
if (thisWeight < DEVEX_TRY_NORM) {
if (referenceIn < 0.0) {
// steepest
thisWeight = CoinMax(DEVEX_TRY_NORM, DEVEX_ADD_ONE + pivotSquared);
} else {
// exact
thisWeight = referenceIn * pivotSquared;
if (reference(iSequence))
thisWeight += 1.0;
thisWeight = CoinMax(thisWeight, DEVEX_TRY_NORM);
}
}
weights[iSequence] = thisWeight;
}
}
dj2->setNumElements(0);
}
// Correct sequence in and out to give true value
void ClpMatrixBase::correctSequence(const ClpSimplex *, int &, int &)
{
}
// Really scale matrix
void ClpMatrixBase::reallyScale(const double *, const double *)
{
std::cerr << "reallyScale not supported - ClpMatrixBase" << std::endl;
abort();
}
// Updates two arrays for steepest
int ClpMatrixBase::transposeTimes2(const ClpSimplex *,
const CoinIndexedVector *, CoinIndexedVector *,
const CoinIndexedVector *,
CoinIndexedVector *,
double *, double *,
double, double,
// Array for exact devex to say what is in reference framework
unsigned int *,
double *, double)
{
std::cerr << "transposeTimes2 not supported - ClpMatrixBase" << std::endl;
abort();
return 0;
}
/* Set the dimensions of the matrix. In effect, append new empty
columns/rows to the matrix. A negative number for either dimension
means that that dimension doesn't change. Otherwise the new dimensions
MUST be at least as large as the current ones otherwise an exception
is thrown. */
void ClpMatrixBase::setDimensions(int, int)
{
// If odd matrix assume user knows what they are doing
}
/* Append a set of rows/columns to the end of the matrix. Returns number of errors
i.e. if any of the new rows/columns contain an index that's larger than the
number of columns-1/rows-1 (if numberOther>0) or duplicates
If 0 then rows, 1 if columns */
int ClpMatrixBase::appendMatrix(int, int,
const CoinBigIndex *, const int *,
const double *, int)
{
std::cerr << "appendMatrix not supported - ClpMatrixBase" << std::endl;
abort();
return -1;
}
/* Modify one element of packed matrix. An element may be added.
This works for either ordering If the new element is zero it will be
deleted unless keepZero true */
void ClpMatrixBase::modifyCoefficient(int, int, double,
bool)
{
std::cerr << "modifyCoefficient not supported - ClpMatrixBase" << std::endl;
abort();
}
#if COIN_LONG_WORK
// For long double versions (aborts if not supported)
void ClpMatrixBase::times(CoinWorkDouble scalar,
const CoinWorkDouble *x, CoinWorkDouble *y) const
{
std::cerr << "long times not supported - ClpMatrixBase" << std::endl;
abort();
}
void ClpMatrixBase::transposeTimes(CoinWorkDouble scalar,
const CoinWorkDouble *x, CoinWorkDouble *y) const
{
std::cerr << "long transposeTimes not supported - ClpMatrixBase" << std::endl;
abort();
}
#endif
/* vi: softtabstop=2 shiftwidth=2 expandtab tabstop=2
*/