ambit 0.10.1 → 0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (6) hide show
  1. data/History.txt +10 -1
  2. data/README.rdoc +65 -18
  3. data/README.txt +65 -18
  4. data/examples/example.rb +43 -0
  5. data/lib/ambit.rb +30 -7
  6. metadata +7 -13
@@ -1,4 +1,13 @@
1
- === 0.10.1 / 2011-04-26
1
+ === 0.11 / 2012-10-12
2
+
3
+ * Additional documentation on side effects and rewinding.
4
+
5
+ * Fixed Ambit::trace and Ambit::untrace to work as described in the docs.
6
+ This breaks the (undocumented) ability to turn on tracing
7
+ generator-by-generator, but buys the ability to trace operation of the
8
+ anonymous generator used by Ambit::choose.
9
+
10
+ === 0.10.1 / 2012-10-10
2
11
 
3
12
  * Updated repo path -- no functional change.
4
13
 
@@ -8,13 +8,8 @@ License:: 2-clause BSD-Style (see LICENSE.txt)
8
8
 
9
9
  == DESCRIPTION:
10
10
 
11
- This is an all-ruby implementation of choose/fail nondeterministic
12
- programming with branch cut, as described in Chapter 22 of Paul Graham's
13
- <em>On Lisp</em>[1], or Section 4.3 of <em>SICP</em>[2].
14
-
15
- Due to Ruby containing a true call/cc, this is a much straighter port of
16
- Paul Graham's scheme version of this code than his Common Lisp or my C
17
- versions are. :-)
11
+ Ambit is a ruby non-deterministic programming system with backtracking and
12
+ branch cut.
18
13
 
19
14
  == REQUIREMENTS:
20
15
 
@@ -116,7 +111,7 @@ enumerable is returned <em>from the same call to Ambit::choose</em>:
116
111
  Ambit::fail! unless a.even?
117
112
  puts a
118
113
  prints
119
- 2
114
+ 2
120
115
  (and only "2")
121
116
 
122
117
  <em>This means that computation now proceeds as if that had been the value
@@ -181,21 +176,68 @@ prints
181
176
  2
182
177
 
183
178
  instead of only "2" -- the printing has already been done by the time we
184
- call Ambit::fail!.
179
+ call Ambit::fail!.
180
+
181
+ Likewise, this code:
182
+
183
+ x = 1
184
+ y = Ambit::choose([1, 2, 3])
185
+ if y == 2
186
+ puts x
187
+ else
188
+ x = 42
189
+ end
190
+ Ambit::fail! unless a.even?
191
+
192
+ prints
193
+ 42
194
+
195
+ , not +1+, as Ambit does not rewind the setting of 'x' after the first
196
+ return from Ambit::choose.
185
197
 
186
198
  Such side effects can also be useful, however. This code:
187
199
 
188
200
  i = 0
189
201
  first = Ambit.choose(1..10)
202
+ i += 1
190
203
  second = Ambit.choose(1..10)
204
+ i += 1
191
205
  third = Ambit.choose(1..10)
192
206
  i += 1
193
207
  Ambit.fail! unless open_lock(first, second, third)
194
208
  puts i
195
209
 
