solver.dart 17.1 KB
Newer Older
1 2 3 4 5 6 7
// Copyright (c) 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

part of cassowary;

class Solver {
8 9 10 11 12 13 14
  final Map<Constraint, _Tag> _constraints = new Map<Constraint, _Tag>();
  final Map<_Symbol, _Row> _rows = new Map<_Symbol, _Row>();
  final Map<Variable, _Symbol> _vars = new Map<Variable, _Symbol>();
  final Map<Variable, _EditInfo> _edits = new Map<Variable, _EditInfo>();
  final List<_Symbol> _infeasibleRows = new List<_Symbol>();
  final _Row _objective = new _Row(0.0);
  _Row _artificial = new _Row(0.0);
15
  int tick = 1;
16

17 18 19 20
  /// Attempts to add the constraints in the list to the solver. If it cannot
  /// add any for some reason, a cleanup is attempted so that either all
  /// constraints will be added or none.
  Result addConstraints(List<Constraint> constraints) {
21 22
    _SolverBulkUpdate applier = (Constraint c) => addConstraint(c);
    _SolverBulkUpdate undoer = (Constraint c) => removeConstraint(c);
23

24
    return _bulkEdit(constraints, applier, undoer);
25 26
  }

27 28 29 30 31
  Result addConstraint(Constraint constraint) {
    if (_constraints.containsKey(constraint)) {
      return Result.duplicateConstraint;
    }

32 33
    _Tag tag = new _Tag(new _Symbol(_SymbolType.invalid, 0),
        new _Symbol(_SymbolType.invalid, 0));
34

35
    _Row row = _createRow(constraint, tag);
36

37
    _Symbol subject = _chooseSubjectForRow(row, tag);
38

39
    if (subject.type == _SymbolType.invalid && _allDummiesInRow(row)) {
40 41 42 43 44 45 46
      if (!_nearZero(row.constant)) {
        return Result.unsatisfiableConstraint;
      } else {
        subject = tag.marker;
      }
    }

47
    if (subject.type == _SymbolType.invalid) {
48 49 50 51 52 53 54 55 56 57 58
      if (!_addWithArtificialVariableOnRow(row)) {
        return Result.unsatisfiableConstraint;
      }
    } else {
      row.solveForSymbol(subject);
      _substitute(subject, row);
      _rows[subject] = row;
    }

    _constraints[constraint] = tag;

59
    return _optimizeObjectiveRow(_objective);
60 61
  }

62 63 64 65 66 67 68
  Result removeConstraints(List<Constraint> constraints) {
    _SolverBulkUpdate applier = (Constraint c) => removeConstraint(c);
    _SolverBulkUpdate undoer = (Constraint c) => addConstraint(c);

    return _bulkEdit(constraints, applier, undoer);
  }

69
  Result removeConstraint(Constraint constraint) {
70
    _Tag tag = _constraints[constraint];
71 72 73 74
    if (tag == null) {
      return Result.unknownConstraint;
    }

75
    tag = new _Tag.fromTag(tag);
76 77 78 79
    _constraints.remove(constraint);

    _removeConstraintEffects(constraint, tag);

80
    _Row row = _rows[tag.marker];
81 82 83
    if (row != null) {
      _rows.remove(tag.marker);
    } else {
84
      _Pair<_Symbol, _Row> rowPair = _leavingRowPairForMarkerSymbol(tag.marker);
85 86 87 88 89

      if (rowPair == null) {
        return Result.internalSolverError;
      }

90
      _Symbol leaving = rowPair.first;
91
      row = rowPair.second;
92
      _Row removed = _rows.remove(rowPair.first);
93 94 95 96 97 98
      assert(removed != null);
      row.solveForSymbols(leaving, tag.marker);
      _substitute(tag.marker, row);
    }

    return _optimizeObjectiveRow(_objective);
99 100
  }

101 102
  bool hasConstraint(Constraint constraint) {
    return _constraints.containsKey(constraint);
103 104
  }

105 106 107 108 109 110 111
  Result addEditVariables(List<Variable> variables, double priority) {
    _SolverBulkUpdate applier = (Variable v) => addEditVariable(v, priority);
    _SolverBulkUpdate undoer = (Variable v) => removeEditVariable(v);

    return _bulkEdit(variables, applier, undoer);
  }

112 113 114 115 116 117 118 119 120 121 122
  Result addEditVariable(Variable variable, double priority) {
    if (_edits.containsKey(variable)) {
      return Result.duplicateEditVariable;
    }

    if (!_isValidNonRequiredPriority(priority)) {
      return Result.badRequiredStrength;
    }

    Constraint constraint = new Constraint(
        new Expression([new Term(variable, 1.0)], 0.0), Relation.equalTo);
123
    constraint.priority = priority;
124 125 126 127 128

    if (addConstraint(constraint) != Result.success) {
      return Result.internalSolverError;
    }

129
    _EditInfo info = new _EditInfo();
130 131 132 133 134 135 136
    info.tag = _constraints[constraint];
    info.constraint = constraint;
    info.constant = 0.0;

    _edits[variable] = info;

    return Result.success;
137 138
  }

139 140 141 142 143 144 145 146
  Result removeEditVariables(List<Variable> variables) {
    _SolverBulkUpdate applier = (Variable v) => removeEditVariable(v);
    _SolverBulkUpdate undoer = (Variable v) =>
        addEditVariable(v, _edits[v].constraint.priority);

    return _bulkEdit(variables, applier, undoer);
  }

147
  Result removeEditVariable(Variable variable) {
148
    _EditInfo info = _edits[variable];
149
    if (info == null)
150 151
      return Result.unknownEditVariable;

152
    if (removeConstraint(info.constraint) != Result.success)
153 154 155 156
      return Result.internalSolverError;

    _edits.remove(variable);
    return Result.success;
157 158
  }

159 160
  bool hasEditVariable(Variable variable) {
    return _edits.containsKey(variable);
161 162
  }

163 164 165 166 167 168 169 170
  Result suggestValueForVariable(Variable variable, double value) {
    if (!_edits.containsKey(variable)) {
      return Result.unknownEditVariable;
    }

    _suggestValueForEditInfoWithoutDualOptimization(_edits[variable], value);

    return _dualOptimize();
171 172
  }

173 174
  Set<dynamic> flushUpdates() {
    Set<dynamic> updates = new HashSet<dynamic>();
175

176
    for (Variable variable in _vars.keys) {
177 178
      _Symbol symbol = _vars[variable];
      _Row row = _rows[symbol];
179 180 181 182

      double updatedValue = row == null ? 0.0 : row.constant;

      if (variable._applyUpdate(updatedValue) && variable._owner != null) {
183
        dynamic context = variable._owner.context;
184
        if (context != null)
185
          updates.add(context);
186 187
      }
    }
188

189
    return updates;
190
  }
191

192 193 194 195 196 197
  Result _bulkEdit(
    Iterable<dynamic> items,
    _SolverBulkUpdate applier,
    _SolverBulkUpdate undoer
  ) {
    List<dynamic> applied = <dynamic>[];
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
    bool needsCleanup = false;

    Result result = Result.success;

    for (dynamic item in items) {
      result = applier(item);
      if (result == Result.success) {
        applied.add(item);
      } else {
        needsCleanup = true;
        break;
      }
    }

    if (needsCleanup) {
213
      for (dynamic item in applied.reversed)
214 215 216 217 218 219
        undoer(item);
    }

    return result;
  }

220
  _Symbol _symbolForVariable(Variable variable) {
221
    _Symbol symbol = _vars[variable];
222

223
    if (symbol != null)
224 225
      return symbol;

226
    symbol = new _Symbol(_SymbolType.external, tick++);
227 228 229 230 231
    _vars[variable] = symbol;

    return symbol;
  }

232
  _Row _createRow(Constraint constraint, _Tag tag) {
233
    Expression expr = new Expression.fromExpression(constraint.expression);
234
    _Row row = new _Row(expr.constant);
235

236
    expr.terms.forEach((Term term) {
237
      if (!_nearZero(term.coefficient)) {
238
        _Symbol symbol = _symbolForVariable(term.variable);
239

240
        _Row foundRow = _rows[symbol];
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256

        if (foundRow != null) {
          row.insertRow(foundRow, term.coefficient);
        } else {
          row.insertSymbol(symbol, term.coefficient);
        }
      }
    });

    switch (constraint.relation) {
      case Relation.lessThanOrEqualTo:
      case Relation.greaterThanOrEqualTo:
        {
          double coefficient =
              constraint.relation == Relation.lessThanOrEqualTo ? 1.0 : -1.0;

257
          _Symbol slack = new _Symbol(_SymbolType.slack, tick++);
258 259 260
          tag.marker = slack;
          row.insertSymbol(slack, coefficient);

261
          if (constraint.priority < Priority.required) {
262
            _Symbol error = new _Symbol(_SymbolType.error, tick++);
263 264 265 266 267 268 269
            tag.other = error;
            row.insertSymbol(error, -coefficient);
            _objective.insertSymbol(error, constraint.priority);
          }
        }
        break;
      case Relation.equalTo:
270
        if (constraint.priority < Priority.required) {
271 272
          _Symbol errPlus = new _Symbol(_SymbolType.error, tick++);
          _Symbol errMinus = new _Symbol(_SymbolType.error, tick++);
273 274 275 276 277 278 279
          tag.marker = errPlus;
          tag.other = errMinus;
          row.insertSymbol(errPlus, -1.0);
          row.insertSymbol(errMinus, 1.0);
          _objective.insertSymbol(errPlus, constraint.priority);
          _objective.insertSymbol(errMinus, constraint.priority);
        } else {
280
          _Symbol dummy = new _Symbol(_SymbolType.dummy, tick++);
281 282 283 284 285 286 287 288 289 290 291 292 293
          tag.marker = dummy;
          row.insertSymbol(dummy);
        }
        break;
    }

    if (row.constant < 0.0) {
      row.reverseSign();
    }

    return row;
  }

294 295
  _Symbol _chooseSubjectForRow(_Row row, _Tag tag) {
    for (_Symbol symbol in row.cells.keys) {
296
      if (symbol.type == _SymbolType.external) {
297 298 299 300
        return symbol;
      }
    }

301 302
    if (tag.marker.type == _SymbolType.slack ||
        tag.marker.type == _SymbolType.error) {
303 304 305 306 307
      if (row.coefficientForSymbol(tag.marker) < 0.0) {
        return tag.marker;
      }
    }

308 309
    if (tag.other.type == _SymbolType.slack ||
        tag.other.type == _SymbolType.error) {
310 311 312 313 314
      if (row.coefficientForSymbol(tag.other) < 0.0) {
        return tag.other;
      }
    }

315
    return new _Symbol(_SymbolType.invalid, 0);
316 317
  }

318 319
  bool _allDummiesInRow(_Row row) {
    for (_Symbol symbol in row.cells.keys) {
320
      if (symbol.type != _SymbolType.dummy) {
321 322 323 324 325 326
        return false;
      }
    }
    return true;
  }

327
  bool _addWithArtificialVariableOnRow(_Row row) {
328
    _Symbol artificial = new _Symbol(_SymbolType.slack, tick++);
329 330
    _rows[artificial] = new _Row.fromRow(row);
    _artificial = new _Row.fromRow(row);
331 332 333 334 335 336 337 338 339

    Result result = _optimizeObjectiveRow(_artificial);

    if (result.error) {
      // FIXME(csg): Propagate this up!
      return false;
    }

    bool success = _nearZero(_artificial.constant);
340
    _artificial = new _Row(0.0);
341

342
    _Row foundRow = _rows[artificial];
343 344 345 346 347 348
    if (foundRow != null) {
      _rows.remove(artificial);
      if (foundRow.cells.isEmpty) {
        return success;
      }

349
      _Symbol entering = _anyPivotableSymbol(foundRow);
350
      if (entering.type == _SymbolType.invalid) {
351 352 353 354 355 356 357 358
        return false;
      }

      foundRow.solveForSymbols(artificial, entering);
      _substitute(entering, foundRow);
      _rows[entering] = foundRow;
    }

359
    for (_Row row in _rows.values) {
360 361 362 363 364 365
      row.removeSymbol(artificial);
    }
    _objective.removeSymbol(artificial);
    return success;
  }

366
  Result _optimizeObjectiveRow(_Row objective) {
367
    while (true) {
368
      _Symbol entering = _enteringSymbolForObjectiveRow(objective);
369
      if (entering.type == _SymbolType.invalid) {
370 371 372
        return Result.success;
      }

373
      _Pair<_Symbol, _Row> leavingPair = _leavingRowForEnteringSymbol(entering);
374 375 376 377 378

      if (leavingPair == null) {
        return Result.internalSolverError;
      }

379 380
      _Symbol leaving = leavingPair.first;
      _Row row = leavingPair.second;
381 382 383 384 385 386 387
      _rows.remove(leavingPair.first);
      row.solveForSymbols(leaving, entering);
      _substitute(entering, row);
      _rows[entering] = row;
    }
  }

388
  _Symbol _enteringSymbolForObjectiveRow(_Row objective) {
389
    Map<_Symbol, double> cells = objective.cells;
390

391
    for (_Symbol symbol in cells.keys) {
392
      if (symbol.type != _SymbolType.dummy && cells[symbol] < 0.0) {
393 394 395 396
        return symbol;
      }
    }

397
    return new _Symbol(_SymbolType.invalid, 0);
398 399
  }

400
  _Pair<_Symbol, _Row> _leavingRowForEnteringSymbol(_Symbol entering) {
401
    double ratio = double.MAX_FINITE;
402
    _Pair<_Symbol, _Row> result = new _Pair<_Symbol, _Row>(null, null);
403

404
    _rows.forEach((_Symbol symbol, _Row row) {
405
      if (symbol.type != _SymbolType.external) {
406 407 408
        double temp = row.coefficientForSymbol(entering);

        if (temp < 0.0) {
Hixie's avatar
Hixie committed
409
          double tempRatio = -row.constant / temp;
410

Hixie's avatar
Hixie committed
411 412
          if (tempRatio < ratio) {
            ratio = tempRatio;
413 414 415 416 417 418 419 420 421 422 423 424 425 426
            result.first = symbol;
            result.second = row;
          }
        }
      }
    });

    if (result.first == null || result.second == null) {
      return null;
    }

    return result;
  }

427
  void _substitute(_Symbol symbol, _Row row) {
428
    _rows.forEach((_Symbol first, _Row second) {
429
      second.substitute(symbol, row);
430
      if (first.type != _SymbolType.external && second.constant < 0.0) {
431 432 433 434 435 436 437 438 439 440
        _infeasibleRows.add(first);
      }
    });

    _objective.substitute(symbol, row);
    if (_artificial != null) {
      _artificial.substitute(symbol, row);
    }
  }

441 442
  _Symbol _anyPivotableSymbol(_Row row) {
    for (_Symbol symbol in row.cells.keys) {
443 444
      if (symbol.type == _SymbolType.slack ||
          symbol.type == _SymbolType.error) {
445 446 447
        return symbol;
      }
    }
448
    return new _Symbol(_SymbolType.invalid, 0);
449
  }
450

451
  void _removeConstraintEffects(Constraint cn, _Tag tag) {
452
    if (tag.marker.type == _SymbolType.error) {
453 454
      _removeMarkerEffects(tag.marker, cn.priority);
    }
455
    if (tag.other.type == _SymbolType.error) {
456 457 458 459
      _removeMarkerEffects(tag.other, cn.priority);
    }
  }

460 461
  void _removeMarkerEffects(_Symbol marker, double strength) {
    _Row row = _rows[marker];
462 463 464 465 466 467 468
    if (row != null) {
      _objective.insertRow(row, -strength);
    } else {
      _objective.insertSymbol(marker, -strength);
    }
  }

469
  _Pair<_Symbol, _Row> _leavingRowPairForMarkerSymbol(_Symbol marker) {
470 471 472
    double r1 = double.MAX_FINITE;
    double r2 = double.MAX_FINITE;

473
    _Pair<_Symbol, _Row> first, second, third;
474

475
    _rows.forEach((_Symbol symbol, _Row row) {
476 477 478 479 480 481
      double c = row.coefficientForSymbol(marker);

      if (c == 0.0) {
        return;
      }

482
      if (symbol.type == _SymbolType.external) {
483
        third = new _Pair<_Symbol, _Row>(symbol, row);
484 485 486 487
      } else if (c < 0.0) {
        double r = -row.constant / c;
        if (r < r1) {
          r1 = r;
488
          first = new _Pair<_Symbol, _Row>(symbol, row);
489 490 491 492 493
        }
      } else {
        double r = row.constant / c;
        if (r < r2) {
          r2 = r;
494
          second = new _Pair<_Symbol, _Row>(symbol, row);
495 496 497 498 499 500 501 502 503 504 505 506
        }
      }
    });

    if (first != null) {
      return first;
    }
    if (second != null) {
      return second;
    }
    return third;
  }
507 508

