Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
c7dfbc04
Commit
c7dfbc04
authored
Nov 03, 2015
by
Adam Barth
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'cassowary'
parents
6fea7f58
d29a0b52
Changes
16
Show whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
1858 additions
and
0 deletions
+1858
-0
cassowary.dart
packages/cassowary/lib/cassowary.dart
+22
-0
constant_member.dart
packages/cassowary/lib/constant_member.dart
+19
-0
constraint.dart
packages/cassowary/lib/constraint.dart
+42
-0
equation_member.dart
packages/cassowary/lib/equation_member.dart
+30
-0
expression.dart
packages/cassowary/lib/expression.dart
+172
-0
param.dart
packages/cassowary/lib/param.dart
+29
-0
parser_exception.dart
packages/cassowary/lib/parser_exception.dart
+16
-0
priority.dart
packages/cassowary/lib/priority.dart
+24
-0
result.dart
packages/cassowary/lib/result.dart
+29
-0
row.dart
packages/cassowary/lib/row.dart
+78
-0
solver.dart
packages/cassowary/lib/solver.dart
+652
-0
symbol.dart
packages/cassowary/lib/symbol.dart
+36
-0
term.dart
packages/cassowary/lib/term.dart
+34
-0
utils.dart
packages/cassowary/lib/utils.dart
+21
-0
variable.dart
packages/cassowary/lib/variable.dart
+27
-0
cassowary_test.dart
packages/cassowary/test/cassowary_test.dart
+627
-0
No files found.
packages/cassowary/lib/cassowary.dart
0 → 100644
View file @
c7dfbc04
// 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.
library
cassowary
;
import
'dart:math'
;
part
'constraint.dart'
;
part
'expression.dart'
;
part
'term.dart'
;
part
'variable.dart'
;
part
'equation_member.dart'
;
part
'constant_member.dart'
;
part
'solver.dart'
;
part
'symbol.dart'
;
part
'row.dart'
;
part
'utils.dart'
;
part
'result.dart'
;
part
'parser_exception.dart'
;
part
'param.dart'
;
part
'priority.dart'
;
packages/cassowary/lib/constant_member.dart
0 → 100644
View file @
c7dfbc04
// 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
ConstantMember
extends
_EquationMember
{
final
double
value
;
bool
get
isConstant
=>
true
;
ConstantMember
(
this
.
value
);
Expression
asExpression
()
=>
new
Expression
([],
this
.
value
);
}
ConstantMember
cm
(
double
value
)
{
return
new
ConstantMember
(
value
);
}
packages/cassowary/lib/constraint.dart
0 → 100644
View file @
c7dfbc04
// 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
;
enum
Relation
{
equalTo
,
lessThanOrEqualTo
,
greaterThanOrEqualTo
,
}
class
Constraint
{
final
Relation
relation
;
final
Expression
expression
;
double
priority
=
Priority
.
required
;
Constraint
(
this
.
expression
,
this
.
relation
);
Constraint
operator
|(
double
p
)
=>
this
..
priority
=
p
;
String
toString
()
{
StringBuffer
buffer
=
new
StringBuffer
();
buffer
.
write
(
expression
.
toString
());
switch
(
relation
)
{
case
Relation
.
equalTo
:
buffer
.
write
(
" == 0 "
);
break
;
case
Relation
.
greaterThanOrEqualTo
:
buffer
.
write
(
" >= 0 "
);
break
;
case
Relation
.
lessThanOrEqualTo
:
buffer
.
write
(
" <= 0 "
);
break
;
}
buffer
.
write
(
" | priority =
${priority}
"
);
if
(
priority
==
Priority
.
required
)
{
buffer
.
write
(
" (required)"
);
}
return
buffer
.
toString
();
}
}
packages/cassowary/lib/equation_member.dart
0 → 100644
View file @
c7dfbc04
// 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
;
abstract
class
_EquationMember
{
Expression
asExpression
();
bool
get
isConstant
;
double
get
value
;
Constraint
operator
>=(
_EquationMember
m
)
=>
asExpression
()
>=
m
;
Constraint
operator
<=(
_EquationMember
m
)
=>
asExpression
()
<=
m
;
operator
==(
_EquationMember
m
)
=>
asExpression
()
==
m
;
Expression
operator
+(
_EquationMember
m
)
=>
asExpression
()
+
m
;
Expression
operator
-(
_EquationMember
m
)
=>
asExpression
()
-
m
;
Expression
operator
*(
_EquationMember
m
)
=>
asExpression
()
*
m
;
Expression
operator
/(
_EquationMember
m
)
=>
asExpression
()
/
m
;
int
get
hashCode
=>
throw
"An equation member is not comparable and cannot be added to collections"
;
}
packages/cassowary/lib/expression.dart
0 → 100644
View file @
c7dfbc04
// 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
{
final
List
<
Term
>
terms
;
final
double
constant
;
bool
get
isConstant
=>
terms
.
length
==
0
;
double
get
value
=>
terms
.
fold
(
constant
,
(
value
,
term
)
=>
value
+
term
.
value
);
Expression
(
this
.
terms
,
this
.
constant
);
Expression
.
fromExpression
(
Expression
expr
)
:
this
.
terms
=
new
List
<
Term
>.
from
(
expr
.
terms
),
this
.
constant
=
expr
.
constant
;
Expression
asExpression
()
=>
this
;
Constraint
_createConstraint
(
_EquationMember
/* rhs */
value
,
Relation
relation
)
{
if
(
value
is
ConstantMember
)
{
return
new
Constraint
(
new
Expression
(
new
List
.
from
(
terms
),
constant
-
value
.
value
),
relation
);
}
if
(
value
is
Param
)
{
var
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
)
{
var
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
)
{
var
newTerms
=
value
.
terms
.
fold
(
new
List
<
Term
>.
from
(
terms
),
(
list
,
t
)
=>
list
..
add
(
new
Term
(
t
.
variable
,
-
t
.
coefficient
)));
return
new
Constraint
(
new
Expression
(
newTerms
,
constant
-
value
.
constant
),
relation
);
}
assert
(
false
);
return
null
;
}
Constraint
operator
>=(
_EquationMember
value
)
=>
_createConstraint
(
value
,
Relation
.
greaterThanOrEqualTo
);
Constraint
operator
<=(
_EquationMember
value
)
=>
_createConstraint
(
value
,
Relation
.
lessThanOrEqualTo
);
operator
==(
_EquationMember
value
)
=>
_createConstraint
(
value
,
Relation
.
equalTo
);
Expression
operator
+(
_EquationMember
m
)
{
if
(
m
is
ConstantMember
)
{
return
new
Expression
(
new
List
.
from
(
terms
),
constant
+
m
.
value
);
}
if
(
m
is
Param
)
{
return
new
Expression
(
new
List
.
from
(
terms
)..
add
(
new
Term
(
m
.
variable
,
1.0
)),
constant
);
}
if
(
m
is
Term
)
{
return
new
Expression
(
new
List
.
from
(
terms
)..
add
(
m
),
constant
);
}
if
(
m
is
Expression
)
{
return
new
Expression
(
new
List
.
from
(
terms
)..
addAll
(
m
.
terms
),
constant
+
m
.
constant
);
}
assert
(
false
);
return
null
;
}
Expression
operator
-(
_EquationMember
m
)
{
if
(
m
is
ConstantMember
)
{
return
new
Expression
(
new
List
.
from
(
terms
),
constant
-
m
.
value
);
}
if
(
m
is
Param
)
{
return
new
Expression
(
new
List
.
from
(
terms
)..
add
(
new
Term
(
m
.
variable
,
-
1.0
)),
constant
);
}
if
(
m
is
Term
)
{
return
new
Expression
(
new
List
.
from
(
terms
)
..
add
(
new
Term
(
m
.
variable
,
-
m
.
coefficient
)),
constant
);
}
if
(
m
is
Expression
)
{
var
copiedTerms
=
new
List
<
Term
>.
from
(
terms
);
m
.
terms
.
forEach
(
(
t
)
=>
copiedTerms
.
add
(
new
Term
(
t
.
variable
,
-
t
.
coefficient
)));
return
new
Expression
(
copiedTerms
,
constant
-
m
.
constant
);
}
assert
(
false
);
return
null
;
}
_EquationMember
_applyMultiplicand
(
double
m
)
{
var
newTerms
=
terms
.
fold
(
new
List
<
Term
>(),
(
list
,
term
)
=>
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
(
m
.
asExpression
(),
this
.
value
);
}
if
(
m
.
isConstant
)
{
return
new
_Pair
(
this
.
asExpression
(),
m
.
value
);
}
assert
(
false
);
return
null
;
}
_EquationMember
operator
*(
_EquationMember
m
)
{
_Pair
<
Expression
,
double
>
args
=
_findMulitplierAndMultiplicand
(
m
);
if
(
args
==
null
)
{
throw
new
ParserException
(
"Could not find constant multiplicand or multiplier"
,
[
this
,
m
]);
return
null
;
}
return
args
.
first
.
_applyMultiplicand
(
args
.
second
);
}
_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
);
}
String
toString
()
{
StringBuffer
buffer
=
new
StringBuffer
();
terms
.
forEach
((
t
)
=>
buffer
.
write
(
"
${t}
"
));
if
(
constant
!=
0.0
)
{
buffer
.
write
(
constant
.
sign
>
0.0
?
"+"
:
"-"
);
buffer
.
write
(
constant
.
abs
());
}
return
buffer
.
toString
();
}
}
packages/cassowary/lib/param.dart
0 → 100644
View file @
c7dfbc04
// 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
Param
extends
_EquationMember
{
final
Variable
variable
;
dynamic
context
;
Param
([
double
value
=
0.0
])
:
variable
=
new
Variable
(
value
)
{
variable
.
_owner
=
this
;
}
Param
.
withContext
(
ctx
,
[
double
value
=
0.0
])
:
variable
=
new
Variable
(
value
),
context
=
ctx
{
variable
.
_owner
=
this
;
}
bool
get
isConstant
=>
false
;
double
get
value
=>
variable
.
value
;
String
get
name
=>
variable
.
name
;
set
name
(
String
name
)
=>
variable
.
name
=
name
;
Expression
asExpression
()
=>
new
Expression
([
new
Term
(
variable
,
1.0
)],
0.0
);
}
packages/cassowary/lib/parser_exception.dart
0 → 100644
View file @
c7dfbc04
// 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
ParserException
implements
Exception
{
final
String
message
;
List
<
_EquationMember
>
members
;
ParserException
(
this
.
message
,
this
.
members
);
String
toString
()
{
if
(
message
==
null
)
return
"Error while parsing constraint or expression"
;
return
"Error: '
$message
' while trying to parse constraint or expression"
;
}
}
packages/cassowary/lib/priority.dart
0 → 100644
View file @
c7dfbc04
// 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
Priority
{
static
final
double
required
=
create
(
1
e3
,
1
e3
,
1
e3
);
static
final
double
strong
=
create
(
1.0
,
0.0
,
0.0
);
static
final
double
medium
=
create
(
0.0
,
1.0
,
0.0
);
static
final
double
weak
=
create
(
0.0
,
0.0
,
1.0
);
static
double
create
(
double
a
,
double
b
,
double
c
)
{
double
result
=
0.0
;
result
+=
max
(
0.0
,
min
(
1
e3
,
a
))
*
1
e6
;
result
+=
max
(
0.0
,
min
(
1
e3
,
b
))
*
1
e3
;
result
+=
max
(
0.0
,
min
(
1
e3
,
c
));
return
result
;
}
static
double
clamp
(
double
value
)
{
return
max
(
0.0
,
min
(
required
,
value
));
}
}
packages/cassowary/lib/result.dart
0 → 100644
View file @
c7dfbc04
// 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
Result
{
final
String
message
;
final
bool
error
;
const
Result
(
this
.
message
,
{
bool
isError:
true
})
:
error
=
isError
;
static
final
Result
success
=
const
Result
(
"Success"
,
isError:
false
);
static
final
Result
unimplemented
=
const
Result
(
"Unimplemented"
);
static
final
Result
duplicateConstraint
=
const
Result
(
"Duplicate Constraint"
);
static
final
Result
unsatisfiableConstraint
=
const
Result
(
"Unsatisfiable Constraint"
);
static
final
Result
unknownConstraint
=
const
Result
(
"Unknown Constraint"
);
static
final
Result
duplicateEditVariable
=
const
Result
(
"Duplicate Edit Variable"
);
static
final
Result
badRequiredStrength
=
const
Result
(
"Bad Required Strength"
);
static
final
Result
unknownEditVariable
=
const
Result
(
"Unknown Edit Variable"
);
static
final
Result
internalSolverError
=
const
Result
(
"Internal Solver Error"
);
}
packages/cassowary/lib/row.dart
0 → 100644
View file @
c7dfbc04
// 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
_Row
{
final
Map
<
_Symbol
,
double
>
cells
;
double
constant
=
0.0
;
_Row
(
this
.
constant
)
:
this
.
cells
=
new
Map
<
_Symbol
,
double
>();
_Row
.
fromRow
(
_Row
row
)
:
this
.
cells
=
new
Map
<
_Symbol
,
double
>.
from
(
row
.
cells
),
this
.
constant
=
row
.
constant
;
double
add
(
double
value
)
=>
constant
+=
value
;
void
insertSymbol
(
_Symbol
symbol
,
[
double
coefficient
=
1.0
])
{
double
val
=
_elvis
(
cells
[
symbol
],
0.0
);
if
(
_nearZero
(
val
+
coefficient
))
{
cells
.
remove
(
symbol
);
}
else
{
cells
[
symbol
]
=
val
+
coefficient
;
}
}
void
insertRow
(
_Row
other
,
[
double
coefficient
=
1.0
])
{
constant
+=
other
.
constant
*
coefficient
;
other
.
cells
.
forEach
((
s
,
v
)
=>
insertSymbol
(
s
,
v
*
coefficient
));
}
void
removeSymbol
(
_Symbol
symbol
)
{
cells
.
remove
(
symbol
);
}
void
reverseSign
()
{
constant
=
-
constant
;
cells
.
forEach
((
s
,
v
)
=>
cells
[
s
]
=
-
v
);
}
void
solveForSymbol
(
_Symbol
symbol
)
{
assert
(
cells
.
containsKey
(
symbol
));
double
coefficient
=
-
1.0
/
cells
[
symbol
];
cells
.
remove
(
symbol
);
constant
*=
coefficient
;
cells
.
forEach
((
s
,
v
)
=>
cells
[
s
]
=
v
*
coefficient
);
}
void
solveForSymbols
(
_Symbol
lhs
,
_Symbol
rhs
)
{
insertSymbol
(
lhs
,
-
1.0
);
solveForSymbol
(
rhs
);
}
double
coefficientForSymbol
(
_Symbol
symbol
)
=>
_elvis
(
cells
[
symbol
],
0.0
);
void
substitute
(
_Symbol
symbol
,
_Row
row
)
{
double
coefficient
=
cells
[
symbol
];
if
(
coefficient
==
null
)
{
return
;
}
cells
.
remove
(
symbol
);
insertRow
(
row
,
coefficient
);
}
String
toString
()
{
StringBuffer
buffer
=
new
StringBuffer
();
buffer
.
write
(
constant
);
cells
.
forEach
((
symbol
,
value
)
=>
buffer
.
write
(
" + "
+
value
.
toString
()
+
" * "
+
symbol
.
toString
()));
return
buffer
.
toString
();
}
}
packages/cassowary/lib/solver.dart
0 → 100644
View file @
c7dfbc04
// 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
{
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
);
int
tick
=
1
;
/// 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
)
{
_SolverBulkUpdate
applier
=
(
Constraint
c
)
=>
addConstraint
(
c
);
_SolverBulkUpdate
undoer
=
(
Constraint
c
)
=>
removeConstraint
(
c
);
return
_bulkEdit
(
constraints
,
applier
,
undoer
);
}
Result
addConstraint
(
Constraint
constraint
)
{
if
(
_constraints
.
containsKey
(
constraint
))
{
return
Result
.
duplicateConstraint
;
}
_Tag
tag
=
new
_Tag
(
new
_Symbol
(
_SymbolType
.
invalid
,
0
),
new
_Symbol
(
_SymbolType
.
invalid
,
0
));
_Row
row
=
_createRow
(
constraint
,
tag
);
_Symbol
subject
=
_chooseSubjectForRow
(
row
,
tag
);
if
(
subject
.
type
==
_SymbolType
.
invalid
&&
_allDummiesInRow
(
row
))
{
if
(!
_nearZero
(
row
.
constant
))
{
return
Result
.
unsatisfiableConstraint
;
}
else
{
subject
=
tag
.
marker
;
}
}
if
(
subject
.
type
==
_SymbolType
.
invalid
)
{
if
(!
_addWithArtificialVariableOnRow
(
row
))
{
return
Result
.
unsatisfiableConstraint
;
}
}
else
{
row
.
solveForSymbol
(
subject
);
_substitute
(
subject
,
row
);
_rows
[
subject
]
=
row
;
}
_constraints
[
constraint
]
=
tag
;
return
_optimizeObjectiveRow
(
_objective
);
}
Result
removeConstraints
(
List
<
Constraint
>
constraints
)
{
_SolverBulkUpdate
applier
=
(
Constraint
c
)
=>
removeConstraint
(
c
);
_SolverBulkUpdate
undoer
=
(
Constraint
c
)
=>
addConstraint
(
c
);
return
_bulkEdit
(
constraints
,
applier
,
undoer
);
}
Result
removeConstraint
(
Constraint
constraint
)
{
_Tag
tag
=
_constraints
[
constraint
];
if
(
tag
==
null
)
{
return
Result
.
unknownConstraint
;
}
tag
=
new
_Tag
.
fromTag
(
tag
);
_constraints
.
remove
(
constraint
);
_removeConstraintEffects
(
constraint
,
tag
);
_Row
row
=
_rows
[
tag
.
marker
];
if
(
row
!=
null
)
{
_rows
.
remove
(
tag
.
marker
);
}
else
{
_Pair
<
_Symbol
,
_Row
>
rowPair
=
_leavingRowPairForMarkerSymbol
(
tag
.
marker
);
if
(
rowPair
==
null
)
{
return
Result
.
internalSolverError
;
}
_Symbol
leaving
=
rowPair
.
first
;
row
=
rowPair
.
second
;
var
removed
=
_rows
.
remove
(
rowPair
.
first
);
assert
(
removed
!=
null
);
row
.
solveForSymbols
(
leaving
,
tag
.
marker
);
_substitute
(
tag
.
marker
,
row
);
}
return
_optimizeObjectiveRow
(
_objective
);
}
bool
hasConstraint
(
Constraint
constraint
)
{
return
_constraints
.
containsKey
(
constraint
);
}
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
);
}
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
);
constraint
.
priority
=
priority
;
if
(
addConstraint
(
constraint
)
!=
Result
.
success
)
{
return
Result
.
internalSolverError
;
}
_EditInfo
info
=
new
_EditInfo
();
info
.
tag
=
_constraints
[
constraint
];
info
.
constraint
=
constraint
;
info
.
constant
=
0.0
;
_edits
[
variable
]
=
info
;
return
Result
.
success
;
}
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
);
}
Result
removeEditVariable
(
Variable
variable
)
{
_EditInfo
info
=
_edits
[
variable
];
if
(
info
==
null
)
{
return
Result
.
unknownEditVariable
;
}
if
(
removeConstraint
(
info
.
constraint
)
!=
Result
.
success
)
{
return
Result
.
internalSolverError
;
}
_edits
.
remove
(
variable
);
return
Result
.
success
;
}
bool
hasEditVariable
(
Variable
variable
)
{
return
_edits
.
containsKey
(
variable
);
}
Result
suggestValueForVariable
(
Variable
variable
,
double
value
)
{
if
(!
_edits
.
containsKey
(
variable
))
{
return
Result
.
unknownEditVariable
;
}
_suggestValueForEditInfoWithoutDualOptimization
(
_edits
[
variable
],
value
);
return
_dualOptimize
();
}
Set
flushUpdates
()
{
Set
updates
=
new
Set
();
for
(
Variable
variable
in
_vars
.
keys
)
{
_Symbol
symbol
=
_vars
[
variable
];
_Row
row
=
_rows
[
symbol
];
double
updatedValue
=
row
==
null
?
0.0
:
row
.
constant
;
if
(
variable
.
_applyUpdate
(
updatedValue
)
&&
variable
.
_owner
!=
null
)
{
dynamic
context
=
variable
.
_owner
.
context
;
if
(
context
!=
null
)
{
updates
.
add
(
context
);
}
}
}
return
updates
;
}
Result
_bulkEdit
(
Iterable
items
,
_SolverBulkUpdate
applier
,
_SolverBulkUpdate
undoer
)
{
List
applied
=
new
List
();
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
)
{
for
(
dynamic
item
in
applied
.
reversed
)
{
undoer
(
item
);
}
}
return
result
;
}
_Symbol
_symbolForVariable
(
Variable
variable
)
{
_Symbol
symbol
=
_vars
[
variable
];
if
(
symbol
!=
null
)
{
return
symbol
;
}
symbol
=
new
_Symbol
(
_SymbolType
.
external
,
tick
++);
_vars
[
variable
]
=
symbol
;
return
symbol
;
}
_Row
_createRow
(
Constraint
constraint
,
_Tag
tag
)
{
Expression
expr
=
new
Expression
.
fromExpression
(
constraint
.
expression
);
_Row
row
=
new
_Row
(
expr
.
constant
);
expr
.
terms
.
forEach
((
term
)
{
if
(!
_nearZero
(
term
.
coefficient
))
{
_Symbol
symbol
=
_symbolForVariable
(
term
.
variable
);
_Row
foundRow
=
_rows
[
symbol
];
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
;
_Symbol
slack
=
new
_Symbol
(
_SymbolType
.
slack
,
tick
++);
tag
.
marker
=
slack
;
row
.
insertSymbol
(
slack
,
coefficient
);
if
(
constraint
.
priority
<
Priority
.
required
)
{
_Symbol
error
=
new
_Symbol
(
_SymbolType
.
error
,
tick
++);
tag
.
other
=
error
;
row
.
insertSymbol
(
error
,
-
coefficient
);
_objective
.
insertSymbol
(
error
,
constraint
.
priority
);
}
}
break
;
case
Relation
.
equalTo
:
if
(
constraint
.
priority
<
Priority
.
required
)
{
_Symbol
errPlus
=
new
_Symbol
(
_SymbolType
.
error
,
tick
++);
_Symbol
errMinus
=
new
_Symbol
(
_SymbolType
.
error
,
tick
++);
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
{
_Symbol
dummy
=
new
_Symbol
(
_SymbolType
.
dummy
,
tick
++);
tag
.
marker
=
dummy
;
row
.
insertSymbol
(
dummy
);
}
break
;
}
if
(
row
.
constant
<
0.0
)
{
row
.
reverseSign
();
}
return
row
;
}
_Symbol
_chooseSubjectForRow
(
_Row
row
,
_Tag
tag
)
{
for
(
_Symbol
symbol
in
row
.
cells
.
keys
)
{
if
(
symbol
.
type
==
_SymbolType
.
external
)
{
return
symbol
;
}
}
if
(
tag
.
marker
.
type
==
_SymbolType
.
slack
||
tag
.
marker
.
type
==
_SymbolType
.
error
)
{
if
(
row
.
coefficientForSymbol
(
tag
.
marker
)
<
0.0
)
{
return
tag
.
marker
;
}
}
if
(
tag
.
other
.
type
==
_SymbolType
.
slack
||
tag
.
other
.
type
==
_SymbolType
.
error
)
{
if
(
row
.
coefficientForSymbol
(
tag
.
other
)
<
0.0
)
{
return
tag
.
other
;
}
}
return
new
_Symbol
(
_SymbolType
.
invalid
,
0
);
}
bool
_allDummiesInRow
(
_Row
row
)
{
for
(
_Symbol
symbol
in
row
.
cells
.
keys
)
{
if
(
symbol
.
type
!=
_SymbolType
.
dummy
)
{
return
false
;
}
}
return
true
;
}
bool
_addWithArtificialVariableOnRow
(
_Row
row
)
{
_Symbol
artificial
=
new
_Symbol
(
_SymbolType
.
slack
,
tick
++);
_rows
[
artificial
]
=
new
_Row
.
fromRow
(
row
);
_artificial
=
new
_Row
.
fromRow
(
row
);
Result
result
=
_optimizeObjectiveRow
(
_artificial
);
if
(
result
.
error
)
{
// FIXME(csg): Propagate this up!
return
false
;
}
bool
success
=
_nearZero
(
_artificial
.
constant
);
_artificial
=
new
_Row
(
0.0
);
_Row
foundRow
=
_rows
[
artificial
];
if
(
foundRow
!=
null
)
{
_rows
.
remove
(
artificial
);
if
(
foundRow
.
cells
.
isEmpty
)
{
return
success
;
}
_Symbol
entering
=
_anyPivotableSymbol
(
foundRow
);
if
(
entering
.
type
==
_SymbolType
.
invalid
)
{
return
false
;
}
foundRow
.
solveForSymbols
(
artificial
,
entering
);
_substitute
(
entering
,
foundRow
);
_rows
[
entering
]
=
foundRow
;
}
for
(
_Row
row
in
_rows
.
values
)
{
row
.
removeSymbol
(
artificial
);
}
_objective
.
removeSymbol
(
artificial
);
return
success
;
}
Result
_optimizeObjectiveRow
(
_Row
objective
)
{
while
(
true
)
{
_Symbol
entering
=
_enteringSymbolForObjectiveRow
(
objective
);
if
(
entering
.
type
==
_SymbolType
.
invalid
)
{
return
Result
.
success
;
}
_Pair
<
_Symbol
,
_Row
>
leavingPair
=
_leavingRowForEnteringSymbol
(
entering
);
if
(
leavingPair
==
null
)
{
return
Result
.
internalSolverError
;
}
_Symbol
leaving
=
leavingPair
.
first
;
_Row
row
=
leavingPair
.
second
;
_rows
.
remove
(
leavingPair
.
first
);
row
.
solveForSymbols
(
leaving
,
entering
);
_substitute
(
entering
,
row
);
_rows
[
entering
]
=
row
;
}
}
_Symbol
_enteringSymbolForObjectiveRow
(
_Row
objective
)
{
Map
<
_Symbol
,
double
>
cells
=
objective
.
cells
;
for
(
_Symbol
symbol
in
cells
.
keys
)
{
if
(
symbol
.
type
!=
_SymbolType
.
dummy
&&
cells
[
symbol
]
<
0.0
)
{
return
symbol
;
}
}
return
new
_Symbol
(
_SymbolType
.
invalid
,
0
);
}
_Pair
<
_Symbol
,
_Row
>
_leavingRowForEnteringSymbol
(
_Symbol
entering
)
{
double
ratio
=
double
.
MAX_FINITE
;
_Pair
<
_Symbol
,
_Row
>
result
=
new
_Pair
(
null
,
null
);
_rows
.
forEach
((
symbol
,
row
)
{
if
(
symbol
.
type
!=
_SymbolType
.
external
)
{
double
temp
=
row
.
coefficientForSymbol
(
entering
);
if
(
temp
<
0.0
)
{
double
temp_ratio
=
-
row
.
constant
/
temp
;
if
(
temp_ratio
<
ratio
)
{
ratio
=
temp_ratio
;
result
.
first
=
symbol
;
result
.
second
=
row
;
}
}
}
});
if
(
result
.
first
==
null
||
result
.
second
==
null
)
{
return
null
;
}
return
result
;
}
void
_substitute
(
_Symbol
symbol
,
_Row
row
)
{
_rows
.
forEach
((
first
,
second
)
{
second
.
substitute
(
symbol
,
row
);
if
(
first
.
type
!=
_SymbolType
.
external
&&
second
.
constant
<
0.0
)
{
_infeasibleRows
.
add
(
first
);
}
});
_objective
.
substitute
(
symbol
,
row
);
if
(
_artificial
!=
null
)
{
_artificial
.
substitute
(
symbol
,
row
);
}
}
_Symbol
_anyPivotableSymbol
(
_Row
row
)
{
for
(
_Symbol
symbol
in
row
.
cells
.
keys
)
{
if
(
symbol
.
type
==
_SymbolType
.
slack
||
symbol
.
type
==
_SymbolType
.
error
)
{
return
symbol
;
}
}
return
new
_Symbol
(
_SymbolType
.
invalid
,
0
);
}
void
_removeConstraintEffects
(
Constraint
cn
,
_Tag
tag
)
{
if
(
tag
.
marker
.
type
==
_SymbolType
.
error
)
{
_removeMarkerEffects
(
tag
.
marker
,
cn
.
priority
);
}
if
(
tag
.
other
.
type
==
_SymbolType
.
error
)
{
_removeMarkerEffects
(
tag
.
other
,
cn
.
priority
);
}
}
void
_removeMarkerEffects
(
_Symbol
marker
,
double
strength
)
{
_Row
row
=
_rows
[
marker
];
if
(
row
!=
null
)
{
_objective
.
insertRow
(
row
,
-
strength
);
}
else
{
_objective
.
insertSymbol
(
marker
,
-
strength
);
}
}
_Pair
<
_Symbol
,
_Row
>
_leavingRowPairForMarkerSymbol
(
_Symbol
marker
)
{
double
r1
=
double
.
MAX_FINITE
;
double
r2
=
double
.
MAX_FINITE
;
_Pair
<
_Symbol
,
_Row
>
first
,
second
,
third
;
_rows
.
forEach
((
symbol
,
row
)
{
double
c
=
row
.
coefficientForSymbol
(
marker
);
if
(
c
==
0.0
)
{
return
;
}
if
(
symbol
.
type
==
_SymbolType
.
external
)
{
third
=
new
_Pair
(
symbol
,
row
);
}
else
if
(
c
<
0.0
)
{
double
r
=
-
row
.
constant
/
c
;
if
(
r
<
r1
)
{
r1
=
r
;
first
=
new
_Pair
(
symbol
,
row
);
}
}
else
{
double
r
=
row
.
constant
/
c
;
if
(
r
<
r2
)
{
r2
=
r
;
second
=
new
_Pair
(
symbol
,
row
);
}
}
});
if
(
first
!=
null
)
{
return
first
;
}
if
(
second
!=
null
)
{
return
second
;
}
return
third
;
}
void
_suggestValueForEditInfoWithoutDualOptimization
(
_EditInfo
info
,
double
value
)
{
double
delta
=
value
-
info
.
constant
;
info
.
constant
=
value
;
{
_Symbol
symbol
=
info
.
tag
.
marker
;
_Row
row
=
_rows
[
info
.
tag
.
marker
];
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
;
}
}
for
(
_Symbol
symbol
in
_rows
.
keys
)
{
_Row
row
=
_rows
[
symbol
];
double
coeff
=
row
.
coefficientForSymbol
(
info
.
tag
.
marker
);
if
(
coeff
!=
0.0
&&
row
.
add
(
delta
*
coeff
)
<
0.0
&&
symbol
.
type
!=
_SymbolType
.
external
)
{
_infeasibleRows
.
add
(
symbol
);
}
}
}
Result
_dualOptimize
()
{
while
(
_infeasibleRows
.
length
!=
0
)
{
_Symbol
leaving
=
_infeasibleRows
.
removeLast
();
_Row
row
=
_rows
[
leaving
];
if
(
row
!=
null
&&
row
.
constant
<
0.0
)
{
_Symbol
entering
=
_dualEnteringSymbolForRow
(
row
);
if
(
entering
.
type
==
_SymbolType
.
invalid
)
{
return
Result
.
internalSolverError
;
}
_rows
.
remove
(
leaving
);
row
.
solveForSymbols
(
leaving
,
entering
);
_substitute
(
entering
,
row
);
_rows
[
entering
]
=
row
;
}
}
return
Result
.
success
;
}
_Symbol
_dualEnteringSymbolForRow
(
_Row
row
)
{
_Symbol
entering
;
double
ratio
=
double
.
MAX_FINITE
;
Map
<
_Symbol
,
double
>
rowCells
=
row
.
cells
;
for
(
_Symbol
symbol
in
rowCells
.
keys
)
{
double
value
=
rowCells
[
symbol
];
if
(
value
>
0.0
&&
symbol
.
type
!=
_SymbolType
.
dummy
)
{
double
coeff
=
_objective
.
coefficientForSymbol
(
symbol
);
double
r
=
coeff
/
value
;
if
(
r
<
ratio
)
{
ratio
=
r
;
entering
=
symbol
;
}
}
}
return
_elvis
(
entering
,
new
_Symbol
(
_SymbolType
.
invalid
,
0
));
}
String
toString
()
{
StringBuffer
buffer
=
new
StringBuffer
();
String
separator
=
"
\n
~~~~~~~~~"
;
// Objective
buffer
.
writeln
(
separator
+
" Objective"
);
buffer
.
writeln
(
_objective
.
toString
());
// Tableau
buffer
.
writeln
(
separator
+
" Tableau"
);
_rows
.
forEach
((
symbol
,
row
)
{
buffer
.
write
(
symbol
.
toString
());
buffer
.
write
(
" | "
);
buffer
.
writeln
(
row
.
toString
());
});
// Infeasible
buffer
.
writeln
(
separator
+
" Infeasible"
);
_infeasibleRows
.
forEach
((
symbol
)
=>
buffer
.
writeln
(
symbol
.
toString
()));
// Variables
buffer
.
writeln
(
separator
+
" Variables"
);
_vars
.
forEach
((
variable
,
symbol
)
=>
buffer
.
writeln
(
"
${variable.toString()}
=
${symbol.toString()}
"
));
// Edit Variables
buffer
.
writeln
(
separator
+
" Edit Variables"
);
_edits
.
forEach
((
variable
,
editinfo
)
=>
buffer
.
writeln
(
variable
));
// Constraints
buffer
.
writeln
(
separator
+
" Constraints"
);
_constraints
.
forEach
((
constraint
,
_
)
=>
buffer
.
writeln
(
constraint
));
return
buffer
.
toString
();
}
}
class
_Tag
{
_Symbol
marker
;
_Symbol
other
;
_Tag
(
this
.
marker
,
this
.
other
);
_Tag
.
fromTag
(
_Tag
tag
)
:
this
.
marker
=
tag
.
marker
,
this
.
other
=
tag
.
other
;
}
class
_EditInfo
{
_Tag
tag
;
Constraint
constraint
;
double
constant
;
}
bool
_isValidNonRequiredPriority
(
double
priority
)
{
return
(
priority
>=
0.0
&&
priority
<
Priority
.
required
);
}
typedef
Result
_SolverBulkUpdate
(
dynamic
item
);
packages/cassowary/lib/symbol.dart
0 → 100644
View file @
c7dfbc04
// 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
;
enum
_SymbolType
{
invalid
,
external
,
slack
,
error
,
dummy
,
}
class
_Symbol
{
final
_SymbolType
type
;
final
int
tick
;
_Symbol
(
this
.
type
,
this
.
tick
);
String
toString
()
{
String
typeString
=
"unknown"
;
switch
(
type
)
{
case
_SymbolType
.
invalid
:
typeString
=
"i"
;
break
;
case
_SymbolType
.
external
:
typeString
=
"v"
;
break
;
case
_SymbolType
.
slack
:
typeString
=
"s"
;
break
;
case
_SymbolType
.
error
:
typeString
=
"e"
;
break
;
case
_SymbolType
.
dummy
:
typeString
=
"d"
;
break
;
}
return
"
${typeString}${tick}
"
;
}
}
packages/cassowary/lib/term.dart
0 → 100644
View file @
c7dfbc04
// 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
Term
extends
_EquationMember
{
final
Variable
variable
;
final
double
coefficient
;
bool
get
isConstant
=>
false
;
double
get
value
=>
coefficient
*
variable
.
value
;
Term
(
this
.
variable
,
this
.
coefficient
);
Expression
asExpression
()
=>
new
Expression
([
new
Term
(
this
.
variable
,
this
.
coefficient
)],
0.0
);
String
toString
()
{
StringBuffer
buffer
=
new
StringBuffer
();
buffer
.
write
(
coefficient
.
sign
>
0.0
?
"+"
:
"-"
);
if
(
coefficient
.
abs
()
!=
1.0
)
{
buffer
.
write
(
coefficient
.
abs
());
buffer
.
write
(
"*"
);
}
buffer
.
write
(
variable
);
return
buffer
.
toString
();
}
}
packages/cassowary/lib/utils.dart
0 → 100644
View file @
c7dfbc04
// 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
;
bool
_nearZero
(
double
value
)
{
const
double
epsilon
=
1.0e-8
;
return
value
<
0.0
?
-
value
<
epsilon
:
value
<
epsilon
;
}
// Workaround for the lack of a null coalescing operator. Uses a ternary
// instead. Sadly, due the lack of generic types on functions, we have to use
// dynamic instead.
_elvis
(
a
,
b
)
=>
a
!=
null
?
a
:
b
;
class
_Pair
<
X
,
Y
>
{
X
first
;
Y
second
;
_Pair
(
this
.
first
,
this
.
second
);
}
packages/cassowary/lib/variable.dart
0 → 100644
View file @
c7dfbc04
// 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
Variable
{
double
value
;
String
name
;
Param
_owner
;
final
int
_tick
;
static
int
_total
=
0
;
Variable
(
this
.
value
)
:
_tick
=
_total
++;
bool
_applyUpdate
(
double
updated
)
{
bool
res
=
updated
!=
value
;
value
=
updated
;
return
res
;
}
String
get
debugName
=>
_elvis
(
name
,
"variable
${_tick}
"
);
String
toString
()
=>
debugName
;
}
packages/cassowary/test/cassowary_test.dart
0 → 100644
View file @
c7dfbc04
// 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.
library
cassowary
.
test
;
import
'package:test/test.dart'
;
import
'package:cassowary/cassowary.dart'
;
void
main
(
)
{
test
(
'variable'
,
()
{
var
v
=
new
Param
(
22.0
);
expect
(
v
.
value
,
22
);
});
test
(
'variable1'
,
()
{
var
v
=
new
Param
(
22.0
);
expect
((
v
+
cm
(
22.0
)).
value
,
44.0
);
expect
((
v
-
cm
(
20.0
)).
value
,
2.0
);
});
test
(
'term'
,
()
{
var
t
=
new
Term
(
new
Variable
(
22.0
),
2.0
);
expect
(
t
.
value
,
44
);
});
test
(
'expression'
,
()
{
var
terms
=
[
new
Term
(
new
Variable
(
22.0
),
2.0
),
new
Term
(
new
Variable
(
1.0
),
1.0
),
];
var
e
=
new
Expression
(
terms
,
40.0
);
expect
(
e
.
value
,
85.0
);
});
test
(
'expression1'
,
()
{
var
v1
=
new
Param
(
10.0
);
var
v2
=
new
Param
(
10.0
);
var
v3
=
new
Param
(
22.0
);
expect
(
v1
is
Param
,
true
);
expect
(
v1
+
cm
(
20.0
)
is
Expression
,
true
);
expect
(
v1
+
v2
is
Expression
,
true
);
expect
((
v1
+
v2
).
value
,
20.0
);
expect
((
v1
-
v2
).
value
,
0.0
);
expect
((
v1
+
v2
+
v3
)
is
Expression
,
true
);
expect
((
v1
+
v2
+
v3
).
value
,
42.0
);
});
test
(
'expression2'
,
()
{
var
e
=
new
Param
(
10.0
)
+
cm
(
5.0
);
expect
(
e
.
value
,
15.0
);
expect
(
e
is
Expression
,
true
);
// Constant
expect
((
e
+
cm
(
2.0
))
is
Expression
,
true
);
expect
((
e
+
cm
(
2.0
)).
value
,
17.0
);
expect
((
e
-
cm
(
2.0
))
is
Expression
,
true
);
expect
((
e
-
cm
(
2.0
)).
value
,
13.0
);
expect
(
e
.
value
,
15.0
);
// Param
var
v
=
new
Param
(
2.0
);
expect
((
e
+
v
)
is
Expression
,
true
);
expect
((
e
+
v
).
value
,
17.0
);
expect
((
e
-
v
)
is
Expression
,
true
);
expect
((
e
-
v
).
value
,
13.0
);
expect
(
e
.
value
,
15.0
);
// Term
var
t
=
new
Term
(
v
.
variable
,
2.0
);
expect
((
e
+
t
)
is
Expression
,
true
);
expect
((
e
+
t
).
value
,
19.0
);
expect
((
e
-
t
)
is
Expression
,
true
);
expect
((
e
-
t
).
value
,
11.0
);
expect
(
e
.
value
,
15.0
);
// Expression
var
e2
=
new
Param
(
7.0
)
+
new
Param
(
3.0
);
expect
((
e
+
e2
)
is
Expression
,
true
);
expect
((
e
+
e2
).
value
,
25.0
);
expect
((
e
-
e2
)
is
Expression
,
true
);
expect
((
e
-
e2
).
value
,
5.0
);
expect
(
e
.
value
,
15.0
);
});
test
(
'term2'
,
()
{
var
t
=
new
Term
(
new
Variable
(
12.0
),
1.0
);
// Constant
var
c
=
cm
(
2.0
);
expect
((
t
+
c
)
is
Expression
,
true
);
expect
((
t
+
c
).
value
,
14.0
);
expect
((
t
-
c
)
is
Expression
,
true
);
expect
((
t
-
c
).
value
,
10.0
);
// Variable
var
v
=
new
Param
(
2.0
);
expect
((
t
+
v
)
is
Expression
,
true
);
expect
((
t
+
v
).
value
,
14.0
);
expect
((
t
-
v
)
is
Expression
,
true
);
expect
((
t
-
v
).
value
,
10.0
);
// Term
var
t2
=
new
Term
(
new
Variable
(
1.0
),
2.0
);
expect
((
t
+
t2
)
is
Expression
,
true
);
expect
((
t
+
t2
).
value
,
14.0
);
expect
((
t
-
t2
)
is
Expression
,
true
);
expect
((
t
-
t2
).
value
,
10.0
);
// Expression
var
exp
=
new
Param
(
1.0
)
+
cm
(
1.0
);
expect
((
t
+
exp
)
is
Expression
,
true
);
expect
((
t
+
exp
).
value
,
14.0
);
expect
((
t
-
exp
)
is
Expression
,
true
);
expect
((
t
-
exp
).
value
,
10.0
);
});
test
(
'variable3'
,
()
{
var
v
=
new
Param
(
3.0
);
// Constant
var
c
=
cm
(
2.0
);
expect
((
v
+
c
)
is
Expression
,
true
);
expect
((
v
+
c
).
value
,
5.0
);
expect
((
v
-
c
)
is
Expression
,
true
);
expect
((
v
-
c
).
value
,
1.0
);
// Variable
var
v2
=
new
Param
(
2.0
);
expect
((
v
+
v2
)
is
Expression
,
true
);
expect
((
v
+
v2
).
value
,
5.0
);
expect
((
v
-
v2
)
is
Expression
,
true
);
expect
((
v
-
v2
).
value
,
1.0
);
// Term
var
t2
=
new
Term
(
new
Variable
(
1.0
),
2.0
);
expect
((
v
+
t2
)
is
Expression
,
true
);
expect
((
v
+
t2
).
value
,
5.0
);
expect
((
v
-
t2
)
is
Expression
,
true
);
expect
((
v
-
t2
).
value
,
1.0
);
// Expression
var
exp
=
new
Param
(
1.0
)
+
cm
(
1.0
);
expect
(
exp
.
terms
.
length
,
1
);
expect
((
v
+
exp
)
is
Expression
,
true
);
expect
((
v
+
exp
).
value
,
5.0
);
expect
((
v
-
exp
)
is
Expression
,
true
);
expect
((
v
-
exp
).
value
,
1.0
);
});
test
(
'constantmember'
,
()
{
var
c
=
cm
(
3.0
);
// Constant
var
c2
=
cm
(
2.0
);
expect
((
c
+
c2
)
is
Expression
,
true
);
expect
((
c
+
c2
).
value
,
5.0
);
expect
((
c
-
c2
)
is
Expression
,
true
);
expect
((
c
-
c2
).
value
,
1.0
);
// Variable
var
v2
=
new
Param
(
2.0
);
expect
((
c
+
v2
)
is
Expression
,
true
);
expect
((
c
+
v2
).
value
,
5.0
);
expect
((
c
-
v2
)
is
Expression
,
true
);
expect
((
c
-
v2
).
value
,
1.0
);
// Term
var
t2
=
new
Term
(
new
Variable
(
1.0
),
2.0
);
expect
((
c
+
t2
)
is
Expression
,
true
);
expect
((
c
+
t2
).
value
,
5.0
);
expect
((
c
-
t2
)
is
Expression
,
true
);
expect
((
c
-
t2
).
value
,
1.0
);
// Expression
var
exp
=
new
Param
(
1.0
)
+
cm
(
1.0
);
expect
((
c
+
exp
)
is
Expression
,
true
);
expect
((
c
+
exp
).
value
,
5.0
);
expect
((
c
-
exp
)
is
Expression
,
true
);
expect
((
c
-
exp
).
value
,
1.0
);
});
test
(
'constraint2'
,
()
{
var
left
=
new
Param
(
10.0
);
var
right
=
new
Param
(
100.0
);
var
c
=
right
-
left
>=
cm
(
25.0
);
expect
(
c
is
Constraint
,
true
);
});
test
(
'simple_multiplication'
,
()
{
// Constant
var
c
=
cm
(
20.0
);
expect
((
c
*
cm
(
2.0
)).
value
,
40.0
);
// Variable
var
v
=
new
Param
(
20.0
);
expect
((
v
*
cm
(
2.0
)).
value
,
40.0
);
// Term
var
t
=
new
Term
(
v
.
variable
,
1.0
);
expect
((
t
*
cm
(
2.0
)).
value
,
40.0
);
// Expression
var
e
=
new
Expression
([
t
],
0.0
);
expect
((
e
*
cm
(
2.0
)).
value
,
40.0
);
});
test
(
'simple_division'
,
()
{
// Constant
var
c
=
cm
(
20.0
);
expect
((
c
/
cm
(
2.0
)).
value
,
10.0
);
// Variable
var
v
=
new
Param
(
20.0
);
expect
((
v
/
cm
(
2.0
)).
value
,
10.0
);
// Term
var
t
=
new
Term
(
v
.
variable
,
1.0
);
expect
((
t
/
cm
(
2.0
)).
value
,
10.0
);
// Expression
var
e
=
new
Expression
([
t
],
0.0
);
expect
((
e
/
cm
(
2.0
)).
value
,
10.0
);
});
test
(
'full_constraints_setup'
,
()
{
var
left
=
new
Param
(
2.0
);
var
right
=
new
Param
(
10.0
);
var
c1
=
right
-
left
>=
cm
(
20.0
);
expect
(
c1
is
Constraint
,
true
);
expect
(
c1
.
expression
.
constant
,
-
20.0
);
expect
(
c1
.
relation
,
Relation
.
greaterThanOrEqualTo
);
var
c2
=
(
right
-
left
==
cm
(
30.0
))
as
Constraint
;
expect
(
c2
is
Constraint
,
true
);
expect
(
c2
.
expression
.
constant
,
-
30.0
);
expect
(
c2
.
relation
,
Relation
.
equalTo
);
var
c3
=
right
-
left
<=
cm
(
30.0
);
expect
(
c3
is
Constraint
,
true
);
expect
(
c3
.
expression
.
constant
,
-
30.0
);
expect
(
c3
.
relation
,
Relation
.
lessThanOrEqualTo
);
});
test
(
'constraint_strength_update'
,
()
{
var
left
=
new
Param
(
2.0
);
var
right
=
new
Param
(
10.0
);
var
c
=
(
right
-
left
>=
cm
(
200.0
))
|
750.0
;
expect
(
c
is
Constraint
,
true
);
expect
(
c
.
expression
.
terms
.
length
,
2
);
expect
(
c
.
expression
.
constant
,
-
200.0
);
expect
(
c
.
priority
,
750.0
);
});
test
(
'solver'
,
()
{
var
s
=
new
Solver
();
var
left
=
new
Param
(
2.0
);
var
right
=
new
Param
(
100.0
);
var
c1
=
right
-
left
>=
cm
(
200.0
);
expect
((
right
>=
left
)
is
Constraint
,
true
);
expect
(
s
.
addConstraint
(
c1
),
Result
.
success
);
});
test
(
'constraint_complex'
,
()
{
var
e
=
new
Param
(
200.0
)
-
new
Param
(
100.0
);
// Constant
var
c1
=
e
>=
cm
(
50.0
);
expect
(
c1
is
Constraint
,
true
);
expect
(
c1
.
expression
.
terms
.
length
,
2
);
expect
(
c1
.
expression
.
constant
,
-
50.0
);
// Variable
var
c2
=
e
>=
new
Param
(
2.0
);
expect
(
c2
is
Constraint
,
true
);
expect
(
c2
.
expression
.
terms
.
length
,
3
);
expect
(
c2
.
expression
.
constant
,
0.0
);
// Term
var
c3
=
e
>=
new
Term
(
new
Variable
(
2.0
),
1.0
);
expect
(
c3
is
Constraint
,
true
);
expect
(
c3
.
expression
.
terms
.
length
,
3
);
expect
(
c3
.
expression
.
constant
,
0.0
);
// Expression
var
c4
=
e
>=
new
Expression
([
new
Term
(
new
Variable
(
2.0
),
1.0
)],
20.0
);
expect
(
c4
is
Constraint
,
true
);
expect
(
c4
.
expression
.
terms
.
length
,
3
);
expect
(
c4
.
expression
.
constant
,
-
20.0
);
});
test
(
'constraint_complex_non_exprs'
,
()
{
// Constant
var
c1
=
cm
(
100.0
)
>=
cm
(
50.0
);
expect
(
c1
is
Constraint
,
true
);
expect
(
c1
.
expression
.
terms
.
length
,
0
);
expect
(
c1
.
expression
.
constant
,
50.0
);
// Variable
var
c2
=
new
Param
(
100.0
)
>=
new
Param
(
2.0
);
expect
(
c2
is
Constraint
,
true
);
expect
(
c2
.
expression
.
terms
.
length
,
2
);
expect
(
c2
.
expression
.
constant
,
0.0
);
// Term
var
t
=
new
Term
(
new
Variable
(
100.0
),
1.0
);
var
c3
=
t
>=
new
Term
(
new
Variable
(
2.0
),
1.0
);
expect
(
c3
is
Constraint
,
true
);
expect
(
c3
.
expression
.
terms
.
length
,
2
);
expect
(
c3
.
expression
.
constant
,
0.0
);
// Expression
var
e
=
new
Expression
([
t
],
0.0
);
var
c4
=
e
>=
new
Expression
([
new
Term
(
new
Variable
(
2.0
),
1.0
)],
20.0
);
expect
(
c4
is
Constraint
,
true
);
expect
(
c4
.
expression
.
terms
.
length
,
2
);
expect
(
c4
.
expression
.
constant
,
-
20.0
);
});
test
(
'constraint_update_in_solver'
,
()
{
var
s
=
new
Solver
();
var
left
=
new
Param
(
2.0
);
var
right
=
new
Param
(
100.0
);
var
c1
=
right
-
left
>=
cm
(
200.0
);
var
c2
=
right
>=
right
;
expect
(
s
.
addConstraint
(
c1
),
Result
.
success
);
expect
(
s
.
addConstraint
(
c1
),
Result
.
duplicateConstraint
);
expect
(
s
.
removeConstraint
(
c2
),
Result
.
unknownConstraint
);
expect
(
s
.
removeConstraint
(
c1
),
Result
.
success
);
expect
(
s
.
removeConstraint
(
c1
),
Result
.
unknownConstraint
);
});
test
(
'test_multiplication_division_override'
,
()
{
var
c
=
cm
(
10.0
);
var
v
=
new
Param
(
c
.
value
);
var
t
=
new
Term
(
v
.
variable
,
1.0
);
var
e
=
new
Expression
([
t
],
0.0
);
// Constant
expect
((
c
*
cm
(
10.0
)).
value
,
100
);
// Variable
expect
((
v
*
cm
(
10.0
)).
value
,
100
);
// Term
expect
((
t
*
cm
(
10.0
)).
value
,
100
);
// Expression
expect
((
e
*
cm
(
10.0
)).
value
,
100
);
// Constant
expect
((
c
/
cm
(
10.0
)).
value
,
1
);
// Variable
expect
((
v
/
cm
(
10.0
)).
value
,
1
);
// Term
expect
((
t
/
cm
(
10.0
)).
value
,
1
);
// Expression
expect
((
e
/
cm
(
10.0
)).
value
,
1
);
});
test
(
'test_multiplication_division_exceptions'
,
()
{
var
c
=
cm
(
10.0
);
var
v
=
new
Param
(
c
.
value
);
var
t
=
new
Term
(
v
.
variable
,
1.0
);
var
e
=
new
Expression
([
t
],
0.0
);
expect
((
c
*
c
).
value
,
100
);
expect
(()
=>
v
*
v
,
throwsA
(
new
isInstanceOf
<
ParserException
>()));
expect
(()
=>
v
/
v
,
throwsA
(
new
isInstanceOf
<
ParserException
>()));
expect
(()
=>
v
*
t
,
throwsA
(
new
isInstanceOf
<
ParserException
>()));
expect
(()
=>
v
/
t
,
throwsA
(
new
isInstanceOf
<
ParserException
>()));
expect
(()
=>
v
*
e
,
throwsA
(
new
isInstanceOf
<
ParserException
>()));
expect
(()
=>
v
/
e
,
throwsA
(
new
isInstanceOf
<
ParserException
>()));
expect
(()
=>
v
*
c
,
returnsNormally
);
expect
(()
=>
v
/
c
,
returnsNormally
);
});
test
(
'edit_updates'
,
()
{
Solver
s
=
new
Solver
();
var
left
=
new
Param
(
0.0
);
var
right
=
new
Param
(
100.0
);
var
mid
=
new
Param
(
0.0
);
Constraint
c
=
left
+
right
>=
cm
(
2.0
)
*
mid
;
expect
(
s
.
addConstraint
(
c
),
Result
.
success
);
expect
(
s
.
addEditVariable
(
mid
.
variable
,
999.0
),
Result
.
success
);
expect
(
s
.
addEditVariable
(
mid
.
variable
,
999.0
),
Result
.
duplicateEditVariable
);
expect
(
s
.
removeEditVariable
(
mid
.
variable
),
Result
.
success
);
expect
(
s
.
removeEditVariable
(
mid
.
variable
),
Result
.
unknownEditVariable
);
});
test
(
'bug1'
,
()
{
var
left
=
new
Param
(
0.0
);
var
right
=
new
Param
(
100.0
);
var
mid
=
new
Param
(
0.0
);
expect
(((
left
+
right
)
>=
(
cm
(
2.0
)
*
mid
))
is
Constraint
,
true
);
});
test
(
'single_item'
,
()
{
var
left
=
new
Param
(-
20.0
);
Solver
s
=
new
Solver
();
s
.
addConstraint
(
left
>=
cm
(
0.0
));
s
.
flushUpdates
();
expect
(
left
.
value
,
0.0
);
});
test
(
'midpoints'
,
()
{
var
left
=
new
Param
(
0.0
)..
name
=
"left"
;
var
right
=
new
Param
(
0.0
)..
name
=
"right"
;
var
mid
=
new
Param
(
0.0
)..
name
=
"mid"
;
Solver
s
=
new
Solver
();
expect
(
s
.
addConstraint
((
right
+
left
==
mid
*
cm
(
2.0
))
as
Constraint
),
Result
.
success
);
expect
(
s
.
addConstraint
(
right
-
left
>=
cm
(
100.0
)),
Result
.
success
);
expect
(
s
.
addConstraint
(
left
>=
cm
(
0.0
)),
Result
.
success
);
s
.
flushUpdates
();
expect
(
left
.
value
,
0.0
);
expect
(
mid
.
value
,
50.0
);
expect
(
right
.
value
,
100.0
);
});
test
(
'addition_of_multiple'
,
()
{
var
left
=
new
Param
(
0.0
);
var
right
=
new
Param
(
0.0
);
var
mid
=
new
Param
(
0.0
);
Solver
s
=
new
Solver
();
var
c
=
(
left
>=
cm
(
0.0
));
expect
(
s
.
addConstraints
([
(
left
+
right
==
cm
(
2.0
)
*
mid
)
as
Constraint
,
(
right
-
left
>=
cm
(
100.0
)),
c
]),
Result
.
success
);
expect
(
s
.
addConstraints
([(
right
>=
cm
(-
20.0
)),
c
]),
Result
.
duplicateConstraint
);
});
test
(
'edit_constraints'
,
()
{
var
left
=
new
Param
(
0.0
)..
name
=
"left"
;
var
right
=
new
Param
(
0.0
)..
name
=
"right"
;
var
mid
=
new
Param
(
0.0
)..
name
=
"mid"
;
Solver
s
=
new
Solver
();
expect
(
s
.
addConstraint
((
right
+
left
==
mid
*
cm
(
2.0
))
as
Constraint
),
Result
.
success
);
expect
(
s
.
addConstraint
(
right
-
left
>=
cm
(
100.0
)),
Result
.
success
);
expect
(
s
.
addConstraint
(
left
>=
cm
(
0.0
)),
Result
.
success
);
expect
(
s
.
addEditVariable
(
mid
.
variable
,
Priority
.
strong
),
Result
.
success
);
expect
(
s
.
suggestValueForVariable
(
mid
.
variable
,
300.0
),
Result
.
success
);
s
.
flushUpdates
();
expect
(
left
.
value
,
0.0
);
expect
(
mid
.
value
,
300.0
);
expect
(
right
.
value
,
600.0
);
});
test
(
'test_description'
,
()
{
var
left
=
new
Param
(
0.0
);
var
right
=
new
Param
(
100.0
);
var
c1
=
right
>=
left
;
var
c2
=
right
<=
left
;
var
c3
=
(
right
==
left
)
as
Constraint
;
Solver
s
=
new
Solver
();
expect
(
s
.
addConstraint
(
c1
),
Result
.
success
);
expect
(
s
.
addConstraint
(
c2
),
Result
.
success
);
expect
(
s
.
addConstraint
(
c3
),
Result
.
success
);
expect
(
s
.
toString
()
!=
null
,
true
);
});
test
(
'solution_with_optimize'
,
()
{
Param
p1
=
new
Param
();
Param
p2
=
new
Param
();
Param
p3
=
new
Param
();
Param
container
=
new
Param
();
Solver
solver
=
new
Solver
();
solver
.
addEditVariable
(
container
.
variable
,
Priority
.
strong
);
solver
.
suggestValueForVariable
(
container
.
variable
,
100.0
);
solver
.
addConstraint
((
p1
>=
cm
(
30.0
))
|
Priority
.
strong
);
solver
.
addConstraint
(((
p1
==
p3
)
as
Constraint
)
|
Priority
.
medium
);
solver
.
addConstraint
((
p2
==
cm
(
2.0
)
*
p1
)
as
Constraint
);
solver
.
addConstraint
((
container
==
(
p1
+
p2
+
p3
))
as
Constraint
);
solver
.
flushUpdates
();
expect
(
container
.
value
,
100.0
);
expect
(
p1
.
value
,
30.0
);
expect
(
p2
.
value
,
60.0
);
expect
(
p3
.
value
,
10.0
);
});
test
(
'test_updates_collection'
,
()
{
Param
left
=
new
Param
.
withContext
(
"left"
);
Param
mid
=
new
Param
.
withContext
(
"mid"
);
Param
right
=
new
Param
.
withContext
(
"right"
);
Solver
s
=
new
Solver
();
expect
(
s
.
addEditVariable
(
mid
.
variable
,
Priority
.
strong
),
Result
.
success
);
expect
(
s
.
addConstraint
((
mid
*
cm
(
2.0
)
==
left
+
right
)
as
Constraint
),
Result
.
success
);
expect
(
s
.
addConstraint
(
left
>=
cm
(
0.0
)),
Result
.
success
);
expect
(
s
.
suggestValueForVariable
(
mid
.
variable
,
50.0
),
Result
.
success
);
var
updates
=
s
.
flushUpdates
();
expect
(
updates
.
length
,
2
);
expect
(
left
.
value
,
0.0
);
expect
(
mid
.
value
,
50.0
);
expect
(
right
.
value
,
100.0
);
});
test
(
'test_updates_collection_is_set'
,
()
{
Param
left
=
new
Param
.
withContext
(
"a"
);
Param
mid
=
new
Param
.
withContext
(
"a"
);
Param
right
=
new
Param
.
withContext
(
"a"
);
Solver
s
=
new
Solver
();
expect
(
s
.
addEditVariable
(
mid
.
variable
,
Priority
.
strong
),
Result
.
success
);
expect
(
s
.
addConstraint
((
mid
*
cm
(
2.0
)
==
left
+
right
)
as
Constraint
),
Result
.
success
);
expect
(
s
.
addConstraint
(
left
>=
cm
(
10.0
)),
Result
.
success
);
expect
(
s
.
suggestValueForVariable
(
mid
.
variable
,
50.0
),
Result
.
success
);
var
updates
=
s
.
flushUpdates
();
expect
(
updates
.
length
,
1
);
expect
(
left
.
value
,
10.0
);
expect
(
mid
.
value
,
50.0
);
expect
(
right
.
value
,
90.0
);
});
test
(
'param_context_non_final'
,
()
{
var
p
=
new
Param
.
withContext
(
"a"
);
p
.
context
=
"b"
;
expect
(
p
.
context
,
"b"
);
});
test
(
'check_type_of_eq_result'
,
()
{
Param
left
=
new
Param
();
Param
right
=
new
Param
();
expect
((
left
==
right
).
runtimeType
,
Constraint
);
});
test
(
'bulk_add_edit_variables'
,
()
{
Solver
s
=
new
Solver
();
var
left
=
new
Param
(
0.0
);
var
right
=
new
Param
(
100.0
);
var
mid
=
new
Param
(
0.0
);
expect
(
s
.
addEditVariables
(
[
left
.
variable
,
right
.
variable
,
mid
.
variable
],
999.0
),
Result
.
success
);
});
test
(
'bulk_remove_constraints_and_variables'
,
()
{
Solver
s
=
new
Solver
();
var
left
=
new
Param
(
0.0
);
var
right
=
new
Param
(
100.0
);
var
mid
=
new
Param
(
0.0
);
expect
(
s
.
addEditVariables
(
[
left
.
variable
,
right
.
variable
,
mid
.
variable
],
999.0
),
Result
.
success
);
var
c1
=
left
<=
mid
;
var
c2
=
mid
<=
right
;
expect
(
s
.
addConstraints
([
c1
,
c2
]),
Result
.
success
);
expect
(
s
.
removeConstraints
([
c1
,
c2
]),
Result
.
success
);
expect
(
s
.
removeEditVariables
(
[
left
.
variable
,
right
.
variable
,
mid
.
variable
]),
Result
.
success
);
});
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment