symbo 0.1.0pre
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/workflows/ruby.yml +26 -0
- data/.gitignore +56 -0
- data/.rubocop.yml +31 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +0 -0
- data/Gemfile +19 -0
- data/Gemfile.lock +65 -0
- data/LICENSE +21 -0
- data/README.md +37 -0
- data/Rakefile +12 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/symbo.rb +21 -0
- data/lib/symbo/algebraic_operators.rb +35 -0
- data/lib/symbo/complex.rb +78 -0
- data/lib/symbo/constant.rb +5 -0
- data/lib/symbo/cos.rb +94 -0
- data/lib/symbo/diff.rb +33 -0
- data/lib/symbo/e.rb +5 -0
- data/lib/symbo/expression.rb +114 -0
- data/lib/symbo/expression_type.rb +43 -0
- data/lib/symbo/factorial.rb +81 -0
- data/lib/symbo/float.rb +8 -0
- data/lib/symbo/fraction.rb +176 -0
- data/lib/symbo/function.rb +118 -0
- data/lib/symbo/integer.rb +126 -0
- data/lib/symbo/matrix.rb +22 -0
- data/lib/symbo/mergeable.rb +30 -0
- data/lib/symbo/pi.rb +5 -0
- data/lib/symbo/power.rb +198 -0
- data/lib/symbo/product.rb +218 -0
- data/lib/symbo/qubit.rb +124 -0
- data/lib/symbo/quot.rb +37 -0
- data/lib/symbo/relational_operators.rb +15 -0
- data/lib/symbo/sin.rb +91 -0
- data/lib/symbo/sqrt.rb +16 -0
- data/lib/symbo/sum.rb +211 -0
- data/lib/symbo/symbol.rb +102 -0
- data/lib/symbo/tensor_product.rb +15 -0
- data/lib/symbo/trigonometric_function.rb +26 -0
- data/lib/symbo/version.rb +5 -0
- data/symbo.gemspec +33 -0
- metadata +116 -0
@@ -0,0 +1,118 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'symbo/expression'
|
4
|
+
require 'symbo/integer'
|
5
|
+
require 'symbo/symbol'
|
6
|
+
|
7
|
+
module Symbo
|
8
|
+
class Function < Expression
|
9
|
+
include Symbo
|
10
|
+
|
11
|
+
using Symbo
|
12
|
+
|
13
|
+
def name
|
14
|
+
@operands[0]
|
15
|
+
end
|
16
|
+
|
17
|
+
def parameters
|
18
|
+
@operands[1..-1]
|
19
|
+
end
|
20
|
+
|
21
|
+
# :section: Power Transformation Methods
|
22
|
+
|
23
|
+
# べき乗の低
|
24
|
+
#
|
25
|
+
# Function(:f, :x).base # => Function(:f, :x)
|
26
|
+
def base
|
27
|
+
dup
|
28
|
+
end
|
29
|
+
|
30
|
+
# べき指数
|
31
|
+
#
|
32
|
+
# Function(:f, :x).exponent # => 1
|
33
|
+
def exponent
|
34
|
+
1
|
35
|
+
end
|
36
|
+
|
37
|
+
# :section: Basic Distributive Transformation Methods
|
38
|
+
|
39
|
+
# 同類項の項部分
|
40
|
+
#
|
41
|
+
# Function(:f, :x).term # => Product(Function(:f, :x))
|
42
|
+
def term
|
43
|
+
Product[self]
|
44
|
+
end
|
45
|
+
|
46
|
+
# 同類項の定数部分
|
47
|
+
#
|
48
|
+
# Function(:f, :x).const # => 1
|
49
|
+
def const
|
50
|
+
1
|
51
|
+
end
|
52
|
+
|
53
|
+
# :section: Order Relation Methods
|
54
|
+
|
55
|
+
# 交換法則によるオペランド並べ替えに使う順序関係
|
56
|
+
#
|
57
|
+
# - 相手が関数の場合
|
58
|
+
# 関数名が異なる場合、関数名で順序を決定。
|
59
|
+
#
|
60
|
+
# Function(:f, :x).compare(Function(:g, :x)) # => true
|
61
|
+
#
|
62
|
+
# 関数名が同じの場合、関数の最左のオペランドから順に compare していき、
|
63
|
+
# 異なるものがあればそれで順序を決定する。
|
64
|
+
#
|
65
|
+
# Function(:f, :x).compare(Function(:f, :y)) # => true
|
66
|
+
#
|
67
|
+
# どちらかのオペランドがなくなれば、短いほうが左側。
|
68
|
+
#
|
69
|
+
# Function(:g, :x).compare(Function(:g, :x, :y)) # => true
|
70
|
+
#
|
71
|
+
# - シンボルの場合
|
72
|
+
# 関数名とシンボルが等しい場合 false
|
73
|
+
#
|
74
|
+
# Function(:f, :x).compare(:f) # => false
|
75
|
+
#
|
76
|
+
# 異なる場合、関数名とシンボルで比較
|
77
|
+
#
|
78
|
+
# Function(:f, :x).compare(:g) # => true
|
79
|
+
#
|
80
|
+
# - それ以外の場合
|
81
|
+
# 次のルールで比較
|
82
|
+
#
|
83
|
+
# !other.compare(self)
|
84
|
+
#
|
85
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
86
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
87
|
+
# rubocop:disable Metrics/AbcSize
|
88
|
+
def compare(other)
|
89
|
+
case other
|
90
|
+
when Function
|
91
|
+
if name != other.name
|
92
|
+
name.compare other.name
|
93
|
+
else
|
94
|
+
return parameters.first.compare other.parameters.first if parameters.first != other.parameters.first
|
95
|
+
|
96
|
+
m = parameters.length
|
97
|
+
n = other.parameters.length
|
98
|
+
0.upto([m, n].min - 2) do |j|
|
99
|
+
return parameters[j + 1].compare(other.parameters[j + 1]) if (parameters[j] == other.parameters[j]) && (parameters[j + 1] != other.parameters[j + 1])
|
100
|
+
end
|
101
|
+
|
102
|
+
m.compare(n)
|
103
|
+
end
|
104
|
+
when Symbol
|
105
|
+
if name == other
|
106
|
+
false
|
107
|
+
else
|
108
|
+
name.compare other
|
109
|
+
end
|
110
|
+
else
|
111
|
+
!other.compare(self)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
115
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
116
|
+
# rubocop:enable Metrics/AbcSize
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'symbo/algebraic_operators'
|
4
|
+
require 'symbo/constant'
|
5
|
+
require 'symbo/expression_type'
|
6
|
+
|
7
|
+
# Symbolic computation
|
8
|
+
module Symbo
|
9
|
+
# Integer refinements
|
10
|
+
refine Integer do
|
11
|
+
alias_method :mult, :*
|
12
|
+
alias_method :div, :/
|
13
|
+
|
14
|
+
include AlgebraicOperators
|
15
|
+
include ExpressionType
|
16
|
+
include Constant
|
17
|
+
|
18
|
+
def simplify
|
19
|
+
self
|
20
|
+
end
|
21
|
+
|
22
|
+
# :section: Power Transformation Methods
|
23
|
+
|
24
|
+
# べき乗の低
|
25
|
+
#
|
26
|
+
# 1.base # => UNDEFINED
|
27
|
+
def base
|
28
|
+
UNDEFINED
|
29
|
+
end
|
30
|
+
|
31
|
+
# べき指数
|
32
|
+
#
|
33
|
+
# 1.exponent # => UNDEFINED
|
34
|
+
def exponent
|
35
|
+
UNDEFINED
|
36
|
+
end
|
37
|
+
|
38
|
+
# :section: Basic Distributive Transformation Methods
|
39
|
+
|
40
|
+
# 同類項の項部分
|
41
|
+
#
|
42
|
+
# 1.term # => UNDEFINED
|
43
|
+
def term
|
44
|
+
UNDEFINED
|
45
|
+
end
|
46
|
+
|
47
|
+
# 同類項の定数部分
|
48
|
+
#
|
49
|
+
# 1.const # => UNDEFINED
|
50
|
+
def const
|
51
|
+
UNDEFINED
|
52
|
+
end
|
53
|
+
|
54
|
+
# :section: Order Relation Methods
|
55
|
+
|
56
|
+
# 交換法則によるオペランド並べ替えに使う順序関係
|
57
|
+
#
|
58
|
+
# - 相手が定数の場合
|
59
|
+
# 大小関係で順序を決定
|
60
|
+
#
|
61
|
+
# 2.compare(4) # => true
|
62
|
+
# 2.compare(5/2) # => true
|
63
|
+
#
|
64
|
+
# - それ以外の場合
|
65
|
+
# 常に true
|
66
|
+
#
|
67
|
+
# 2.compare(:x + :y) # => true
|
68
|
+
# 2.compare(:x * :y) # => true
|
69
|
+
# 2.compare(2**:x) # => true
|
70
|
+
# 2.compare(Factorial(2)) # => true
|
71
|
+
# 2.compare(Function(:f, :x)) # => true
|
72
|
+
def compare(other)
|
73
|
+
case other
|
74
|
+
when Integer
|
75
|
+
self < other
|
76
|
+
when Fraction
|
77
|
+
self < other.rational
|
78
|
+
else
|
79
|
+
true
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# :section:
|
84
|
+
|
85
|
+
def numerator
|
86
|
+
self
|
87
|
+
end
|
88
|
+
|
89
|
+
def denominator
|
90
|
+
1
|
91
|
+
end
|
92
|
+
|
93
|
+
def evaluate
|
94
|
+
self
|
95
|
+
end
|
96
|
+
|
97
|
+
def simplify_rational_number
|
98
|
+
self
|
99
|
+
end
|
100
|
+
|
101
|
+
def simplify_rne_rec
|
102
|
+
self
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# Matrix などの中で使われる Integer#+ などをハイジャック
|
108
|
+
class Integer
|
109
|
+
include Symbo::Constant
|
110
|
+
include Symbo::ExpressionType
|
111
|
+
|
112
|
+
alias plus +
|
113
|
+
alias mult *
|
114
|
+
|
115
|
+
def +(other)
|
116
|
+
plus other
|
117
|
+
rescue TypeError
|
118
|
+
Symbo::Sum[self, other]
|
119
|
+
end
|
120
|
+
|
121
|
+
def *(other)
|
122
|
+
mult other
|
123
|
+
rescue TypeError
|
124
|
+
Symbo::Product[self, other]
|
125
|
+
end
|
126
|
+
end
|
data/lib/symbo/matrix.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'matrix'
|
4
|
+
|
5
|
+
module Symbo
|
6
|
+
# シンボリック演算を使う行列
|
7
|
+
refine Matrix do
|
8
|
+
alias_method :mult, :*
|
9
|
+
|
10
|
+
def *(other)
|
11
|
+
if other.respond_to?(:to_matrix)
|
12
|
+
(mult other.to_matrix).simplify
|
13
|
+
else
|
14
|
+
mult other
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def simplify
|
19
|
+
map(&:simplify)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Symbo
|
4
|
+
module Mergeable
|
5
|
+
private
|
6
|
+
|
7
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
8
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
9
|
+
def merge(p, q) # rubocop:disable Naming/MethodParameterName
|
10
|
+
return p if q.empty?
|
11
|
+
return q if p.empty?
|
12
|
+
|
13
|
+
p1 = p[0]
|
14
|
+
q1 = q[0]
|
15
|
+
h = simplify_rec([p1, q1])
|
16
|
+
case h
|
17
|
+
in []
|
18
|
+
merge p[1..-1], q[1..-1]
|
19
|
+
in [_]
|
20
|
+
h + merge(p[1..-1], q[1..-1])
|
21
|
+
in ^p1, ^q1
|
22
|
+
[p1] + merge(p[1..-1], q)
|
23
|
+
in ^q1, ^p1
|
24
|
+
[q1] + merge(p, q[1..-1])
|
25
|
+
end
|
26
|
+
end
|
27
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
28
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
29
|
+
end
|
30
|
+
end
|
data/lib/symbo/pi.rb
ADDED
data/lib/symbo/power.rb
ADDED
@@ -0,0 +1,198 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'symbo/expression'
|
4
|
+
|
5
|
+
module Symbo
|
6
|
+
class Power < Expression
|
7
|
+
using Symbo
|
8
|
+
|
9
|
+
# :section: Power Transformation Methods
|
10
|
+
|
11
|
+
# べき乗の低
|
12
|
+
#
|
13
|
+
# (:x**2).base # => :x
|
14
|
+
def base
|
15
|
+
@operands[0]
|
16
|
+
end
|
17
|
+
|
18
|
+
# べき指数
|
19
|
+
#
|
20
|
+
# (:x**2).exponent # => 2
|
21
|
+
def exponent
|
22
|
+
@operands[1]
|
23
|
+
end
|
24
|
+
|
25
|
+
# :section: Basic Distributive Transformation Methods
|
26
|
+
|
27
|
+
# 同類項の項部分
|
28
|
+
#
|
29
|
+
# (:x**2).term # => Product(:x**2)
|
30
|
+
def term
|
31
|
+
Product[self]
|
32
|
+
end
|
33
|
+
|
34
|
+
# 同類項の定数部分
|
35
|
+
#
|
36
|
+
# (:x**2).const # => 1
|
37
|
+
def const
|
38
|
+
1
|
39
|
+
end
|
40
|
+
|
41
|
+
# :section: Order Relation Methods
|
42
|
+
|
43
|
+
# 交換法則によるオペランド並べ替えに使う順序関係
|
44
|
+
#
|
45
|
+
# - 相手がべき乗の場合
|
46
|
+
# 底が異なる場合、底同士で順序を決める。
|
47
|
+
# 底が等しい場合、べき指数同士で順序を決める。
|
48
|
+
#
|
49
|
+
# ((1 + :x)**3).compare((1 + :y)**2) # => true
|
50
|
+
# ((1 + :x)**2).compare((1 + :x)**3) # => true
|
51
|
+
#
|
52
|
+
# - 和、階乗、関数、シンボルの場合
|
53
|
+
# 相手を 1 乗のべき乗に変換して比較
|
54
|
+
#
|
55
|
+
# ((1 + :x)**3).compare(1 + :y) # => true
|
56
|
+
#
|
57
|
+
# - それ以外の場合
|
58
|
+
# 次のルールで比較
|
59
|
+
#
|
60
|
+
# !other.compare(self)
|
61
|
+
def compare(other)
|
62
|
+
case other
|
63
|
+
when Power
|
64
|
+
return base.compare(other.base) if base != other.base
|
65
|
+
|
66
|
+
exponent.compare other.exponent
|
67
|
+
when Sum, Factorial, Function, Symbol
|
68
|
+
compare Power[other, 1]
|
69
|
+
else
|
70
|
+
!other.compare(self)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# :section: Evaluation Methods
|
75
|
+
|
76
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
77
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
78
|
+
# rubocop:disable Metrics/AbcSize
|
79
|
+
def evaluate
|
80
|
+
raise unless base.constant?
|
81
|
+
raise unless exponent.integer?
|
82
|
+
|
83
|
+
if base.numerator != 0
|
84
|
+
if exponent.positive?
|
85
|
+
Product[Power[base, exponent - 1].evaluate, base].evaluate
|
86
|
+
elsif exponent.zero?
|
87
|
+
1
|
88
|
+
elsif exponent == -1
|
89
|
+
Fraction[1, base]
|
90
|
+
elsif exponent < -1
|
91
|
+
raise NotImplementedError
|
92
|
+
end
|
93
|
+
elsif base.numerator.zero?
|
94
|
+
if n >= 1
|
95
|
+
0
|
96
|
+
else
|
97
|
+
UNDEFINED
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
102
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
103
|
+
# rubocop:enable Metrics/AbcSize
|
104
|
+
|
105
|
+
def to_s
|
106
|
+
"#{base}^(#{exponent})"
|
107
|
+
end
|
108
|
+
|
109
|
+
protected
|
110
|
+
|
111
|
+
# :section: Simplification Methods
|
112
|
+
|
113
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
114
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
115
|
+
# rubocop:disable Metrics/AbcSize
|
116
|
+
def _simplify
|
117
|
+
return UNDEFINED if base == UNDEFINED || exponent == UNDEFINED
|
118
|
+
|
119
|
+
if base.zero?
|
120
|
+
return 1 if exponent.positive? && exponent.constant?
|
121
|
+
|
122
|
+
return UNDEFINED
|
123
|
+
end
|
124
|
+
|
125
|
+
return 1 if base == 1
|
126
|
+
return simplify_integer_power if exponent.integer?
|
127
|
+
return simplify_eulers_formula if base == E
|
128
|
+
|
129
|
+
self
|
130
|
+
end
|
131
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
132
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
133
|
+
# rubocop:enable Metrics/AbcSize
|
134
|
+
|
135
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
136
|
+
# rubocop:disable Metrics/AbcSize
|
137
|
+
def simplify_integer_power
|
138
|
+
return Power[base, exponent].simplify_rne if base.constant?
|
139
|
+
return 1 if exponent.zero?
|
140
|
+
return base if exponent == 1
|
141
|
+
|
142
|
+
case base
|
143
|
+
when Power
|
144
|
+
r = base.operands[0]
|
145
|
+
s = base.operands[1]
|
146
|
+
p = Product.new(s, exponent).simplify
|
147
|
+
|
148
|
+
if p.integer?
|
149
|
+
Power[r, p].simplify_integer_power
|
150
|
+
else
|
151
|
+
Power[r, p]
|
152
|
+
end
|
153
|
+
when Product
|
154
|
+
r = base.operands.map { |each| Power[each, exponent].simplify_integer_power }
|
155
|
+
Product[*r].simplify
|
156
|
+
else
|
157
|
+
self
|
158
|
+
end
|
159
|
+
end
|
160
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
161
|
+
# rubocop:enable Metrics/AbcSize
|
162
|
+
|
163
|
+
# e^ix = cos(x) + sin(x)
|
164
|
+
#
|
165
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
166
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
167
|
+
# rubocop:disable Metrics/AbcSize
|
168
|
+
def simplify_eulers_formula
|
169
|
+
if exponent.product? &&
|
170
|
+
exponent.operand(0).is_a?(Complex) && exponent.operand(0).real.zero? &&
|
171
|
+
exponent.operand(1) == PI
|
172
|
+
# eg e^{ki * π}
|
173
|
+
x = Product[exponent.operand(0).imag, exponent.operand(1)]
|
174
|
+
(Cos[x] + 1i * Sin[x]).simplify
|
175
|
+
elsif exponent.product? &&
|
176
|
+
exponent.operand(0).fraction? && exponent.operand(0).operand(0).is_a?(Complex) && exponent.operand(0).operand(0).real.zero? &&
|
177
|
+
exponent.operand(1) == PI
|
178
|
+
# eg e^{(k/n)i * π}
|
179
|
+
x = Product[Fraction[exponent.operand(0).operand(0).imag, exponent.operand(0).operand(1)], exponent.operand(1)]
|
180
|
+
(Cos[x] + 1i * Sin[x]).simplify
|
181
|
+
else
|
182
|
+
self
|
183
|
+
end
|
184
|
+
end
|
185
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
186
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
187
|
+
# rubocop:enable Metrics/AbcSize
|
188
|
+
|
189
|
+
def simplify_rne_rec
|
190
|
+
v = base.simplify_rne_rec
|
191
|
+
if v == UNDEFINED
|
192
|
+
UNDEFINED
|
193
|
+
else
|
194
|
+
Power[v, exponent].evaluate
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|