mll 0.2.0 → 0.3.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 +20 -15
- data/lib/mll.rb +34 -16
- data/mll.gemspec +1 -1
- data/spec/_spec.rb +144 -19
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0b28b0ef583cd90f87454f37cebdc8a3088ba42a
|
4
|
+
data.tar.gz: 05757c078b5eade518f1895e71c9bf3e0af97f5f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cf8caa79c3a7cc275b234c1dcb1d1bc6a0bc9a772f585bddc171cc8d4bd2dacff587cc37c963df7fbab53880c48ca62579ba5c63e109235836288611b6011f8a
|
7
|
+
data.tar.gz: 8c3053016c69c2ead9e8fd965a661167332e45b00841e15fbdd570325888e5c74e03c5ee89b339bcd665ae75d24bf37574e201686ae0bf3a3b9f3127a1ea9331
|
data/README.md
CHANGED
@@ -1,29 +1,34 @@
|
|
1
1
|
# MLL (Mathematica Language Library)
|
2
2
|
|
3
|
-
|
3
|
+
## What
|
4
4
|
|
5
|
-
|
5
|
+
Этот гем не ставит перед собой цель полностью имитировать типы данных, синтаксис Wolfram Mathematica Language, или научить Ruby крутым визуализациям. Целью является вложить в Ruby мощь стандартной библиотеки. В перспективе визуализация возможна при помощи других гемов.
|
6
6
|
|
7
|
-
|
7
|
+
## Why
|
8
8
|
|
9
|
-
|
9
|
+
1. Важной является реализация https://reference.wolfram.com/language/ref/Listable.html: автоматическое применение функции ко всем элементам аргумента, если тот является List-ом (Array-ем в среде Ruby).
|
10
|
+
2. `::range`, в отличие от рубишного, может иметь отрицательный step.
|
11
|
+
3. `::table`, в отличие от рубишного `.map`, может создавать многомерные массивы одним вызовом, а не только вложенными.
|
10
12
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
13
|
+
## How
|
14
|
+
|
15
|
+
MLL::range(2, 3) #=> 2..3
|
16
|
+
MLL::range([2, 3]) #=> [1..2, 1..3]
|
17
|
+
MLL::range(1..3) #=> [1..1, 1..2, 1..3]
|
18
|
+
|
19
|
+
MLL::table ->(i,j){ i+j }, [[1, 0, 1]], [[0, 2, 0]]
|
20
|
+
#=> [[1, 3, 1],
|
21
|
+
[0, 2, 0],
|
22
|
+
[1, 3, 1]]
|
23
|
+
MLL::table ->(i,j,k){ 100*i + 10*j + k }, 2, 3, 4
|
24
|
+
# => [[[111, 112, 113, 114], [121, 122, 123, 124], [131, 132, 133, 134]],
|
25
|
+
[[211, 212, 213, 214], [221, 222, 223, 224], [231, 232, 233, 234]]]
|
21
26
|
|
22
27
|
## Installation
|
23
28
|
|
24
29
|
$ gem install mll
|
25
30
|
|
26
|
-
|
31
|
+
## Testing with RSpec before contributing
|
27
32
|
|
28
33
|
rspec
|
29
34
|
|
data/lib/mll.rb
CHANGED
@@ -1,22 +1,22 @@
|
|
1
1
|
module MLL
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
(class << self; self end).class_eval do
|
3
|
+
# https://reference.wolfram.com/language/ref/Listable.html
|
4
|
+
def self.define_listable_function name, &block
|
5
|
+
(class << self; self end).class_eval do # http://stackoverflow.com/a/12792313/322020
|
6
6
|
define_method name do |*args|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
7
|
+
# p [name, args]
|
8
|
+
next block.call *args unless args[0].respond_to? :map
|
9
|
+
next args[0].lazy.map{ |i| send name, i, *args.drop(1) } unless args[1].respond_to? :map
|
10
|
+
# raise "idk how to list this function" if args.size > 2
|
11
|
+
next args[0].lazy.zip(args[1]).map{ |i,j| send name, i, j, *args.drop(2) }
|
12
12
|
end
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
|
-
|
16
|
+
define_listable_function :range do |*args|
|
17
17
|
case args.size
|
18
18
|
when 1 ; range 1, args[0] # TODO do smth with #table(-n)
|
19
|
-
when 2 ; Range.new(args[0], args[1])
|
19
|
+
when 2 ; Range.new(args[0], args[1]).step
|
20
20
|
when 3
|
21
21
|
case args[2] <=> 0
|
22
22
|
when 0 ; raise ArgumentError.new("step can't be zero")
|
@@ -24,34 +24,52 @@ module MLL
|
|
24
24
|
else
|
25
25
|
Enumerator.new do |e|
|
26
26
|
from, to, step = *args
|
27
|
-
while (step > 0) ? from <= to : from >= to
|
27
|
+
# while (step > 0) ? from <= to : from >= to
|
28
|
+
while from >= to
|
28
29
|
e << from
|
29
30
|
from += step
|
30
31
|
end
|
31
32
|
end
|
32
33
|
end
|
33
34
|
else
|
34
|
-
raise ArgumentError.new("wrong number of arguments (#{args.size} for 1..3)")
|
35
|
+
raise ArgumentError.new("wrong number of arguments (#{args.size} for 1..3)")
|
35
36
|
end
|
36
37
|
end
|
37
38
|
|
38
39
|
def self.table f, *args
|
39
|
-
# TODO make it lazy?
|
40
|
-
|
41
40
|
[].tap do |result|
|
42
|
-
[[result, args.map{ |r|
|
41
|
+
[[result, args.map{ |r| # add lazy?
|
42
|
+
r.respond_to?(:map) && r.first.respond_to?(:map) ?
|
43
|
+
r.first : range(*r)
|
44
|
+
}]].tap do |stack|
|
43
45
|
stack.each do |ai, ri|
|
46
|
+
# TODO try to make #table lazy (Enumerator instead of Array)
|
47
|
+
# "no implicit conversion of Enumerator::Lazy into Array"
|
48
|
+
# "undefined method `replace' for #<Enumerator::Lazy: []>"
|
44
49
|
ai.replace ri.first.map{ |i|
|
45
50
|
if ri.size == 1
|
46
51
|
f.call(*ai, i)
|
47
52
|
else
|
48
53
|
[*ai.dup, i].tap{ |t| stack << [t, ri.drop(1)] }
|
49
54
|
end
|
50
|
-
}
|
55
|
+
}#.to_a # WTF
|
51
56
|
end
|
52
57
|
end
|
53
58
|
end
|
59
|
+
end
|
60
|
+
|
61
|
+
define_listable_function :divide do |a, b|
|
62
|
+
a / b
|
63
|
+
end
|
54
64
|
|
65
|
+
def self.subdivide *args
|
66
|
+
case args.size
|
67
|
+
when 1 ; subdivide 1, args[0]
|
68
|
+
when 2 ; subdivide 0, args[0], args[1]
|
69
|
+
when 3 ; range(args[0], args[1], (args[1] - args[0]) * 1.0 / args[2])
|
70
|
+
else
|
71
|
+
raise ArgumentError.new("wrong number of arguments (#{args.size} for 1..3)")
|
72
|
+
end
|
55
73
|
end
|
56
74
|
|
57
75
|
end
|
data/mll.gemspec
CHANGED
data/spec/_spec.rb
CHANGED
@@ -1,9 +1,74 @@
|
|
1
1
|
require_relative File.join "..", "lib", "mll"
|
2
2
|
|
3
3
|
|
4
|
+
# PERMANENT TODO test all implemented exceptions
|
5
|
+
# PERMANENT TODO test all types returned
|
6
|
+
|
7
|
+
|
4
8
|
# http://reference.wolfram.com/language/guide/LanguageOverview.html
|
5
9
|
describe MLL do
|
6
10
|
|
11
|
+
# http://reference.wolfram.com/language/guide/Syntax.html
|
12
|
+
describe "Syntax" do
|
13
|
+
|
14
|
+
# NO URL
|
15
|
+
describe "Mathematics & Operators" do
|
16
|
+
|
17
|
+
# http://reference.wolfram.com/language/ref/Divide.html
|
18
|
+
describe "#divide" do
|
19
|
+
|
20
|
+
describe "Basic Examples" do
|
21
|
+
|
22
|
+
example "n1 / n2" do
|
23
|
+
expect(MLL::divide(77,11)).to be_a Fixnum
|
24
|
+
expect(MLL::divide(77,11)).to eq 7
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "Scope" do
|
30
|
+
|
31
|
+
example "list / n" do
|
32
|
+
expect(MLL::divide([2,3,4,5],2.0)).to be_a Enumerator
|
33
|
+
expect(MLL::divide([2,3,4,5],2.0).to_a).to eq [1,1.5,2,2.5]
|
34
|
+
end
|
35
|
+
example "list / list" do
|
36
|
+
expect(MLL::divide([2,3,4],[2,1,4])).to be_a Enumerator
|
37
|
+
expect(MLL::divide([2,3,4],[2,1,4]).to_a).to eq [1,3,1]
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
describe "Applications" do
|
43
|
+
|
44
|
+
example "foldlist(divide, 1, range(10))" do
|
45
|
+
pending "#foldlist is yet to be implemented"
|
46
|
+
fail
|
47
|
+
end
|
48
|
+
|
49
|
+
# TODO: "Successive ratios in a list:"
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "Neat Examples" do
|
54
|
+
|
55
|
+
example "nest_list(lambda_with_divide), n" do
|
56
|
+
pending "#nestlist is yet to be implemented"
|
57
|
+
fail
|
58
|
+
end
|
59
|
+
example "table(divide, n1, n2)" do
|
60
|
+
expect(MLL::table(MLL.method(:divide), [[3,6]], 4.0)).to be_a Array
|
61
|
+
expect(MLL::table(MLL.method(:divide), [[6]], 4.0)).to eq [[6.0,3.0,2.0,1.5]]
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
7
72
|
# http://reference.wolfram.com/language/guide/ListManipulation.html
|
8
73
|
describe "List Manipulation" do
|
9
74
|
|
@@ -13,7 +78,7 @@ describe MLL do
|
|
13
78
|
# http://reference.wolfram.com/language/ref/Range.html
|
14
79
|
describe "#range" do
|
15
80
|
|
16
|
-
# TODO
|
81
|
+
# TODO take from docs more examples that involve other functions
|
17
82
|
|
18
83
|
example "range( >3 args )" do
|
19
84
|
expect{ MLL::range(1,2,3,4) }.to raise_error ArgumentError
|
@@ -22,22 +87,24 @@ describe MLL do
|
|
22
87
|
describe "Basic Examples" do
|
23
88
|
|
24
89
|
example "range(n)" do
|
25
|
-
expect(MLL::range(4)).to be_a
|
90
|
+
expect(MLL::range(4)).to be_a Enumerator
|
26
91
|
expect(MLL::range(4).to_a).to eq [1,2,3,4]
|
27
92
|
end
|
28
|
-
example "range(
|
29
|
-
expect(MLL::range(2,5)).to be_a
|
93
|
+
example "range(min, max)" do
|
94
|
+
expect(MLL::range(2,5)).to be_a Enumerator
|
30
95
|
expect(MLL::range(2,5).to_a).to eq [2,3,4,5]
|
31
96
|
end
|
32
|
-
example "range(
|
97
|
+
example "range(min, max, step)" do
|
33
98
|
expect(MLL::range(1,2,3)).to be_a Enumerator
|
34
99
|
expect(MLL::range(1,2,0.5).to_a).to eq [1,1.5,2] # can be precision problems
|
35
100
|
expect(MLL::range(2,6,2).to_a).to eq [2,4,6]
|
36
101
|
expect(MLL::range(-4,9,3).to_a).to eq [-4,-1,2,5,8]
|
37
|
-
|
102
|
+
end
|
103
|
+
example "range(max, min, -step)" do
|
38
104
|
expect(MLL::range(10,-5,-2).to_a).to eq [10,8,6,4,2,0,-2,-4]
|
39
105
|
expect(MLL::range(3,1,-1).to_a).to eq [3,2,1]
|
40
106
|
end
|
107
|
+
|
41
108
|
end
|
42
109
|
|
43
110
|
describe "Generalizations & Extensions" do
|
@@ -45,7 +112,7 @@ describe MLL do
|
|
45
112
|
example "range([n1, n2, n3, n4])" do
|
46
113
|
expect(MLL::range([5,2,6,3])).to be_a Enumerator
|
47
114
|
MLL::range([5,2,6,3]).each do |i|
|
48
|
-
expect(i).to be_a
|
115
|
+
expect(i).to be_a Enumerator
|
49
116
|
end
|
50
117
|
expect(MLL::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]]
|
51
118
|
end
|
@@ -63,10 +130,10 @@ describe MLL do
|
|
63
130
|
|
64
131
|
describe "Neat Examples" do
|
65
132
|
|
66
|
-
example "range(
|
67
|
-
expect(MLL::range(
|
68
|
-
MLL::range(
|
69
|
-
expect(i).to be_a
|
133
|
+
example "range(min..max)" do
|
134
|
+
expect(MLL::range(1..3)).to be_a Enumerator
|
135
|
+
MLL::range(1..3).each do |i|
|
136
|
+
expect(i).to be_a Enumerator
|
70
137
|
end
|
71
138
|
expect(MLL::range(1..3).to_a.map(&:to_a)).to eq [[1],[1,2],[1,2,3]]
|
72
139
|
end
|
@@ -77,7 +144,7 @@ describe MLL do
|
|
77
144
|
o.each do |i|
|
78
145
|
expect(i).to be_a Enumerator
|
79
146
|
i.each do |j|
|
80
|
-
expect(j).to be_a
|
147
|
+
expect(j).to be_a Enumerator
|
81
148
|
end
|
82
149
|
end
|
83
150
|
end
|
@@ -95,27 +162,85 @@ describe MLL do
|
|
95
162
|
|
96
163
|
# http://reference.wolfram.com/language/ref/Table.html
|
97
164
|
describe "#table" do
|
165
|
+
# TODO type checks
|
98
166
|
|
99
167
|
describe "Basic Examples" do
|
100
168
|
|
101
|
-
example "table(lambda,
|
102
|
-
expect(MLL::table(->(i){ i**2 },
|
169
|
+
example "table(lambda, n)" do
|
170
|
+
expect(MLL::table(->(i){ i**2 }, 10)).to be_a Array
|
171
|
+
expect(MLL::table(->(i){ i**2 }, 10)).to eq [1,4,9,16,25,36,49,64,81,100]
|
103
172
|
end
|
104
|
-
example "table(lambda, [
|
173
|
+
example "table(lambda, [min, max, step])" do
|
174
|
+
expect(MLL::table(->(i){ i+2 }, [0, 20, 2])).to be_a Array
|
105
175
|
expect(MLL::table(->(i){ i+2 }, [0, 20, 2])).to eq [2,4,6,8,10,12,14,16,18,20,22]
|
106
176
|
end
|
107
|
-
example "table(lambda,
|
108
|
-
|
177
|
+
example "table(lambda, n1, n2)" do
|
178
|
+
# TODO example to README.rb about multiplication table
|
179
|
+
expect(MLL::table(->(i, j){ 10*i + j }, 4, 3)).to be_a Array
|
180
|
+
expect(MLL::table(->(i, j){ 10*i + j }, 4, 3)).to eq [[11,12,13],[21,22,23],[31,32,33],[41,42,43]]
|
181
|
+
end
|
182
|
+
example "table(lambda, n1, min..max, [max, min, -step])" do
|
183
|
+
expect(MLL::table(->(i,j,k){ [i,j,k] }, 3, 2..3, [5, 1, -2])).to be_a Array
|
184
|
+
expect(MLL::table(->(i,j,k){ [i,j,k] }, 3, 2..3, [5, 1, -2])).to eq \
|
185
|
+
[
|
186
|
+
[[[1, 2, 5], [1, 2, 3], [1, 2, 1]], [[1, 3, 5], [1, 3, 3], [1, 3, 1]]],
|
187
|
+
[[[2, 2, 5], [2, 2, 3], [2, 2, 1]], [[2, 3, 5], [2, 3, 3], [2, 3, 1]]],
|
188
|
+
[[[3, 2, 5], [3, 2, 3], [3, 2, 1]], [[3, 3, 5], [3, 3, 3], [3, 3, 1]]]
|
189
|
+
]
|
109
190
|
end
|
110
191
|
|
111
|
-
example "matrix_form table(lambda,
|
192
|
+
example "matrix_form table(lambda, n1, n2)" do
|
112
193
|
pending "#matrix_form is yet to be implemented"
|
113
|
-
expect(MLL::matrix_form MLL::table(->(i, j){ 10*i + j },
|
194
|
+
expect(MLL::matrix_form MLL::table(->(i, j){ 10*i + j }, 4, 3)).to eq "
|
114
195
|
"
|
115
196
|
end
|
116
197
|
|
117
198
|
end
|
118
199
|
|
200
|
+
describe "Scope" do
|
201
|
+
|
202
|
+
# TODO: "Make a triangular array:"
|
203
|
+
|
204
|
+
example "table(lambda, [list1], [list2])" do
|
205
|
+
expect(MLL::table(->(base, power){ base ** power }, [[1,2,4]], [[1,3,4]])).to be_a Array
|
206
|
+
expect(MLL::table(->(base, power){ base ** power }, [[1,2,4]], [[1,3,4]])).to eq [[1,1,1],[2,8,16],[4,64,256]]
|
207
|
+
expect(MLL::table(->(i,j){ i+j }, [[1]], [[2]])).to be_a Array
|
208
|
+
expect(MLL::table(->(i,j){ i+j }, [[1]], [[2]])).to eq [[3]]
|
209
|
+
end
|
210
|
+
|
211
|
+
end
|
212
|
+
|
213
|
+
describe "Applications" do
|
214
|
+
|
215
|
+
example "column table(binomial, )" do
|
216
|
+
pending "#binomial and #column are yet to be implemented"
|
217
|
+
fail
|
218
|
+
end
|
219
|
+
|
220
|
+
end
|
221
|
+
|
222
|
+
end
|
223
|
+
|
224
|
+
# http://reference.wolfram.com/language/ref/Subdivide.html
|
225
|
+
describe "#subdivide" do
|
226
|
+
|
227
|
+
example "subdivide(n)" do
|
228
|
+
expect(MLL::subdivide(4)).to be_a Enumerator
|
229
|
+
expect(MLL::subdivide(4).to_a).to eq [0,0.25,0.5,0.75,1]
|
230
|
+
end
|
231
|
+
example "subdivide(max, n)" do
|
232
|
+
expect(MLL::subdivide(10,5)).to be_a Enumerator
|
233
|
+
expect(MLL::subdivide(10,5).to_a).to eq [0,2,4,6,8,10]
|
234
|
+
end
|
235
|
+
example "subdivide(min, max, n)" do
|
236
|
+
expect(MLL::subdivide(-1,1,8)).to be_a Enumerator
|
237
|
+
expect(MLL::subdivide(-1,1,8).to_a).to eq [-1,-0.75,-0.5,-0.25,0,0.25,0.5,0.75,1]
|
238
|
+
end
|
239
|
+
example "subdivide(max, min, n)" do
|
240
|
+
expect(MLL::subdivide(1,-1,8)).to be_a Enumerator
|
241
|
+
expect(MLL::subdivide(1,-1,8).to_a).to eq [1,0.75,0.5,0.25,0,-0.25,-0.5,-0.75,-1]
|
242
|
+
end
|
243
|
+
|
119
244
|
end
|
120
245
|
|
121
246
|
end
|