hyper_complex 1.0.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: bc2ded74b42084d30a37f220acef7f64b61c86d9081b348b86a1a87a2ede8697
4
+ data.tar.gz: 387d3b3132215c75dd73cc7dafc0df63249783ee5b1e9bdacca445f094d1db16
5
+ SHA512:
6
+ metadata.gz: 59c192cde4da76a0875720fb3ce5ae262611ce1f5a9b8424c5693e9258bb0fbfbc94f6e3966dfb7f1a6d87a0dfbca8f4c25097ab8f205021cbe57c59885e01e7
7
+ data.tar.gz: 2cc6b32a325a6b74d922afd52732988b4d0c74c72223cb0f08a566f4af3e3aa0b9d5b36550a37f6dcd41c56d9e6671e458e1a9132d3aa5be4b22d33c06c313cb
data/.yardopts ADDED
@@ -0,0 +1,6 @@
1
+ --protected
2
+ --title "HyperComplex"
3
+ --readme README.html
4
+ -
5
+
6
+ LICENSE
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Boris Fifelin
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.html ADDED
@@ -0,0 +1,170 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+
4
+ <body>
5
+ <h1 id="hypercomplex">HyperComplex</h1>
6
+
7
+ <p>This gem provides a <code>HyperComplex</code> class highly compatible with other numeric classes.</p>
8
+
9
+ <p>The <a href="https://en.wikipedia.org/wiki/Hypercomplex_number">hypercomplex numbers</a> form finite-dimensional
10
+ algebra over the real numbers. These algebras are produced by the <a
11
+ href="https://en.wikipedia.org/wiki/Cayley%E2%80%93Dickson_construction">Cayley–Dickson construction</a>.
12
+ Examples of such algebras are complex numbers, quaternions, octonions, sedenions, etc.</p>
13
+
14
+ <p>The hypercomplex number can be represented as</p>
15
+ <math>
16
+ <munderover>
17
+ <mi>&Sum;</mi>
18
+ <mrow>
19
+ <mi>i</mi>
20
+ <mo>=</mo>
21
+ <mn>0</mn>
22
+ </mrow>
23
+ <mrow>
24
+ <msup>
25
+ <mn>2</mn>
26
+ <mi>n</mi>
27
+ </msup>
28
+ <mo>-</mo>
29
+ <mn>1</mn>
30
+ </mrow>
31
+ </munderover>
32
+ <msub>
33
+ <mi>a</mi>
34
+ <mi>i</mi>
35
+ </msub>
36
+ <msub>
37
+ <mi>e</mi>
38
+ <mi>i</mi>
39
+ </msub>
40
+ <mtext>&ThickSpace; where &MediumSpace;</mtext>
41
+ <msub>
42
+ <mi>a</mi>
43
+ <mi>i</mi>
44
+ </msub>
45
+ <mo>&in;</mo>
46
+ <mstyle mathvariant="bold" , mathsize="big">
47
+ <mi>&Ropf;</mi>
48
+ </mstyle>
49
+ <mtext>, &MediumSpace;</mtext>
50
+ <msub>
51
+ <mi>e</mi>
52
+ <mn>0</mn>
53
+ </msub>
54
+ <mo>=</mo>
55
+ <mn>1</mn>
56
+ <mtext>, &MediumSpace;</mtext>
57
+ <msubsup>
58
+ <mi>e</mi>
59
+ <mn>1</mn>
60
+ <mn>2</mn>
61
+ </msubsup>
62
+ <mo>=</mo>
63
+ <mi>...</mi>
64
+ <mo>=</mo>
65
+ <msubsup>
66
+ <mi>e</mi>
67
+ <mrow>
68
+ <msup>
69
+ <mn>2</mn>
70
+ <mi>n</mi>
71
+ </msup>
72
+ <mo>-</mo>
73
+ <mn>1</mn>
74
+ </mrow>
75
+ <mn>2</mn>
76
+ </msubsup>
77
+ <mo>=</mo>
78
+ <mo>-</mo>
79
+ <mn>1</mn>
80
+ <mtext>,&MediumSpace;</mtext>
81
+ <mi>n</mi>
82
+ <mo>&in;</mo>
83
+ <mstyle mathvariant="bold" , mathsize="big">
84
+ <mi>&Nopf;</mi>
85
+ </mstyle>
86
+ </math>
87
+
88
+ <p><math>
89
+ <mtext>The identity unit &MediumSpace;&lpar;</mtext>
90
+ <msub>
91
+ <mi>e</mi>
92
+ <mn>0</mn>
93
+ </msub>
94
+ <mtext>&rpar;&MediumSpace; and imaginary units &MediumSpace;&lpar;</mtext>
95
+ <msub>
96
+ <mi>e</mi>
97
+ <mi>i</mi>
98
+ </msub>
99
+ <mtext>,&MediumSpace;</mtext>
100
+ <mi>i</mi>
101
+ <mo>&ne;</mo>
102
+ <mn>0</mn>
103
+ <mtext>&rpar;&MediumSpace; form the basis for space of dimension &MediumSpace;</mtext>
104
+ <msup>
105
+ <mn>2</mn>
106
+ <mi>n</mi>
107
+ </msup>
108
+ <mtext>&MediumSpace; over &MediumSpace;</mtext>
109
+ <mstyle mathvariant="bold" , mathsize="big">
110
+ <mi>&Ropf;</mi>
111
+ </mstyle>
112
+ <mtext>.</mtext>
113
+ </math></p>
114
+
115
+ <h2 id="requirements">Requirements</h2>
116
+
117
+ <p>Ruby &gt;= 3.1</p>
118
+
119
+ <h2 id="installation">Installation</h2>
120
+
121
+ <p>Add this line to your application's Gemfile:</p>
122
+
123
+ <pre class="code ruby"><code class="ruby">gem 'mcalendar'</code></pre>
124
+
125
+ <p>And then execute:</p>
126
+
127
+ <pre class="code ruby"><code class="ruby">$ bundle install</code></pre>
128
+
129
+ <p>Or install it yourself as:</p>
130
+
131
+ <pre class="code ruby"><code class="ruby">$ gem install hyper_complex
132
+ </code></pre>
133
+
134
+ <h2 id="usage">Usage</h2>
135
+
136
+ <pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_require'>require</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>hyper_complex</span><span class='tstring_end'>&#39;</span></span>
137
+
138
+ <span class='comment'># Creation from complex numbers
139
+ </span><span class='id identifier rubyid_q1'>q1</span> <span class='op'>=</span> <span class='const'><span class='object_link'><a href="HyperComplex.html" title="HyperComplex (class)">HyperComplex</a></span></span><span class='period'>.</span><span class='id identifier rubyid_rect'><span class='object_link'><a href="HyperComplex.html#rect-class_method" title="HyperComplex.rect (method)">rect</a></span></span><span class='lparen'>(</span><span class='lparen'>(</span><span class='int'>1</span><span class='op'>+</span><span class='imaginary'>2i</span><span class='rparen'>)</span><span class='comma'>,</span> <span class='lparen'>(</span><span class='int'>3</span><span class='op'>+</span><span class='imaginary'>4i</span><span class='rparen'>)</span><span class='rparen'>)</span> <span class='comment'>#=&gt; HyperComplex[1, 2, 3, 4]
140
+ </span><span class='id identifier rubyid_q2'>q2</span> <span class='op'>=</span> <span class='const'><span class='object_link'><a href="HyperComplex.html" title="HyperComplex (class)">HyperComplex</a></span></span><span class='period'>.</span><span class='id identifier rubyid_rect'><span class='object_link'><a href="HyperComplex.html#rect-class_method" title="HyperComplex.rect (method)">rect</a></span></span><span class='lparen'>(</span><span class='lparen'>(</span><span class='int'>5</span><span class='op'>+</span><span class='imaginary'>6i</span><span class='rparen'>)</span><span class='comma'>,</span> <span class='lparen'>(</span><span class='int'>7</span><span class='op'>+</span><span class='imaginary'>8i</span><span class='rparen'>)</span><span class='rparen'>)</span> <span class='comment'>#=&gt; HyperComplex[5, 6, 7, 8]
141
+ </span>
142
+ <span class='comment'># Creation from HyperComplex numbers
143
+ </span><span class='id identifier rubyid_o1'>o1</span> <span class='op'>=</span> <span class='const'><span class='object_link'><a href="HyperComplex.html" title="HyperComplex (class)">HyperComplex</a></span></span><span class='period'>.</span><span class='id identifier rubyid_rect'><span class='object_link'><a href="HyperComplex.html#rect-class_method" title="HyperComplex.rect (method)">rect</a></span></span><span class='lparen'>(</span><span class='id identifier rubyid_q1'>q1</span><span class='comma'>,</span> <span class='id identifier rubyid_q2'>q2</span><span class='rparen'>)</span> <span class='comment'>#=&gt; HyperComplex[1, 2, 3, 4, 5, 6, 7, 8]
144
+ </span>
145
+ <span class='comment'># Creation from real numbers
146
+ </span><span class='id identifier rubyid_o2'>o2</span> <span class='op'>=</span> <span class='const'>HyperCoplex</span><span class='lbracket'>[</span><span class='int'>9</span><span class='comma'>,</span> <span class='int'>10</span><span class='comma'>,</span> <span class='int'>11</span><span class='comma'>,</span> <span class='int'>12</span><span class='comma'>,</span> <span class='int'>13</span><span class='rbracket'>]</span> <span class='comment'>#=&gt; HyperComplex[9, 10, 11, 12, 13, 0, 0, 0]
147
+ </span>
148
+ <span class='comment'># Creation from polar form
149
+ </span><span class='id identifier rubyid_q3'>q3</span> <span class='op'>=</span> <span class='const'><span class='object_link'><a href="HyperComplex.html" title="HyperComplex (class)">HyperComplex</a></span></span><span class='period'>.</span><span class='id identifier rubyid_polar'><span class='object_link'><a href="HyperComplex.html#polar-class_method" title="HyperComplex.polar (method)">polar</a></span></span><span class='lparen'>(</span><span class='int'>1</span><span class='comma'>,</span> <span class='const'>Math</span><span class='op'>::</span><span class='const'>PI</span><span class='op'>/</span><span class='int'>3</span><span class='comma'>,</span> <span class='const'>Vector</span><span class='lbracket'>[</span><span class='int'>1</span><span class='comma'>,</span> <span class='int'>1</span><span class='comma'>,</span> <span class='int'>1</span><span class='rbracket'>]</span><span class='period'>.</span><span class='id identifier rubyid_normalize'>normalize</span><span class='rparen'>)</span> <span class='comment'>#=&gt; HyperComplex[0.5, 0.5, 0.5, 0.5]
150
+ </span>
151
+ <span class='comment'># standard calculations between numeric instances
152
+ </span><span class='lparen'>(</span><span class='id identifier rubyid_q1'>q1</span><span class='op'>+</span><span class='id identifier rubyid_q2'>q2</span><span class='rparen'>)</span><span class='op'>*</span><span class='id identifier rubyid_o1'>o1</span> <span class='op'>/</span> <span class='const'>Complex</span><span class='op'>::</span><span class='const'>I</span> <span class='op'>-</span> <span class='int'>24</span> <span class='comment'>#=&gt; HyperComplex[(0/1), (88/1), (-40/1), (20/1), (-80/1), (-184/1), (112/1), (-84/1)]
153
+ </span></code></pre>
154
+
155
+ <h2 id="contributing">Contributing</h2>
156
+
157
+ <p>Bug reports and pull requests are welcome on GitHub at <a
158
+ href="https://github.com/bfifelin/hyper_complex">github.com/bfifelin/hyper_complex</a>.</p>
159
+
160
+ <h2 id="license">License</h2>
161
+
162
+ <p>This project is licensed under the terms of the <a href="http://opensource.org/licenses/MIT">MIT license</a>.</p>
163
+
164
+ <h2 id="acknowledgments">Acknowledgments</h2>
165
+
166
+ <p>This gem is based on the gem <a href="https://rubygems.org/gems/quaternion_c2">quaternion_c2</a> by Masahiro
167
+ Nomoto.</p>
168
+ </body>
169
+
170
+ </html>
data/README.md ADDED
@@ -0,0 +1,63 @@
1
+ # HyperComplex
2
+
3
+ This gem provides a `HyperComplex` class highly compatible with other numeric classes.
4
+
5
+ The [hypercomplex numbers](https://en.wikipedia.org/wiki/Hypercomplex_number) form finite-dimensional algebra over the real numbers. These algebras are produced by the [Cayley–Dickson construction](https://en.wikipedia.org/wiki/Cayley%E2%80%93Dickson_construction). Examples of such algebras are complex numbers, quaternions, octonions, sedenions, etc.
6
+
7
+ The hypercomplex number can be represented as
8
+
9
+ $\displaystyle\sum_{i=0}^{2^n-1} a_ie_i$ where $a_i \in \mathbf{R}$, $e_0=1$, $e_1^2= \ldots =e_{2^n-1}^2=-1$, $n \in \mathbf{N}$
10
+
11
+ The identity unit ($e_0$) and imaginary units ($e_i, i\gt0$) form the basis for space of dimension $2^n$ over $\mathbf{R}$.
12
+
13
+ ## Requirements
14
+
15
+ Ruby >= 3.1
16
+
17
+ ## Installation
18
+
19
+ Add this line to your application's Gemfile:
20
+
21
+ gem 'mcalendar'
22
+
23
+ And then execute:
24
+
25
+ $ bundle install
26
+
27
+ Or install it yourself as:
28
+
29
+ $ gem install hyper_complex
30
+
31
+ ## Usage
32
+
33
+ ```ruby
34
+ require 'hyper_complex'
35
+
36
+ # Creation from complex numbers
37
+ q1 = HyperComplex.rect((1+2i), (3+4i)) #=> HyperComplex[1, 2, 3, 4]
38
+ q2 = HyperComplex.rect((5+6i), (7+8i)) #=> HyperComplex[5, 6, 7, 8]
39
+
40
+ # Creation from HyperComplex numbers
41
+ o1 = HyperComplex.rect(q1, q2) #=> HyperComplex[1, 2, 3, 4, 5, 6, 7, 8]
42
+
43
+ # Creation from real numbers
44
+ o2 = HyperCoplex[9, 10, 11, 12, 13] #=> HyperComplex[9, 10, 11, 12, 13, 0, 0, 0]
45
+
46
+ # Creation from polar form
47
+ q3 = HyperComplex.polar(1, Math::PI/3, Vector[1, 1, 1].normalize) #=> HyperComplex[0.5, 0.5, 0.5, 0.5]
48
+
49
+ # standard calculations between numeric instances
50
+ (q1+q2)*o1 / Complex::I - 24 #=> HyperComplex[(0/1), (88/1), (-40/1), (20/1), (-80/1), (-184/1), (112/1), (-84/1)]
51
+ ```
52
+
53
+ ## Contributing
54
+
55
+ Bug reports and pull requests are welcome on GitHub at https://github.com/bfifelin/hyper_complex.
56
+
57
+ ## License
58
+
59
+ This project is licensed under the terms of the [MIT license](http://opensource.org/licenses/MIT).
60
+
61
+ ## Acknowledgments
62
+
63
+ This gem is based on the gem [quaternion_c2](https://rubygems.org/gems/quaternion_c2) by Masahiro Nomoto.
data/Rakefile ADDED
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'minitest/test_task'
4
+ require File.expand_path("#{File.dirname(__FILE__)}/lib/version.rb")
5
+
6
+ Minitest::TestTask.create(:test) do |t|
7
+ t.libs << 'test'
8
+ t.libs << 'lib'
9
+ t.test_globs = ['test/**/*_test.rb']
10
+ end
11
+
12
+ task build: :gendoc do
13
+ system 'gem build hyper_complex.gemspec'
14
+ end
15
+
16
+ task :gendoc do
17
+ system 'yardoc'
18
+ end
19
+
20
+ task release: :build do
21
+ system "gem push hyper_complex-#{HyperComplex::VERSION}.gem"
22
+ end
23
+
24
+ task default: :build
@@ -0,0 +1,834 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'version'
4
+ require 'matrix'
5
+
6
+ # @private
7
+ class Numeric
8
+ def hrect = [real, imag]
9
+ alias hyperrectangular hrect
10
+ end
11
+
12
+ # rubocop:disable Metrics/ClassLength, Lint/MissingCopEnableDirective
13
+
14
+ ## Class HyperComplex
15
+ # Uses Cayley-Dickson construction
16
+ # * A subclass of +Numeric+
17
+ class HyperComplex < Numeric
18
+ private
19
+
20
+ @@mt = [[]]
21
+
22
+ undef_method(*Comparable.instance_methods)
23
+
24
+ def initialize(*arg) = @arv = arg.clone # rubocop:disable Lint/MissingSuper
25
+
26
+ public
27
+
28
+ class << self
29
+ ##
30
+ # Creates a HyperComplex object arg_a + arg_b*e[[i]]
31
+ #
32
+ # @param arg_a [Numeric]
33
+ # @param arg_b [Numeric]
34
+ # @return [HyperComplex]
35
+ # @raise [ArgumentError]
36
+ #
37
+ # @example
38
+ # HyperComplex.rect(HyperComplex.rect(1+2i, 3+4i), HyperComplex.rect(5,6))
39
+ # #=> HyperComplex[1, 2, 3, 4, 5, 6, 0, 0]
40
+ #
41
+ def rect(arg_a, arg_b = 0)
42
+ raise ArgumentError, 'Not all arguments are Numeric' unless arg_a.is_a?(Numeric) && arg_b.is_a?(Numeric)
43
+
44
+ a = arg_a.real? ? [arg_a] : arg_a.hrect
45
+ b = arg_b.real? ? [arg_b] : arg_b.hrect
46
+ as = a.length
47
+ bs = b.length
48
+ if as > bs
49
+ b.concat(Array.new(as - bs, 0))
50
+ elsif as < bs
51
+ a.concat(Array.new(bs - as, 0))
52
+ end
53
+ new(*(a + b))
54
+ end
55
+ alias rectangular rect
56
+
57
+ ##
58
+ # Creates a HyperComplex object.
59
+ #
60
+ # @param args [Integer or Rational or Float, ...]
61
+ # @return [HyperComplex]
62
+ # @raise [ArgumentError]
63
+ #
64
+ # @example
65
+ # HyperComplex[1, 2, 3, 4, 5, 6] #=> HyperComplex[1, 2, 3, 4, 5, 6, 0, 0]
66
+ #
67
+ def hrect(*args)
68
+ begin
69
+ raise ArgumentError, 'Not all components are real' unless args.map(&:real?).all?
70
+ rescue NoMethodError
71
+ raise ArgumentError, 'Not all components are numeric'
72
+ end
73
+ s = args.length
74
+ if s < 2
75
+ if s.zero?
76
+ args = [0, 0]
77
+ else
78
+ args.push 0
79
+ end
80
+ s = 2
81
+ end
82
+ s1 = 1 << (s.bit_length - 1)
83
+ if s == s1
84
+ new(*args)
85
+ else
86
+ new(*args.concat(Array.new((s1 << 1) - s, 0)))
87
+ end
88
+ end
89
+ alias hyperrectangular hrect
90
+ alias [] hrect
91
+
92
+ private
93
+
94
+ ##
95
+ # Fast variant of rect (only HyperComplex arguments of the same dimension are valid, no any check are performed)
96
+ #
97
+ def _rect(arg_a, arg_b) = new(*(arg_a.hrect + arg_b.hrect))
98
+
99
+ ##
100
+ # Fast variant of hrect (no any check are performed for parameters' validity)
101
+ #
102
+ def _hrect(*arg) = new(*arg)
103
+
104
+ public
105
+
106
+ ##
107
+ # Creates a HyperComplex object.
108
+ #
109
+ # @param radius [Integer or Rational or Float]
110
+ # @param theta [Integer or Rational or Float]
111
+ # @param vector [Vector or *[Integer or Rational or Float]]
112
+ # @return [HyperComplex]
113
+ # @raise [ArgumentError, TypeError]
114
+ #
115
+ # @example
116
+ # HyperComplex.polar(1, Math::PI / 4 , [1, 2, 3])
117
+ # #=> HyperComplex[-0.9794859508794878, 0.0538564706483192, 0.1077129412966384, 0.1615694119449576]
118
+ #
119
+ def polar(radius, theta, vector)
120
+ vs1 = vector.size + 1
121
+ raise TypeError, 'Vector size must be at least 3' if vs1 < 4
122
+ raise TypeError, 'Vector size is not equal to 2**n - 1' if vs1 != 1 << (vs1.bit_length - 1)
123
+
124
+ begin
125
+ raise ArgumentError, 'Not all components are real' unless [radius, theta, *vector].map(&:real?).all?
126
+ rescue NoMethodError
127
+ raise ArgumentError, 'Not all components are numeric'
128
+ end
129
+ vector = Vector[*vector] unless vector.is_a?(Vector)
130
+ norm = vector.norm
131
+ theta *= norm
132
+ r_cos = radius * Math.cos(theta)
133
+ r_sin = radius * Math.sin(theta)
134
+ r_sin /= norm unless norm.zero?
135
+ hrect(r_cos, *(r_sin * vector))
136
+ end
137
+
138
+ ##
139
+ # Creates HyperComplex basis element (identity or imaginary)
140
+ #
141
+ # @param num [Integer]
142
+ # @return [HyperComplex or Integer]
143
+ # @raise [ArgumentError]
144
+ #
145
+ # @example
146
+ # HyperComplex.e(5) #=> HyperComplex[0, 0, 0, 0, 0, 1, 0, 0]
147
+ #
148
+ def e(num)
149
+ raise ArgumentError, 'Argument must be non-negative integer' if !num.is_a?(Integer) || num.negative?
150
+ return 1 if num.zero?
151
+
152
+ hrect(*Array.new(num, 0), 1)
153
+ end
154
+
155
+ ##
156
+ # Creates HyperComplex zero
157
+ #
158
+ # @param num [Integer]
159
+ # @return [HyperComplex or Integer]
160
+ # @raise [ArgumentError]
161
+ #
162
+ # @example
163
+ # HyperComplex.zero(5) #=> HyperComplex[0, 0, 0, 0, 0, 0, 0, 0]
164
+ #
165
+ def zero(num)
166
+ raise ArgumentError, 'Argument must positive integer' unless num.is_a?(Integer) && num.positive?
167
+ return 0 if num == 1
168
+
169
+ hrect(*Array.new(num, 0))
170
+ end
171
+
172
+ ##
173
+ # Prints the multiplication table to stdout
174
+ #
175
+ # @param dim [Integer]
176
+ # @raise [ArgumentError]
177
+ #
178
+ # @example
179
+ # HyperComplex.print_mt(8)
180
+ # | e0 e1 e2 e3 e4 e5 e6 e7
181
+ # ----+--------------------------------
182
+ # e0| e0 e1 e2 e3 e4 e5 e6 e7
183
+ # e1| e1 -e0 e3 -e2 e5 -e4 -e7 e6
184
+ # e2| e2 -e3 -e0 e1 e6 e7 -e4 -e5
185
+ # e3| e3 e2 -e1 -e0 e7 -e6 e5 -e4
186
+ # e4| e4 -e5 -e6 -e7 -e0 e1 e2 e3
187
+ # e5| e5 e4 -e7 e6 -e1 -e0 -e3 e2
188
+ # e6| e6 e7 e4 -e5 -e2 e3 -e0 -e1
189
+ # e7| e7 -e6 e5 e4 -e3 -e2 e1 -e0
190
+ #
191
+ def print_mt(dim) # rubocop:disable Metrics/AbcSize
192
+ table = @@mt = calc_mt(dim) if dim > @@mt.length
193
+ ss = dim
194
+ sf = ss.to_s.length + 3
195
+ out_s = "#{' ' * sf}|"
196
+ (0...ss).each { out_s << format("%#{sf}s", "e#{_1}") }
197
+ puts out_s
198
+ puts "#{'-' * sf}+#{'-' * ss * sf}"
199
+ out_s = format("%#{sf}s|", 'e0')
200
+ (0...ss).each { out_s << format("%#{sf}s", "e#{_1}") }
201
+ puts out_s
202
+ (1...ss).each do |i|
203
+ out_s = format("%#{sf}s|%#{sf}s", "e#{i}", "e#{i}")
204
+ (1...i).each do |j|
205
+ t = table[i][j]
206
+ out_s << format("%#{sf}s", (t.negative? ? '-' : ' ') + "e#{t.abs}")
207
+ end
208
+ out_s << format("%#{sf}s", '-e0')
209
+ ((i + 1)...ss).each do |j|
210
+ t = table[j][i]
211
+ out_s << format("%#{sf}s", (t.negative? ? ' ' : '-') + "e#{t.abs}")
212
+ end
213
+ puts out_s
214
+ end
215
+ end
216
+
217
+ private
218
+
219
+ def calc_mt(dim) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
220
+ raise ArgumentError, 'Argument must be positive integer' unless dim.is_a?(Integer) && dim.positive?
221
+
222
+ raise ArgumentError, 'Argument must be equal to power of 2' unless (dim & (dim - 1)).zero?
223
+
224
+ raise "Seems to have infite loop while calculating multiplication table, dim=#{dim}" if dim <= @@mt.length
225
+
226
+ mt = Array.new(dim) { [] }
227
+ (1...dim).each do |i|
228
+ ((i + 1)...dim).each do |j|
229
+ c = dim
230
+ r_and = i & j
231
+ res_e = (i ^ j)
232
+ f1 = i
233
+ f2 = j
234
+ while (c >>= 1) > 1
235
+ unless ((i | j) & c).zero? # (Not a & c)
236
+ if !(r_and & c).zero?
237
+ res_e = -res_e if (f2 & ~c).zero?
238
+ f1, f2 = f2, f1 # -d.conj*b
239
+ elsif (f1 & c).zero?
240
+ f1, f2 = f2, f1 # d*a
241
+ else
242
+ res_e = -res_e unless (f2 & ~c).zero? # b*c.conj
243
+ end
244
+ end
245
+ break if (f1 &= ~c).zero? || (f2 &= ~c).zero?
246
+ end
247
+ res_e = -res_e unless (r_and & 1).zero?
248
+ mt[j][i] = -res_e
249
+ end
250
+ end
251
+ mt
252
+ end
253
+
254
+ def calc_mt_classic(dim)
255
+ raise ArgumentError, 'Argument must be positive integer' unless dim.is_a?(Integer) && dim.positive?
256
+
257
+ raise ArgumentError, 'Argument must be equal to power of 2' unless (dim & (dim - 1)).zero?
258
+
259
+ mt = Array.new(dim) { [] }
260
+ t_ar = Array.new(dim, 0)
261
+ t_ar[0] = 1
262
+ ar11 = [1, -1]
263
+ ids = Array.new(dim) { HyperComplex.e(_1) }
264
+ (1...dim).each do |i|
265
+ ((i + 1)...dim).each do |j|
266
+ t_ar = ids[i].mul(ids[j]).hrect
267
+ ind = t_ar.index { ar11.include?(_1) }
268
+ mt[j][i] = -ind * t_ar[ind].to_i
269
+ end
270
+ end
271
+ mt
272
+ end
273
+ end
274
+
275
+ ##
276
+ # Accessors
277
+ #
278
+
279
+ ##
280
+ # Returns an array of two numbers.
281
+ #
282
+ # @return [[Integer or Rational or Float, Integer or Rational or Float] or [HyperComplex, HyperComplex]]
283
+ #
284
+ # @example
285
+ # HyperComplex[1, 2, 3, 4].rect #=> [HyperComplex[1, 2], HyperComplex[3, 4]]
286
+ #
287
+ def rect
288
+ ssh = @arv.length >> 1
289
+ return @arv if ssh == 1
290
+
291
+ [__new__(*@arv[0...(ssh)]), __new__(*@arv[ssh..])]
292
+ end
293
+ alias rectangular rect
294
+
295
+ ##
296
+ # Returns an array of real numbers.
297
+ #
298
+ # @return [[Integer or Rational or Float, ...]]
299
+ #
300
+ # @example
301
+ # HyperComplex[1, 2, 3, 4].hrect #=> [1, 2, 3, 4]
302
+ #
303
+ def hrect = @arv
304
+ alias hyperrectangular hrect
305
+ alias to_a hrect
306
+
307
+ ##
308
+ # Returns the real part.
309
+ #
310
+ # @return [Integer or Rational or Float]
311
+ #
312
+ # @example
313
+ # HyperComplex[1, 2, 3, 4].real #=> 1
314
+ #
315
+ def real = @arv[0]
316
+ alias scalar real
317
+
318
+ ##
319
+ # Returns the imaginary part as a vector.
320
+ #
321
+ # @return [Vector]
322
+ #
323
+ # @example
324
+ # HyperComplex[1, 2, 3, 4].imag #=> Vector[2, 3, 4]
325
+ #
326
+ def imag = Vector[*hrect.drop(1)]
327
+ alias imaginary imag
328
+ alias vector imag
329
+
330
+ ##
331
+ # Returns the angle part of its polar form.
332
+ #
333
+ # @return [Integer or Rational or Float]
334
+ #
335
+ # @example
336
+ # HyperComplex[3, 2, 2, 1].arg #=> 0.7853981633974483 (Math::PI/4)
337
+ #
338
+ def arg = Math.atan2(imag.norm, real)
339
+
340
+ alias angle arg
341
+ alias phase arg
342
+ ##
343
+ # Returns the axis part of its polar form.
344
+ #
345
+ # @return [Vector]
346
+ #
347
+ # @example
348
+ # HyperComplex[6, 4, 4, 2].axis
349
+ # #=> Vector[0.6666666666666666, 0.6666666666666666, 0.3333333333333333]
350
+ #
351
+ def axis
352
+ v = imag
353
+ norm = v.norm
354
+ norm.zero? ? Vector[1, *Array.new(@arv.length - 2, 0)] : v / norm
355
+ end
356
+
357
+ ##
358
+ # HyperComplex is not real number.
359
+ #
360
+ # @return [false]
361
+ #
362
+ # @example
363
+ # HyperComplex[6, 4, 4, 2].real? #=> false
364
+ #
365
+ def real? = false
366
+
367
+ ##
368
+ # Returns true if all components are zero, otherwise returns false
369
+ #
370
+ # @return [true or false]
371
+ #
372
+ # @example
373
+ # HyperComplex[6, 4, 4, 2].zero? #=> false
374
+ #
375
+ def zero? = @arv.map(&:zero?).all?
376
+
377
+ ##
378
+ # Returns true if any component is NaN, otherwise returns false
379
+ #
380
+ # @return [true or false]
381
+ #
382
+ # @example
383
+ # HyperComplex[6, 4, Float::NAN, 2].nan? #=> true
384
+ #
385
+ def nan? = @arv.map { |i| i.equal?(Float::NAN) }.any?
386
+
387
+ ##
388
+ # Unary operations
389
+ #
390
+
391
+ # defined by Numeric:
392
+ # * +@ #=> self
393
+
394
+ ##
395
+ # Returns negation of the value.
396
+ #
397
+ # @return [HyperComplex]
398
+ #
399
+ # @example
400
+ # -HyperComplex[6, 4, 1, 2] #=> HyperComplex[-6, -4, -1, -2]
401
+ #
402
+ def -@ = __new__(*@arv.map(&:-@))
403
+
404
+ ##
405
+ # Returns its conjugate.
406
+ #
407
+ # @return [HyperComplex]
408
+ #
409
+ # @example
410
+ # HyperComplex[6, 4, 1, 2].conj #=> HyperComplex[6, -4, -1, -2]
411
+ #
412
+ def conj = __new__ @arv[0], *@arv[1..].map(&:-@)
413
+ alias conjugate conj
414
+
415
+ ##
416
+ # Returns square of the absolute value.
417
+ #
418
+ # @return [Integer or Rational or Float]
419
+ #
420
+ # @example
421
+ # HyperComplex[2, 2, 2, 2].abs2 #=> 16
422
+ #
423
+ def abs2 = @arv.sum { _1**2 }
424
+
425
+ ##
426
+ # Returns the absolute part of its polar form.
427
+ #
428
+ # @return [Integer or Rational or Float]
429
+ #
430
+ # @example
431
+ # HyperComplex[2, 2, 2, 2].abs #=> 4
432
+ #
433
+ def abs = Math.sqrt(abs2)
434
+ alias magnitude abs
435
+
436
+ ##
437
+ # Returns an array; +[abs, arg, axis]+.
438
+ #
439
+ # @return [[Integer or Rational or Float, Integer or Rational or Float, Vector]]
440
+ #
441
+ # @example
442
+ # HyperComplex[3, 4, 4, 0].polar
443
+ # #=> [6.4031242374328485, 1.0831800840797905, Vector[0.7071067811865475, 0.7071067811865475, 0.0]]
444
+ #
445
+ def polar = [abs, arg, axis]
446
+
447
+ ##
448
+ # Returns true if it equals to the other algebraically.
449
+ #
450
+ # @param other [Object]
451
+ # @return [true or false]
452
+ #
453
+ # @example
454
+ # HyperComplex[1, 2, 3] == HyperComplex[1, 2, 3, 0] #=> true
455
+ #
456
+ def ==(other)
457
+ sar, oar = homogenize(other)
458
+ sar == oar
459
+ end
460
+
461
+ ##
462
+ # Returns true if it have the same dimension and the same elements.
463
+ #
464
+ # @param other [Object]
465
+ # @return [true or false]
466
+ #
467
+ # @example
468
+ # HyperComplex[1, 2, 3].eql?(HyperComplex[1, 2, 3, 0]) #=> true
469
+ # HyperComplex[1/1r, 2, 3, 4].eql?(HyperComplex[1, 2, 3, 4]) #=> false
470
+ #
471
+ def eql?(other) = @arv.eql?(other.hrect)
472
+
473
+ # defined by Numeric:
474
+ # * nonzero? #=> zero? ? nil : self
475
+
476
+ defined_methods = public_instance_methods
477
+
478
+ if defined_methods.include?(:finite?)
479
+ ##
480
+ # Returns true if its magnitude is finite, oterwise returns false.
481
+ #
482
+ # @return [true or false]
483
+ #
484
+ # @example
485
+ # HyperComplex[1, 2, 3, 4].finite? #=> true
486
+ # HyperComplex[1, 2, Float::INFINITY, 4].finite? #=> false
487
+ #
488
+ def finite? = @arv.map(&:finite?).all?
489
+ end
490
+
491
+ if defined_methods.include?(:infinite?)
492
+ ##
493
+ # Returns true if its magnitude is infinite, oterwise returns false.
494
+ #
495
+ # @return [true or false]
496
+ #
497
+ # @example
498
+ # HyperComplex[1, 2, 3, 4].infinite? #=> false
499
+ # HyperComplex[1, 2, Float::INFINITY, 4].infinite? #=> true
500
+ #
501
+ def infinite? = @arv.map(&:infinite?).any?
502
+ end
503
+
504
+ undef positive? if defined_methods.include?(:positive?)
505
+ undef negative? if defined_methods.include?(:negative?)
506
+ undef step, ceil, floor, round, truncate
507
+
508
+ ##
509
+ # Performs addition.
510
+ #
511
+ # @param other [Numeric]
512
+ # @return [HyperComplex]
513
+ #
514
+ # @example
515
+ # HyperComplex[1, 1] + HyperComplex[0, 0, 0, 0, 1, 1] #=> HyperComplex[1, 1, 0, 0, 1, 1, 0, 0]
516
+ #
517
+ def +(other)
518
+ sar, oar = homogenize(other)
519
+ __new__(*sar.zip(oar).map(&:sum))
520
+ end
521
+
522
+ ##
523
+ # Performs subtraction.
524
+ #
525
+ # @param other [Numeric]
526
+ # @return [HyperComplex]
527
+ #
528
+ # @example
529
+ # HyperComplex[1, 1] - HyperComplex[0, 0, 0, 0, 1, 1] #=> HyperComplex[1, 1, 0, 0, -1, -1, 0, 0]
530
+ #
531
+ def -(other)
532
+ sar, oar = homogenize(other)
533
+ __new__(*sar.zip(oar).map { |x| x.reduce(:-) })
534
+ end
535
+
536
+ ##
537
+ # Performs multiplication (a, b)*(c, d) = (a*c - d.conj*b, d*a + b*c.conj).
538
+ #
539
+ # @param other [Numeric]
540
+ # @return [HyperComplex]
541
+ #
542
+ # @example
543
+ # HyperComplex[1, 2, 3, 4] * HyperComplex[4, 3, 2, 1] #=> HyperComplex[-12, 6, 24, 12]
544
+ #
545
+ def *(other) # rubocop:disable Metrics/AbcSize
546
+ sar, oar = homogenize(other)
547
+ ss = sar.length
548
+ begin
549
+ res = Array.new(ss, 0)
550
+ res[0] = sar[0] * oar[0]
551
+ (1...ss).each do |i|
552
+ res[0] -= sar[i] * oar[i]
553
+ res[i] += sar[0] * oar[i] + sar[i] * oar[0]
554
+ ((i + 1)...ss).each do |j|
555
+ ind = @@mt[j][i]
556
+ if ind.positive?
557
+ res[ind] -= sar[i] * oar[j] - sar[j] * oar[i]
558
+ else
559
+ res[-ind] += sar[i] * oar[j] - sar[j] * oar[i]
560
+ end
561
+ end
562
+ end
563
+ rescue NoMethodError, TypeError
564
+ @@mt = HyperComplex.send(:calc_mt, ss)
565
+ retry
566
+ end
567
+ __new__(*res)
568
+ end
569
+
570
+ ##
571
+ # Same as *, but 'classic' non-effective algorythm is used.
572
+ #
573
+ # @param other [Numeric]
574
+ # @return [HyperComplex]
575
+ #
576
+ # @example
577
+ # HyperComplex[1, 2, 3, 4].mul(HyperComplex[4, 3, 2, 1]) #=> HyperComplex[-12, 6, 24, 12]
578
+ #
579
+ def mul(other) # rubocop:disable Metrics/AbcSize
580
+ sar, oar = homogenize(other)
581
+ ss = sar.length
582
+ return __new__(sar[0] * oar[0] - oar[1] * sar[1], oar[1] * sar[0] + sar[1] * oar[0]) if ss == 2
583
+
584
+ a = __new__(*sar[0...(ss / 2)])
585
+ b = __new__(*sar[(ss / 2)..])
586
+ c = __new__(*oar[0...(ss / 2)])
587
+ d = __new__(*oar[(ss / 2)..])
588
+ __new__(*(a.mul(c) - d.conj.mul(b)).hrect, *(d.mul(a) + b.mul(c.conj)).hrect)
589
+ end
590
+
591
+ ##
592
+ # Inverse element. Rational arithmetic is used as possible.
593
+ #
594
+ # @return [HyperComplex]
595
+ # @raise [ZeroDivisionError] if all componetns are zero and not Float
596
+ #
597
+ # @example
598
+ # HyperComplex[1/4r, 1/4r, 1/4r, 1/4r] #=> HyperComplex[1, -1, -1, -1]
599
+ #
600
+ def inv
601
+ t = abs2
602
+ __new__(*conj.hrect.map { _1.to_r / t })
603
+ end
604
+ alias inverse inv
605
+
606
+ ##
607
+ # Float Inverse element.
608
+ #
609
+ # @return [HyperComplex]
610
+ #
611
+ # @example
612
+ # HyperComplex[0.25, 0.25, 0.25, 0.25].inv #=> HyperComplex[1.0, -1.0, -1.0, -1.0]
613
+ # HyperComplex[0, 0, 0, 0].inv #=> HyperComplex[NaN, NaN, NaN, NaN]
614
+ #
615
+ def finv
616
+ t = abs2
617
+ __new__(*conj.hrect.map { _1.to_f / t })
618
+ end
619
+
620
+ ##
621
+ # @!method quo(other)
622
+ #
623
+ # Performs rational as possible division.
624
+ #
625
+ # @param other [Numeric]
626
+ # @return [HyperComplex]
627
+ # @raise [ZeroDivisionError] if +other+ is zero and no conversion to float was performed.
628
+ #
629
+ # @example
630
+ # HyperComplex[12, -4, -2, 1] / HyperComplex[1, 24, -4, -8]
631
+ # #=> HyperComplex[-28/219r, -104/219r, 6/73r, 11/219r]
632
+ #
633
+ def quo(other)
634
+ t = other.abs2
635
+ self * __new__(*other.conj.hrect.map { _1.to_r / t })
636
+ end
637
+ alias / quo
638
+
639
+ ##
640
+ # @!method fdiv(other)
641
+ #
642
+ # Performs float division.
643
+ #
644
+ # @param other [Numeric]
645
+ # @return [HyperComplex]
646
+ #
647
+ # @example
648
+ # HyperComplex[12, -4, -2, 1].fdiv(HyperComplex[1, 24, -4, -8])
649
+ # #=> HyperComplex[-0.1278538812785388, -0.4748858447488584, 0.0821917808219178, 0.0502283105022831]
650
+ # HyperComplex[12, -4, -2, 1].fdiv(HyperComplex[0, 0, 0, 0]) #=> HyperComplex[NaN, NaN, NaN, NaN]
651
+ def fdiv(other)
652
+ t = other.abs2
653
+ self * __new__(*other.conj.hrect.map { _1.to_f / t })
654
+ end
655
+
656
+ undef div, %, modulo, remainder, divmod
657
+
658
+ ##
659
+ # Performs type conversion.
660
+ #
661
+ # @param other [Numeric]
662
+ # @return [[HyperComplex, self]]
663
+ # @raise [TypeError]
664
+ #
665
+ # @example
666
+ # HyperComplex[1, 2, 3, 4].coerce(1) #=> [HyperComplex[1, 0], HyperComplex[1, 2, 3, 4]]
667
+ #
668
+ def coerce(other) = [__new__(*other.hrect), self]
669
+
670
+ ##
671
+ # Performs conversion to Integer.
672
+ #
673
+ # @return [Integer]
674
+ # @raise [RangeError]
675
+ #
676
+ # @example
677
+ # HyperComplex[3, 0, 0, 0].to_i #=> 3
678
+ #
679
+ def to_i
680
+ raise RangeError, "Can not convert #{inspect} to Integer" unless @arv[1..].map(&:zero?).all?
681
+
682
+ @arv[0].to_i
683
+ end
684
+
685
+ ##
686
+ # Performs conversion to Float.
687
+ #
688
+ # @return [Float]
689
+ # @raise [RangeError]
690
+ #
691
+ # @example
692
+ # HyperComplex[3, 0, 0, 0].to_f #=> 3.0
693
+ #
694
+ def to_f
695
+ raise RangeError, "Can not convert #{inspect} to Float" unless @arv[1..].map(&:zero?).all?
696
+
697
+ @arv[0].to_f
698
+ end
699
+
700
+ ##
701
+ # Performs conversion to Rational.
702
+ #
703
+ # @return [Rational]
704
+ # @raise [RangeError]
705
+ #
706
+ # @example
707
+ # HyperComplex[3, 0, 0, 0].to_r #=> 3/1r
708
+ #
709
+ def to_r
710
+ raise RangeError, "Can not convert #{inspect} to Rational" unless @arv[1..].map(&:zero?).all?
711
+
712
+ @arv[0].to_r
713
+ end
714
+
715
+ ##
716
+ # Performs conversion to Complex.
717
+ #
718
+ # @return [Complex]
719
+ # @raise [RangeError]
720
+ #
721
+ # @example
722
+ # HyperComplex[3, 1, 0, 0].to_f #=> (3+1i)
723
+ #
724
+ def to_c
725
+ return Complex(@arv[0], @arv[1]) if @arv.length <= 2 || @arv[2..].map(&:zero?).all?
726
+
727
+ raise RangeError, "Can not convert #{inspect} to Complex"
728
+ end
729
+
730
+ ##
731
+ # Performs conversion to String.
732
+ #
733
+ # @return [String]
734
+ #
735
+ # @example
736
+ # HyperComplex[4, 3, 2, 1].to_f #=> "HyperComplex[4, 3, 2, 1]"
737
+ #
738
+ def to_s = "HyperComplex#{@arv}"
739
+ alias inspect to_s
740
+
741
+ ##
742
+ # Returns the dimension of hypercomplex number.
743
+ #
744
+ # @return [Integer]
745
+ #
746
+ # @example
747
+ # HyperComplex[4, 3, 2, 1].dim #=> 4
748
+ #
749
+ def dim = @arv.length
750
+ alias dimension dim
751
+
752
+ ##
753
+ # Returns the index's element of hypercomplex number.
754
+ #
755
+ # @param index [Integer]
756
+ # @return [Integer or Rational or Float or nil]
757
+ #
758
+ # @example
759
+ # HyperComplex[4, 3, 2, 1].1 #=> 3
760
+ #
761
+ def [](index) = @arv[index]
762
+
763
+ ##
764
+ # Performs exponentiation.
765
+ #
766
+ # @param other [Numeric]
767
+ # @return [HyperComplex]
768
+ #
769
+ # @example
770
+ # HyperComplex[1, 2, 3, 4]**HyperComplex[4, 3, 2, 1]
771
+ # #=> HyperComplex[9.648225704568818, -5.4921479890865506, -8.477947559523633, -4.2389737797618166]
772
+ #
773
+ def **(other) # rubocop:disable Metrics/AbcSize
774
+ unless other.is_a?(Numeric)
775
+ num1, num2 = other.coerce(self)
776
+ return num1**num2
777
+ end
778
+ if other.zero?
779
+ return __new__(*Array.new(dim, Float::NAN)) if zero?
780
+
781
+ return __new__(*Array.new(dim - 1, 0).unshift(1))
782
+ end
783
+
784
+ unless other.real?
785
+ begin
786
+ other.to_f
787
+ rescue # rubocop:disable Lint/SuppressedException,Style/RescueStandardError
788
+ else
789
+ other = other.real
790
+ end
791
+ end
792
+ other = other.numerator if other.is_a?(Rational) && other.denominator == 1
793
+ if other.integer?
794
+ x = other >= 0 ? self : 1.to_r / self
795
+ n = other.abs
796
+ z = 1
797
+ loop do
798
+ z *= x if n.odd?
799
+ n >>= 1
800
+ return z if n.zero?
801
+
802
+ x *= x
803
+ end
804
+ elsif other.real?
805
+ r, theta, vector = polar
806
+ HyperComplex.polar(r**other, theta * other, vector)
807
+ elsif other.is_a?(HyperComplex)
808
+ r, theta, vector = polar
809
+ q = HyperComplex.hrect(Math.log(r), *(theta * vector))
810
+ q *= other
811
+ HyperComplex.polar(Math.exp(q.real), 1, q.imag)
812
+ else
813
+ num1, num2 = other.coerce(self)
814
+ num1**num2
815
+ end
816
+ end
817
+
818
+ private
819
+
820
+ def homogenize(other)
821
+ ar = hrect
822
+ as = ar.length
823
+ br = other.hrect
824
+ bs = br.length
825
+ if as > bs
826
+ br.concat(Array.new(as - bs, 0))
827
+ elsif as < bs
828
+ ar.concat(Array.new(bs - as, 0))
829
+ end
830
+ [ar, br]
831
+ end
832
+
833
+ def __new__(*arg) = HyperComplex.send(:new, *arg)
834
+ end
data/lib/version.rb ADDED
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class HyperComplex < Numeric
4
+ VERSION = '1.0.1'
5
+ end
metadata ADDED
@@ -0,0 +1,88 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hyper_complex
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Boris Fifelin
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 2026-02-01 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: minitest
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '5.0'
19
+ type: :development
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '5.0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: rake
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '13.0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '13.0'
40
+ - !ruby/object:Gem::Dependency
41
+ name: yard
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0.9'
47
+ type: :development
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0.9'
54
+ description: Hypercomplex numbers (by Cayley-Dickson construction)
55
+ email: bfifelin@gmail.com
56
+ executables: []
57
+ extensions: []
58
+ extra_rdoc_files: []
59
+ files:
60
+ - ".yardopts"
61
+ - LICENSE
62
+ - README.html
63
+ - README.md
64
+ - Rakefile
65
+ - lib/hyper_complex.rb
66
+ - lib/version.rb
67
+ homepage: https://github.com/bfifelin/hyper_complex
68
+ licenses:
69
+ - MIT
70
+ metadata: {}
71
+ rdoc_options: []
72
+ require_paths:
73
+ - lib
74
+ required_ruby_version: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: 3.1.0
79
+ required_rubygems_version: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ requirements: []
85
+ rubygems_version: 4.0.3
86
+ specification_version: 4
87
+ summary: Hypercomplex numbers
88
+ test_files: []