mll 0.4.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|