cassowary-ruby 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ OWZkYjdhMWMwYjdkZWM3OWE0NGM2NDVhODFlMjdkZDQ0YzkxN2FjMg==
5
+ data.tar.gz: !binary |-
6
+ NmU1YWEyOTZkNGIyNTM2YmFiZjk3ZjVjMDczNjMyMGJmYWVkNDMxMg==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ YTFhOTI5ZjZjMjAzMGMwN2JkMzJlYWYxZGMyZjg2NjllMWU2NTA1ZmExN2Y5
10
+ NDA1Nzk5ZWI4MDcxYjBjOWY1ZDRhYjNkY2EyNmQ3YWI4ODE1ZjdiMDkyMGFi
11
+ YWRlZjZmN2UwNDQ3NmZmMjNkNTMyNjRjMzlhMmM5OTY3N2FhOTU=
12
+ data.tar.gz: !binary |-
13
+ N2NlZDE5NGYwMWRiZDgwNjViYjFmOWJlZDJmYThiMmI5ZGZhZjNlZDYyNjRk
14
+ N2YxNWEzODliYjZlMzE0MTliZjY3OTk1MjRkOWQ5OGJhMDNkZDEyMjRhODc4
15
+ ZTQ1ZjcyOGIzZDVjMmJlOGRlYzlkZDY0Y2I1MWJkYWJkYjA3ZTE=
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Tim Felgentreff
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,18 @@
1
+ ## Cassowary
2
+
3
+ Cassowary is an incremental constraint solving toolkit that
4
+ efficiently solves systems of linear equalities and
5
+ inequalities. Constraints may be either requirements or
6
+ preferences. Client code specifies the constraints to be maintained,
7
+ and the solver updates the constrained variables to have values that
8
+ satisfy the constraints.
9
+
10
+ This is a Ruby port of the Smalltalk version of Cassowary. The
11
+ original distribution can be found
12
+ [here](http://www.cs.washington.edu/research/constraints/cassowary/).
13
+
14
+ A technical report is included in the original distribution that
15
+ describes the algorithm, interface, and implementation of the
16
+ Cassowary solver. Additionally, the distribution contains toy sample
17
+ applications written in Smalltalk, C++, Java, and Python, and a more
18
+ complex example Java applet, the "Constraint Drawing Application".
data/lib/cassowary.rb ADDED
@@ -0,0 +1,25 @@
1
+ # Copyright (C) 2012 by Tim Felgentreff
2
+
3
+ module Cassowary
4
+ VERSION = "0.5.0"
5
+
6
+ class Error < StandardError; end
7
+ class InternalError < Error; end
8
+ class NonLinearResult < Error; end
9
+ class NotEnoughStays < Error; end
10
+ class RequiredFailure < Error; end
11
+ class TooDifficult < Error; end
12
+ end
13
+
14
+ require "utils/equalities"
15
+
16
+ require "variables"
17
+ require "constraint"
18
+ require "symbolic_weight"
19
+ require "strength"
20
+ require "linear_expression"
21
+ require "simplex_solver"
22
+
23
+ require "ext/object"
24
+ require "ext/float"
25
+ require "ext/numeric"
@@ -0,0 +1,40 @@
1
+ # Copyright (C) 2012 by Tim Felgentreff
2
+
3
+ module Cassowary
4
+ class EditOrStayConstraint < Constraint
5
+ attr_accessor :variable
6
+
7
+ def initialize(hash = {})
8
+ hash = {:weight => 1.0}.merge(hash)
9
+ self.variable = hash[:variable]
10
+ self.strength = hash[:strength]
11
+ self.weight = hash[:weight]
12
+ end
13
+
14
+ def expression
15
+ e = LinearExpression.new
16
+ e.constant = variable.value
17
+ e.terms[variable] = -1.0
18
+ e
19
+ end
20
+ end
21
+
22
+ class EditConstraint < EditOrStayConstraint
23
+ attr_accessor :value
24
+
25
+ def initialize(hash = {})
26
+ super
27
+ self.value = hash[:value]
28
+ end
29
+
30
+ def edit_constraint?
31
+ true
32
+ end
33
+ end
34
+
35
+ class StayConstraint < EditOrStayConstraint
36
+ def stay_constraint?
37
+ true
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,23 @@
1
+ # Copyright (C) 2012 by Tim Felgentreff
2
+
3
+ module Cassowary
4
+ class LinearConstraint < Constraint
5
+ attr_accessor :expression
6
+ end
7
+
8
+ class LinearEquation < LinearConstraint
9
+ def inspect
10
+ "#{strength.inspect}(#{expression.inspect}=0)"
11
+ end
12
+ end
13
+
14
+ class LinearInequality < LinearConstraint
15
+ def inequality?
16
+ true
17
+ end
18
+
19
+ def inspect
20
+ "#{strength.inspect}(#{expression.inspect}>=0)"
21
+ end
22
+ end
23
+ end
data/lib/constraint.rb ADDED
@@ -0,0 +1,30 @@
1
+ # Copyright (C) 2012 by Tim Felgentreff
2
+
3
+ module Cassowary
4
+ class Constraint
5
+ attr_accessor :strength, :weight
6
+
7
+ def expression
8
+ raise NotImplementedError, "my subclass should have implemented #expression"
9
+ end
10
+
11
+ def edit_constraint?
12
+ false
13
+ end
14
+
15
+ def inequality?
16
+ false
17
+ end
18
+
19
+ def required?
20
+ strength.required?
21
+ end
22
+
23
+ def stay_constraint?
24
+ false
25
+ end
26
+ end
27
+ end
28
+
29
+ require "constraint/edit_or_stay_constraint"
30
+ require "constraint/linear_constraint"
data/lib/ext/float.rb ADDED
@@ -0,0 +1,24 @@
1
+ # Copyright (C) 2012 by Tim Felgentreff
2
+
3
+ class Float
4
+ def cl_approx(float)
5
+ # Answer true if I am approximately equal to the argument
6
+ epsilon = Cassowary::SimplexSolver::Epsilon
7
+ if self == 0.0
8
+ float.abs < epsilon
9
+ elsif float == 0.0
10
+ abs < epsilon
11
+ else
12
+ (self - float).abs < (abs * epsilon)
13
+ end
14
+ end
15
+
16
+ def cl_approx_zero
17
+ cl_approx 0.0
18
+ end
19
+
20
+ def definitely_negative
21
+ # return true if I am definitely negative (i.e. smaller than negative epsilon)"
22
+ self < (0.0 - Cassowary::SimplexSolver::Epsilon)
23
+ end
24
+ end
@@ -0,0 +1,11 @@
1
+ # Copyright (C) 2012 by Tim Felgentreff
2
+
3
+ class Numeric
4
+ include Cassowary::Equalities
5
+
6
+ def as_linear_expression
7
+ expr = Cassowary::LinearExpression.new
8
+ expr.constant = self.to_f
9
+ expr
10
+ end
11
+ end
data/lib/ext/object.rb ADDED
@@ -0,0 +1,11 @@
1
+ # Copyright (C) 2012 by Tim Felgentreff
2
+
3
+ class Object
4
+ def cl_approx(x)
5
+ self == x
6
+ end
7
+
8
+ def symbolic_weight?
9
+ false
10
+ end
11
+ end
@@ -0,0 +1,163 @@
1
+ # Copyright (C) 2012 by Tim Felgentreff
2
+
3
+ module Cassowary
4
+ class LinearExpression
5
+ include Equalities
6
+
7
+ attr_accessor :constant, :terms
8
+
9
+ def self.new_with_symbolic_weight
10
+ result = self.new
11
+ result.constant = SymbolicWeight::Zero
12
+ result
13
+ end
14
+
15
+ def initialize
16
+ self.constant = 0.0
17
+ self.terms = {}
18
+ end
19
+
20
+ def any_variable
21
+ if terms.any?
22
+ terms.keys.first
23
+ else
24
+ raise InternalError, "expression is constant"
25
+ end
26
+ end
27
+
28
+ def as_linear_expression
29
+ self
30
+ end
31
+
32
+ def coefficient_for(variable)
33
+ terms[variable] || 0.0
34
+ end
35
+
36
+ def constant?
37
+ terms.empty?
38
+ end
39
+
40
+ def each_variable_and_coefficient(&block)
41
+ terms.each_pair(&block)
42
+ end
43
+
44
+ def add_variable(variable, coefficient, subject = nil, solver = nil)
45
+ if terms.has_key? variable
46
+ new_coeff = coefficient + terms[variable]
47
+ if new_coeff.cl_approx_zero
48
+ terms.delete variable
49
+ solver.note_removed_variable(variable, subject) if solver
50
+ else
51
+ terms[variable] = new_coeff
52
+ end
53
+ else
54
+ terms[variable] = coefficient
55
+ solver.note_added_variable(variable, subject) if solver
56
+ end
57
+ end
58
+
59
+ def add_expression(expr, times, subject = nil, solver = nil)
60
+ increment_constant(times * expr.constant)
61
+ expr.each_variable_and_coefficient do |v, c|
62
+ add_variable(v, times * c, subject, solver)
63
+ end
64
+ end
65
+
66
+ def new_subject(subject)
67
+ nreciprocal = -(1.0 / terms.delete(subject))
68
+ self.constant *= nreciprocal
69
+ terms.each_pair do |v, c|
70
+ terms[v] = c * nreciprocal
71
+ end
72
+ end
73
+
74
+ def change_subject(old, new)
75
+ reciprocal = 1.0 / terms.delete(new)
76
+ nreciprocal = -reciprocal
77
+ self.constant *= nreciprocal
78
+ terms.each_pair do |v, c|
79
+ terms[v] = c * nreciprocal
80
+ end
81
+ terms[old] = reciprocal
82
+ end
83
+
84
+ def increment_constant(num)
85
+ self.constant += num
86
+ end
87
+
88
+ def substitute_variable(var, expr, subject, solver)
89
+ multiplier = terms.delete(var)
90
+ increment_constant(multiplier * expr.constant)
91
+ expr.each_variable_and_coefficient do |v, c|
92
+ if old_coeff = terms[v]
93
+ new_coeff = old_coeff + (multiplier * c)
94
+ if new_coeff.cl_approx_zero
95
+ terms.delete v
96
+ solver.note_removed_variable v, subject
97
+ else
98
+ terms[v] = new_coeff
99
+ end
100
+ else
101
+ terms[v] = multiplier * c
102
+ solver.note_added_variable v, subject
103
+ end
104
+ end
105
+ end
106
+
107
+ def *(x)
108
+ return x * constant if constant?
109
+
110
+ n = if x.is_a? Numeric
111
+ x.to_f
112
+ else
113
+ expr = x.as_linear_expression
114
+ raise NonLinearResult unless expr.constant?
115
+ expr.constant
116
+ end
117
+ result = LinearExpression.new
118
+ result.constant = n * constant
119
+ terms.each_pair do |v, c|
120
+ result.terms[v] = n * c
121
+ end
122
+ result
123
+ end
124
+
125
+ def /(x)
126
+ expr = x.as_linear_expression
127
+ raise NonLinearResult unless expr.constant?
128
+ self * (1.0 / expr.constant)
129
+ end
130
+
131
+ def +(x)
132
+ expr = x.as_linear_expression
133
+ result = LinearExpression.new
134
+ result.constant = constant + expr.constant
135
+ terms.each_pair do |v, c|
136
+ result.terms[v] = c
137
+ end
138
+ expr.each_variable_and_coefficient do |v, c|
139
+ result.add_variable(v, c)
140
+ end
141
+ result
142
+ end
143
+
144
+ def -(x)
145
+ expr = x.as_linear_expression
146
+ result = LinearExpression.new
147
+ result.constant = constant - expr.constant
148
+ terms.each_pair do |v, c|
149
+ result.terms[v] = c
150
+ end
151
+ expr.each_variable_and_coefficient do |v, c|
152
+ result.add_variable(v, -c)
153
+ end
154
+ result
155
+ end
156
+
157
+ def inspect
158
+ terms.keys.inject(constant.inspect) do |str, v|
159
+ "#{str}+#{terms[v].inspect}*#{v.inspect}"
160
+ end
161
+ end
162
+ end
163
+ end