196
- prints out the number of combinations which were tried in total (since +i+
210
+ prints out the number of values which were chosen in total (since +i+
197
211
  remains incremented even when we rewind computation).
198
212
 
213
+ If we wanted to avoid this type of side effect, one option would be to use a
214
+ function argument to capture this setting, as function calls (and thus the
215
+ value of their arguments and local variables) are rewindable. This version,
216
+ for instance:
217
+
218
+ def try_first
219
+ i = 0
220
+ first = Ambit::choose(1..10)
221
+ try_second(i + 1, first)
222
+ end
223
+
224
+ def try_second i, first
225
+ second = Ambit::choose(1..10)
226
+ try_third(i + 1, first, second)
227
+ end
228
+
229
+ def try_third i, first, second
230
+ third = Ambit::choose(1..10)
231
+ Ambit.fail! unless open_lock(first, second, third)
232
+ puts i+1
233
+ end
234
+
235
+ try_first
236
+
237
+ will always print +3+ -- the number of values tried in the ultimately
238
+ successful series of choices, rather than the number of combinations tried
239
+ over all.
240
+
199
241
  ==== More Than One Answer
200
242
 
201
243
  Often, more than one combination of choices is interesting to consider -- it
@@ -291,11 +333,11 @@ commit to all choices made so far.
291
333
 
292
334
  ==== Watching Ambit work
293
335
 
294
- The methods Ambit::trace and Ambit::untrace can be used to enable debug
295
- tracing of Ambit operations. Repeated calls to Ambit::trace increase the
296
- verbosity of trace output (though this has no effect in the current
297
- version), and a specific trace level (as an integer) may also be passed to
298
- Ambit::trace as an optional argument.
336
+ The class method Ambit::trace can be used to enable debug tracing of Ambit
337
+ operations. Repeated calls to Ambit::trace increase the verbosity of trace
338
+ output (though this has no effect in the current version), and a specific
339
+ trace level (as an integer) may also be passed to Generator#trace as an
340
+ optional argument.
299
341
 
300
342
  Trace output is written to STDERR. Trace output can be disabled by
301
343
  specifying a trace level of 0, or by calling Ambit::untrace.
@@ -413,11 +455,16 @@ a given N.
413
455
 
414
456
  === References
415
457
 
416
- [1] Graham, Paul, <em>On Lisp</em>, Prentice Hall, 1993. Available online at http://www.paulgraham.com/onlisp.html
458
+ For more information on nondeterministic programming, see
459
+
460
+ * Abelson, Harold and Gerald Jay Sussman, <em>Structure and Interpretation
461
+ of Computer Programs, 2nd Edition</em>, Section 4.3, MIT Press, 1996.
462
+ Available online at http://mitpress.mit.edu/sicp/
417
463
 
418
- [2] Abelson, Harold and Gerald Jay Sussman, <em>Structure and Interpretation of Computer Programs, 2nd Edition</em>, MIT Press, 1996. Available online at http://mitpress.mit.edu/sicp/
464
+ * Graham, Paul, <em>On Lisp</em>, Chapter 22, Prentice Hall, 1993. Available
465
+ online at http://www.paulgraham.com/onlisp.html
419
466
 
420
- [3] Sterling, Leon and Ehud Shapiro, <em>The Art of Prolog</em>, MIT Press, 1994
467
+ * Sterling, Leon and Ehud Shapiro, <em>The Art of Prolog</em>, MIT Press, 1994
421
468
 
422
469
  == LICENSE:
423
470
 
data/README.txt CHANGED
@@ -8,13 +8,8 @@ License:: 2-clause BSD-Style (see LICENSE.txt)
8
8
 
9
9
  == DESCRIPTION:
10
10
 
11
- This is an all-ruby implementation of choose/fail nondeterministic
12
- programming with branch cut, as described in Chapter 22 of Paul Graham's
13
- <em>On Lisp</em>[1], or Section 4.3 of <em>SICP</em>[2].
14
-
15
- Due to Ruby containing a true call/cc, this is a much straighter port of
16
- Paul Graham's scheme version of this code than his Common Lisp or my C
17
- versions are. :-)
11
+ Ambit is a ruby non-deterministic programming system with backtracking and
12
+ branch cut.
18
13
 
19
14
  == REQUIREMENTS:
20
15
 
@@ -116,7 +111,7 @@ enumerable is returned <em>from the same call to Ambit::choose</em>:
116
111
  Ambit::fail! unless a.even?
117
112
  puts a
118
113
  prints
119
- 2
114
+ 2
120
115
  (and only "2")
121
116
 
122
117
  <em>This means that computation now proceeds as if that had been the value
@@ -181,21 +176,68 @@ prints
181
176
  2
182
177
 
183
178
  instead of only "2" -- the printing has already been done by the time we
184
- call Ambit::fail!.
179
+ call Ambit::fail!.
180
+
181
+ Likewise, this code:
182
+
183
+ x = 1
184
+ y = Ambit::choose([1, 2, 3])
185
+ if y == 2
186
+ puts x
187
+ else
188
+ x = 42
189
+ end
190
+ Ambit::fail! unless a.even?
191
+
192
+ prints
193
+ 42
194
+
195
+ , not +1+, as Ambit does not rewind the setting of 'x' after the first
196
+ return from Ambit::choose.
185
197
 
186
198
  Such side effects can also be useful, however. This code:
187
199
 
188
200
  i = 0
189
201
  first = Ambit.choose(1..10)
202
+ i += 1
190
203
  second = Ambit.choose(1..10)
204
+ i += 1
191
205
  third = Ambit.choose(1..10)
192
206
  i += 1
193
207
  Ambit.fail! unless open_lock(first, second, third)
194
208
  puts i
195
209
 
