symbo 0.1.0pre
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 +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
data/lib/symbo/cos.rb
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'symbo/trigonometric_function'
|
4
|
+
|
5
|
+
module Symbo
|
6
|
+
class Cos < TrigonometricFunction
|
7
|
+
using Symbo
|
8
|
+
|
9
|
+
def self.[](x) # rubocop:disable Naming/MethodParameterName
|
10
|
+
new(x)
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(x) # rubocop:disable Naming/MethodParameterName
|
14
|
+
super :cos, x
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_s
|
18
|
+
"cos(#{operand(1)})"
|
19
|
+
end
|
20
|
+
|
21
|
+
protected
|
22
|
+
|
23
|
+
# rubocop:disable Metrics/AbcSize
|
24
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
25
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
26
|
+
def _simplify
|
27
|
+
if x.zero?
|
28
|
+
1
|
29
|
+
elsif x == PI
|
30
|
+
-1
|
31
|
+
elsif x.constant? && x.negative?
|
32
|
+
Cos[Product[-1, x].simplify].simplify
|
33
|
+
elsif x.product? && x.operand(0).integer? && x.operand(0).negative?
|
34
|
+
Cos[Product[-1, x.operand(0), *x.operands[1..-1]].simplify].simplify
|
35
|
+
elsif kn_pi?
|
36
|
+
simplify_kn_pi.simplify
|
37
|
+
else
|
38
|
+
self
|
39
|
+
end
|
40
|
+
end
|
41
|
+
# rubocop:enable Metrics/AbcSize
|
42
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
43
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
# Simplification of cos(kπ/n)
|
48
|
+
#
|
49
|
+
# rubocop:disable Metrics/AbcSize
|
50
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
51
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
52
|
+
def simplify_kn_pi
|
53
|
+
k = x.operand(0).numerator
|
54
|
+
n = x.operand(0).denominator
|
55
|
+
|
56
|
+
case n
|
57
|
+
when 1
|
58
|
+
case k % 2
|
59
|
+
when 0
|
60
|
+
1
|
61
|
+
end
|
62
|
+
when 2
|
63
|
+
case k % 2
|
64
|
+
when 1
|
65
|
+
0
|
66
|
+
end
|
67
|
+
when 3
|
68
|
+
case k % 6
|
69
|
+
when 1, 5
|
70
|
+
1/2
|
71
|
+
when 2, 4
|
72
|
+
-1/2
|
73
|
+
end
|
74
|
+
when 4
|
75
|
+
case k % 8
|
76
|
+
when 1, 7
|
77
|
+
1/√(2)
|
78
|
+
when 3, 5
|
79
|
+
-1/√(2)
|
80
|
+
end
|
81
|
+
when 6
|
82
|
+
case k % 12
|
83
|
+
when 1, 11
|
84
|
+
√(3)/2
|
85
|
+
when 5, 7
|
86
|
+
Product[-1, √(3)/2]
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
# rubocop:enable Metrics/AbcSize
|
91
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
92
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
93
|
+
end
|
94
|
+
end
|
data/lib/symbo/diff.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'symbo/expression'
|
4
|
+
|
5
|
+
module Symbo
|
6
|
+
class Diff < Expression
|
7
|
+
using Symbo
|
8
|
+
|
9
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
10
|
+
# rubocop:disable Metrics/AbcSize
|
11
|
+
def evaluate
|
12
|
+
v = operand(0).simplify
|
13
|
+
|
14
|
+
if length == 1
|
15
|
+
if v == UNDEFINED
|
16
|
+
UNDEFINED
|
17
|
+
else
|
18
|
+
Product[-1, v].evaluate
|
19
|
+
end
|
20
|
+
elsif length == 2
|
21
|
+
w = operand(1).simplify
|
22
|
+
|
23
|
+
if v == UNDEFINED || w == UNDEFINED
|
24
|
+
UNDEFINED
|
25
|
+
else
|
26
|
+
Sum[v, -w].evaluate
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
31
|
+
# rubocop:enable Metrics/AbcSize
|
32
|
+
end
|
33
|
+
end
|
data/lib/symbo/e.rb
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'symbo/algebraic_operators'
|
4
|
+
require 'symbo/integer'
|
5
|
+
require 'symbo/relational_operators'
|
6
|
+
require 'symbo/symbol'
|
7
|
+
|
8
|
+
module Symbo
|
9
|
+
UNDEFINED = :undefined
|
10
|
+
|
11
|
+
# General expression interface
|
12
|
+
class Expression
|
13
|
+
using Symbo
|
14
|
+
|
15
|
+
include AlgebraicOperators
|
16
|
+
include ExpressionType
|
17
|
+
include RelationalOperators
|
18
|
+
|
19
|
+
attr_reader :operands
|
20
|
+
|
21
|
+
def self.[](*operands)
|
22
|
+
new(*operands)
|
23
|
+
end
|
24
|
+
|
25
|
+
def initialize(*operands)
|
26
|
+
@operands = operands
|
27
|
+
end
|
28
|
+
|
29
|
+
# :section: Simplification Methods
|
30
|
+
|
31
|
+
def simplify
|
32
|
+
self.class.new(*@operands.map(&:simplify))._simplify
|
33
|
+
end
|
34
|
+
|
35
|
+
# :section: Power Transformation Methods
|
36
|
+
#
|
37
|
+
# 自動簡約式 u のべき乗変形に使うオペレータ。
|
38
|
+
#
|
39
|
+
# u^v·u^w = u^{v+w}
|
40
|
+
#
|
41
|
+
|
42
|
+
# べき乗の低
|
43
|
+
def base
|
44
|
+
raise NotImplementedError, "#{self.class}#base"
|
45
|
+
end
|
46
|
+
|
47
|
+
# べき指数
|
48
|
+
#
|
49
|
+
# べき指数を書かない b のような式では exponent → 1 を返すことで、
|
50
|
+
#
|
51
|
+
# b·b^2 = b^3
|
52
|
+
#
|
53
|
+
# のような式変形を簡単にする。
|
54
|
+
def exponent
|
55
|
+
raise NotImplementedError
|
56
|
+
end
|
57
|
+
|
58
|
+
# :section: Basic Distributive Transformation Methods
|
59
|
+
#
|
60
|
+
# 同類項のまとめに使うオペレータ。
|
61
|
+
#
|
62
|
+
# v·u + w·u = (v+w)u
|
63
|
+
#
|
64
|
+
|
65
|
+
# 同類項の項部分
|
66
|
+
#
|
67
|
+
# 返り値は Product または UNDEFINED になる。返り値が単項の積 ·u の場合があるが、
|
68
|
+
# これは x と 2x の term を取ったときにどちらも同じ ·x を返すようにするための工夫。
|
69
|
+
def term
|
70
|
+
raise NotImplementedError, "#{self.class}#term"
|
71
|
+
end
|
72
|
+
|
73
|
+
# 同類項の定数部分
|
74
|
+
def const
|
75
|
+
raise NotImplementedError
|
76
|
+
end
|
77
|
+
|
78
|
+
# :section: Order Relation Methods
|
79
|
+
|
80
|
+
# 交換法則によるオペランド並べ替えに使う順序関係
|
81
|
+
def compare(_other)
|
82
|
+
raise NotImplementedError, "#{self.class}#compare"
|
83
|
+
end
|
84
|
+
|
85
|
+
# :section: Operand Methods
|
86
|
+
|
87
|
+
# Returns nth operand
|
88
|
+
def operand(n) # rubocop:disable Naming/MethodParameterName
|
89
|
+
@operands[n]
|
90
|
+
end
|
91
|
+
|
92
|
+
# Returns the number of operands
|
93
|
+
def length
|
94
|
+
@operands.length
|
95
|
+
end
|
96
|
+
|
97
|
+
protected
|
98
|
+
|
99
|
+
# :category: Simplification Methods
|
100
|
+
|
101
|
+
def _simplify
|
102
|
+
raise NotImplementedError
|
103
|
+
end
|
104
|
+
|
105
|
+
def simplify_rne
|
106
|
+
v = simplify_rne_rec
|
107
|
+
if v == UNDEFINED
|
108
|
+
UNDEFINED
|
109
|
+
else
|
110
|
+
v.simplify_rational_number
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Symbo
|
4
|
+
module ExpressionType
|
5
|
+
# :section: Expression Type Methods
|
6
|
+
|
7
|
+
def undefined?
|
8
|
+
self == UNDEFINED
|
9
|
+
end
|
10
|
+
|
11
|
+
def integer?
|
12
|
+
is_a?(Integer)
|
13
|
+
end
|
14
|
+
|
15
|
+
def complex?
|
16
|
+
is_a?(Complex)
|
17
|
+
end
|
18
|
+
|
19
|
+
def fraction?
|
20
|
+
is_a?(Fraction)
|
21
|
+
end
|
22
|
+
|
23
|
+
def constant?
|
24
|
+
is_a?(Constant)
|
25
|
+
end
|
26
|
+
|
27
|
+
def sum?
|
28
|
+
is_a?(Sum)
|
29
|
+
end
|
30
|
+
|
31
|
+
def product?
|
32
|
+
is_a?(Product)
|
33
|
+
end
|
34
|
+
|
35
|
+
def power?
|
36
|
+
is_a?(Power)
|
37
|
+
end
|
38
|
+
|
39
|
+
def symbol?
|
40
|
+
is_a?(Symbol)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'symbo/integer'
|
4
|
+
require 'symbo/symbol'
|
5
|
+
|
6
|
+
module Symbo
|
7
|
+
# シンボリックな階乗
|
8
|
+
class Factorial < Expression
|
9
|
+
using Symbo
|
10
|
+
|
11
|
+
# :section: Power Transformation Methods
|
12
|
+
|
13
|
+
# べき乗の低
|
14
|
+
#
|
15
|
+
# Factorial[:x].base # => Factorial[:x]
|
16
|
+
def base
|
17
|
+
dup
|
18
|
+
end
|
19
|
+
|
20
|
+
# べき指数
|
21
|
+
#
|
22
|
+
# Factorial[:x].exponent # => 1
|
23
|
+
def exponent
|
24
|
+
1
|
25
|
+
end
|
26
|
+
|
27
|
+
# :section: Basic Distributive Transformation Methods
|
28
|
+
|
29
|
+
# 同類項の項部分
|
30
|
+
#
|
31
|
+
# Factorial[:x].term # => Product[Factorial[:x]]
|
32
|
+
def term
|
33
|
+
Product[self]
|
34
|
+
end
|
35
|
+
|
36
|
+
# 同類項の定数部分
|
37
|
+
#
|
38
|
+
# Factorial[:x].const # => 1
|
39
|
+
def const
|
40
|
+
1
|
41
|
+
end
|
42
|
+
|
43
|
+
# :section: Order Relation Methods
|
44
|
+
|
45
|
+
# 交換法則によるオペランド並べ替えに使う順序関係
|
46
|
+
#
|
47
|
+
# - 相手が階乗の場合
|
48
|
+
# オペランド同士を比較する
|
49
|
+
#
|
50
|
+
# Factorial[:m].compare(:n) # => true
|
51
|
+
#
|
52
|
+
# - 関数またはシンボルの場合
|
53
|
+
# 最初のオペランドが相手と同じ場合 false
|
54
|
+
#
|
55
|
+
# Factorial[Function[:f, :x]].compare(Function[:f, :x]) # => false
|
56
|
+
# Factorial[:x].compare(:x) # => true
|
57
|
+
#
|
58
|
+
# 異なる場合、相手を階乗と見て比較
|
59
|
+
#
|
60
|
+
# Factorial[:x].compare(Function[:f, :x]) # => true
|
61
|
+
#
|
62
|
+
# - それ以外の場合
|
63
|
+
# 次のルールで比較
|
64
|
+
#
|
65
|
+
# !other.compare(self)
|
66
|
+
def compare(other)
|
67
|
+
case other
|
68
|
+
when Factorial
|
69
|
+
@operands[0].compare other.operands[0]
|
70
|
+
when Function, Symbol
|
71
|
+
if @operands[0] == other
|
72
|
+
false
|
73
|
+
else
|
74
|
+
compare Factorial[other]
|
75
|
+
end
|
76
|
+
else
|
77
|
+
!other.compare(self)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
data/lib/symbo/float.rb
ADDED
@@ -0,0 +1,176 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'symbo/constant'
|
4
|
+
|
5
|
+
module Symbo
|
6
|
+
# Symbo fraction computation
|
7
|
+
class Fraction < Expression
|
8
|
+
include Constant
|
9
|
+
|
10
|
+
using Symbo
|
11
|
+
|
12
|
+
# :section: Power Transformation Methods
|
13
|
+
|
14
|
+
# べき乗の低
|
15
|
+
#
|
16
|
+
# (1/3).base # => UNDEFINED
|
17
|
+
def base
|
18
|
+
UNDEFINED
|
19
|
+
end
|
20
|
+
|
21
|
+
# べき指数
|
22
|
+
#
|
23
|
+
# (1/3).exponent # => UNDEFINED
|
24
|
+
def exponent
|
25
|
+
UNDEFINED
|
26
|
+
end
|
27
|
+
|
28
|
+
# :section: Basic Distributive Transformation Methods
|
29
|
+
|
30
|
+
# 同類項の項部分
|
31
|
+
#
|
32
|
+
# (1/3).term # => UNDEFINED
|
33
|
+
def term
|
34
|
+
UNDEFINED
|
35
|
+
end
|
36
|
+
|
37
|
+
# 同類項の定数部分
|
38
|
+
#
|
39
|
+
# (1/3).const # => UNDEFINED
|
40
|
+
def const
|
41
|
+
UNDEFINED
|
42
|
+
end
|
43
|
+
|
44
|
+
# :section: Order Relation Methods
|
45
|
+
|
46
|
+
# 交換法則によるオペランド並べ替えに使う順序関係
|
47
|
+
#
|
48
|
+
# - 相手が定数の場合
|
49
|
+
# 大小関係で順序を決定
|
50
|
+
#
|
51
|
+
# (1/2).compare(4) # => true
|
52
|
+
# (1/2).compare(5/2) # => true
|
53
|
+
#
|
54
|
+
# - それ以外の場合
|
55
|
+
# 常に true
|
56
|
+
#
|
57
|
+
# (1/2).compare(:x + :y) # => true
|
58
|
+
# (1/2).compare(:x * :y) # => true
|
59
|
+
# (1/2).compare(2**:x) # => true
|
60
|
+
# (1/2).compare(Factorial(2)) # => true
|
61
|
+
# (1/2).compare(Function(:f, :x)) # => true
|
62
|
+
def compare(other)
|
63
|
+
case other
|
64
|
+
when Integer
|
65
|
+
rational < other
|
66
|
+
when Fraction
|
67
|
+
rational < other.rational
|
68
|
+
else
|
69
|
+
true
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# :section:
|
74
|
+
|
75
|
+
def positive?
|
76
|
+
rational.positive?
|
77
|
+
end
|
78
|
+
|
79
|
+
def rational
|
80
|
+
Rational operand(0), operand(1)
|
81
|
+
end
|
82
|
+
|
83
|
+
def numerator
|
84
|
+
if operands.all?(&:integer?)
|
85
|
+
rational.numerator
|
86
|
+
else
|
87
|
+
operand(0)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def denominator
|
92
|
+
if operands.all?(&:integer?)
|
93
|
+
rational.denominator
|
94
|
+
else
|
95
|
+
operand(1)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def evaluate
|
100
|
+
if denominator.zero?
|
101
|
+
UNDEFINED
|
102
|
+
else
|
103
|
+
self
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def simplify_rne_rec
|
108
|
+
if denominator.zero?
|
109
|
+
UNDEFINED
|
110
|
+
else
|
111
|
+
self
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
# rubocop:disable Metrics/AbcSize
|
116
|
+
def simplify_rational_number
|
117
|
+
n = operand(0)
|
118
|
+
d = operand(1)
|
119
|
+
|
120
|
+
case [n, d]
|
121
|
+
in Integer, Integer
|
122
|
+
if (n % d).zero?
|
123
|
+
n.div d
|
124
|
+
else
|
125
|
+
g = n.gcd(d)
|
126
|
+
if d.positive?
|
127
|
+
Fraction[n.div(g), d.div(g)]
|
128
|
+
else
|
129
|
+
Fraction[(-n).div(g), (-d).div(g)]
|
130
|
+
end
|
131
|
+
end
|
132
|
+
in Complex, Integer
|
133
|
+
real_mod = n.real % d
|
134
|
+
imag_mod = n.imag % d
|
135
|
+
if real_mod.zero? && imag_mod.zero?
|
136
|
+
if n.imag.div(d).zero?
|
137
|
+
n.real.div d
|
138
|
+
else
|
139
|
+
Complex(n.real.div(d), n.imag.div(d))
|
140
|
+
end
|
141
|
+
else
|
142
|
+
gr = n.real.gcd(d)
|
143
|
+
gi = n.imag.gcd(d)
|
144
|
+
if gr == gi
|
145
|
+
if d.positive?
|
146
|
+
Fraction[Complex(n.real.div(gr), n.imag.div(gr)), d.div(gr)]
|
147
|
+
else
|
148
|
+
Fraction[Complex(-n.real.div(gr), -n.imag.div(gr)), -d.div(gr)]
|
149
|
+
end
|
150
|
+
else
|
151
|
+
self
|
152
|
+
end
|
153
|
+
end
|
154
|
+
else
|
155
|
+
raise NotImplementedError, "Fraction#simplify_rational_number(#{n.inspect}/#{d.inspect})"
|
156
|
+
end
|
157
|
+
end
|
158
|
+
# rubocop:enable Metrics/AbcSize
|
159
|
+
|
160
|
+
def negative?
|
161
|
+
false
|
162
|
+
end
|
163
|
+
|
164
|
+
def to_s
|
165
|
+
"#{operand(0)}/#{operand(1)}"
|
166
|
+
end
|
167
|
+
|
168
|
+
protected
|
169
|
+
|
170
|
+
def _simplify
|
171
|
+
return UNDEFINED if operand(1).zero?
|
172
|
+
|
173
|
+
simplify_rational_number
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|