195 lines
5.1 KiB
Dart
195 lines
5.1 KiB
Dart
// 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 Expression extends _EquationMember {
|
|
Expression(this.terms, this.constant);
|
|
Expression.fromExpression(Expression expr)
|
|
: this.terms = new List<Term>.from(expr.terms),
|
|
this.constant = expr.constant;
|
|
|
|
final List<Term> terms;
|
|
|
|
final double constant;
|
|
|
|
@override
|
|
bool get isConstant => terms.length == 0;
|
|
|
|
@override
|
|
double get value => terms.fold(constant, (double value, Term term) => value + term.value);
|
|
|
|
@override
|
|
Expression asExpression() => this;
|
|
|
|
Constraint _createConstraint(_EquationMember /* rhs */ value, Relation relation) {
|
|
if (value is ConstantMember) {
|
|
return new Constraint(
|
|
new Expression(new List<Term>.from(terms), constant - value.value),
|
|
relation
|
|
);
|
|
}
|
|
|
|
if (value is Param) {
|
|
List<Term> newTerms = new List<Term>.from(terms)
|
|
..add(new Term(value.variable, -1.0));
|
|
return new Constraint(new Expression(newTerms, constant), relation);
|
|
}
|
|
|
|
if (value is Term) {
|
|
List<Term> newTerms = new List<Term>.from(terms)
|
|
..add(new Term(value.variable, -value.coefficient));
|
|
return new Constraint(new Expression(newTerms, constant), relation);
|
|
}
|
|
|
|
if (value is Expression) {
|
|
List<Term> newTerms = value.terms.fold(
|
|
new List<Term>.from(terms),
|
|
(List<Term> list, Term t) {
|
|
return list..add(new Term(t.variable, -t.coefficient));
|
|
}
|
|
);
|
|
return new Constraint(
|
|
new Expression(newTerms, constant - value.constant),
|
|
relation
|
|
);
|
|
}
|
|
assert(false);
|
|
return null;
|
|
}
|
|
|
|
@override
|
|
Constraint operator >=(_EquationMember value) {
|
|
return _createConstraint(value, Relation.greaterThanOrEqualTo);
|
|
}
|
|
|
|
@override
|
|
Constraint operator <=(_EquationMember value) {
|
|
return _createConstraint(value, Relation.lessThanOrEqualTo);
|
|
}
|
|
|
|
@override
|
|
Constraint equals(_EquationMember value) {
|
|
return _createConstraint(value, Relation.equalTo);
|
|
}
|
|
|
|
@override
|
|
Expression operator +(_EquationMember m) {
|
|
if (m is ConstantMember)
|
|
return new Expression(new List<Term>.from(terms), constant + m.value);
|
|
|
|
if (m is Param) {
|
|
return new Expression(
|
|
new List<Term>.from(terms)..add(new Term(m.variable, 1.0)),
|
|
constant
|
|
);
|
|
}
|
|
|
|
if (m is Term)
|
|
return new Expression(new List<Term>.from(terms)..add(m), constant);
|
|
|
|
if (m is Expression) {
|
|
return new Expression(
|
|
new List<Term>.from(terms)..addAll(m.terms),
|
|
constant + m.constant
|
|
);
|
|
}
|
|
assert(false);
|
|
return null;
|
|
}
|
|
|
|
@override
|
|
Expression operator -(_EquationMember m) {
|
|
if (m is ConstantMember)
|
|
return new Expression(new List<Term>.from(terms), constant - m.value);
|
|
|
|
if (m is Param) {
|
|
return new Expression(
|
|
new List<Term>.from(terms)..add(new Term(m.variable, -1.0)),
|
|
constant
|
|
);
|
|
}
|
|
|
|
if (m is Term) {
|
|
return new Expression(new List<Term>.from(terms)
|
|
..add(new Term(m.variable, -m.coefficient)), constant);
|
|
}
|
|
|
|
if (m is Expression) {
|
|
List<Term> copiedTerms = new List<Term>.from(terms);
|
|
for (Term t in m.terms)
|
|
copiedTerms.add(new Term(t.variable, -t.coefficient));
|
|
return new Expression(copiedTerms, constant - m.constant);
|
|
}
|
|
assert(false);
|
|
return null;
|
|
}
|
|
|
|
_EquationMember _applyMultiplicand(double m) {
|
|
List<Term> newTerms = terms.fold(
|
|
new List<Term>(),
|
|
(List<Term> list, Term term) {
|
|
return list..add(new Term(term.variable, term.coefficient * m));
|
|
}
|
|
);
|
|
return new Expression(newTerms, constant * m);
|
|
}
|
|
|
|
_Pair<Expression, double> _findMulitplierAndMultiplicand(_EquationMember m) {
|
|
// At least on of the the two members must be constant for the resulting
|
|
// expression to be linear
|
|
|
|
if (!this.isConstant && !m.isConstant)
|
|
return null;
|
|
|
|
if (this.isConstant)
|
|
return new _Pair<Expression, double>(m.asExpression(), this.value);
|
|
|
|
if (m.isConstant)
|
|
return new _Pair<Expression, double>(this.asExpression(), m.value);
|
|
|
|
assert(false);
|
|
return null;
|
|
}
|
|
|
|
@override
|
|
_EquationMember operator *(_EquationMember m) {
|
|
_Pair<Expression, double> args = _findMulitplierAndMultiplicand(m);
|
|
|
|
if (args == null) {
|
|
throw new ParserException(
|
|
'Could not find constant multiplicand or multiplier',
|
|
<_EquationMember>[this, m]
|
|
);
|
|
}
|
|
|
|
return args.first._applyMultiplicand(args.second);
|
|
}
|
|
|
|
@override
|
|
_EquationMember operator /(_EquationMember m) {
|
|
if (!m.isConstant) {
|
|
throw new ParserException(
|
|
'The divisor was not a constant expression', [this, m]);
|
|
return null;
|
|
}
|
|
|
|
return this._applyMultiplicand(1.0 / m.value);
|
|
}
|
|
|
|
@override
|
|
String toString() {
|
|
StringBuffer buffer = new StringBuffer();
|
|
|
|
terms.forEach((Term t) => buffer.write('$t'));
|
|
|
|
if (constant != 0.0) {
|
|
buffer.write(constant.sign > 0.0 ? '+' : '-');
|
|
buffer.write(constant.abs());
|
|
}
|
|
|
|
return buffer.toString();
|
|
}
|
|
}
|