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.
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Symbo
4
+ module Constant; end
5
+ end
@@ -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
@@ -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
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Symbo
4
+ E = :E
5
+ end
@@ -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
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ # 浮動小数点数のシンボリック演算
4
+ class Float
5
+ def simplify
6
+ self
7
+ end
8
+ end
@@ -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