  void _suggestValueForEditInfoWithoutDualOptimization(
509
      _EditInfo info, double value) {
510 511 512 513
    double delta = value - info.constant;
    info.constant = value;

    {
514 515
      _Symbol symbol = info.tag.marker;
      _Row row = _rows[info.tag.marker];
516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534

      if (row != null) {
        if (row.add(-delta) < 0.0) {
          _infeasibleRows.add(symbol);
        }
        return;
      }

      symbol = info.tag.other;
      row = _rows[info.tag.other];

      if (row != null) {
        if (row.add(delta) < 0.0) {
          _infeasibleRows.add(symbol);
        }
        return;
      }
    }

535 536
    for (_Symbol symbol in _rows.keys) {
      _Row row = _rows[symbol];
537 538 539
      double coeff = row.coefficientForSymbol(info.tag.marker);
      if (coeff != 0.0 &&
          row.add(delta * coeff) < 0.0 &&
540
          symbol.type != _SymbolType.external) {
541 542 543 544 545 546 547
        _infeasibleRows.add(symbol);
      }
    }
  }

  Result _dualOptimize() {
    while (_infeasibleRows.length != 0) {
548 549
      _Symbol leaving = _infeasibleRows.removeLast();
      _Row row = _rows[leaving];
550 551

      if (row != null && row.constant < 0.0) {
552
        _Symbol entering = _dualEnteringSymbolForRow(row);
553

554
        if (entering.type == _SymbolType.invalid) {
555 556 557 558 559 560 561 562 563 564 565 566 567
          return Result.internalSolverError;
        }

        _rows.remove(leaving);

        row.solveForSymbols(leaving, entering);
        _substitute(entering, row);
        _rows[entering] = row;
      }
    }
    return Result.success;
  }

568
  _Symbol _dualEnteringSymbolForRow(_Row row) {
569
    _Symbol entering;
570 571 572

    double ratio = double.MAX_FINITE;

573
    Map<_Symbol, double> rowCells = row.cells;
574

575
    for (_Symbol symbol in rowCells.keys) {
576 577
      double value = rowCells[symbol];

578
      if (value > 0.0 && symbol.type != _SymbolType.dummy) {
579 580 581 582 583 584 585 586 587
        double coeff = _objective.coefficientForSymbol(symbol);
        double r = coeff / value;
        if (r < ratio) {
          ratio = r;
          entering = symbol;
        }
      }
    }

588
    return entering ?? new _Symbol(_SymbolType.invalid, 0);
589
  }
590 591 592 593 594 595 596 597 598 599 600

