symbo 0.1.0pre

Sign up to get free protection for your applications and to get access to all the features.
@@ -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