bud 0.9.4 → 0.9.9

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 628133a838208bab16e5ec51d166da3b35803cc1
4
+ data.tar.gz: afeab2b5aaa75b379aa5561559fb7acc89cfb50a
5
+ SHA512:
6
+ metadata.gz: cd64cbf997cd2592e90f1be28e9818c074ff8bbfbb0cc997dfe0d4af455484e98959f72408ab70487ba29de32cfd10fdf7d662bca702c8ff92ddf82862d47941
7
+ data.tar.gz: 541c9f257e269de04137d6217e8960c680e1864cc9065cd12eb6a04eecf869dc6080ea184ac12c8d45e0f24ae589339aaddf99ea47c4020b2d3060a0669a7b00
@@ -1,3 +1,109 @@
1
+ == 0.9.8 / ???
2
+
3
+ * Fix bug in the stratification algorithm
4
+ * Fix bug with insertions into stdio inside bootstrap blocks
5
+ * Improve error message when <~ applied to a collection type that doesn't
6
+ support it (#316)
7
+ * Fix rescan logic for Zookeeper-backed collections (#317)
8
+ * Fix rescan logic for chained negation operators in a single rule
9
+ * Support + operator for concatenating tuples
10
+ * More consistent behavior for #==, #eql?, and #hash methods on Bud tuple
11
+ objects (TupleStruct)
12
+ * Fix intermittent EM::ConnectionNotBound exceptions during the Bud shutdown
13
+ sequence
14
+ * Improve stratification algorithm to be slightly more aggressive; that is, we
15
+ can place certain rules in an earlier strata than we were previously
16
+ (partially fixes #277)
17
+ * Add Rakefile to simplify common development operations (Joel VanderWerf, #324)
18
+
19
+ == 0.9.7 / 2013-04-22
20
+
21
+ * Avoid raising an exception when Bud is used with Ruby 2.0. There isn't
22
+ anything special that Bud itself needs to do to support Ruby 2.0, but
23
+ RubyParser doesn't properly support 2.0 yet. So using 2.0-only syntax in Bud
24
+ rules is unlikely to work (until RubyParser is updated), but no other problems
25
+ have been observed.
26
+ * Reject <= on collections from outside Bloom rules (#289, Aaron Davidson). The
27
+ previous behavior was error-prone: inserting into a scratch collection via <=
28
+ was not rejected but the inserted data would immediately be discarded at the
29
+ beginning of the next tick. Hence, it is simpler to require <+ or <~ for all
30
+ insertions from outside Bloom rules.
31
+ * Fix bug in join operators whose qualifiers reference collections defined
32
+ inside imported modules (#301)
33
+ * Fix bug in join operators when the same table and column name appears on the
34
+ LHS of multiple join predicates (#313)
35
+ * Fix bug in outer joins with multiple predicates (#315)
36
+ * Fix several bugs in rescan/invalidation logic for tables in the presence of
37
+ upstream deletions (#303)
38
+ * Fix regression in file_reader collections (#304)
39
+ * Improve chaining of notin operators
40
+ * Optimize join evaluation with multiple predicates
41
+ * Optimize notin self joins
42
+ * Improve error reporting for syntax errors on temp collections (#310)
43
+ * Add Travis CI integration hooks (#300, Josh Rosen)
44
+
45
+ Lattices:
46
+
47
+ * Rename lmap#apply_monotone to lmap#apply. Also, allow #apply to take either
48
+ monotone functions or morphisms, and improve error reporting.
49
+ * Add lmap#filter. This takes an lmap whose values are elements of the lbool
50
+ lattice and returns an lmap containing only those k/v pairs where the value is
51
+ true.
52
+ * More intuitive lattice equi-join syntax (lset#eqjoin). Rather than specifying
53
+ the join predicate(s) using array indexes, instead allow them to be specified
54
+ using a hash of field names, as in traditional Bloom joins. This only works
55
+ when the lset contains Structs.
56
+ * Remove lset#project, and allow lset#eqjoin to take zero predicates; in the
57
+ latter case, eqjoin computes the Cartesian product.
58
+ * Support deletion rules (<-) with lattice values on the RHS
59
+
60
+ == 0.9.6 / 2013-02-25
61
+
62
+ * Support syntax sugar for initializing lattices (#294). For example, rather
63
+ than writing "foo <= Bud::MaxLattice.new(2)", you can now just write "foo <=
64
+ 2". Note that, due to a bug in the superator gem, you cannot use this syntax
65
+ with the <+ operator.
66
+ * Allow nested lattice values to be sent over channels (#295, patch from Josh
67
+ Rosen). Lattice values could previously be sent as a field value in a tuple
68
+ delivered over a channel, but they could not be embedded arbitrarily deeply
69
+ within tuples (e.g., lattices nested within an array could not previously be
70
+ sent as a field value).
71
+ * Support "Comparable" for Bud::Lattice values
72
+ * Add support for lattices to rebl
73
+ * Reject attempts to insert into stdio via <+ (#288)
74
+ * Restore functionality of reading from stdio (i.e., stdin) with MRI 1.9
75
+ * Improve MRI 1.8 compatibility
76
+ * Require ruby_parser >= 3.1.0
77
+ * Fix bug in bootstrap blocks for lattice values
78
+ * Fix bug in rescan/invalidation for rules that reference lattice values and use
79
+ the <+ or <~ operators (#290)
80
+ * Fix bug in rescan logic for notin operator (#291)
81
+ * Fix bug in notin operators involving self joins (#298)
82
+ * Fix error when output from a notin operator was fed into a lattice
83
+
84
+ == 0.9.5 / 2012-11-24
85
+
86
+ * Lattice branch (Bloom^L) merged
87
+ * Compatibility with recent versions of ruby_parser (3.0.2+) and ruby2ruby
88
+ (2.0.1+). Older versions of these two gems are no longer supported
89
+ * Add support for aggregate functions that take multiple input columns
90
+ * Add built-in aggregate function accum_pair(x, y), which produces a Set of
91
+ pairs (two-element arrays [x,y])
92
+ * Support user-specified code blocks in payloads(), argagg(), argmin() and
93
+ argmax()
94
+ * Change behavior of BudChannel#payloads for channels with two
95
+ columns. Previously we returned a single *column* (scalar) value in this case;
96
+ now we always return a tuple with k-1 columns
97
+ * More consistent behavior for BudCollection#sort when used outside Bloom
98
+ programs
99
+ * Restore support for each_with_index() over Bud collections
100
+ * Restore functionality of Zookeeper-backed Bud collections and fix
101
+ incompatibility with recent (> 0.4.4) versions of the Zookeeper gem
102
+ * Optimize parsing of Bloom statements, particularly for large Bloom programs
103
+ * Fix bug in argagg state materialization
104
+ * Fix bug in chaining argmin() or argmax() expressions
105
+ * Fix bug in chaining notin() expressions
106
+
1
107
  == 0.9.4 / 2012-09-06
2
108
 
3
109
  * Optimize grouping performance
data/README.md CHANGED
@@ -1,3 +1,4 @@
1
+ [![Build Status](https://travis-ci.org/bloom-lang/bud.svg?branch=v0.9.8)](https://travis-ci.org/bloom-lang/bud)
1
2
  # Bud
2
3
 
3
4
  This is Bud, a.k.a. "Bloom Under Development". It is an initial cut at a Bloom
@@ -11,11 +12,12 @@ documentation.
11
12
  Main deficiencies at this point are:
12
13
 
13
14
  - No Ruby constraints: Within Bloom programs the full power of Ruby is also
14
- available, including mutable state. This allows programmers to get outside
15
- the Bloom framework and lose cleanliness.
15
+ available, including mutable state. This allows programmers to get outside the
16
+ Bloom framework and lose cleanliness.
16
17
 
17
- - Compatibility: Bud only works with Ruby (MRI) 1.8.7 and 1.9. JRuby and other
18
- Ruby implementations are currently not supported.
18
+ - Compatibility: Bud only works with Ruby (MRI) 1.8.7 and 1.9. Bud also has
19
+ experimental support for Ruby 2.0. JRuby and other Ruby implementations are
20
+ currently not supported.
19
21
 
20
22
  ## Installation
21
23
 
@@ -0,0 +1,91 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+
4
+ PRJ = "bud"
5
+
6
+ def version
7
+ @version ||= begin
8
+ $LOAD_PATH.unshift 'lib'
9
+ require 'bud/version'
10
+ warn "Bud::VERSION not a string" unless Bud::VERSION.kind_of? String
11
+ Bud::VERSION
12
+ end
13
+ end
14
+
15
+ def tag
16
+ @tag ||= "v#{version}"
17
+ end
18
+
19
+ desc "Run all tests"
20
+ task :test => "test:unit"
21
+
22
+ TESTS = FileList["test/tc_*.rb"]
23
+ SLOW_TESTS = %w{ test/tc_execmodes.rb }
24
+
25
+ namespace :test do
26
+ desc "Run unit tests"
27
+ Rake::TestTask.new :unit do |t|
28
+ t.libs << "lib"
29
+ t.ruby_opts = %w{ -C test }
30
+ t.test_files = TESTS.sub('test/', '')
31
+ ### it would be better to make each tc_*.rb not depend on pwd
32
+ end
33
+
34
+ desc "Run quick unit tests"
35
+ Rake::TestTask.new :quick do |t|
36
+ t.libs << "lib"
37
+ t.ruby_opts = %w{ -C test }
38
+ t.test_files = TESTS.exclude(*SLOW_TESTS).sub('test/', '')
39
+ end
40
+
41
+ desc "Run quick non-zk unit tests"
42
+ Rake::TestTask.new :quick_no_zk do |t|
43
+ t.libs << "lib"
44
+ t.ruby_opts = %w{ -C test }
45
+ t.test_files = TESTS.
46
+ exclude('test/tc_zookeeper.rb').
47
+ exclude(*SLOW_TESTS).
48
+ sub('test/', '')
49
+ end
50
+ end
51
+
52
+ desc "Commit, tag, and push repo; build and push gem"
53
+ task :release => "release:is_new_version" do
54
+ require 'tempfile'
55
+
56
+ sh "gem build #{PRJ}.gemspec"
57
+
58
+ file = Tempfile.new "template"
59
+ begin
60
+ file.puts "release #{version}"
61
+ file.close
62
+ sh "git commit --allow-empty -a -v -t #{file.path}"
63
+ ensure
64
+ file.close unless file.closed?
65
+ file.unlink
66
+ end
67
+
68
+ sh "git tag #{tag}"
69
+ sh "git push"
70
+ sh "git push --tags"
71
+
72
+ sh "gem push #{tag}.gem"
73
+ end
74
+
75
+ namespace :release do
76
+ desc "Diff to latest release"
77
+ task :diff do
78
+ latest = `git describe --abbrev=0 --tags --match 'v*'`.chomp
79
+ sh "git diff #{latest}"
80
+ end
81
+
82
+ desc "Log to latest release"
83
+ task :log do
84
+ latest = `git describe --abbrev=0 --tags --match 'v*'`.chomp
85
+ sh "git log #{latest}.."
86
+ end
87
+
88
+ task :is_new_version do
89
+ abort "#{tag} exists; update version!" unless `git tag -l #{tag}`.empty?
90
+ end
91
+ end
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'bud'
5
+ require 'getopt/std'
6
+ require 'bud/labeling/labeling'
7
+ require 'bud/labeling/bloomgraph'
8
+ require 'bud/labeling/budplot_style'
9
+
10
+ $LOAD_PATH.unshift(".")
11
+
12
+ @opts = Getopt::Std.getopts("r:i:p:O:CP")
13
+
14
+ unless @opts["r"] and @opts["i"]
15
+ puts "USAGE:"
16
+ puts "-r REQUIRE"
17
+ puts "-i INCLUDE"
18
+ puts "[-p INCLUDE PATH]"
19
+ puts "[-O <FMT> Output a graphviz representation of the module in FMT format (pdf if not specified)."
20
+ puts "-C Concise output -- Associate a single label with each output interface"
21
+ puts "-P Path-based output -- For each output interface, attribute a label to paths from each input interface"
22
+ exit
23
+ end
24
+
25
+ hreadable = {
26
+ "D" => "Diffluent: Nondeterministic output contents.",
27
+ "A" => "Asynchronous. Nondeterministic output orders.",
28
+ "N" => "Nonmonotonic. Output contents are sensitive to input orders.",
29
+ "Bot" => "Monotonic. Order-insensitive and retraction-free."
30
+ }
31
+
32
+ if @opts["p"]
33
+ $LOAD_PATH.unshift @opts["p"]
34
+ end
35
+
36
+ require @opts["r"]
37
+ c = Label.new(@opts["i"])
38
+
39
+ puts "--- Report for module #{@opts["i"]} ---"
40
+
41
+ if @opts["C"]
42
+ puts "---------------"
43
+ puts "Output\t\tLabel"
44
+ puts "---------------"
45
+ c.output_report.each_pair do |k, v|
46
+ puts [k, hreadable[v]].join("\t")
47
+ end
48
+ end
49
+
50
+ if @opts["P"]
51
+ c.path_report.each_pair do |output, inpaths|
52
+ puts ""
53
+ puts "--------------------"
54
+ puts "Output\tInput\tLabel"
55
+ puts "--------------------"
56
+ puts output
57
+ inpaths.each_pair do |inp, lbl|
58
+ puts "\t#{inp}\t#{hreadable[lbl]}"
59
+ end
60
+ end
61
+ end
62
+
63
+ c.write_graph(@opts["O"]) if @opts["O"]
@@ -21,6 +21,10 @@ def make_instance(mods)
21
21
  # If we're given a single identifier that names a class, just return an
22
22
  # instance of that class. Otherwise, define a bogus class that includes all
23
23
  # the module names specified by the user and return an instance.
24
+ tmpserver = TCPServer.new('127.0.0.1', 0) # get a free port
25
+ default_params = {:dbm_dir => "/tmp/budplot_dbm_" + SecureRandom.uuid.to_s, :port => tmpserver.addr[1]}
26
+
27
+
24
28
  mods.each do |m|
25
29
  unless is_constant? m
26
30
  puts "Error: unable to find definition for module or class \"#{m}\""
@@ -30,7 +34,7 @@ def make_instance(mods)
30
34
  mod_klass = eval m
31
35
  if mod_klass.class == Class
32
36
  if mods.length == 1
33
- return mod_klass.new
37
+ return mod_klass.new(default_params)
34
38
  else
35
39
  puts "Error: cannot intermix class \"#{mod_klass}\" with modules"
36
40
  exit
@@ -50,7 +54,7 @@ def make_instance(mods)
50
54
  ]
51
55
  class_def = def_lines.flatten.join("\n")
52
56
  eval(class_def)
53
- f =FooBar.new
57
+ f = FooBar.new(default_params)
54
58
  3.times{ f.tick }
55
59
  f
56
60
  end
@@ -77,8 +81,8 @@ def process(mods)
77
81
  d = make_instance(mods)
78
82
 
79
83
  interfaces = {}
80
- d.t_provides.each do |name, is_input|
81
- interfaces[name] = is_input
84
+ d.t_provides.to_a.each do |prov|
85
+ interfaces[prov.interface] = prov.input
82
86
  end
83
87
 
84
88
  tabinf = {}
@@ -201,13 +205,18 @@ def get_trace_data
201
205
  end
202
206
 
203
207
  if ARGV.length < 2
204
- puts "Usage: budplot LIST_OF_FILES LIST_OF_MODULES_OR_CLASSES"
208
+ puts "Usage: budplot [-I PATH_TO_RUBY_INCLUDES] LIST_OF_FILES LIST_OF_MODULES_OR_CLASSES"
205
209
  exit
206
210
  end
207
211
 
208
- @opts = Getopt::Std.getopts("t:")
209
-
210
-
212
+ @opts = Getopt::Std.getopts("I:t:")
213
+ unless @opts["I"].nil?
214
+ if @opts["I"].class == Array
215
+ @opts["I"].each{|i| $:.unshift i}
216
+ else
217
+ $:.unshift @opts["I"]
218
+ end
219
+ end
211
220
 
212
221
  @data = get_trace_data
213
222
  `mkdir bud_doc`
@@ -215,6 +224,7 @@ end
215
224
  modules = []
216
225
  ARGV.each do |arg|
217
226
  if File.exists? arg
227
+ arg = File.expand_path arg
218
228
  require arg
219
229
  else
220
230
  modules << arg
@@ -10,7 +10,7 @@ include VizUtil
10
10
 
11
11
  module Depends
12
12
  state do
13
- table :depends, [:rid, :lhs, :op, :rhs, :nm]
13
+ table :depends, [:bud_obj, :rid, :lhs, :op, :rhs, :nm, :in_body]
14
14
  end
15
15
  end
16
16
 
@@ -49,7 +49,7 @@ end
49
49
  module DeltaLogic
50
50
  include TPSchema
51
51
  bloom do
52
- zerod_cards <= cardinalities{|c| c + [c.bud_time-1]}
52
+ zerod_cards <= cardinalities{|c| c.to_a + [c.bud_time-1]}
53
53
  zerod_cards <= (times * depends).pairs do |t, d|
54
54
  unless cardinalities{|c| c[1] if c[0] == t.bud_time}.include? d[1]
55
55
  [t.bud_time, d[1], 0, t.bud_time - 1]
data/bin/budvis CHANGED
@@ -28,7 +28,13 @@ usage unless ARGV[0]
28
28
  usage if ARGV[0] == '--help'
29
29
 
30
30
  meta, data = get_meta2(BUD_DBM_DIR)
31
- vh = VizHelper.new(meta[:tabinf], meta[:cycle], meta[:depends], meta[:rules], ARGV[0], meta[:provides])
31
+
32
+ # prune outbufs from tabinf
33
+ tabinf = meta[:tabinf].find_all do |k|
34
+ !(k[1] == "Bud::BudChannel" and k[0] =~ /_snd\z/)
35
+ end
36
+
37
+ vh = VizHelper.new(tabinf, meta[:cycle], meta[:depends], meta[:rules], ARGV[0], meta[:provides])
32
38
  data.each do |d|
33
39
  vh.full_info << d
34
40
  end
@@ -6,28 +6,19 @@ Welcome to the documentation for *Bud*, a prototype of Bloom under development.
6
6
  The documents here are organized to be read in any order, but you might like to
7
7
  try the following:
8
8
 
9
- * [intro.md][intro]: A brief introduction to Bud and Bloom.
10
- * [getstarted.md][getstarted]: A quickstart to teach you basic Bloom
9
+ * [intro](intro.md): A brief introduction to Bud and Bloom.
10
+ * [getstarted](getstarted.md): A quickstart to teach you basic Bloom
11
11
  concepts, the use of `rebl` interactive terminal, and the embedding of Bloom
12
12
  code in Ruby via the `Bud` module.
13
- * [operational.md][operational]: An operational view of Bloom, to provide
13
+ * [operational](operational.md): An operational view of Bloom, to provide
14
14
  a more detailed model of how Bloom code is evaluated by Bud.
15
- * [cheat.md][cheat]: A concise "cheat sheet" to remind you about Bloom syntax.
16
- * [modules.md][modules]: An overview of Bloom's modularity features.
17
- * [ruby\_hooks.md][ruby_hooks]: Bud module methods that allow you to
15
+ * [cheat](cheat.md): Full documentation of the language constructs in a concise "cheat sheet" style.
16
+ * [modules](modules.md): An overview of Bloom's modularity features.
17
+ * [ruby_hooks](ruby\_hooks.md): Bud module methods that allow you to
18
18
  interact with the Bud evaluator from other Ruby threads.
19
- * [visualizations.md][visualizations]: Overview of the `budvis` and
19
+ * [visualizations](visualizations.md): Overview of the `budvis` and
20
20
  `budplot` tools for visualizing Bloom program analyses.
21
- * [bfs.md][bfs]: A walkthrough of the Bloom distributed filesystem.
22
-
23
- [intro]: /bloom-lang/bud/blob/master/docs/intro.md
24
- [getstarted]: /bloom-lang/bud/blob/master/docs/getstarted.md
25
- [operational]: /bloom-lang/bud/blob/master/docs/operational.md
26
- [cheat]: /bloom-lang/bud/blob/master/docs/cheat.md
27
- [modules]: /bloom-lang/bud/blob/master/docs/modules.md
28
- [ruby_hooks]: /bloom-lang/bud/blob/master/docs/ruby_hooks.md
29
- [visualizations]: /bloom-lang/bud/blob/master/docs/visualizations.md
30
- [bfs]: /bloom-lang/bud/blob/master/docs/bfs.md
21
+ * [bfs](bfs.md): A walkthrough of the Bloom distributed filesystem.
31
22
 
32
23
  In addition, the [bud-sandbox](http://github.com/bloom-lang/bud-sandbox) GitHub
33
24
  repository contains lots of useful libraries and example programs built using
@@ -21,15 +21,23 @@ As in Ruby, backslash is used to escape a newline.<br>
21
21
  end
22
22
 
23
23
  ## State Declarations ##
24
- A `state` block contains Bud collection definitions. A Bud collection is a *set*
25
- of *facts*; each fact is an array of Ruby values. Note that collections do not
26
- contain duplicates (inserting a duplicate fact into a collection is ignored).
24
+
25
+ A `state` block contains definitions of two kinds of program state:
26
+ *collections* and *lattices*. A Bud collection is a *set* of *facts*; each fact
27
+ is an array of Ruby values. Note that collections do not contain duplicates
28
+ (inserting a duplicate fact into a collection is ignored).
27
29
 
28
30
  Like a table in a relational database, a subset of the columns in a collection
29
31
  makeup the collection's _key_. Attempting to insert two facts into a collection
30
32
  that agree on the key columns (but are not duplicates) results in a runtime
31
33
  exception.
32
34
 
35
+ A lattice represents a value that *grows* over time, where the definition of
36
+ "growth" depends on the kind of lattice in question. For example, an `lset`
37
+ lattice contains a set of facts that grows over time (similar to a traditional
38
+ Bud collection), whereas an `lmax` lattice holds an increasing integer
39
+ value. For more information on lattices, see the section below.
40
+
33
41
  ### Default Declaration Syntax ###
34
42
  *BudCollection :name, [keys] => [values]*
35
43
 
@@ -186,7 +194,7 @@ implicit map:
186
194
  end
187
195
 
188
196
  ## BudCollection-Specific Methods ##
189
- `bc.schema`: returns the schema of `bc` (Hash of key column names => non-key column names). Note that for channels, this omits the location specifier (<tt>@</tt>).<br>
197
+ `bc.schema`: returns the schema of `bc` (Hash of key column names => non-key column names; if no non-key columns, just an Array of key column names). Note that for channels, this omits the location specifier (<tt>@</tt>).<br>
190
198
 
191
199
  `bc.cols`: returns the column names in `bc` as an Array<br>
192
200
 
@@ -224,14 +232,14 @@ Output the facts in `bc` that do not appear in `bc2`, as follows. First, we form
224
232
  :attr2`).
225
233
 
226
234
  2. If a code block is specified, invoke the block on every pair of matching
227
- tuples in the join result. Any matches for which the block returns `nil`
235
+ tuples in the join result. Any matches for which the block returns `false`
228
236
  are removed from `t`.
229
237
 
230
238
  Finally, we output every tuple of `bc` that does *not* appear in `t`.
231
239
 
232
240
  # output items from foo if (a) there is no matching key in bar, or
233
241
  # (b) all matching keys in bar have a smaller value
234
- stdio <~ foo.notin(bar, :key=>:key) {|f, b| true if f.val <= b.val}
242
+ stdio <~ foo.notin(bar, :key=>:key) {|f, b| f.val <= b.val}
235
243
 
236
244
 
237
245
  ## SQL-style grouping/aggregation (and then some) ##
@@ -239,18 +247,12 @@ Finally, we output every tuple of `bc` that does *not* appear in `t`.
239
247
  * `bc.group([:col1, :col2], min(:col3))`. *akin to min(col3) GROUP BY col1,col2*
240
248
  * exemplary aggs: `min`, `max`, `bool_and`, `bool_or`, `choose`
241
249
  * summary aggs: `sum`, `avg`, `count`
242
- * structural aggs: `accum` *accumulates inputs into a Set*
250
+ * structural aggs: `accum`, `accum_pair` *accumulates inputs into a Set; accum_pair takes two inputs and accumulates a Set of pairs (two element arrays)*
243
251
  * `bc.argmax([:attr1], :attr2)` &nbsp;&nbsp;&nbsp;&nbsp; *returns the bc items per attr1 that have highest attr2*
244
252
  * `bc.argmin([:attr1], :attr2)`
245
253
  * `bc.argagg(:exemplary_agg_name, [:attr1], :attr2))`. *generalizes argmin/max: returns the bc items per attr1 that are chosen by the exemplary
246
254
  aggregate named*
247
255
 
248
- ### Built-in Aggregates: ###
249
-
250
- * Exemplary aggs: `min`, `max`, `choose`
251
- * Summary aggs: `count`, `sum`, `avg`
252
- * Structural aggs: `accum`
253
-
254
256
  Note that custom aggregation can be written using `reduce`.
255
257
 
256
258
  ## Collection Combination (Join) ###
@@ -313,6 +315,103 @@ The schema of a temp collection in inherited from the rhs; if the rhs has no
313
315
  schema, a simple one is manufactured to suit the data found in the rhs at
314
316
  runtime: `[c0, c1, ...]`.
315
317
 
318
+ ## Lattices ##
319
+
320
+ In addition to traditional Bud collections and relational-style statements that
321
+ operate over collections, Bud also supports lattices and rules that operate over
322
+ lattices. Lattices provide a way to represent values that *grow over time*,
323
+ where the definition of "growth" depends on the kind of lattice. The following
324
+ built-in lattice types are currently supported:
325
+
326
+ <table>
327
+ <tr>
328
+ <td><b>Name</b></td>
329
+ <td><b>Description</b></td>
330
+ <td><b>Initial Value</b></td>
331
+ <td><b>Monotone Functions</b></td>
332
+ </tr>
333
+
334
+ <tr>
335
+ <td><code>lbool</code></td>
336
+ <td>Threshold test (<code>false</code> => <code>true</code> conditional)</td>
337
+ <td>false</td>
338
+ <td>when_true</td>
339
+ </tr>
340
+
341
+ <tr>
342
+ <td><code>lmax</code></td>
343
+ <td>Increasing numeric value</td>
344
+ <td>-&infin;</td>
345
+ <td>gt(n), gt_eq(n), +(n), -(n)</td>
346
+ </tr>
347
+
348
+ <tr>
349
+ <td><code>lmin</code></td>
350
+ <td>Decreasing numeric value</td>
351
+ <td>+&infin;</td>
352
+ <td>lt(n), lt_eq(n), +(n), -(n)</td>
353
+ </tr>
354
+
355
+ <tr>
356
+ <td><code>lset</code></td>
357
+ <td>Growing set of values</td>
358
+ <td>empty set</td>
359
+ <td>contains?, eqjoin, filter, intersect, product, project, size</td>
360
+ </tr>
361
+
362
+ <tr>
363
+ <td><code>lpset</code></td>
364
+ <td>Growing set of non-negative numeric values</td>
365
+ <td>empty set</td>
366
+ <td>contains?, eqjoin, filter, intersect, product, project, size, sum</td>
367
+ </tr>
368
+
369
+ <tr>
370
+ <td><code>lbag</code></td>
371
+ <td>Growing multiset of values</td>
372
+ <td>empty multiset</td>
373
+ <td>contains?, multiplicity, intersect, product, project, size</td>
374
+ </tr>
375
+
376
+ <tr>
377
+ <td><code>lmap</code></td>
378
+ <td>Map from keys to lattice values</td>
379
+ <td>empty map</td>
380
+ <td>at, intersect, key?, key_set, project, size</td>
381
+ </tr>
382
+ </table>
383
+
384
+ Lattices can be declared in `state` blocks in a similar manner to traditional
385
+ Bud collections. Similarly, Bloom rules can invoke functions on lattice
386
+ values. A simple Bloom program that uses lattices to compute a quorum vote is as
387
+ follows:
388
+
389
+ ```ruby
390
+ QUORUM_SIZE = 5
391
+ RESULT_ADDR = "example.org"
392
+
393
+ class QuorumVote
394
+ include Bud
395
+
396
+ state do
397
+ channel :vote_chn, [:@addr, :voter_id]
398
+ channel :result_chn, [:@addr]
399
+ lset :votes
400
+ lmax :vote_cnt
401
+ lbool :vote_done
402
+ end
403
+
404
+ bloom do
405
+ votes <= vote_chn {|v| v.voter_id}
406
+ vote_cnt <= votes.size
407
+ got_quorum <= vote_cnt.gt_eq(QUORUM_SIZE)
408
+ result_chn <~ got_quorum.when_true { [RESULT_ADDR] }
409
+ end
410
+ end
411
+ ```
412
+
413
+ For more information on lattice support in Bloom, see this [recent paper](http://db.cs.berkeley.edu/papers/socc12-blooml.pdf).
414
+
316
415
  ## Bud Modules ##
317
416
  A Bud module combines state (collections) and logic (Bloom rules). Using modules allows your program to be decomposed into a collection of smaller units.
318
417