mll 0.4.0 → 1.1.0
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.
- checksums.yaml +4 -4
- data/README.md +100 -29
- data/Rakefile +29 -2
- data/lib/mll.rb +77 -63
- data/mll.gemspec +1 -1
- data/spec/_spec.rb +347 -223
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 812325964160837ba11226c5585e372463dd9fd7
|
4
|
+
data.tar.gz: fb060b7f5a405a230b21a20c9cc8426e5bd7e19b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5fe15ad50531a0b9740847b01c27ed76e598d0345a0158b22474715a7fbb8bc917479c406ef1cac3580b167dd19b30bca820665888792657e8be6bc2a1f67b81
|
7
|
+
data.tar.gz: dd3547ff6b62c5ecd29d91529aee42e1552cb0d90bde926e7d8e090cdcf1df7ca1792aa110835a82133127f2f33d2c56a6421ab2ca56e778acbead64537c7380
|
data/README.md
CHANGED
@@ -2,39 +2,62 @@
|
|
2
2
|
|
3
3
|
## What
|
4
4
|
|
5
|
-
|
5
|
+
This gem isn't supposed to mimic all data types, exact syntax of Wolfram Mathematica or make Ruby able to make the same visualisations.
|
6
|
+
|
7
|
+
The main goal is to make Ruby more powerful by including the most used functions, that Ruby lacks, such as `Table[]`, `FoldList[]`, etc. Visualisations are possible later by using additional gems.
|
6
8
|
|
7
9
|
## Why
|
8
10
|
|
9
|
-
1.
|
10
|
-
2. `::range
|
11
|
-
3.
|
11
|
+
1. One of the most useful things is automatic zipping vectors (`Array`s) when you apply scalar functions to them. https://reference.wolfram.com/language/ref/Listable.html
|
12
|
+
2. unlike Ruby's `Range` class, `::range` can handle negative `step` and even have `float` starting value
|
13
|
+
3. unlike Ruby's `Array#map`, `::table` can create multidimensional arrays with a single call, not nested
|
14
|
+
4. `#fold_list` was wanted [here](http://stackoverflow.com/q/1475808/322020) in Ruby while being already implemented as [FoldList[]](http://reference.wolfram.com/language/ref/FoldList.html) in Mathematica and [scanl](http://hackage.haskell.org/package/base-4.8.0.0/docs/Prelude.html#v:scanl) in Haskell
|
15
|
+
5. `#nest` (n times) and `#nest_list` for repetitive applying the same function -- `#nest_while` and `#nest_while_list` are going to be implemented later
|
12
16
|
|
13
17
|
## How
|
14
18
|
|
15
|
-
MLL::range
|
16
|
-
MLL::range
|
17
|
-
MLL::range
|
18
|
-
|
19
|
-
MLL::table ->(i,j){ i+j }, [[1, 0, 1]], [[0, 2, 0]]
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
MLL::table
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
19
|
+
MLL::range[ 2, 3 ] # => 2..3
|
20
|
+
MLL::range[[2, 3]] # => [1..2, 1..3]
|
21
|
+
MLL::range[ 1..3 ] # => [1..1, 1..2, 1..3]
|
22
|
+
|
23
|
+
MLL::table[ ->(i,j){ i+j }, [[1, 0, 1]], [[0, 2, 0]] ]
|
24
|
+
# => [[1, 3, 1],
|
25
|
+
[0, 2, 0],
|
26
|
+
[1, 3, 1]]
|
27
|
+
MLL::table[ MLL.method(:times), 9, 9 ]
|
28
|
+
# => [[1, 2, 3, 4, 5, 6, 7, 8, 9],
|
29
|
+
[2, 4, 6, 8, 10, 12, 14, 16, 18],
|
30
|
+
[3, 6, 9, 12, 15, 18, 21, 24, 27],
|
31
|
+
[4, 8, 12, 16, 20, 24, 28, 32, 36],
|
32
|
+
[5, 10, 15, 20, 25, 30, 35, 40, 45],
|
33
|
+
[6, 12, 18, 24, 30, 36, 42, 48, 54],
|
34
|
+
[7, 14, 21, 28, 35, 42, 49, 56, 63],
|
35
|
+
[8, 16, 24, 32, 40, 48, 56, 64, 72],
|
36
|
+
[9, 18, 27, 36, 45, 54, 63, 72, 81]]
|
37
|
+
|
38
|
+
MLL::fold_list[ MLL::times, MLL::range[10] ]
|
39
|
+
# => [1,2,6,24,120,720,5040,40320,362880,3628800]
|
40
|
+
|
41
|
+
# here is `Listable' magic, allowing to zip arrays
|
42
|
+
# even of different dimensions with basic operations
|
43
|
+
MLL::times[ [[1,2],[3,4]], [5,6] ]
|
44
|
+
# => [[5,10], [18,24]]
|
45
|
+
# ::times means *
|
46
|
+
# ::divide means /
|
47
|
+
# ::subtract means -
|
48
|
+
# ::plus means +
|
49
|
+
|
50
|
+
# http://en.wikipedia.org/wiki/Collatz_conjecture
|
51
|
+
MLL::nest_list[ ->(i){ i.even? ? i/2 : (i*3+1)/2 }, 20, 10 ]
|
52
|
+
# => [20, 10, 5, 8, 4, 2, 1, 2, 1, 2, 1]
|
53
|
+
|
54
|
+
MLL::fold_list[ ->(a,b){ 10*a + b }, 0, [4,5,1,6,7,8] ]
|
55
|
+
# => [0,4,45,451,4516,45167,451678]
|
56
|
+
|
57
|
+
MLL::subdivide[ 5, 10, 4 ]
|
58
|
+
# => [5.0, 6.25, 7.5, 8.75, 10.0]
|
59
|
+
|
60
|
+
Note that to see some of above examples working you need `.to_a`, `.map(&:to_a)` or even `.to_a.map(&:to_a)` since lazyness is intensively used.
|
38
61
|
|
39
62
|
## Installation
|
40
63
|
|
@@ -46,5 +69,53 @@
|
|
46
69
|
|
47
70
|
or
|
48
71
|
|
49
|
-
rake
|
50
|
-
|
72
|
+
rake spec
|
73
|
+
|
74
|
+
## TODO (this section is filled automatically by `rake todo` task -- do not remove)
|
75
|
+
|
76
|
+
#### lib/mll.rb
|
77
|
+
|
78
|
+
```
|
79
|
+
module MLL
|
80
|
+
def self.fold_list
|
81
|
+
lambda do |f, x, list = nil|
|
82
|
+
# TODO use Ruby#inject ?
|
83
|
+
def self.table
|
84
|
+
lambda do |f, *args|
|
85
|
+
[].tap do |result|
|
86
|
+
}]].tap do |stack|
|
87
|
+
stack.each do |ai, ri|
|
88
|
+
# TODO try to make #table lazy (Enumerator instead of Array)
|
89
|
+
# TODO not sure if we need any other kind of Listability except of #range[[Array]]
|
90
|
+
```
|
91
|
+
|
92
|
+
#### spec/_spec.rb
|
93
|
+
|
94
|
+
```
|
95
|
+
# TODO move Properties & Relations to some separate contexts maybe
|
96
|
+
# TODO @fraggedICE wishes using Rational -- would also allow implementing more examples
|
97
|
+
# TODO elegantly get rid of repetitive type checks
|
98
|
+
# TODO ? let(:fake_lambda){ ->(*args){fail} }
|
99
|
+
describe MLL do
|
100
|
+
describe "List Manipulation" do
|
101
|
+
describe "Constructing Lists" do
|
102
|
+
describe "#table" do
|
103
|
+
describe "Scope" do
|
104
|
+
# TODO: "Make a triangular array:"
|
105
|
+
describe "#range" do
|
106
|
+
# TODO take from docs more examples that involve other functions
|
107
|
+
describe "Applying Functions to Lists" do
|
108
|
+
describe "#fold_list" do
|
109
|
+
describe "Applications" do
|
110
|
+
# TODO maybe move it to README.md
|
111
|
+
# TODO http://reference.wolfram.com/language/guide/ElementsOfLists.html
|
112
|
+
# TODO http://reference.wolfram.com/language/guide/RearrangingAndRestructuringLists.html
|
113
|
+
# TODO http://reference.wolfram.com/language/guide/MathematicalAndCountingOperationsOnLists.html
|
114
|
+
describe "Functional Programming" do
|
115
|
+
describe "Iteratively Applying Functions" do
|
116
|
+
# TODO move #nest_list and #fold_list and others here?
|
117
|
+
describe "#nest" do
|
118
|
+
# TODO neat graphic examples
|
119
|
+
# TODO http://reference.wolfram.com/language/guide/HandlingArraysOfData.html
|
120
|
+
# TODO http://reference.wolfram.com/language/guide/ComputationWithStructuredDatasets.html
|
121
|
+
```
|
data/Rakefile
CHANGED
@@ -1,9 +1,36 @@
|
|
1
1
|
require "bundler/gem_tasks"
|
2
2
|
require "rspec/core/rake_task"
|
3
3
|
|
4
|
+
desc "Append TODO-list to README.md"
|
5
|
+
task :todo do |t|
|
6
|
+
fail unless File.exist? "README.md"
|
7
|
+
File.open("README.md", "r+") do |readme_file|
|
8
|
+
# begin readme_file.gets end until $_[/^## TODO/]
|
9
|
+
readme_file.gets "## TODO"
|
10
|
+
readme_file.gets
|
11
|
+
%w{ lib/mll.rb spec/_spec.rb }.each do |file|
|
12
|
+
readme_file.puts "", "#### #{file}", "", "```"
|
13
|
+
stack = []
|
14
|
+
lines = []
|
15
|
+
File.foreach(file).with_index do |line, i|
|
16
|
+
next unless shift = /\S/ =~ line
|
17
|
+
depth = shift / 2
|
18
|
+
stack[depth] = i
|
19
|
+
lines |= stack.take(depth + 1) if line[/^\s*# TODO/]
|
20
|
+
end
|
21
|
+
next_line_to_print = lines.shift
|
22
|
+
File.foreach(file).with_index do |line, i|
|
23
|
+
next unless i == next_line_to_print
|
24
|
+
readme_file.puts line
|
25
|
+
next_line_to_print = lines.shift
|
26
|
+
end
|
27
|
+
readme_file.puts "```"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
4
32
|
RSpec::Core::RakeTask.new(:spec) do |t|
|
5
33
|
t.verbose = false
|
6
34
|
end
|
7
35
|
|
8
|
-
task :default =>
|
9
|
-
|
36
|
+
task :default => %w{ todo spec }
|
data/lib/mll.rb
CHANGED
@@ -1,74 +1,83 @@
|
|
1
1
|
module MLL
|
2
2
|
|
3
|
-
def self.nest_list
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
3
|
+
def self.nest_list
|
4
|
+
lambda do |f, expr, n|
|
5
|
+
Enumerator.new do |e|
|
6
|
+
e << expr
|
7
|
+
n.times do
|
8
|
+
e << expr = f.call(expr)
|
9
|
+
end
|
8
10
|
end
|
9
11
|
end
|
10
12
|
end
|
11
13
|
# def self.nest *args
|
12
14
|
# nest_list(*args).last
|
13
15
|
# end
|
14
|
-
def self.nest
|
15
|
-
|
16
|
-
|
16
|
+
def self.nest
|
17
|
+
lambda do |f, expr, n|
|
18
|
+
n.times{ expr = f.call expr }
|
19
|
+
expr
|
20
|
+
end
|
17
21
|
end
|
18
22
|
|
19
|
-
def self.fold_list
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
23
|
+
def self.fold_list
|
24
|
+
lambda do |f, x, list = nil|
|
25
|
+
x, *list = x.to_a unless list
|
26
|
+
# TODO use Ruby#inject ?
|
27
|
+
Enumerator.new do |e|
|
28
|
+
e << x
|
29
|
+
list.each do |i|
|
30
|
+
e << x = f.call(x, i)
|
31
|
+
end
|
27
32
|
end
|
28
33
|
end
|
29
34
|
end
|
30
35
|
|
31
|
-
def self.table
|
32
|
-
|
33
|
-
[
|
34
|
-
|
35
|
-
r.
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
36
|
+
def self.table
|
37
|
+
lambda do |f, *args|
|
38
|
+
[].tap do |result|
|
39
|
+
[[result, args.map{ |r| # add lazy?
|
40
|
+
r.respond_to?(:map) && r.first.respond_to?(:map) ?
|
41
|
+
r.first : range[*r]
|
42
|
+
}]].tap do |stack|
|
43
|
+
stack.each do |ai, ri|
|
44
|
+
# TODO try to make #table lazy (Enumerator instead of Array)
|
45
|
+
# "no implicit conversion of Enumerator::Lazy into Array"
|
46
|
+
# "undefined method `replace' for #<Enumerator::Lazy: []>"
|
47
|
+
ai.replace ri.first.map{ |i|
|
48
|
+
if ri.size == 1
|
49
|
+
f.call(*ai, i)
|
50
|
+
else
|
51
|
+
[*ai.dup, i].tap{ |t| stack << [t, ri.drop(1)] }
|
52
|
+
end
|
53
|
+
}
|
54
|
+
end
|
48
55
|
end
|
49
56
|
end
|
50
57
|
end
|
51
58
|
end
|
52
59
|
|
53
|
-
# http://reference.wolfram.com/language/ref/Listable.html
|
54
60
|
def self.define_listable_function name, &block
|
55
|
-
(class << self; self end).class_eval do
|
56
|
-
define_method name do
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
61
|
+
(class << self; self end).class_eval do
|
62
|
+
define_method name do
|
63
|
+
lambda do |*args|
|
64
|
+
case args.map{ |i| i.respond_to? :map }
|
65
|
+
when [true] ; args.first.lazy.map &method(name).call
|
66
|
+
when [true, true] ; args.first.lazy.zip(args.last).map{ |i, j| send(name)[i, j] }
|
67
|
+
when [true, false] ; args.first.lazy.map{ |i| send(name)[i, args.last] }
|
68
|
+
when [false, true] ; args.last.lazy.map{ |i| send(name)[args.first, i] }
|
69
|
+
else
|
70
|
+
block.call *args
|
71
|
+
end
|
64
72
|
end
|
65
73
|
end
|
66
74
|
end
|
67
75
|
end
|
68
76
|
|
77
|
+
# TODO not sure if we need any other kind of Listability except of #range[[Array]]
|
69
78
|
define_listable_function :range do |*args|
|
70
79
|
case args.size
|
71
|
-
when 1 ; range
|
80
|
+
when 1 ; range[1, args[0]] # TODO do smth with #table(-n)
|
72
81
|
when 2 ; Range.new(args[0], args[1]).step
|
73
82
|
when 3
|
74
83
|
case args[2] <=> 0
|
@@ -89,34 +98,39 @@ module MLL
|
|
89
98
|
end
|
90
99
|
end
|
91
100
|
|
92
|
-
define_listable_function
|
93
|
-
define_listable_function
|
94
|
-
define_listable_function
|
95
|
-
define_listable_function
|
101
|
+
define_listable_function(:subtract) { |*args| raise ArgumentError.new("need two arguments") unless args.size == 2 ; args[0] - args[1] }
|
102
|
+
define_listable_function(:divide) { |*args| raise ArgumentError.new("need two arguments") unless args.size == 2 ; args[0] / args[1] }
|
103
|
+
define_listable_function(:_plus) { |*args| raise ArgumentError.new("need two arguments") unless args.size == 2 ; args[0] + args[1] }
|
104
|
+
define_listable_function(:_times) { |*args| raise ArgumentError.new("need two arguments") unless args.size == 2 ; args[0] * args[1] }
|
105
|
+
# define_listable_function (:power) { |*args| raise ArgumentError.new("need two arguments") unless args.size == 2 ; args[0] ** args[1] }
|
96
106
|
|
97
107
|
# http://reference.wolfram.com/language/ref/Orderless.html
|
98
|
-
def self.define_orderless_function name, &block
|
108
|
+
def self.define_orderless_function name, start, &block
|
99
109
|
(class << self; self end).class_eval do # http://stackoverflow.com/a/12792313/322020
|
100
|
-
define_method name do
|
101
|
-
|
102
|
-
|
110
|
+
define_method name do
|
111
|
+
lambda do |*args|
|
112
|
+
args.inject(start) do |memo, obj|
|
113
|
+
block.call memo, obj
|
114
|
+
end
|
103
115
|
end
|
104
116
|
end
|
105
117
|
end
|
106
118
|
end
|
107
119
|
|
108
|
-
define_orderless_function
|
109
|
-
define_orderless_function
|
120
|
+
define_orderless_function(:plus, 0) { |a, b| _plus.call a, b }
|
121
|
+
define_orderless_function(:times, 1) { |a, b| _times.call a, b }
|
110
122
|
|
111
|
-
def self.subdivide
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
123
|
+
def self.subdivide
|
124
|
+
lambda do |*args|
|
125
|
+
case args.size
|
126
|
+
when 1 ; subdivide[1, args[0]]
|
127
|
+
when 2 ; subdivide[0, args[0], args[1]]
|
128
|
+
when 3
|
129
|
+
# raise ArgumentError.new("can't divide into 0 parts") if args[2].zero?
|
130
|
+
range[args[0], args[1], (args[1] - args[0]) * 1.0 / args[2]]
|
131
|
+
else
|
132
|
+
raise ArgumentError.new("wrong number of arguments (#{args.size} for 1..3)")
|
133
|
+
end
|
120
134
|
end
|
121
135
|
end
|
122
136
|
|
data/mll.gemspec
CHANGED
data/spec/_spec.rb
CHANGED
@@ -5,26 +5,23 @@ require_relative File.join "..", "lib", "mll"
|
|
5
5
|
# PERMATODO test all types returned (not actually all but about lazyness)
|
6
6
|
# PERMATODO check for "Details" paragraphs to make more trivial examples
|
7
7
|
# PERMATODO leave here only useful tests, not demostrations -- move them to README.rb
|
8
|
-
# PERMATODO
|
8
|
+
# PERMATODO polymorphic functions should have ArgumentError-s and tests about that
|
9
9
|
# PERMATODO move Properties & Relations to some separate contexts maybe
|
10
10
|
|
11
|
-
# TODO test all implemented exceptions
|
12
|
-
# TODO test all types returned (not actually all but about lazyness)
|
13
|
-
# TODO check for "Details" paragraphs to make more trivial examples
|
14
|
-
# TODO leave here only useful tests, not demostrations -- move them to README.rb
|
15
|
-
# TODO single element Arrays tests
|
16
11
|
# TODO move Properties & Relations to some separate contexts maybe
|
17
12
|
|
18
13
|
# TODO @fraggedICE wishes using Rational -- would also allow implementing more examples
|
19
|
-
# TODO rake task for appending TODOs and pendings to README.rb
|
20
|
-
# TODO rename examples according to their description not content
|
21
14
|
# TODO elegantly get rid of repetitive type checks
|
22
|
-
# TODO
|
23
|
-
|
15
|
+
# TODO ? let(:fake_lambda){ ->(*args){fail} }
|
16
|
+
|
24
17
|
|
25
18
|
# http://reference.wolfram.com/language/guide/LanguageOverview.html
|
26
19
|
describe MLL do
|
27
20
|
|
21
|
+
def method_missing *args
|
22
|
+
described_class.send *args
|
23
|
+
end
|
24
|
+
|
28
25
|
# http://reference.wolfram.com/language/guide/Syntax.html
|
29
26
|
describe "Syntax" do
|
30
27
|
|
@@ -34,19 +31,38 @@ describe MLL do
|
|
34
31
|
# http://reference.wolfram.com/language/ref/Subtract.html
|
35
32
|
describe "#subtract" do
|
36
33
|
|
34
|
+
example "less than 2 args raise ArgumentError" do
|
35
|
+
expect{ subtract[0 ] }.to raise_error ArgumentError
|
36
|
+
end
|
37
|
+
example "more than 2 args raise ArgumentError" do
|
38
|
+
expect{ subtract[0,0,0] }.to raise_error ArgumentError
|
39
|
+
end
|
40
|
+
|
37
41
|
describe "Basic Examples" do
|
38
42
|
|
39
|
-
example "subtract
|
40
|
-
expect(
|
43
|
+
example "subtract numbers" do
|
44
|
+
expect(subtract[10,3]).to eq 7
|
41
45
|
end
|
42
46
|
|
43
47
|
end
|
44
48
|
|
45
49
|
describe "Scope" do
|
46
50
|
|
47
|
-
example "
|
48
|
-
expect(
|
49
|
-
expect(
|
51
|
+
example "threads element‐wise over lists" do
|
52
|
+
expect(subtract[[1,2,3,4],0.5]).to be_a Enumerator
|
53
|
+
expect(subtract[[1,2,3,4],0.5].to_a).to eq [0.5,1.5,2.5,3.5]
|
54
|
+
expect(subtract[6,[3,2]]).to be_a Enumerator
|
55
|
+
expect(subtract[6,[3,2]].to_a).to eq [3,4]
|
56
|
+
expect(subtract[[[1,2],[3,4]],1]).to be_a Enumerator
|
57
|
+
expect(subtract[[[1,2],[3,4]],1].to_a.map(&:to_a)).to eq [[0,1],[2,3]]
|
58
|
+
expect(subtract[[3,4],[2,1]]).to be_a Enumerator
|
59
|
+
expect(subtract[[3,4],[2,1]].to_a).to eq [1,3]
|
60
|
+
expect(subtract[[[1,3],[2,4]],[1,2]]).to be_a Enumerator
|
61
|
+
expect(subtract[[[1,3],[2,4]],[1,2]].to_a.map(&:to_a)).to eq [[0,2],[0,2]]
|
62
|
+
end
|
63
|
+
example "matrices subtract element-wise" do
|
64
|
+
expect(subtract[[[5,6],[7,8]],[[4,3],[2,1]]]).to be_a Enumerator
|
65
|
+
expect(subtract[[[5,6],[7,8]],[[4,3],[2,1]]].to_a.map(&:to_a)).to eq [[1,3],[5,7]]
|
50
66
|
end
|
51
67
|
|
52
68
|
end
|
@@ -56,110 +72,151 @@ describe MLL do
|
|
56
72
|
# http://reference.wolfram.com/language/ref/Divide.html
|
57
73
|
describe "#divide" do
|
58
74
|
|
75
|
+
example "less than 2 args raise ArgumentError" do
|
76
|
+
expect{ divide[0 ] }.to raise_error ArgumentError
|
77
|
+
end
|
78
|
+
example "more than 2 args raise ArgumentError" do
|
79
|
+
expect{ divide[0,0,0] }.to raise_error ArgumentError
|
80
|
+
end
|
81
|
+
|
59
82
|
describe "Basic Examples" do
|
60
83
|
|
61
|
-
example "divide
|
62
|
-
|
63
|
-
expect(MLL::divide(77,11)).to eq 7
|
84
|
+
example "divide numbers" do
|
85
|
+
expect(divide[77,11]).to eq 7
|
64
86
|
end
|
65
87
|
|
66
88
|
end
|
67
89
|
|
68
90
|
describe "Scope" do
|
69
91
|
|
70
|
-
example "
|
71
|
-
expect(
|
72
|
-
expect(
|
92
|
+
example "threads element‐wise over lists" do
|
93
|
+
expect(divide[[2,3,4,5],2.0]).to be_a Enumerator
|
94
|
+
expect(divide[[2,3,4,5],2.0].to_a).to eq [1,1.5,2,2.5]
|
95
|
+
expect(divide[6,[3,2]]).to be_a Enumerator
|
96
|
+
expect(divide[6,[3,2]].to_a).to eq [2,3]
|
97
|
+
expect(divide[[[4,2],[6,8]],2]).to be_a Enumerator
|
98
|
+
expect(divide[[[4,2],[6,8]],2].to_a.map(&:to_a)).to eq [[2,1],[3,4]]
|
99
|
+
expect(divide[[2,3,4],[2,1,4]]).to be_a Enumerator
|
100
|
+
expect(divide[[2,3,4],[2,1,4]].to_a).to eq [1,3,1]
|
101
|
+
expect(divide[[[1,3],[2,4]],[1,2]]).to be_a Enumerator
|
102
|
+
expect(divide[[[1,3],[2,4]],[1,2]].to_a.map(&:to_a)).to eq [[1,3],[1,2]]
|
73
103
|
end
|
74
|
-
example "divide
|
75
|
-
expect(
|
76
|
-
expect(
|
104
|
+
example "matrices divide element-wise" do
|
105
|
+
expect(divide[[[5,8],[9,8]],[[1,2],[3,4]]]).to be_a Enumerator
|
106
|
+
expect(divide[[[5,8],[9,8]],[[1,2],[3,4]]].to_a.map(&:to_a)).to eq [[5,4],[3,2]]
|
77
107
|
end
|
78
108
|
|
79
109
|
end
|
80
110
|
|
81
111
|
describe "Applications" do
|
82
112
|
|
83
|
-
|
84
|
-
|
85
|
-
end
|
86
|
-
|
87
|
-
describe "Neat Examples" do
|
88
|
-
|
89
|
-
example "nest_list(lambda_with_divide), n" do
|
90
|
-
pending "#nestlist is yet to be implemented"
|
91
|
-
fail
|
92
|
-
end
|
93
|
-
example "table(function, n1, n2)" do
|
94
|
-
expect(MLL::table(MLL.method(:divide), [[3,6]], 4.0)).to be_a Array
|
95
|
-
expect(MLL::table(MLL.method(:divide), [[6]], 4.0)).to eq [[6.0,3.0,2.0,1.5]]
|
113
|
+
example "successive ratios in a list" do
|
114
|
+
skip "waiting for Rationals to be used"
|
96
115
|
end
|
97
116
|
|
98
117
|
end
|
99
118
|
|
100
119
|
end
|
101
120
|
|
102
|
-
# TODO common tests for threading functions like times, plus, etc.
|
103
|
-
|
104
121
|
# http://reference.wolfram.com/language/ref/Plus.html
|
105
122
|
describe "#plus" do
|
106
123
|
|
107
|
-
describe "
|
124
|
+
describe "Details" do
|
108
125
|
|
109
|
-
example "plus
|
110
|
-
expect(
|
126
|
+
example "#plus[] is taken to be 0" do
|
127
|
+
expect(plus[]).to eq 0
|
111
128
|
end
|
112
|
-
example "plus
|
113
|
-
expect(
|
114
|
-
expect(MLL::plus([3,4,5],2).to_a).to eq [5,6,7]
|
129
|
+
example "#plus[x] is x" do
|
130
|
+
expect(plus[5]).to eq 5
|
115
131
|
end
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
expect(
|
132
|
+
|
133
|
+
end
|
134
|
+
|
135
|
+
describe "Basic Examples" do
|
136
|
+
|
137
|
+
example "sums numbers" do
|
138
|
+
expect(plus[2,3,4]).to eq 9
|
123
139
|
end
|
124
|
-
example "
|
125
|
-
|
126
|
-
expect(
|
140
|
+
example "threads element‐wise over lists" do
|
141
|
+
# idk why not in Scope
|
142
|
+
expect(plus[[3,4,5],2]).to be_a Enumerator
|
143
|
+
expect(plus[[3,4,5],2].to_a).to eq [5,6,7]
|
144
|
+
expect(plus[2,3,[4,5]]).to be_a Enumerator
|
145
|
+
expect(plus[2,3,[4,5]].to_a).to eq [9,10]
|
146
|
+
expect(plus[[[1,2],[3,4]],[5,6]]).to be_a Enumerator
|
147
|
+
expect(plus[[[1,2],[3,4]],[5,6]].to_a.map(&:to_a)).to eq [[6,7],[9,10]]
|
127
148
|
end
|
128
|
-
|
129
|
-
|
130
|
-
|
149
|
+
|
150
|
+
end
|
151
|
+
|
152
|
+
describe "Scope" do
|
153
|
+
|
154
|
+
example "threads element‐wise over lists" do
|
155
|
+
expect(plus[[10,20,30],[1,2,3]]).to be_a Enumerator
|
156
|
+
expect(plus[[10,20,30],[1,2,3]].to_a).to eq [11,22,33]
|
157
|
+
expect(plus[[[1,2],[3,4]],5]).to be_a Enumerator
|
158
|
+
expect(plus[[[1,2],[3,4]],5].to_a.map(&:to_a)).to eq [[6,7],[8,9]]
|
131
159
|
end
|
132
|
-
example "
|
133
|
-
expect(
|
134
|
-
expect(
|
160
|
+
example "matrices add element-wise" do
|
161
|
+
expect(plus[[[1,2],[3,4]],[[5,6],[7,8]]]).to be_a Enumerator
|
162
|
+
expect(plus[[[1,2],[3,4]],[[5,6],[7,8]]].to_a.map(&:to_a)).to eq [[6,8],[10,12]]
|
135
163
|
end
|
136
164
|
|
137
165
|
end
|
138
166
|
|
139
|
-
|
167
|
+
describe "Possible Issues" do
|
168
|
+
|
169
|
+
# idk why not in 'Properties & Relations'
|
170
|
+
example "accumulate makes a cumulative sum" do
|
171
|
+
expect(fold_list[plus, 0, [1,2,3]]).to be_a Enumerator
|
172
|
+
expect(fold_list[plus, 0, [1,2,3]].to_a).to eq [0,1,3,6]
|
173
|
+
end
|
174
|
+
|
175
|
+
end
|
140
176
|
|
141
177
|
end
|
142
178
|
|
143
179
|
# http://reference.wolfram.com/language/ref/Times.html
|
144
180
|
describe "#times" do
|
145
181
|
|
182
|
+
describe "Details" do
|
183
|
+
|
184
|
+
example "#times[] is taken to be 1" do
|
185
|
+
expect(times[]).to eq 1
|
186
|
+
end
|
187
|
+
example "#times[x] is x" do
|
188
|
+
expect(times[5]).to eq 5
|
189
|
+
end
|
190
|
+
|
191
|
+
end
|
192
|
+
|
146
193
|
describe "Basic Examples" do
|
147
194
|
|
148
|
-
example "
|
149
|
-
|
150
|
-
expect(MLL::times(2,3,4)).to eq 24
|
195
|
+
example "multiplies numbers" do
|
196
|
+
expect(times[2,3,4]).to eq 24
|
151
197
|
end
|
152
|
-
example "
|
153
|
-
expect(
|
154
|
-
expect(
|
198
|
+
example "threads element‐wise over lists" do
|
199
|
+
expect(times[[3,4,5],2]).to be_a Enumerator
|
200
|
+
expect(times[[3,4,5],2].to_a).to eq [6,8,10]
|
201
|
+
expect(times[2,3,[4,5]]).to be_a Enumerator
|
202
|
+
expect(times[2,3,[4,5]].to_a).to eq [24,30]
|
203
|
+
expect(times[[[1,2],[3,4]],[5,6]]).to be_a Enumerator
|
204
|
+
expect(times[[[1,2],[3,4]],[5,6]].to_a.map(&:to_a)).to eq [[5,10],[18,24]]
|
155
205
|
end
|
156
|
-
|
157
|
-
|
158
|
-
|
206
|
+
|
207
|
+
end
|
208
|
+
|
209
|
+
describe "Scope" do
|
210
|
+
|
211
|
+
example "threads element‐wise over lists" do
|
212
|
+
expect(times[[2,3],[4,5]]).to be_a Enumerator
|
213
|
+
expect(times[[2,3],[4,5]].to_a).to eq [8,15]
|
214
|
+
expect(times[[[1,2],[3,4]],5]).to be_a Enumerator
|
215
|
+
expect(times[[[1,2],[3,4]],5].to_a.map(&:to_a)).to eq [[5,10],[15,20]]
|
159
216
|
end
|
160
|
-
example "
|
161
|
-
expect(
|
162
|
-
expect(
|
217
|
+
example "matrices multiply element-wise" do
|
218
|
+
expect(times[[[4,3],[2,1]],[[5,6],[7,8]]]).to be_a Enumerator
|
219
|
+
expect(times[[[4,3],[2,1]],[[5,6],[7,8]]].to_a.map(&:to_a)).to eq [[20,18],[14,8]]
|
163
220
|
end
|
164
221
|
|
165
222
|
end
|
@@ -179,48 +236,50 @@ describe MLL do
|
|
179
236
|
# http://reference.wolfram.com/language/ref/Table.html
|
180
237
|
describe "#table" do
|
181
238
|
|
182
|
-
describe "
|
239
|
+
describe "Details" do
|
183
240
|
|
184
|
-
example "table
|
185
|
-
expect(
|
186
|
-
expect(MLL::table(->(i){ i**2 }, 10)).to eq [1,4,9,16,25,36,49,64,81,100]
|
241
|
+
example "#table[expr,spec1,spec2] is effectively equivalent to #table[#table[expr,spec2],spec1]" do
|
242
|
+
expect(table[->(i,j){ [i,j] }, 2, 3]).to eq table[->(i){ table[->(j){ [i,j] }, 3] }, 2]
|
187
243
|
end
|
188
|
-
|
189
|
-
|
190
|
-
|
244
|
+
|
245
|
+
end
|
246
|
+
|
247
|
+
describe "Basic Examples" do
|
248
|
+
|
249
|
+
example "a table of the first 10 squares" do
|
250
|
+
expect(table[->(i){ i**2 }, 10]).to be_a Array
|
251
|
+
expect(table[->(i){ i**2 }, 10]).to eq [1,4,9,16,25,36,49,64,81,100]
|
191
252
|
end
|
192
|
-
example "table
|
193
|
-
|
194
|
-
expect(
|
195
|
-
expect(MLL::table(->(i,j){ 10*i + j }, 4, 3)).to eq [[11,12,13],[21,22,23],[31,32,33],[41,42,43]]
|
253
|
+
example "a table with running from 0 to 20 in steps of 2" do
|
254
|
+
expect(table[->(i){ i+2 }, [0, 20, 2]]).to be_a Array
|
255
|
+
expect(table[->(i){ i+2 }, [0, 20, 2]]).to eq [2,4,6,8,10,12,14,16,18,20,22]
|
196
256
|
end
|
197
|
-
example "
|
198
|
-
expect(
|
199
|
-
expect(
|
200
|
-
[
|
201
|
-
[[[1, 2, 5], [1, 2, 3], [1, 2, 1]], [[1, 3, 5], [1, 3, 3], [1, 3, 1]]],
|
202
|
-
[[[2, 2, 5], [2, 2, 3], [2, 2, 1]], [[2, 3, 5], [2, 3, 3], [2, 3, 1]]],
|
203
|
-
[[[3, 2, 5], [3, 2, 3], [3, 2, 1]], [[3, 3, 5], [3, 3, 3], [3, 3, 1]]]
|
204
|
-
]
|
257
|
+
example "make a 4×3 matrix" do
|
258
|
+
expect(table[->(i,j){ 10*i + j }, 4, 3]).to be_a Array
|
259
|
+
expect(table[->(i,j){ 10*i + j }, 4, 3]).to eq [[11,12,13],[21,22,23],[31,32,33],[41,42,43]]
|
205
260
|
end
|
206
261
|
|
207
|
-
|
208
|
-
pending "#matrix_form is yet to be implemented"
|
209
|
-
expect(MLL::matrix_form MLL::table(->(i,j){ 10*i + j }, 4, 3)).to eq "
|
210
|
-
"
|
211
|
-
end
|
262
|
+
end
|
212
263
|
|
264
|
+
example "table(lambda, n1, min..max, [max, min, -step])" do
|
265
|
+
expect(table[->(i,j,k){ [i,j,k] }, 3, 2..3, [5, 1, -2]]).to be_a Array
|
266
|
+
expect(table[->(i,j,k){ [i,j,k] }, 3, 2..3, [5, 1, -2]]).to eq \
|
267
|
+
[
|
268
|
+
[[[1, 2, 5], [1, 2, 3], [1, 2, 1]], [[1, 3, 5], [1, 3, 3], [1, 3, 1]]],
|
269
|
+
[[[2, 2, 5], [2, 2, 3], [2, 2, 1]], [[2, 3, 5], [2, 3, 3], [2, 3, 1]]],
|
270
|
+
[[[3, 2, 5], [3, 2, 3], [3, 2, 1]], [[3, 3, 5], [3, 3, 3], [3, 3, 1]]]
|
271
|
+
]
|
213
272
|
end
|
214
273
|
|
215
274
|
describe "Scope" do
|
216
275
|
|
217
276
|
# TODO: "Make a triangular array:"
|
218
277
|
|
219
|
-
example "
|
220
|
-
expect(
|
221
|
-
expect(
|
222
|
-
expect(
|
223
|
-
expect(
|
278
|
+
example "make an array from existing lists" do
|
279
|
+
expect(table[->(base, power){ base ** power }, [[1,2,4]], [[1,3,4]]]).to be_a Array
|
280
|
+
expect(table[->(base, power){ base ** power }, [[1,2,4]], [[1,3,4]]]).to eq [[1,1,1],[2,8,16],[4,64,256]]
|
281
|
+
expect(table[plus, [[1]], [[2]]]).to be_a Array
|
282
|
+
expect(table[plus, [[1]], [[2]]]).to eq [[3]]
|
224
283
|
end
|
225
284
|
|
226
285
|
end
|
@@ -228,8 +287,7 @@ describe MLL do
|
|
228
287
|
describe "Applications" do
|
229
288
|
|
230
289
|
example "column table(binomial, )" do
|
231
|
-
|
232
|
-
fail
|
290
|
+
skip "#binomial and #column are yet to be implemented"
|
233
291
|
end
|
234
292
|
|
235
293
|
end
|
@@ -241,66 +299,97 @@ describe MLL do
|
|
241
299
|
|
242
300
|
# TODO take from docs more examples that involve other functions
|
243
301
|
|
244
|
-
example "
|
245
|
-
expect{
|
302
|
+
example "no args raise ArgumentError" do
|
303
|
+
expect{ range[] }.to raise_error ArgumentError
|
304
|
+
end
|
305
|
+
example "more than 3 args raise ArgumentError" do
|
306
|
+
expect{ range[1,2,3,4] }.to raise_error ArgumentError
|
307
|
+
end
|
308
|
+
example "step equal to 0 raise ArgumentError" do
|
309
|
+
expect{ range[1,2,0] }.to raise_error ArgumentError
|
310
|
+
end
|
311
|
+
|
312
|
+
describe "Details" do
|
313
|
+
|
314
|
+
example "the arguments need not be integers" do
|
315
|
+
expect(range[0.25,2.9,1.25]).to be_a Enumerator
|
316
|
+
expect(range[0.25,2.9,1.25].to_a).to eq [0.25,1.5,2.75]
|
317
|
+
end
|
318
|
+
|
246
319
|
end
|
247
320
|
|
248
321
|
describe "Basic Examples" do
|
249
322
|
|
250
323
|
example "range(n)" do
|
251
|
-
expect(
|
252
|
-
expect(
|
324
|
+
expect(range[4]).to be_a Enumerator
|
325
|
+
expect(range[4].to_a).to eq [1,2,3,4]
|
253
326
|
end
|
254
|
-
example "range(
|
255
|
-
expect(
|
256
|
-
expect(
|
327
|
+
example "range(n1, n2)" do
|
328
|
+
expect(range[2,5]).to be_a Enumerator
|
329
|
+
expect(range[2,5].to_a).to eq [2,3,4,5]
|
257
330
|
end
|
258
331
|
example "range(min, max, step)" do
|
259
|
-
expect(
|
260
|
-
expect(
|
261
|
-
expect(
|
262
|
-
expect(
|
263
|
-
end
|
264
|
-
example "range(max, min, -step)" do
|
265
|
-
expect(MLL::range(10,-5,-2).to_a).to eq [10,8,6,4,2,0,-2,-4]
|
266
|
-
expect(MLL::range(3,1,-1).to_a).to eq [3,2,1]
|
332
|
+
expect(range[1,2,0.5]).to be_a Enumerator
|
333
|
+
expect(range[1,2,0.5].to_a).to eq [1,1.5,2] # can be precision problems
|
334
|
+
expect(range[2,6,2].to_a).to eq [2,4,6]
|
335
|
+
expect(range[-4,9,3].to_a).to eq [-4,-1,2,5,8]
|
267
336
|
end
|
268
337
|
|
269
338
|
end
|
270
339
|
|
340
|
+
# NOTE: Wolfram Mathematica can't do this
|
341
|
+
example "range(max, min, -step)" do
|
342
|
+
expect(range[10,-5,-2]).to be_a Enumerator
|
343
|
+
expect(range[10,-5,-2].to_a).to eq [10,8,6,4,2,0,-2,-4]
|
344
|
+
expect(range[3,1,-1].to_a).to eq [3,2,1]
|
345
|
+
end
|
346
|
+
|
271
347
|
describe "Generalizations & Extensions" do
|
272
348
|
|
273
|
-
example "
|
274
|
-
expect(
|
275
|
-
|
349
|
+
example "use a list of range specifications" do
|
350
|
+
expect(range[[5,2,6,3]]).to be_a Enumerator
|
351
|
+
range[[5,2,6,3]].each do |i|
|
276
352
|
expect(i).to be_a Enumerator
|
277
353
|
end
|
278
|
-
expect(
|
354
|
+
expect(range[[5,2,6,3]].to_a.map(&:to_a)).to eq [[1,2,3,4,5],[1,2],[1,2,3,4,5,6],[1,2,3]]
|
279
355
|
end
|
280
356
|
|
281
357
|
end
|
282
358
|
|
283
359
|
describe "Applications" do
|
284
360
|
|
285
|
-
example "
|
286
|
-
|
287
|
-
expect(power
|
361
|
+
example "produce a geometric sequence" do
|
362
|
+
skip "#power is yet to be implemented"
|
363
|
+
expect(power[2, range[5]]).to be_a Enumerator
|
364
|
+
expect(power[2, range[5]].to_a).to eq [2,4,8,16,32]
|
288
365
|
end
|
289
366
|
|
290
367
|
end
|
291
368
|
|
292
|
-
describe "
|
369
|
+
describe "Properties & Relations" do
|
293
370
|
|
294
|
-
example "range
|
295
|
-
expect(
|
296
|
-
MLL::range(1..3).each do |i|
|
297
|
-
expect(i).to be_a Enumerator
|
298
|
-
end
|
299
|
-
expect(MLL::range(1..3).to_a.map(&:to_a)).to eq [[1],[1,2],[1,2,3]]
|
371
|
+
example "#range[imin,imax,di] is equivalent to #table[i,[imin,imax,di]]" do
|
372
|
+
expect(range[2,8,3].to_a).to eq table[->(i){ i }, [2,8,3]]
|
300
373
|
end
|
301
|
-
|
302
|
-
|
303
|
-
|
374
|
+
|
375
|
+
example "use #range or #span (;;) as #part specification" do
|
376
|
+
skip "#span and #part are yet to be implemented"
|
377
|
+
end
|
378
|
+
|
379
|
+
end
|
380
|
+
|
381
|
+
example "range(min..max)" do
|
382
|
+
expect(range[1..3]).to be_a Enumerator
|
383
|
+
range[1..3].each do |i|
|
384
|
+
expect(i).to be_a Enumerator
|
385
|
+
end
|
386
|
+
expect(range[1..3].to_a.map(&:to_a)).to eq [[1],[1,2],[1,2,3]]
|
387
|
+
end
|
388
|
+
|
389
|
+
describe "Neat Examples" do
|
390
|
+
|
391
|
+
example "make nested ranges" do
|
392
|
+
range[range[range[3]]].tap do |o|
|
304
393
|
expect(o).to be_a Enumerator
|
305
394
|
o.each do |i|
|
306
395
|
expect(i).to be_a Enumerator
|
@@ -309,36 +398,64 @@ describe MLL do
|
|
309
398
|
end
|
310
399
|
end
|
311
400
|
end
|
312
|
-
expect(
|
401
|
+
expect(range[range[range[3]]].to_a.map{ |i| i.to_a.map(&:to_a) }).to eq [[[1]],[[1],[1,2]],[[1],[1,2],[1,2,3]]]
|
313
402
|
end
|
314
403
|
|
315
|
-
# TODO Nest[Range,3,6]
|
316
|
-
|
317
404
|
end
|
318
405
|
|
319
|
-
# TODO "Find an inverse permutation:"
|
320
|
-
# TODO "Use Range or Span (;;) as Part specification:"
|
321
|
-
|
322
406
|
end
|
323
407
|
|
324
408
|
# http://reference.wolfram.com/language/ref/Subdivide.html
|
325
409
|
describe "#subdivide" do
|
326
410
|
|
327
|
-
example "
|
328
|
-
expect
|
329
|
-
expect(MLL::subdivide(4).to_a).to eq [0,0.25,0.5,0.75,1]
|
411
|
+
example "no args raise ArgumentError" do
|
412
|
+
expect{ subdivide[] }.to raise_error ArgumentError
|
330
413
|
end
|
331
|
-
example "
|
332
|
-
expect
|
333
|
-
expect(MLL::subdivide(10,5).to_a).to eq [0,2,4,6,8,10]
|
414
|
+
example "more than 3 args raise ArgumentError" do
|
415
|
+
expect{ subdivide[1,2,3,4] }.to raise_error ArgumentError
|
334
416
|
end
|
335
|
-
example "
|
336
|
-
|
337
|
-
|
417
|
+
# example "division into 0 parts raises ArgumentError" do
|
418
|
+
# expect{ subdivide[0] }.to raise_error ArgumentError
|
419
|
+
# end
|
420
|
+
|
421
|
+
describe "Details" do
|
422
|
+
|
423
|
+
example "generates a list of length n+1" do
|
424
|
+
expect(subdivide[5]).to be_a Enumerator
|
425
|
+
expect(subdivide[5].size).to eq 6
|
426
|
+
end
|
427
|
+
|
338
428
|
end
|
339
|
-
|
340
|
-
|
341
|
-
|
429
|
+
|
430
|
+
describe "Basic Examples" do
|
431
|
+
|
432
|
+
example "subdivide the unit interval into 4 equal parts" do
|
433
|
+
expect(subdivide[4]).to be_a Enumerator
|
434
|
+
expect(subdivide[4].to_a).to eq [0,0.25,0.5,0.75,1]
|
435
|
+
end
|
436
|
+
example "subdivide the interval 0 to 10 into 5 equal parts" do
|
437
|
+
expect(subdivide[10,5]).to be_a Enumerator
|
438
|
+
expect(subdivide[10,5].to_a).to eq [0,2,4,6,8,10]
|
439
|
+
end
|
440
|
+
example "subdivide the interval -1 to 1 into 8 equal parts using machine precision" do
|
441
|
+
expect(subdivide[-1,1,8]).to be_a Enumerator
|
442
|
+
expect(subdivide[-1,1,8].to_a).to eq [-1,-0.75,-0.5,-0.25,0,0.25,0.5,0.75,1]
|
443
|
+
end
|
444
|
+
|
445
|
+
# NOTE: Wolfram Mathematica can't do this
|
446
|
+
example "subdivide(max, min, n)" do
|
447
|
+
expect(subdivide[1,-1,8]).to be_a Enumerator
|
448
|
+
expect(subdivide[1,-1,8].to_a).to eq [1,0.75,0.5,0.25,0,-0.25,-0.5,-0.75,-1]
|
449
|
+
end
|
450
|
+
|
451
|
+
end
|
452
|
+
|
453
|
+
describe "Properties & Relations" do
|
454
|
+
|
455
|
+
example "subdivide[xmin,xmax,n] is equivalent to xmin+(xmax-xmin)Range[0,n]/n" do
|
456
|
+
expect(subdivide[2,10,4].to_a).to eq plus[2,divide[times[10-2,range[0,4]],4]].to_a
|
457
|
+
end
|
458
|
+
|
342
459
|
end
|
343
460
|
|
344
461
|
end
|
@@ -346,16 +463,15 @@ describe MLL do
|
|
346
463
|
# http://reference.wolfram.com/language/ref/NestList.html
|
347
464
|
describe "#nest_list" do
|
348
465
|
|
349
|
-
example "
|
350
|
-
expect(
|
351
|
-
expect(
|
466
|
+
example "gives a list of length n+1" do
|
467
|
+
expect(nest_list[->{}, 0, 5]).to be_a Enumerator
|
468
|
+
expect(nest_list[->(*args){}, 0, 5].to_a.size).to eq 6
|
352
469
|
end
|
353
470
|
|
354
471
|
describe "Basic Examples" do
|
355
472
|
|
356
|
-
example "
|
357
|
-
|
358
|
-
fail
|
473
|
+
example "???" do
|
474
|
+
skip "#cos (or #sqrt or anything unar is yet to be implemented"
|
359
475
|
end
|
360
476
|
|
361
477
|
end
|
@@ -363,8 +479,7 @@ describe MLL do
|
|
363
479
|
describe "Scope" do
|
364
480
|
|
365
481
|
example "nesting can return a single number" do
|
366
|
-
|
367
|
-
fail
|
482
|
+
skip "#sqrt is yet to be implemented"
|
368
483
|
end
|
369
484
|
|
370
485
|
end
|
@@ -372,39 +487,41 @@ describe MLL do
|
|
372
487
|
describe "Applications" do
|
373
488
|
|
374
489
|
example "powers of 2" do
|
375
|
-
expect(
|
376
|
-
expect(
|
490
|
+
expect(nest_list[->(i){ 2*i }, 1, 10]).to be_a Enumerator
|
491
|
+
expect(nest_list[->(i){ 2*i }, 1, 10].to_a).to eq [1,2,4,8,16,32,64,128,256,512,1024]
|
377
492
|
end
|
378
493
|
example "iterates in the problem" do
|
379
|
-
expect(
|
380
|
-
expect(
|
494
|
+
expect(nest_list[->(i){ i.even? ? i/2 : (i*3+1)/2 }, 100, 20]).to be_a Enumerator
|
495
|
+
expect(nest_list[->(i){ i.even? ? i/2 : (i*3+1)/2 }, 100, 20].to_a).to eq [100,50,25,38,19,29,44,22,11,17,26,13,20,10,5,8,4,2,1,2,1]
|
381
496
|
end
|
382
497
|
example "linear congruential pseudorandom generator" do
|
383
|
-
expect(
|
384
|
-
expect(
|
498
|
+
expect(nest_list[->(i){ (i*59)%101 }, 1, 15]).to be_a Enumerator
|
499
|
+
expect(nest_list[->(i){ (i*59)%101 }, 1, 15].to_a).to eq [1,59,47,46,88,41,96,8,68,73,65,98,25,61,64,39]
|
385
500
|
end
|
386
501
|
example "random walk" do
|
387
|
-
expect(( r = Random.new(0);
|
388
|
-
expect(( r = Random.new(0);
|
502
|
+
expect(( r = Random.new(0); nest_list[->(i){ i+[-1,1][r.rand(2)] }, 0, 20] )).to be_a Enumerator
|
503
|
+
expect(( r = Random.new(0); nest_list[->(i){ i+[-1,1][r.rand(2)] }, 0, 20].to_a )).to eq [0,-1,0,1,0,1,2,3,4,5,6,7,6,5,6,5,4,3,2,1,2]
|
389
504
|
end
|
390
505
|
example "successively rotate a list" do
|
391
|
-
expect(
|
392
|
-
expect(
|
506
|
+
expect(nest_list[->(i){ i.rotate 1 }, [1,2,3,4], 4]).to be_a Enumerator
|
507
|
+
expect(nest_list[->(i){ i.rotate 1 }, [1,2,3,4], 4].to_a).to eq [[1,2,3,4],[2,3,4,1],[3,4,1,2],[4,1,2,3],[1,2,3,4]]
|
393
508
|
end
|
394
509
|
|
395
510
|
end
|
396
511
|
|
397
512
|
describe "Properties & Relations" do
|
398
513
|
|
399
|
-
|
514
|
+
example "#nest gives the last element of #nest_list" do
|
515
|
+
expect(nest_list[->(i){ i*2 }, 3, 4].to_a.last).to eq nest[->(i){ i*2 }, 3, 4]
|
516
|
+
end
|
400
517
|
|
401
518
|
example "nesting zero times simply returns to the original argument" do
|
402
|
-
expect(
|
403
|
-
expect(
|
519
|
+
expect(nest_list[->{fail}, 5, 0]).to be_a Enumerator
|
520
|
+
expect(nest_list[->(*args){fail}, 5, 0].to_a).to eq [5]
|
404
521
|
end
|
405
522
|
example "#fold_list automatically inserts second arguments from a list" do
|
406
|
-
expect(
|
407
|
-
|
523
|
+
expect(nest_list[->(i ){ i*2 }, 3, 4].to_a).to eq \
|
524
|
+
fold_list[->(i,j){ i*j }, 3, [2]*4].to_a
|
408
525
|
end
|
409
526
|
|
410
527
|
end
|
@@ -416,69 +533,78 @@ describe MLL do
|
|
416
533
|
# http://reference.wolfram.com/language/guide/ApplyingFunctionsToLists.html
|
417
534
|
describe "Applying Functions to Lists" do
|
418
535
|
|
536
|
+
# http://reference.wolfram.com/language/ref/FoldList.html
|
419
537
|
describe "#fold_list" do
|
420
538
|
|
539
|
+
describe "Details" do
|
540
|
+
|
541
|
+
example "with a length n list, #fold_list generates a list of length n+1" do
|
542
|
+
skip "waiting got Wolfram team to fix the reported bug"
|
543
|
+
end
|
544
|
+
example "#fold_list[f,list] is equivalent to #fold_list[f,[list][0],list[1..-1]]" do
|
545
|
+
expect(fold_list[plus,[1,2,3]]).to be_a Enumerator
|
546
|
+
expect(fold_list[plus,[1,2,3]].to_a).to eq fold_list[plus,1,[2,3]].to_a
|
547
|
+
end
|
548
|
+
|
549
|
+
end
|
550
|
+
|
421
551
|
describe "Basic Examples" do
|
422
552
|
|
423
|
-
example "
|
424
|
-
expect(
|
425
|
-
expect(
|
553
|
+
example "cumulative sums of the elements of the list" do
|
554
|
+
expect(fold_list[plus,5,[1,2,3,4]]).to be_a Enumerator
|
555
|
+
expect(fold_list[plus,5,[1,2,3,4]].to_a).to eq [5,6,8,11,15]
|
426
556
|
end
|
427
|
-
example "
|
428
|
-
expect(
|
429
|
-
expect(
|
557
|
+
example "cumulative powers" do
|
558
|
+
expect(fold_list[->(base, power){ base ** power },2,[3,2,1]]).to be_a Enumerator
|
559
|
+
expect(fold_list[->(base, power){ base ** power },2,[3,2,1]].to_a).to eq [2,8,64,64]
|
430
560
|
end
|
431
|
-
example "
|
432
|
-
expect(
|
433
|
-
expect(
|
561
|
+
example "start from the first element of the list" do
|
562
|
+
expect(fold_list[plus,[1,2,3,4]]).to be_a Enumerator
|
563
|
+
expect(fold_list[plus,[1,2,3,4]].to_a).to eq [1,3,6,10]
|
434
564
|
end
|
435
565
|
|
436
566
|
end
|
437
567
|
|
438
568
|
describe "Applications" do
|
439
569
|
|
440
|
-
|
441
|
-
|
442
|
-
expect(
|
443
|
-
|
444
|
-
example "fold_list(lambda, n, list)" do
|
445
|
-
expect(MLL::fold_list(->(a,b){ 10*a + b }, 0, [4,5,1,6,7,8])).to be_a Enumerator
|
446
|
-
expect(MLL::fold_list(->(a,b){ 10*a + b }, 0, [4,5,1,6,7,8]).to_a).to eq [0,4,45,451,4516,45167,451678]
|
447
|
-
end
|
448
|
-
example "fold_list(lambda, n, list)" do
|
449
|
-
expect(( r = Random.new(0); MLL::fold_list(MLL.method(:plus), 0, Array.new(20){ [-1,1][r.rand(2)] }) )).to be_a Enumerator
|
450
|
-
expect(( r = Random.new(0); MLL::fold_list(MLL.method(:plus), 0, Array.new(20){ [-1,1][r.rand(2)] }).to_a )).to eq [0,-1,0,1,0,1,2,3,4,5,6,7,6,5,6,5,4,3,2,1,2]
|
570
|
+
# TODO maybe move it to README.md
|
571
|
+
example "generate a random walk" do
|
572
|
+
expect(( r = Random.new(0); fold_list[plus, 0, Array.new(20){ [-1,1][r.rand(2)] }] )).to be_a Enumerator
|
573
|
+
expect(( r = Random.new(0); fold_list[plus, 0, Array.new(20){ [-1,1][r.rand(2)] }].to_a )).to eq [0,-1,0,1,0,1,2,3,4,5,6,7,6,5,6,5,4,3,2,1,2]
|
451
574
|
end
|
452
575
|
|
453
|
-
|
576
|
+
example "find successively deeper parts in an expression" do
|
577
|
+
expect(fold_list[->(list,index){ list[index] }, [[1,2],[3,[4,5],6,7],8], [1,1,0]]).to be_a Enumerator
|
578
|
+
expect(fold_list[->(list,index){ list[index] }, [[1,2],[3,[4,5],6,7],8], [1,1,0]].to_a).to eq [[[1,2],[3,[4,5],6,7],8],[3,[4,5],6,7],[4,5],4]
|
579
|
+
end
|
454
580
|
|
455
581
|
end
|
456
582
|
|
457
583
|
describe "Properties & Relations" do
|
458
584
|
|
459
|
-
example "
|
460
|
-
expect(
|
461
|
-
expect(
|
585
|
+
example "makes a list of length n+1" do
|
586
|
+
expect(fold_list[->{}, 0, [*1..10]]).to be_a Enumerator
|
587
|
+
expect(fold_list[->(*args){}, 0, [*1..10]].to_a.size).to eq 11
|
462
588
|
end
|
463
589
|
example "folding with an empty list does not apply the function at all" do
|
464
|
-
expect(
|
465
|
-
expect(
|
590
|
+
expect(fold_list[->{}, 0, []]).to be_a Enumerator
|
591
|
+
expect(fold_list[->(*args){}, 0, []].to_a).to eq [0]
|
466
592
|
end
|
467
593
|
example "Ruby#inject gives the last element of #fold_list" do
|
468
594
|
f = ->(i,j){ i+j }
|
469
|
-
expect(
|
470
|
-
expect(
|
595
|
+
expect(fold_list[f, [1,2,3]]).to be_a Enumerator
|
596
|
+
expect(fold_list[f, [1,2,3]].to_a.last).to eq [1,2,3].inject(&f)
|
597
|
+
end
|
598
|
+
example "functions that ignore their second argument give the same result as in #nest_list" do
|
599
|
+
expect(fold_list[->(i,_){ [i] }, 0, range[5]].to_a).to eq nest_list[->(i){ [i] }, 0, 5].to_a
|
471
600
|
end
|
472
|
-
# TODO "Functions that ignore their second argument give the same result as in NestList:"
|
473
|
-
# TODO "Accumulate is equivalent to FoldList with Plus:"
|
474
601
|
|
475
602
|
end
|
476
603
|
|
477
604
|
describe "Neat Examples" do
|
478
605
|
|
479
606
|
example "compute the minimum number of coins of different value needed to make up an amount" do
|
480
|
-
|
481
|
-
fail
|
607
|
+
skip "at least #mod is yet to be implemented"
|
482
608
|
end
|
483
609
|
|
484
610
|
end
|
@@ -501,12 +627,13 @@ describe MLL do
|
|
501
627
|
|
502
628
|
# TODO move #nest_list and #fold_list and others here?
|
503
629
|
|
630
|
+
# http://reference.wolfram.com/language/ref/Nest.html
|
504
631
|
describe "#nest" do
|
505
632
|
|
506
633
|
describe "Basic Examples" do
|
507
634
|
|
508
635
|
example "the function to nest can be a pure function" do
|
509
|
-
expect(
|
636
|
+
expect(nest[->(i){ (1+i)**2 }, 1, 3]).to eq 676
|
510
637
|
end
|
511
638
|
|
512
639
|
end
|
@@ -514,8 +641,7 @@ describe MLL do
|
|
514
641
|
describe "Scope" do
|
515
642
|
|
516
643
|
example "nesting can return a single number" do
|
517
|
-
|
518
|
-
fail
|
644
|
+
skip "#sqrt is yet to be implemented"
|
519
645
|
end
|
520
646
|
|
521
647
|
end
|
@@ -523,21 +649,18 @@ describe MLL do
|
|
523
649
|
describe "Applications" do
|
524
650
|
|
525
651
|
example "newton iterations for" do
|
526
|
-
|
527
|
-
fail
|
652
|
+
skip "waiting for Rationals to be used"
|
528
653
|
end
|
529
654
|
example "consecutive pairs of Fibonacci numbers" do
|
530
|
-
|
531
|
-
fail
|
655
|
+
skip "#dot is yet to be implemented"
|
532
656
|
end
|
533
657
|
|
534
658
|
end
|
535
659
|
|
536
660
|
describe "Properties & Relations" do
|
537
661
|
|
538
|
-
example "#
|
539
|
-
expect(
|
540
|
-
([2]*4).inject(3){ |i,j| i*j }
|
662
|
+
example "Ruby#inject automatically inserts second arguments from a list" do
|
663
|
+
expect(nest[->(i){ i*2 }, 3, 4]).to eq ([2]*4).inject(3){ |i,j| i*j }
|
541
664
|
end
|
542
665
|
|
543
666
|
end
|
@@ -557,6 +680,7 @@ end
|
|
557
680
|
|
558
681
|
__END__
|
559
682
|
|
560
|
-
Table
|
561
|
-
Times
|
562
|
-
Plus
|
683
|
+
Table Array
|
684
|
+
Times Product
|
685
|
+
Plus Total Sum?
|
686
|
+
NestList Accumulate
|