amb 0.0.3 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,17 @@
1
+ ## 0.0.5
2
+
3
+ * fixed issue with load paths when used as a gem
4
+
5
+ ## 0.0.4
6
+
7
+ ## 0.0.3
8
+
9
+ * mostly bug fixes
10
+
11
+ ## 0.0.2
12
+
13
+ * mostly new features
14
+
1
15
  ## 0.0.1
2
16
 
3
17
  * Initial setup
data/README.md CHANGED
@@ -19,7 +19,7 @@ Typically, the programmer would specify a limited number of alternatives (eg. di
19
19
 
20
20
  To discover which alternatives groups are valid, a check/discard/switch strategy must be enforced by the program. Most often it will make use of a ambiguous operator, `amb()` which implements this strategy. [Quoting Dorai Sitaram](http://www.ccs.neu.edu/home/dorai/t-y-scheme/t-y-scheme-Z-H-16.html#node_chap_14), "`amb` takes zero or more expressions, and makes a nondeterministic (or "ambiguous") choice among them, preferring those choices that cause the program to converge meaningfully". The most basic version of `amb` would be `amb(x,y)`, which returns, *in an unpredictible way*, either x or y when both are defined; if only one is defined, whichever is defined; and terminate the program if none is defined. Using some recursivity, `amb()` may be used to define arbitrary, complex ambiguous functions. It is quite difficult to implement a good `amb()` operator matching that formal definition though (for unpredictability is not what computers enjoys doing). A simpler (yet functional) version has the operator return its first defined argument, then pass over the next defined one in case of a dead-end, in a depth-first selection algorithm. It *is* dumb yet it works as expected.
21
21
 
22
- Thus the most common strategy used for implementing `amb()`'s logic (check/discard) is chronological backtracking. It almost always relies on some sort of continuations (`call/cc`) and a search algorithm (say, depth-first). The algorithm may be tweaked into a smarter backjumping for more efficiency, depending on the problem at stake. Another strategy is reinforcement learning (aka. constraint learning), as is used in some AI systems. This library implements simple backtracking only though.
22
+ Thus the most common strategy used for implementing `amb()`'s logic (check/discard) is chronological backtracking. It is kind of a brute-force, linear approach, which always relies on some sort of continuations (`call/cc`). A continuation is like a savepoint, representing "what's left to run" at a given time. Recording as much continuations as alternatives enables `amb` to test "the rest of the program" multiple times until a valid solution is found. This rather dumb algorithm may be tweaked into a (not so) smarter backjumping algorithm for more efficiency, depending on the nature of the problem at stake. Another strategy is reinforcement learning (aka. constraint learning), as used in some AI systems. Most of the time it's really hard. This library implements simple backtracking only.
23
23
 
24
24
  More details on all of this under the `doc/` folder (*pending*).
25
25
 
@@ -58,13 +58,15 @@ examining x = 3, y = 1
58
58
  examining x = 3, y = 2
59
59
  solution: x = 3, y = 2
60
60
  ```
61
- This illustrates the incremental, backtracking pattern leading to the first valid solution. Many more examples under the `examples/` directory.
61
+ This illustrates the incremental, backtracking pattern leading to the first valid solution.
62
+
63
+ Many more examples under the `examples/` directory. You may run them with the `-d` flag to output information about the solving process.
62
64
 
63
65
  ## Installation
64
66
 
65
67
  gem install amb
66
68
 
67
- ## Usage
69
+ ## Step by step
68
70
 
69
71
  Here's a raw use-case, presenting the required *steps*. For concrete examples, see the `examples/` directory.
70
72
 
@@ -82,15 +84,33 @@ end
82
84
  amb = Ambiguous.new
83
85
  ```
84
86
 
85
- Then define your alternatives using `#choose` (aliased as `#choices` or `#alternatives`). It may take arbitrary code (values, proc…).
87
+ Then, define your alternatives using `#choose` (aliased as `#choices` or `#alternatives`). It may take arbitrary code (values, proc…). Don't forget to assign it to a variable, otherwise it is just useless alternatives. Most of the time, several alternatives set will be defined.
86
88
 
87
89
  ``` ruby
88
- amb.choose()
90
+ x = amb.choose(1, 2, lambda { some code})
91
+ y = amb.choose(:some, :more, :alternatives)
89
92
  ```
90
93
 
94
+ Then, state at least one constraint which, hopefully, references your alternatives. If more than one constraint is expressed, all of them will be considered in the problem solving.
95
+
96
+ ``` ruby
97
+ amb.assert(x != y)
98
+ amb.assert heavy_logical_computation_on(x, y)
99
+ ```
100
+
101
+ And so on. Once again, for real use-cases, see the `examples/` directory.
102
+
91
103
  ## TODO
92
104
 
105
+ * more examples!
106
+ * more specs!
107
+ * spec out `choose` depending on a previous `choose`
108
+ * implements a version of amb matching the original definition (returns one of its argument at random) => keep track of backtracking paths
109
+ * implements a trampoline version (continuation-passing style)
110
+ * memoization/reset?
111
+ * a different selection algo? (BFS, smarter one)
112
+
93
113
  ## See also
94
114
 
95
- * the `doc/` and `examples/` directories.
115
+ * `doc/` and `examples/` directories.
96
116
  * Continuations and fibers concepts.
data/lib/amb.rb CHANGED
@@ -1,2 +1,2 @@
1
- require './lib/amb/amb'
2
- require './lib/amb/amb_operator'
1
+ require 'amb/amb'
2
+ require 'amb/amb_operator'
@@ -98,6 +98,8 @@ module Amb
98
98
  end
99
99
  failure
100
100
  end
101
+ alias :choices :choose
102
+ alias :alternatives :choose
101
103
 
102
104
  # Unconditional failure of a constraint, causing the last choice to be
103
105
  # retried. This is equivalent to saying `assert(false)`.
@@ -106,6 +108,10 @@ module Amb
106
108
  # @TODO it'd be better not to have to
107
109
  #
108
110
  def failure
111
+ if $DEBUG
112
+ @__num_of_tries ||= 1
113
+ @__num_of_tries += 1
114
+ end
109
115
  back_amb.pop.call
110
116
  end
111
117
 
@@ -135,25 +141,33 @@ module Amb
135
141
  puts failure_message
136
142
  end
137
143
 
144
+ def branches_count
145
+ @__num_of_tries
146
+ end
147
+
138
148
  module ClassMethods
139
149
  # Class convenience method to search for the first solution to the
140
150
  # constraints.
141
151
  #
142
- def solve(failure_message = "No Solution")
152
+ def solve(failure_message = "No solution.")
143
153
  amb = self.new
144
154
  yield(amb)
145
155
  rescue Amb::ExhaustedError => ex
156
+ puts
157
+ puts "#{amb.branches_count} branches explored." if $DEBUG
146
158
  amb.report(failure_message)
147
159
  end
148
160
 
149
161
  # Class convenience method to search for all the solutions to the
150
162
  # constraints.
151
163
  #
152
- def solve_all(failure_message = "No More Solutions")
164
+ def solve_all(failure_message = "No more solutions.")
153
165
  amb = self.new
154
166
  yield(amb)
155
167
  amb.failure
156
168
  rescue Amb::ExhaustedError => ex
169
+ puts
170
+ puts "#{amb.branches_count} branches explored." if $DEBUG
157
171
  amb.report(failure_message)
158
172
  end
159
173
  end
@@ -1,6 +1,6 @@
1
1
  module Amb
2
2
  MAJOR = 0
3
3
  MINOR = 0
4
- PATCH = 3
4
+ PATCH = 5
5
5
  VERSION = [MAJOR, MINOR, PATCH].join('.')
6
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: amb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.5
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-08-28 00:00:00.000000000Z
12
+ date: 2011-09-04 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: amb
16
- requirement: &82652280 !ruby/object:Gem::Requirement
16
+ requirement: &75631670 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,7 +21,7 @@ dependencies:
21
21
  version: '0'
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *82652280
24
+ version_requirements: *75631670
25
25
  description: This gem is a compilation of several implementations of the ambiguous
26
26
  function/operator, useful for constraint programming.
27
27
  email: jd@vauguet.fr
@@ -56,7 +56,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
56
56
  version: '0'
57
57
  requirements: []
58
58
  rubyforge_project:
59
- rubygems_version: 1.8.6
59
+ rubygems_version: 1.8.10
60
60
  signing_key:
61
61
  specification_version: 3
62
62
  summary: McCarty's ambiguous function/operator implementations