abst 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/abst.rb +38 -0
- data/lib/config.rb +21 -0
- data/lib/include/array.rb +45 -0
- data/lib/include/bisect.rb +95 -0
- data/lib/include/cache.rb +60 -0
- data/lib/include/compatibility.rb +3 -0
- data/lib/include/complex.rb +10 -0
- data/lib/include/float.rb +19 -0
- data/lib/include/fundamental.rb +903 -0
- data/lib/include/graph.rb +11 -0
- data/lib/include/group.rb +35 -0
- data/lib/include/integer.rb +385 -0
- data/lib/include/matrix.rb +143 -0
- data/lib/include/polynomial.rb +137 -0
- data/lib/include/prime.rb +556 -0
- data/lib/include/prime_mpqs.rb +483 -0
- data/lib/include/rational.rb +155 -0
- data/lib/include/residue.rb +27 -0
- data/lib/include/ring.rb +21 -0
- data/lib/include/sequence.rb +54 -0
- data/lib/include/set.rb +67 -0
- data/lib/include/vector.rb +90 -0
- data/test/test_all.rb +15 -0
- data/test/test_array.rb +10 -0
- data/test/test_bisect.rb +43 -0
- data/test/test_combination.rb +6 -0
- data/test/test_float.rb +13 -0
- data/test/test_fundamental.rb +406 -0
- data/test/test_group.rb +10 -0
- data/test/test_integer.rb +161 -0
- data/test/test_matrix.rb +54 -0
- data/test/test_polynomial.rb +107 -0
- data/test/test_prime.rb +153 -0
- data/test/test_prime_mpqs.rb +24 -0
- data/test/test_rational.rb +33 -0
- data/test/test_sequence.rb +55 -0
- data/test/test_set.rb +36 -0
- data/test/test_vector.rb +37 -0
- metadata +98 -0
@@ -0,0 +1,155 @@
|
|
1
|
+
class Rational
|
2
|
+
def self.one
|
3
|
+
return Rational(1, 1)
|
4
|
+
end
|
5
|
+
|
6
|
+
def self.zero
|
7
|
+
return Rational(0, 1)
|
8
|
+
end
|
9
|
+
|
10
|
+
def inverse
|
11
|
+
return 1 / self
|
12
|
+
end
|
13
|
+
|
14
|
+
# to repeating decimal string
|
15
|
+
def to_rds(base = 10)
|
16
|
+
raise ArgumentError, "invalid radix #{base}" if base < 2 or 36 < base
|
17
|
+
|
18
|
+
# initialize
|
19
|
+
quotient = []
|
20
|
+
|
21
|
+
n = numerator.to_s(base).split('').map(&:to_i)
|
22
|
+
exp = 0
|
23
|
+
while 0 == n.last
|
24
|
+
n.pop
|
25
|
+
exp += 1
|
26
|
+
end
|
27
|
+
d = denominator
|
28
|
+
loop do
|
29
|
+
q, r = d.divmod(base)
|
30
|
+
break unless 0 == r
|
31
|
+
d = q
|
32
|
+
exp -= 1
|
33
|
+
end
|
34
|
+
t = n[0]
|
35
|
+
|
36
|
+
# division loop
|
37
|
+
i = 1
|
38
|
+
loop do
|
39
|
+
q, r = t.divmod(d)
|
40
|
+
t = r * base + n[i].to_i
|
41
|
+
|
42
|
+
quotient.push([q, nil])
|
43
|
+
|
44
|
+
unless n[i]
|
45
|
+
if 0 == t
|
46
|
+
quotient.last[1] = 0
|
47
|
+
break
|
48
|
+
end
|
49
|
+
break if quotient.map(&:last).include?(t)
|
50
|
+
quotient.last[1] = t
|
51
|
+
end
|
52
|
+
|
53
|
+
i += 1
|
54
|
+
end
|
55
|
+
|
56
|
+
# format
|
57
|
+
rslt = "0."
|
58
|
+
|
59
|
+
zero_count = 0
|
60
|
+
while 0 == quotient[0][0]
|
61
|
+
zero_count += 1
|
62
|
+
if t == quotient.shift[1]
|
63
|
+
rslt += '('
|
64
|
+
|
65
|
+
# rotate 0
|
66
|
+
while 0 == quotient[0][0]
|
67
|
+
quotient.push(quotient.shift)
|
68
|
+
zero_count += 1
|
69
|
+
end
|
70
|
+
break
|
71
|
+
end
|
72
|
+
end
|
73
|
+
exp += n.size - zero_count
|
74
|
+
|
75
|
+
convert = "0123456789abcdefghijklmnopqrstuvwxyz"
|
76
|
+
if 0 == quotient.last[1]
|
77
|
+
rslt += quotient.map{|q| convert[q[0]]}.inject(&:+)
|
78
|
+
else
|
79
|
+
quotient.each do |q|
|
80
|
+
rslt += convert[q[0]]
|
81
|
+
rslt += '(' if t == q[1]
|
82
|
+
end
|
83
|
+
rslt += ")"
|
84
|
+
end
|
85
|
+
rslt += "e" + exp.to_s unless 0 == exp
|
86
|
+
|
87
|
+
return rslt
|
88
|
+
end
|
89
|
+
|
90
|
+
# to decimal string
|
91
|
+
def to_ds(length = 64, base = 10)
|
92
|
+
raise ArgumentError, "invalid radix #{base}" if base < 2 or 36 < base
|
93
|
+
|
94
|
+
# initialize
|
95
|
+
quotient = []
|
96
|
+
|
97
|
+
n = numerator.to_s(base).split('').map(&:to_i)
|
98
|
+
exp = 0
|
99
|
+
while 0 == n.last
|
100
|
+
n.pop
|
101
|
+
exp += 1
|
102
|
+
end
|
103
|
+
d = denominator
|
104
|
+
loop do
|
105
|
+
q, r = d.divmod(base)
|
106
|
+
break unless 0 == r
|
107
|
+
d = q
|
108
|
+
exp -= 1
|
109
|
+
end
|
110
|
+
t = n[0]
|
111
|
+
|
112
|
+
# division loop
|
113
|
+
i = 1
|
114
|
+
s = nil
|
115
|
+
loop do
|
116
|
+
q, r = t.divmod(d)
|
117
|
+
t = r * base + n[i].to_i
|
118
|
+
|
119
|
+
s = i - 1 if nil == s and q != 0
|
120
|
+
quotient.push([q, nil])
|
121
|
+
|
122
|
+
unless n[i]
|
123
|
+
if 0 == t
|
124
|
+
quotient.last[1] = 0
|
125
|
+
break
|
126
|
+
end
|
127
|
+
break if s and i - s == length
|
128
|
+
quotient.last[1] = t
|
129
|
+
end
|
130
|
+
|
131
|
+
i += 1
|
132
|
+
end
|
133
|
+
|
134
|
+
# format
|
135
|
+
zero_count = 0
|
136
|
+
while 0 == quotient[0][0]
|
137
|
+
zero_count += 1
|
138
|
+
if t == quotient.shift[1]
|
139
|
+
# rotate 0
|
140
|
+
while 0 == quotient[0][0]
|
141
|
+
quotient.push(quotient.shift)
|
142
|
+
zero_count += 1
|
143
|
+
end
|
144
|
+
break
|
145
|
+
end
|
146
|
+
end
|
147
|
+
exp += n.size - zero_count
|
148
|
+
|
149
|
+
convert = "0123456789abcdefghijklmnopqrstuvwxyz"
|
150
|
+
rslt = "0." + quotient.map{|q| convert[q[0]]}.inject(&:+)
|
151
|
+
rslt += "e" + exp.to_s unless 0 == exp
|
152
|
+
|
153
|
+
return rslt
|
154
|
+
end
|
155
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Abst
|
2
|
+
module_function
|
3
|
+
|
4
|
+
def residue_class(ideal)
|
5
|
+
if prime?(ideal.n)
|
6
|
+
return residue_class_field(ideal)
|
7
|
+
else
|
8
|
+
return residue_class_ring(ideal)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def residue_class_ring(ideal)
|
13
|
+
residue_class = Class.new(IntegerResidueRing) do
|
14
|
+
@mod = ideal.n
|
15
|
+
end
|
16
|
+
|
17
|
+
return residue_class
|
18
|
+
end
|
19
|
+
|
20
|
+
def residue_class_field(maximal_ideal)
|
21
|
+
residue_class = Class.new(IntegerResidueField) do
|
22
|
+
@mod = maximal_ideal.n
|
23
|
+
end
|
24
|
+
|
25
|
+
return residue_class
|
26
|
+
end
|
27
|
+
end
|
data/lib/include/ring.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
module Abst
|
2
|
+
module Ring
|
3
|
+
def self.included(base)
|
4
|
+
base.class_eval do
|
5
|
+
include Abst::Group
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
def /(other)
|
10
|
+
return self.divmod(other)[0]
|
11
|
+
end
|
12
|
+
|
13
|
+
def %(other)
|
14
|
+
return self.divmod(other)[1]
|
15
|
+
end
|
16
|
+
|
17
|
+
def **(e)
|
18
|
+
return Abst.power(self, e)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Abst
|
2
|
+
module_function
|
3
|
+
|
4
|
+
$fibonacci = {0 => 0, 1 => 1}
|
5
|
+
|
6
|
+
# Param:: non-negative integer n
|
7
|
+
# Return:: the n-th Fibonacci number
|
8
|
+
# effect $fibonacci[n] = fibonacci(n)
|
9
|
+
def fibonacci(n)
|
10
|
+
return $fibonacci[n] if $fibonacci.include?(n)
|
11
|
+
|
12
|
+
m = n >> 1
|
13
|
+
if n.even?
|
14
|
+
f1 = fibonacci(m - 1)
|
15
|
+
f2 = fibonacci(m)
|
16
|
+
$fibonacci[n] = (f1 + f1 + f2) * f2
|
17
|
+
else
|
18
|
+
f1 = fibonacci(m)
|
19
|
+
f2 = fibonacci(m + 1)
|
20
|
+
$fibonacci[n] = f1 ** 2 + f2 ** 2
|
21
|
+
end
|
22
|
+
|
23
|
+
return $fibonacci[n]
|
24
|
+
end
|
25
|
+
|
26
|
+
# Triangle numbers are generated by the formula, T_n = n * (n + 1) / 2.
|
27
|
+
# The first ten triangle numbers are:
|
28
|
+
# 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, ...
|
29
|
+
def triangle(n)
|
30
|
+
return n * (n + 1) >> 1
|
31
|
+
end
|
32
|
+
|
33
|
+
# Pentagonal numbers are generated by the formula, P_n = n * (3 * n - 1) / 2.
|
34
|
+
# The first ten pentagonal numbers are:
|
35
|
+
# 1, 5, 12, 22, 35, 51, 70, 92, 117, 145, ...
|
36
|
+
def pentagonal(n)
|
37
|
+
return n * (3 * n - 1) >> 1
|
38
|
+
end
|
39
|
+
|
40
|
+
# Hexagonal numbers are generated by the formula, H_n = n * (2 * n - 1)
|
41
|
+
# The first ten hexagonal numbers are:
|
42
|
+
# 1, 6, 15, 28, 45, 66, 91, 120, 153, 190, ...
|
43
|
+
def hexagonal(n)
|
44
|
+
return n * ((n << 1) - 1)
|
45
|
+
end
|
46
|
+
|
47
|
+
def heptagonal(n)
|
48
|
+
return n * (5 * n - 3) >> 1
|
49
|
+
end
|
50
|
+
|
51
|
+
def octagonal(n)
|
52
|
+
return n * (3 * n - 2)
|
53
|
+
end
|
54
|
+
end
|
data/lib/include/set.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
class Set
|
2
|
+
include Enumerable
|
3
|
+
|
4
|
+
def initialize(ary = [])
|
5
|
+
@set = ary.uniq
|
6
|
+
end
|
7
|
+
|
8
|
+
def add(*items)
|
9
|
+
items.each do |i|
|
10
|
+
@set.push(i) unless @set.include?(i)
|
11
|
+
end
|
12
|
+
return self
|
13
|
+
end
|
14
|
+
|
15
|
+
def ==(other)
|
16
|
+
return false unless self.size == other.size
|
17
|
+
@set.each do |i|
|
18
|
+
return false unless other.include?(i)
|
19
|
+
end
|
20
|
+
|
21
|
+
return true
|
22
|
+
end
|
23
|
+
|
24
|
+
def each(&block)
|
25
|
+
@set.each(&block)
|
26
|
+
end
|
27
|
+
|
28
|
+
def size
|
29
|
+
@set.size
|
30
|
+
end
|
31
|
+
|
32
|
+
def dup
|
33
|
+
self.class.new(@set.dup)
|
34
|
+
end
|
35
|
+
|
36
|
+
def include?(a)
|
37
|
+
@set.include?(a)
|
38
|
+
end
|
39
|
+
|
40
|
+
def inspect
|
41
|
+
str = @set.inspect[1..-2]
|
42
|
+
return "{" + str + "}"
|
43
|
+
end
|
44
|
+
|
45
|
+
def to_a
|
46
|
+
return @set
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class SortableSet < Set
|
51
|
+
def initialize(ary = [], &compare)
|
52
|
+
@set = ary.uniq.sort(&compare)
|
53
|
+
@compare = compare
|
54
|
+
end
|
55
|
+
|
56
|
+
def add(*items)
|
57
|
+
items.each do |i|
|
58
|
+
j = Bisect.bisect_left(@set, i, &@compare)
|
59
|
+
@set.insert(j, i) unless @set[j] == i
|
60
|
+
end
|
61
|
+
return self
|
62
|
+
end
|
63
|
+
|
64
|
+
def dup
|
65
|
+
self.class.new(@set.dup, &@compare)
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module Abst
|
2
|
+
module_function
|
3
|
+
|
4
|
+
class Vector
|
5
|
+
class << self
|
6
|
+
attr_reader :coef_class, :size
|
7
|
+
|
8
|
+
def to_s
|
9
|
+
return "#{size} length #{self.coef_class} Vector"
|
10
|
+
end
|
11
|
+
|
12
|
+
def inspect
|
13
|
+
return to_s
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
attr_reader :coef
|
18
|
+
protected :coef
|
19
|
+
|
20
|
+
def initialize(coef)
|
21
|
+
raise VectorSizeError unless coef.size == self.class.size
|
22
|
+
@coef = coef.to_a
|
23
|
+
end
|
24
|
+
|
25
|
+
def +(other)
|
26
|
+
raise VectorSizeError unless self.size == other.size
|
27
|
+
return self.class.new(self.coef.zip(other.coef).map{|a, b| a + b})
|
28
|
+
end
|
29
|
+
|
30
|
+
def -(other)
|
31
|
+
raise VectorSizeError unless self.size == other.size
|
32
|
+
return self.class.new(self.coef.zip(other.coef).map{|a, b| a - b})
|
33
|
+
end
|
34
|
+
|
35
|
+
def ==(other)
|
36
|
+
return @coef == other.to_a
|
37
|
+
end
|
38
|
+
|
39
|
+
def size
|
40
|
+
return self.class.size
|
41
|
+
end
|
42
|
+
|
43
|
+
def each
|
44
|
+
return Enumerator.new(self) unless block_given?
|
45
|
+
|
46
|
+
@coef.each do |i|
|
47
|
+
yield i
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def squared_length
|
52
|
+
return self.coef.map{|i| i ** 2}.inject(&:+)
|
53
|
+
end
|
54
|
+
|
55
|
+
def [](index)
|
56
|
+
return @coef[index]
|
57
|
+
end
|
58
|
+
|
59
|
+
def to_a
|
60
|
+
return @coef.dup
|
61
|
+
end
|
62
|
+
|
63
|
+
def to_s
|
64
|
+
return @coef.to_s
|
65
|
+
end
|
66
|
+
|
67
|
+
def inspect
|
68
|
+
return "#{self.class}\n#{self}"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def create_vector_space(coef_class, size)
|
73
|
+
if size.kind_of?(Array)
|
74
|
+
elems = size
|
75
|
+
size = size.size
|
76
|
+
end
|
77
|
+
|
78
|
+
vector = Class.new(Vector) do
|
79
|
+
@coef_class = coef_class
|
80
|
+
@size = size
|
81
|
+
end
|
82
|
+
|
83
|
+
return vector.new(elems) if elems
|
84
|
+
return vector
|
85
|
+
end
|
86
|
+
alias Vector create_vector_space
|
87
|
+
module_function :Vector
|
88
|
+
|
89
|
+
class VectorSizeError < Exception; end
|
90
|
+
end
|
data/test/test_all.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require_relative 'test_array'
|
2
|
+
require_relative 'test_bisect'
|
3
|
+
require_relative 'test_combination'
|
4
|
+
require_relative 'test_float'
|
5
|
+
require_relative 'test_fundamental'
|
6
|
+
require_relative 'test_group'
|
7
|
+
require_relative 'test_integer'
|
8
|
+
require_relative 'test_matrix'
|
9
|
+
require_relative 'test_polynomial'
|
10
|
+
require_relative 'test_prime'
|
11
|
+
require_relative 'test_prime_mpqs'
|
12
|
+
require_relative 'test_rational'
|
13
|
+
require_relative 'test_sequence'
|
14
|
+
require_relative 'test_set'
|
15
|
+
require_relative 'test_vector'
|
data/test/test_array.rb
ADDED