  String toString() {
    StringBuffer buffer = new StringBuffer();
    String separator = "\n~~~~~~~~~";

    // Objective
    buffer.writeln(separator + " Objective");
    buffer.writeln(_objective.toString());

    // Tableau
    buffer.writeln(separator + " Tableau");
601 602
    _rows.forEach((_Symbol symbol, _Row row) {
      buffer.writeln('$symbol | $row');
603 604 605 606
    });

    // Infeasible
    buffer.writeln(separator + " Infeasible");
607 608 609
    _infeasibleRows.forEach((_Symbol symbol) {
      buffer.writeln(symbol);
    });
610 611 612

    // Variables
    buffer.writeln(separator + " Variables");
613 614 615
    _vars.forEach((Variable variable, _Symbol symbol) {
      buffer.writeln('$variable = $symbol');
    });
616 617 618

    // Edit Variables
    buffer.writeln(separator + " Edit Variables");
619 620 621
    _edits.forEach((Variable variable, _EditInfo editinfo) {
      buffer.writeln(variable);
    });
622 623 624

    // Constraints
    buffer.writeln(separator + " Constraints");
625 626 627
    _constraints.forEach((Constraint constraint, _Tag tag) {
      buffer.writeln(constraint);
    });
628 629 630

    return buffer.toString();
  }
631
}
632

633 634 635
class _Tag {
  _Symbol marker;
  _Symbol other;
636

637 638
  _Tag(this.marker, this.other);
  _Tag.fromTag(_Tag tag)
639 640
      : this.marker = tag.marker,
        this.other = tag.other;
641 642
}

643 644
class _EditInfo {
  _Tag tag;
645 646 647
  Constraint constraint;
  double constant;
}
648 649

bool _isValidNonRequiredPriority(double priority) {
650
  return (priority >= 0.0 && priority < Priority.required);
651
}
652 653

typedef Result _SolverBulkUpdate(dynamic item);