196
- prints out the number of combinations which were tried in total (since +i+
210
+ prints out the number of values which were chosen in total (since +i+
197
211
  remains incremented even when we rewind computation).
198
212
 
213
+ If we wanted to avoid this type of side effect, one option would be to use a
214
+ function argument to capture this setting, as function calls (and thus the
215
+ value of their arguments and local variables) are rewindable. This version,
216
+ for instance:
217
+
218
+ def try_first
219
+ i = 0
220
+ first = Ambit::choose(1..10)
221
+ try_second(i + 1, first)
222
+ end
223
+
224
+ def try_second i, first
225
+ second = Ambit::choose(1..10)
226
+ try_third(i + 1, first, second)
227
+ end
228
+
229
+ def try_third i, first, second
230
+ third = Ambit::choose(1..10)
231
+ Ambit.fail! unless open_lock(first, second, third)
232
+ puts i+1
233
+ end
234
+
235
+ try_first
236
+
237
+ will always print +3+ -- the number of values tried in the ultimately
238
+ successful series of choices, rather than the number of combinations tried
239
+ over all.
240
+
199
241
  ==== More Than One Answer
200
242
 
201
243
  Often, more than one combination of choices is interesting to consider -- it
@@ -291,11 +333,11 @@ commit to all choices made so far.
291
333
 
292
334
  ==== Watching Ambit work
293
335
 
294
- The methods Ambit::trace and Ambit::untrace can be used to enable debug
295
- tracing of Ambit operations. Repeated calls to Ambit::trace increase the
296
- verbosity of trace output (though this has no effect in the current
297
- version), and a specific trace level (as an integer) may also be passed to
298
- Ambit::trace as an optional argument.
336
+ The class method Ambit::trace can be used to enable debug tracing of Ambit
337
+ operations. Repeated calls to Ambit::trace increase the verbosity of trace
338
+ output (though this has no effect in the current version), and a specific
339
+ trace level (as an integer) may also be passed to Generator#trace as an
340
+ optional argument.
299
341
 
300
342
  Trace output is written to STDERR. Trace output can be disabled by
301
343
  specifying a trace level of 0, or by calling Ambit::untrace.
@@ -413,11 +455,16 @@ a given N.
413
455
 
414
456
  === References
415
457
 
416
- [1] Graham, Paul, <em>On Lisp</em>, Prentice Hall, 1993. Available online at http://www.paulgraham.com/onlisp.html
458
+ For more information on nondeterministic programming, see
459
+
460
+ * Abelson, Harold and Gerald Jay Sussman, <em>Structure and Interpretation
461
+ of Computer Programs, 2nd Edition</em>, Section 4.3, MIT Press, 1996.
462
+ Available online at http://mitpress.mit.edu/sicp/
417
463
 
418
- [2] Abelson, Harold and Gerald Jay Sussman, <em>Structure and Interpretation of Computer Programs, 2nd Edition</em>, MIT Press, 1996. Available online at http://mitpress.mit.edu/sicp/
464
+ * Graham, Paul, <em>On Lisp</em>, Chapter 22, Prentice Hall, 1993. Available
465
+ online at http://www.paulgraham.com/onlisp.html
419
466
 
420
- [3] Sterling, Leon and Ehud Shapiro, <em>The Art of Prolog</em>, MIT Press, 1994
467
+ * Sterling, Leon and Ehud Shapiro, <em>The Art of Prolog</em>, MIT Press, 1994
421
468
 
422
469
  == LICENSE:
423
470
 
@@ -59,3 +59,46 @@ rescue Ambit::ChoicesExhausted
59
59
  end
60
60
 
61
61
  find_boxes
62
+
63
+ Ambit::clear!
64
+
65
+ # Simple combination lock example, used in README
66
+
67
+ # test if we have the right combination
68
+ def open_lock x, y, z
69
+ [x, y, z] == [3, 7, 2]
70
+ end
71
+
72
+ # version with global variable -- counts calls to #choose
73
+ def try_combinations
74
+ i = 0
75
+ first = Ambit.choose(1..10)
76
+ i += 1
77
+ second = Ambit.choose(1..10)
78
+ i += 1
79
+ third = Ambit.choose(1..10)
80
+ i += 1
81
+ Ambit.fail! unless open_lock(first, second, third)
82
+ i
83
+ end
84
+
85
+ puts try_combinations
86
+
87
+ def try_first
88
+ i = 0
89
+ first = Ambit::choose(1..10)
90
+ try_second(i + 1, first)
91
+ end
92
+
93
+ def try_second i, first
94
+ second = Ambit::choose(1..10)
95
+ try_third(i + 1, first, second)
96
+ end
97
+
98
+ def try_third i, first, second
99
+ third = Ambit::choose(1..10)
100
+ Ambit.fail! unless open_lock(first, second, third)
101
+ i+1
102
+ end
103
+
104
+ puts try_first
@@ -7,7 +7,7 @@
7
7
 
8
8
  module Ambit
9
9
 
10
- VERSION = '0.10.1'
10
+ VERSION = '0.11'
11
11
 
12
12
  # A ChoicesExhausted exception is raised if the outermost choose invocation of
13
13
  # a Generator has run out of choices, indicating that no (more) solutions are possible.
@@ -15,6 +15,7 @@ module Ambit
15
15
  end
16
16
 
17
17
  class Generator
18
+ @@trace = 0
18
19
  # Allocate a new private Generator. Usually not needed -- use Ambit::choose et al, instead.
19
20
  #
20
21
  # See "Private Generators" in the README for details
@@ -25,19 +26,23 @@ module Ambit
25
26
 
26
27
  # Turn on tracing (to standard error) of Ambit operations
27
28
  #
29
+ # intended for use by Ambit::trace
30
+ #
28
31
  # The optional level argument sets the verbosity -- if not passed, each
29
32
  # call to this method increases verbosity
30
- def trace lvl=false
33
+ def self.trace lvl=false
31
34
  if lvl
32
- @trace = lvl
35
+ @@trace = lvl
33
36
  else
34
- @trace = @trace + 1
37
+ @@trace = @trace + 1
35
38
  end
36
39
  end
37
40
 
38
41
  # Turn off tracing (to standard error) of Ambit operations
39
- def untrace
40
- @trace = 0
42
+ #
43
+ # intended for use by Ambit::untrace
44
+ def self.untrace
45
+ @@trace = 0
41
46
  end
42
47
 
43
48
  # Clear all outstanding choices registered with this generator.
@@ -131,8 +136,26 @@ module Ambit
131
136
  end
132
137
  end
133
138
 
139
+ # Turn on tracing (to standard error) of Ambit operations
140
+ #
141
+ # See ``Watching Ambit Work'' in README.rdoc
142
+ #
143
+ # The optional level argument sets the verbosity -- if not passed, each
144
+ # call to this method increases verbosity
145
+ def self.trace lvl = false
146
+ Generator::trace lvl
147
+ end
148
+
149
+ # Turn off tracing (to standard error) of Ambit operations
150
+ #
151
+ # See ``Watching Ambit Work'' in README.rdoc
152
+ #
153
+ def self.untrace
154
+ Generator::untrace
155
+ end
156
+
134
157
  # forward method invocations on this module to the default Generator.
135
- def Ambit::method_missing(sym, *args, &block) # :nodoc:
158
+ def self.method_missing(sym, *args, &block) # :nodoc:
136
159
  Ambit::Default_Generator.send(sym, *args, &block)
137
160
  end
138
161
 
metadata CHANGED
@@ -1,13 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ambit
3
3
  version: !ruby/object:Gem::Version
4
- hash: 53
4
+ hash: 29
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 10
9
- - 1
10
- version: 0.10.1
8
+ - 11
9
+ version: "0.11"
11
10
  platform: ruby
12
11
  authors:
13
12
  - Jim Wise
@@ -15,7 +14,7 @@ autorequire:
15
14
  bindir: bin
16
15
  cert_chain: []
17
16
 
18
- date: 2012-01-10 00:00:00 Z
17
+ date: 2012-01-12 00:00:00 Z
19
18
  dependencies:
20
19
  - !ruby/object:Gem::Dependency
21
20
  name: rdoc
@@ -48,13 +47,8 @@ dependencies:
48
47
  type: :development
49
48
  version_requirements: *id002
50
49
  description: |-
51
- This is an all-ruby implementation of choose/fail nondeterministic
52
- programming with branch cut, as described in Chapter 22 of Paul Graham's
53
- <em>On Lisp</em>[1], or Section 4.3 of <em>SICP</em>[2].
54
-
55
- Due to Ruby containing a true call/cc, this is a much straighter port of
56
- Paul Graham's scheme version of this code than his Common Lisp or my C
57
- versions are. :-)
50
+ Ambit is a ruby non-deterministic programming system with backtracking and
51
+ branch cut.
58
52
  email:
59
53
  - jwise@draga.com
60
54
  executables: []
@@ -113,6 +107,6 @@ rubyforge_project: ambit
113
107
  rubygems_version: 1.8.13
114
108
  signing_key:
115
109
  specification_version: 3
116
- summary: This is an all-ruby implementation of choose/fail nondeterministic programming with branch cut, as described in Chapter 22 of Paul Graham's <em>On Lisp</em>[1], or Section 4.3 of <em>SICP</em>[2]
110
+ summary: Ambit is a ruby non-deterministic programming system with backtracking and branch cut.
117
111
  test_files:
118
112
  - test/test_ambit.rb