nmatrix-gemv 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +29 -0
- data/.rspec +2 -0
- data/.travis.yml +14 -0
- data/Gemfile +7 -0
- data/README.md +29 -0
- data/Rakefile +225 -0
- data/ext/nmatrix_gemv/binary_format.txt +53 -0
- data/ext/nmatrix_gemv/data/complex.h +399 -0
- data/ext/nmatrix_gemv/data/data.cpp +298 -0
- data/ext/nmatrix_gemv/data/data.h +771 -0
- data/ext/nmatrix_gemv/data/meta.h +70 -0
- data/ext/nmatrix_gemv/data/rational.h +436 -0
- data/ext/nmatrix_gemv/data/ruby_object.h +471 -0
- data/ext/nmatrix_gemv/extconf.rb +254 -0
- data/ext/nmatrix_gemv/math.cpp +1639 -0
- data/ext/nmatrix_gemv/math/asum.h +143 -0
- data/ext/nmatrix_gemv/math/geev.h +82 -0
- data/ext/nmatrix_gemv/math/gemm.h +271 -0
- data/ext/nmatrix_gemv/math/gemv.h +212 -0
- data/ext/nmatrix_gemv/math/ger.h +96 -0
- data/ext/nmatrix_gemv/math/gesdd.h +80 -0
- data/ext/nmatrix_gemv/math/gesvd.h +78 -0
- data/ext/nmatrix_gemv/math/getf2.h +86 -0
- data/ext/nmatrix_gemv/math/getrf.h +240 -0
- data/ext/nmatrix_gemv/math/getri.h +108 -0
- data/ext/nmatrix_gemv/math/getrs.h +129 -0
- data/ext/nmatrix_gemv/math/idamax.h +86 -0
- data/ext/nmatrix_gemv/math/inc.h +47 -0
- data/ext/nmatrix_gemv/math/laswp.h +165 -0
- data/ext/nmatrix_gemv/math/long_dtype.h +52 -0
- data/ext/nmatrix_gemv/math/math.h +1069 -0
- data/ext/nmatrix_gemv/math/nrm2.h +181 -0
- data/ext/nmatrix_gemv/math/potrs.h +129 -0
- data/ext/nmatrix_gemv/math/rot.h +141 -0
- data/ext/nmatrix_gemv/math/rotg.h +115 -0
- data/ext/nmatrix_gemv/math/scal.h +73 -0
- data/ext/nmatrix_gemv/math/swap.h +73 -0
- data/ext/nmatrix_gemv/math/trsm.h +387 -0
- data/ext/nmatrix_gemv/nm_memory.h +60 -0
- data/ext/nmatrix_gemv/nmatrix_gemv.cpp +90 -0
- data/ext/nmatrix_gemv/nmatrix_gemv.h +374 -0
- data/ext/nmatrix_gemv/ruby_constants.cpp +153 -0
- data/ext/nmatrix_gemv/ruby_constants.h +107 -0
- data/ext/nmatrix_gemv/ruby_nmatrix.c +84 -0
- data/ext/nmatrix_gemv/ttable_helper.rb +122 -0
- data/ext/nmatrix_gemv/types.h +54 -0
- data/ext/nmatrix_gemv/util/util.h +78 -0
- data/lib/nmatrix-gemv.rb +43 -0
- data/lib/nmatrix_gemv/blas.rb +85 -0
- data/lib/nmatrix_gemv/nmatrix_gemv.rb +35 -0
- data/lib/nmatrix_gemv/rspec.rb +75 -0
- data/nmatrix-gemv.gemspec +31 -0
- data/spec/blas_spec.rb +154 -0
- data/spec/spec_helper.rb +128 -0
- metadata +186 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1ae23439e8353af4cb448484f3fbfda6b48b2298
|
4
|
+
data.tar.gz: 62438a8e9422b60195513cda83899d38996bba36
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: bd9f765529f35717cccdae8ecf222c0a04cddf60ff502ef2b4713ee470bb20f7e267a568d40802604c4796db4c2b68ada80b4156e1e7a82dd222fb32a387572f
|
7
|
+
data.tar.gz: 370c1440f3bae1bb28b85823e509204f35cb24db7a5eedcfd7538d4cf4a6eda8eb6238e38364ce16c43eac4b2bfacf58328e6241c35b82622502bc5a4ada997f
|
data/.gitignore
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
.idea
|
2
|
+
Gemfile.lock
|
3
|
+
ext/nmatrix/dense/daxpy.c
|
4
|
+
ext/nmatrix/dense/dgeco.c
|
5
|
+
ext/nmatrix/dense/dgefa.c
|
6
|
+
ext/nmatrix/dense/dgemm.c
|
7
|
+
ext/nmatrix/dense/dgemv.c
|
8
|
+
ext/nmatrix/dense/dscal.c
|
9
|
+
ext/nmatrix/dense/idamax.c
|
10
|
+
ext/nmatrix/dense/467.c
|
11
|
+
ext/nmatrix/dense/*.f
|
12
|
+
ext/nmatrix/dense/transpose.txt
|
13
|
+
ext/nmatrix/yale/aicm.tex
|
14
|
+
tmp/
|
15
|
+
test.c
|
16
|
+
spec/*.mtx
|
17
|
+
*.o
|
18
|
+
*.so
|
19
|
+
*.bundle
|
20
|
+
*.bundle.dSYM
|
21
|
+
*.log
|
22
|
+
/tags
|
23
|
+
*.gem
|
24
|
+
html/
|
25
|
+
doc/
|
26
|
+
docs/
|
27
|
+
pkg/
|
28
|
+
.autotest
|
29
|
+
tags
|
data/.rspec
ADDED
data/.travis.yml
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
language: ruby
|
2
|
+
cache: bundler
|
3
|
+
env:
|
4
|
+
- CPLUS_INCLUDE_PATH=/usr/include/atlas C_INCLUDE_PATH=/usr/include/atlas
|
5
|
+
rvm:
|
6
|
+
- "1.9.2"
|
7
|
+
- "1.9.3"
|
8
|
+
- "2.0.0"
|
9
|
+
- "2.1.0"
|
10
|
+
before_install:
|
11
|
+
- sudo apt-get update -qq
|
12
|
+
- sudo apt-get install -qq libatlas-base-dev
|
13
|
+
script: bundle exec rake compile && bundle exec rake spec
|
14
|
+
|
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# nmatrix-gemv #
|
2
|
+
|
3
|
+
## How to install ##
|
4
|
+
`bundle install`
|
5
|
+
|
6
|
+
`bundle exec rake compile`
|
7
|
+
|
8
|
+
`gem build nmatrix-gemv.gemspec`
|
9
|
+
|
10
|
+
`gem install ./nmatrix-gemv-0.0.2.gem`
|
11
|
+
|
12
|
+
## How to use ##
|
13
|
+
```
|
14
|
+
irb
|
15
|
+
>require 'nmatrix-gemv'
|
16
|
+
=> true
|
17
|
+
```
|
18
|
+
### In file: ###
|
19
|
+
Suppose you have [NMatrix](https://github.com/SciRuby/nmatrix) installed.
|
20
|
+
|
21
|
+
```{.ruby}
|
22
|
+
require 'nmatrix'
|
23
|
+
require 'nmatrix-gemv'
|
24
|
+
|
25
|
+
a = NMatrix.new([2,3], [1.0, 2.0, 3.0, 4.0, 5.0, 6.0], dtype: :float64)
|
26
|
+
x = NMatrix.new([1,4], [2.0, 3.0, 4.0, 5.0], dtype: :float64)
|
27
|
+
|
28
|
+
NMatrix::BLAS.gemv(a, x)
|
29
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1,225 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'rubygems/package_task'
|
5
|
+
require 'bundler'
|
6
|
+
begin
|
7
|
+
Bundler.setup(:default, :development)
|
8
|
+
rescue Bundler::BundlerError => e
|
9
|
+
$stderr.puts e.message
|
10
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
11
|
+
exit e.status_code
|
12
|
+
end
|
13
|
+
|
14
|
+
require 'rake'
|
15
|
+
require "rake/extensiontask"
|
16
|
+
Rake::ExtensionTask.new do |ext|
|
17
|
+
ext.name = 'nmatrix_gemv'
|
18
|
+
ext.ext_dir = 'ext/nmatrix_gemv'
|
19
|
+
ext.lib_dir = 'lib/'
|
20
|
+
ext.source_pattern = "**/*.{c,cpp, h}"
|
21
|
+
end
|
22
|
+
|
23
|
+
gemspec = eval(IO.read("nmatrix-gemv.gemspec"))
|
24
|
+
=begin
|
25
|
+
Gem::PackageTask.new(gemspec).define
|
26
|
+
|
27
|
+
desc "install the gem locally"
|
28
|
+
task :install => [:package] do
|
29
|
+
sh %{gem install pkg/nmatrix-#{NMatrix::VERSION}.gem}
|
30
|
+
end
|
31
|
+
=end
|
32
|
+
|
33
|
+
require 'rspec/core/rake_task'
|
34
|
+
require 'rspec/core'
|
35
|
+
require 'rspec/core/rake_task'
|
36
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
37
|
+
spec.pattern = FileList['spec/**/*_spec.rb'].uniq
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
BASEDIR = Pathname( __FILE__ ).dirname.relative_path_from( Pathname.pwd )
|
42
|
+
SPECDIR = BASEDIR + 'spec'
|
43
|
+
|
44
|
+
VALGRIND_OPTIONS = [
|
45
|
+
"--tool=memcheck",
|
46
|
+
#"--leak-check=yes",
|
47
|
+
"--num-callers=15",
|
48
|
+
#"--error-limit=no",
|
49
|
+
"--partial-loads-ok=yes",
|
50
|
+
"--undef-value-errors=no" #,
|
51
|
+
#"--dsymutil=yes"
|
52
|
+
]
|
53
|
+
|
54
|
+
CALLGRIND_OPTIONS = [
|
55
|
+
"--tool=callgrind",
|
56
|
+
"--dump-instr=yes",
|
57
|
+
"--simulate-cache=yes",
|
58
|
+
"--collect-jumps=yes"
|
59
|
+
]
|
60
|
+
|
61
|
+
VALGRIND_MEMORYFILL_OPTIONS = [
|
62
|
+
"--freelist-vol=100000000",
|
63
|
+
"--malloc-fill=6D",
|
64
|
+
"--free-fill=66 ",
|
65
|
+
]
|
66
|
+
|
67
|
+
GDB_OPTIONS = []
|
68
|
+
|
69
|
+
|
70
|
+
RSpec::Core::RakeTask.new(:spec)
|
71
|
+
|
72
|
+
task :console do |task|
|
73
|
+
cmd = [ 'irb', "-r './lib/nmatrix_gemv.rb'" ]
|
74
|
+
run *cmd
|
75
|
+
end
|
76
|
+
|
77
|
+
=begin
|
78
|
+
task :pry do |task|
|
79
|
+
cmd = [ 'pry', "-r './lib/nmatrix.rb'" ]
|
80
|
+
run *cmd
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
namespace :pry do
|
85
|
+
task :valgrind => [ :compile ] do |task|
|
86
|
+
cmd = [ 'valgrind' ] + VALGRIND_OPTIONS
|
87
|
+
cmd += ['ruby', '-Ilib:ext', "-r './lib/nmatrix.rb'", "-r 'pry'", "-e 'binding.pry'"]
|
88
|
+
run *cmd
|
89
|
+
end
|
90
|
+
end
|
91
|
+
=end
|
92
|
+
|
93
|
+
namespace :console do
|
94
|
+
CONSOLE_CMD = ['irb', "-r './lib/nmatrix_gemv.rb'"]
|
95
|
+
desc "Run console under GDB."
|
96
|
+
task :gdb => [ :compile ] do |task|
|
97
|
+
cmd = [ 'gdb' ] + GDB_OPTIONS
|
98
|
+
cmd += [ '--args' ]
|
99
|
+
cmd += CONSOLE_CMD
|
100
|
+
run( *cmd )
|
101
|
+
end
|
102
|
+
|
103
|
+
desc "Run console under Valgrind."
|
104
|
+
task :valgrind => [ :compile ] do |task|
|
105
|
+
cmd = [ 'valgrind' ] + VALGRIND_OPTIONS
|
106
|
+
cmd += CONSOLE_CMD
|
107
|
+
run( *cmd )
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
task :default => :spec
|
112
|
+
|
113
|
+
def run *cmd
|
114
|
+
sh(cmd.join(" "))
|
115
|
+
end
|
116
|
+
|
117
|
+
namespace :spec do
|
118
|
+
# partial-loads-ok and undef-value-errors necessary to ignore
|
119
|
+
# spurious (and eminently ignorable) warnings from the ruby
|
120
|
+
# interpreter
|
121
|
+
|
122
|
+
RSPEC_CMD = [ 'ruby', '-S', 'rspec', '-Ilib:ext', SPECDIR.to_s ]
|
123
|
+
|
124
|
+
#desc "Run the spec for generator.rb"
|
125
|
+
#task :generator do |task|
|
126
|
+
# run 'rspec spec/generator_spec.rb'
|
127
|
+
#end
|
128
|
+
|
129
|
+
desc "Run specs under GDB."
|
130
|
+
task :gdb => [ :compile ] do |task|
|
131
|
+
cmd = [ 'gdb' ] + GDB_OPTIONS
|
132
|
+
cmd += [ '--args' ]
|
133
|
+
cmd += RSPEC_CMD
|
134
|
+
run( *cmd )
|
135
|
+
end
|
136
|
+
|
137
|
+
desc "Run specs under cgdb."
|
138
|
+
task :cgdb => [ :compile ] do |task|
|
139
|
+
cmd = [ 'cgdb' ] + GDB_OPTIONS
|
140
|
+
cmd += [ '--args' ]
|
141
|
+
cmd += RSPEC_CMD
|
142
|
+
run( *cmd )
|
143
|
+
end
|
144
|
+
|
145
|
+
desc "Run specs under Valgrind."
|
146
|
+
task :valgrind => [ :compile ] do |task|
|
147
|
+
cmd = [ 'valgrind' ] + VALGRIND_OPTIONS
|
148
|
+
cmd += RSPEC_CMD
|
149
|
+
run( *cmd )
|
150
|
+
end
|
151
|
+
|
152
|
+
desc "Run specs under Callgrind."
|
153
|
+
task :callgrind => [ :compile ] do |task|
|
154
|
+
cmd = [ 'valgrind' ] + CALLGRIND_OPTIONS
|
155
|
+
cmd += RSPEC_CMD
|
156
|
+
run( *cmd )
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|
160
|
+
|
161
|
+
=begin
|
162
|
+
LEAKCHECK_CMD = [ 'ruby', '-Ilib:ext', "#{SPECDIR}/leakcheck.rb" ]
|
163
|
+
|
164
|
+
|
165
|
+
desc "Run leakcheck script."
|
166
|
+
task :leakcheck => [ :compile ] do |task|
|
167
|
+
cmd = [ 'valgrind' ] + VALGRIND_OPTIONS
|
168
|
+
cmd += LEAKCHECK_CMD
|
169
|
+
run( *cmd )
|
170
|
+
end
|
171
|
+
=end
|
172
|
+
|
173
|
+
namespace :clean do
|
174
|
+
task :so do |task|
|
175
|
+
tmp_path = "tmp/#{RUBY_PLATFORM}/nmatrix-gemv/#{RUBY_VERSION}"
|
176
|
+
chdir tmp_path do
|
177
|
+
if RUBY_PLATFORM =~ /mswin/
|
178
|
+
`nmake soclean`
|
179
|
+
else
|
180
|
+
mkcmd = ENV['MAKE'] || %w[gmake make].find { |c| system("#{c} -v >> /dev/null 2>&1") }
|
181
|
+
`#{mkcmd} soclean`
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
=begin
|
188
|
+
desc "Check the manifest for correctness"
|
189
|
+
task :check_manifest do |task|
|
190
|
+
manifest_files = File.read("Manifest.txt").split
|
191
|
+
|
192
|
+
git_files = `git ls-files |grep -v 'spec/'`.split
|
193
|
+
ignore_files = %w{.gitignore .rspec ext/nmatrix/binary_format.txt ext/nmatrix/ttable_helper.rb scripts/mac-brew-gcc.sh}
|
194
|
+
|
195
|
+
possible_files = git_files - ignore_files
|
196
|
+
|
197
|
+
missing_files = possible_files - manifest_files
|
198
|
+
extra_files = manifest_files - possible_files
|
199
|
+
|
200
|
+
unless missing_files.empty?
|
201
|
+
STDERR.puts "The following files are in the git repo but not the Manifest:"
|
202
|
+
missing_files.each { |f| STDERR.puts " -- #{f}"}
|
203
|
+
end
|
204
|
+
|
205
|
+
unless extra_files.empty?
|
206
|
+
STDERR.puts "The following files are in the Manifest but may not be necessary:"
|
207
|
+
extra_files.each { |f| STDERR.puts " -- #{f}"}
|
208
|
+
end
|
209
|
+
|
210
|
+
if extra_files.empty? && missing_files.empty?
|
211
|
+
STDERR.puts "Manifest looks good!"
|
212
|
+
end
|
213
|
+
|
214
|
+
end
|
215
|
+
=end
|
216
|
+
|
217
|
+
=begin
|
218
|
+
require "rdoc/task"
|
219
|
+
RDoc::Task.new do |rdoc|
|
220
|
+
rdoc.main = "README.rdoc"
|
221
|
+
rdoc.rdoc_files.include(%w{README.rdoc History.txt LICENSE.txt CONTRIBUTING.md ext/nmatrix/binary_format.txt lib/nmatrix/**/*.rb ext/nmatrix/**/*.cpp ext/nmatrix/**/*.c ext/nmatrix/**/*.h})
|
222
|
+
end
|
223
|
+
=end
|
224
|
+
|
225
|
+
# vim: syntax=ruby
|
@@ -0,0 +1,53 @@
|
|
1
|
+
This is the proposed binary format for saving and loading NMatrix objects.
|
2
|
+
|
3
|
+
Order is little-endian.
|
4
|
+
|
5
|
+
List matrices should be converted to dense or yale matrices. There should be no serious need to load or save
|
6
|
+
linked-list matrices, since these exist primarily in order to construct efficient yale matrices.
|
7
|
+
|
8
|
+
|
9
|
+
First 64-bit block:
|
10
|
+
* ui16 major (version)
|
11
|
+
* ui16 minor
|
12
|
+
* ui16 release
|
13
|
+
* i16 NULL
|
14
|
+
|
15
|
+
|
16
|
+
Second 64-bit block:
|
17
|
+
* ui8 dtype
|
18
|
+
* ui8 stype
|
19
|
+
* ui8 itype # ui32 for dense
|
20
|
+
* ui8 symm
|
21
|
+
* i16 NULL
|
22
|
+
* ui16 dim # if 1, NVector; otherwise, NMatrix
|
23
|
+
|
24
|
+
|
25
|
+
3rd - nth 64-bit block: shape
|
26
|
+
|
27
|
+
itype sets the number of bytes allocated for each shape entry. Since only yale uses itype, dense will pretty
|
28
|
+
much always be the UINT32 itype (see nmatrix.h). If the total number of bytes occupied by the shape array is
|
29
|
+
less than 8, the rest of the 64-bit block will be padded with zeros.
|
30
|
+
|
31
|
+
|
32
|
+
(n+1)th 64-bit block: depends on stype, symm
|
33
|
+
|
34
|
+
symm is designed to reduce file size by allowing us to not save certain elements in symmetric, hermitian, skew-
|
35
|
+
symmetric, and triangular matrices. These values will be defined in nmatrix.h; 0 indicates standard (no symmetry).
|
36
|
+
In later versions, additional patterns may be defined which might even have less to do with symmetry than
|
37
|
+
upper/lower do.
|
38
|
+
|
39
|
+
When storing a symmetric matrix, we will only store the upper portion. If the matrix is lower triangular, only the
|
40
|
+
lower portion will be stored.
|
41
|
+
|
42
|
+
For dense, we simply store the contents of the matrix exactly as in memory (or just the upper-triangular part if
|
43
|
+
symm is set).
|
44
|
+
|
45
|
+
For yale, we store:
|
46
|
+
* ui32 ndnz
|
47
|
+
* ui32 length (AKA size, the number of elements in A/IJA that aren't nil/undefined)
|
48
|
+
|
49
|
+
The latter will serve as the capacity when we read a Yale matrix.
|
50
|
+
|
51
|
+
Then we store the a array, again padding with zeros so it's a multiple of 8 bytes.
|
52
|
+
|
53
|
+
Then we store the ija array, padding with zeros so it's a multiple of 8 bytes.
|
@@ -0,0 +1,399 @@
|
|
1
|
+
/////////////////////////////////////////////////////////////////////
|
2
|
+
// = NMatrix
|
3
|
+
//
|
4
|
+
// A linear algebra library for scientific computation in Ruby.
|
5
|
+
// NMatrix is part of SciRuby.
|
6
|
+
//
|
7
|
+
// NMatrix was originally inspired by and derived from NArray, by
|
8
|
+
// Masahiro Tanaka: http://narray.rubyforge.org
|
9
|
+
//
|
10
|
+
// == Copyright Information
|
11
|
+
//
|
12
|
+
// SciRuby is Copyright (c) 2010 - 2014, Ruby Science Foundation
|
13
|
+
// NMatrix is Copyright (c) 2012 - 2014, John Woods and the Ruby Science Foundation
|
14
|
+
//
|
15
|
+
// Please see LICENSE.txt for additional copyright notices.
|
16
|
+
//
|
17
|
+
// == Contributing
|
18
|
+
//
|
19
|
+
// By contributing source code to SciRuby, you agree to be bound by
|
20
|
+
// our Contributor Agreement:
|
21
|
+
//
|
22
|
+
// * https://github.com/SciRuby/sciruby/wiki/Contributor-Agreement
|
23
|
+
//
|
24
|
+
// == complex.h
|
25
|
+
//
|
26
|
+
// Functions and classes for dealing with complex numbers.
|
27
|
+
|
28
|
+
#ifndef COMPLEX_H
|
29
|
+
#define COMPLEX_H
|
30
|
+
|
31
|
+
/*
|
32
|
+
* Standard Includes
|
33
|
+
*/
|
34
|
+
|
35
|
+
#include <type_traits>
|
36
|
+
#include <iostream>
|
37
|
+
#include <cmath>
|
38
|
+
|
39
|
+
/*
|
40
|
+
* Project Includes
|
41
|
+
*/
|
42
|
+
|
43
|
+
#include "types.h"
|
44
|
+
|
45
|
+
/*
|
46
|
+
* Macros
|
47
|
+
*/
|
48
|
+
|
49
|
+
/*
|
50
|
+
* Types
|
51
|
+
*/
|
52
|
+
namespace nm {
|
53
|
+
|
54
|
+
class RubyObject;
|
55
|
+
template <typename IntType> class Rational;
|
56
|
+
template <typename Type> class Complex;
|
57
|
+
|
58
|
+
typedef Complex<float32_t> Complex64;
|
59
|
+
typedef Complex<float64_t> Complex128;
|
60
|
+
|
61
|
+
/*
|
62
|
+
* Data
|
63
|
+
*/
|
64
|
+
|
65
|
+
/*
|
66
|
+
* Classes and Functions
|
67
|
+
*/
|
68
|
+
|
69
|
+
template <typename Type>
|
70
|
+
class Complex {
|
71
|
+
public:
|
72
|
+
// The real and immaginary parts of the complex number.
|
73
|
+
Type r;
|
74
|
+
Type i;
|
75
|
+
|
76
|
+
/*
|
77
|
+
* Default constructor.
|
78
|
+
*/
|
79
|
+
inline Complex(Type real = 0, Type imaginary = 0) : r(real), i(imaginary) {}
|
80
|
+
|
81
|
+
/*
|
82
|
+
* Copy constructors.
|
83
|
+
*/
|
84
|
+
template <typename ComplexType>
|
85
|
+
inline Complex(const Complex<ComplexType>& other) : r(other.r), i(other.i) {}
|
86
|
+
|
87
|
+
template <typename IntType, typename = typename std::enable_if<std::is_integral<IntType>::value>::type>
|
88
|
+
inline Complex(const Rational<IntType>& other) : r(Type(other.n) / Type(other.d)), i(0) {}
|
89
|
+
|
90
|
+
Complex(const RubyObject& other);
|
91
|
+
|
92
|
+
/*
|
93
|
+
* Complex conjugate function -- creates a copy, but inverted.
|
94
|
+
*/
|
95
|
+
inline Complex<Type> conjugate() const {
|
96
|
+
return Complex<Type>(this->r, -(this->i));
|
97
|
+
}
|
98
|
+
|
99
|
+
/*
|
100
|
+
* Complex inverse function -- creates a copy, but inverted.
|
101
|
+
*
|
102
|
+
* FIXME: Check that this doesn't duplicate functionality of NativeType / Complex<Type>
|
103
|
+
*/
|
104
|
+
inline Complex<Type> inverse() const {
|
105
|
+
Complex<Type> conj = conjugate();
|
106
|
+
Type denom = this->r * this->r + this->i * this->i;
|
107
|
+
return Complex<Type>(conj.r / denom, conj.i / denom);
|
108
|
+
}
|
109
|
+
|
110
|
+
|
111
|
+
|
112
|
+
/*
|
113
|
+
* Binary operator definitions for various types.
|
114
|
+
*/
|
115
|
+
|
116
|
+
////////////////////////////////
|
117
|
+
// Complex-Complex Operations //
|
118
|
+
////////////////////////////////
|
119
|
+
|
120
|
+
template <typename OtherType>
|
121
|
+
inline Complex<Type> operator+(const Complex<OtherType>& other) const {
|
122
|
+
return Complex<Type>(this->r + other.r, this->i + other.i);
|
123
|
+
}
|
124
|
+
|
125
|
+
template <typename OtherType>
|
126
|
+
inline Complex<Type>& operator+=(const Complex<OtherType>& other) {
|
127
|
+
this->r += other.r;
|
128
|
+
this->i += other.i;
|
129
|
+
return *this;
|
130
|
+
}
|
131
|
+
|
132
|
+
template <typename OtherType>
|
133
|
+
inline Complex<Type> operator-(const Complex<OtherType>& other) const {
|
134
|
+
return Complex<Type>(this->r - other.r, this->i - other.i);
|
135
|
+
}
|
136
|
+
|
137
|
+
template <typename OtherType>
|
138
|
+
inline Complex<Type> operator*(const Complex<OtherType>& other) const {
|
139
|
+
return Complex<Type>(this->r * other.r - this->i * other.i, this->r * other.i + this->i * other.r);
|
140
|
+
}
|
141
|
+
|
142
|
+
template <typename OtherType>
|
143
|
+
inline Complex<Type>& operator*=(const Complex<OtherType>& other) {
|
144
|
+
this->r = this->r * other.r - this->i * other.i;
|
145
|
+
this->i = this->r * other.i + this->i * other.r;
|
146
|
+
return *this;
|
147
|
+
}
|
148
|
+
|
149
|
+
template <typename OtherType>
|
150
|
+
inline Complex<Type> operator/(const Complex<OtherType>& other) const {
|
151
|
+
Type new_r, new_i;
|
152
|
+
Type denom = other.i * other.i + other.r * other.r;
|
153
|
+
|
154
|
+
new_r = (this->r * other.r + this->i * other.i) / denom;
|
155
|
+
new_i = (this->i * other.r - this->r * other.i) / denom;
|
156
|
+
|
157
|
+
return Complex<Type>(new_r, new_i);
|
158
|
+
}
|
159
|
+
|
160
|
+
template <typename OtherType>
|
161
|
+
inline bool operator<(const Complex<OtherType>& other) const {
|
162
|
+
return (this->r < other.r) || ((this->r <= other.r) && (this->i < other.i));
|
163
|
+
}
|
164
|
+
|
165
|
+
template <typename OtherType>
|
166
|
+
inline bool operator>(const Complex<OtherType>& other) const {
|
167
|
+
return (this->r > other.r) || ((this->r >= other.r) && (this->i > other.i));
|
168
|
+
}
|
169
|
+
|
170
|
+
template <typename OtherType>
|
171
|
+
inline bool operator==(const Complex<OtherType>& other) const {
|
172
|
+
return FP_EQUAL(this->r, other.r) && FP_EQUAL(this->i, other.i);
|
173
|
+
}
|
174
|
+
|
175
|
+
template <typename OtherType>
|
176
|
+
inline bool operator!=(const Complex<OtherType>& other) const {
|
177
|
+
return !(*this == other);
|
178
|
+
}
|
179
|
+
|
180
|
+
template <typename OtherType>
|
181
|
+
inline bool operator<=(const Complex<OtherType>& other) const {
|
182
|
+
return (*this < other) || (*this == other);
|
183
|
+
}
|
184
|
+
|
185
|
+
template <typename OtherType>
|
186
|
+
inline bool operator>=(const Complex<OtherType>& other) const {
|
187
|
+
return (*this > other) || (*this == other);
|
188
|
+
}
|
189
|
+
|
190
|
+
template <typename OtherType>
|
191
|
+
inline operator Complex<OtherType> () const {
|
192
|
+
return Complex<OtherType>((OtherType)this->r, (OtherType)this->i);
|
193
|
+
}
|
194
|
+
|
195
|
+
/////////////////////////////////
|
196
|
+
// Complex-Rational Operations //
|
197
|
+
/////////////////////////////////
|
198
|
+
|
199
|
+
template <typename RationalType>
|
200
|
+
inline Complex<Type> operator+(const Rational<RationalType>& other) const {
|
201
|
+
return *this + Complex<Type>(other);
|
202
|
+
}
|
203
|
+
|
204
|
+
template <typename RationalType>
|
205
|
+
inline Complex<Type> operator-(const Rational<RationalType>& other) const {
|
206
|
+
return *this - Complex<Type>(other);
|
207
|
+
}
|
208
|
+
|
209
|
+
template <typename RationalType>
|
210
|
+
inline Complex<Type> operator*(const Rational<RationalType>& other) const {
|
211
|
+
return *this * Complex<Type>(other);
|
212
|
+
}
|
213
|
+
|
214
|
+
template <typename RationalType>
|
215
|
+
inline Complex<Type> operator/(const Rational<RationalType>& other) const {
|
216
|
+
return *this / Complex<Type>(other);
|
217
|
+
}
|
218
|
+
|
219
|
+
template <typename RationalType, typename = typename std::enable_if<std::is_integral<RationalType>::value>::type>
|
220
|
+
inline bool operator!=(const Rational<RationalType>& other) const {
|
221
|
+
return *this != Complex<Type>(other);
|
222
|
+
}
|
223
|
+
|
224
|
+
template <typename RationalType, typename = typename std::enable_if<std::is_integral<RationalType>::value>::type>
|
225
|
+
inline bool operator==(const Rational<RationalType>& other) const {
|
226
|
+
return *this == Complex<Type>(other);
|
227
|
+
}
|
228
|
+
|
229
|
+
///////////////////////////////
|
230
|
+
// Complex-Native Operations //
|
231
|
+
///////////////////////////////
|
232
|
+
|
233
|
+
template <typename NativeType, typename = typename std::enable_if<std::is_arithmetic<NativeType>::value>::type>
|
234
|
+
inline Complex<Type> operator+(const NativeType& other) const {
|
235
|
+
return *this + Complex<Type>(other);
|
236
|
+
}
|
237
|
+
|
238
|
+
template <typename NativeType, typename = typename std::enable_if<std::is_arithmetic<NativeType>::value>::type>
|
239
|
+
inline Complex<Type> operator-(const NativeType& other) const {
|
240
|
+
return *this - Complex<Type>(other);
|
241
|
+
}
|
242
|
+
|
243
|
+
template <typename NativeType, typename = typename std::enable_if<std::is_arithmetic<NativeType>::value>::type>
|
244
|
+
inline Complex<Type> operator*(const NativeType& other) const {
|
245
|
+
return *this * Complex<Type>(other);
|
246
|
+
}
|
247
|
+
|
248
|
+
template <typename NativeType, typename = typename std::enable_if<std::is_arithmetic<NativeType>::value>::type>
|
249
|
+
inline Complex<Type> operator/(const NativeType& other) const {
|
250
|
+
return *this / Complex<Type>(other);
|
251
|
+
}
|
252
|
+
|
253
|
+
template <typename NativeType, typename = typename std::enable_if<std::is_arithmetic<NativeType>::value>::type>
|
254
|
+
inline bool operator<(const NativeType& other) const {
|
255
|
+
return *this < Complex<Type>(other);
|
256
|
+
}
|
257
|
+
|
258
|
+
template <typename NativeType, typename = typename std::enable_if<std::is_arithmetic<NativeType>::value>::type>
|
259
|
+
inline bool operator>(const NativeType& other) const {
|
260
|
+
return *this > Complex<Type>(other);
|
261
|
+
}
|
262
|
+
|
263
|
+
template <typename NativeType, typename = typename std::enable_if<std::is_arithmetic<NativeType>::value>::type>
|
264
|
+
inline bool operator==(const NativeType& other) const {
|
265
|
+
return *this == Complex<Type>(other);
|
266
|
+
}
|
267
|
+
|
268
|
+
template <typename NativeType, typename = typename std::enable_if<std::is_arithmetic<NativeType>::value>::type>
|
269
|
+
inline bool operator!=(const NativeType& other) const {
|
270
|
+
return *this != Complex<Type>(other);
|
271
|
+
}
|
272
|
+
|
273
|
+
template <typename NativeType, typename = typename std::enable_if<std::is_arithmetic<NativeType>::value>::type>
|
274
|
+
inline bool operator<=(const NativeType& other) const {
|
275
|
+
return *this <= Complex<Type>(other);
|
276
|
+
}
|
277
|
+
|
278
|
+
template <typename NativeType, typename = typename std::enable_if<std::is_arithmetic<NativeType>::value>::type>
|
279
|
+
inline bool operator>=(const NativeType& other) const {
|
280
|
+
return *this >= Complex<Type>(other);
|
281
|
+
}
|
282
|
+
|
283
|
+
template <typename NativeType, typename = typename std::enable_if<std::is_arithmetic<NativeType>::value>::type>
|
284
|
+
inline operator NativeType () const {
|
285
|
+
return (NativeType)this->r;
|
286
|
+
}
|
287
|
+
};
|
288
|
+
|
289
|
+
|
290
|
+
/////////////////////////////////
|
291
|
+
// Rational-Complex Operations //
|
292
|
+
/////////////////////////////////
|
293
|
+
|
294
|
+
|
295
|
+
template <typename IntType, typename ComplexType, typename = typename std::enable_if<std::is_integral<IntType>::value>::type>
|
296
|
+
inline bool operator==(const Rational<IntType>& left, const Complex<ComplexType>& right) {
|
297
|
+
return Complex<ComplexType>(left) == right;
|
298
|
+
}
|
299
|
+
|
300
|
+
template <typename IntType, typename ComplexType, typename = typename std::enable_if<std::is_integral<IntType>::value>::type>
|
301
|
+
inline bool operator!=(const Rational<IntType>& left, const Complex<ComplexType>& right) {
|
302
|
+
return Complex<ComplexType>(left) != right;
|
303
|
+
}
|
304
|
+
|
305
|
+
|
306
|
+
///////////////////////////////
|
307
|
+
// Native-Complex Operations //
|
308
|
+
///////////////////////////////
|
309
|
+
|
310
|
+
template <typename NativeType, typename ComplexType, typename = typename std::enable_if<std::is_arithmetic<NativeType>::value>::type>
|
311
|
+
inline Complex<ComplexType> operator+(const NativeType& left, const Complex<ComplexType>& right) {
|
312
|
+
return Complex<ComplexType>(left) + right;
|
313
|
+
}
|
314
|
+
|
315
|
+
template <typename NativeType, typename ComplexType, typename = typename std::enable_if<std::is_arithmetic<NativeType>::value>::type>
|
316
|
+
inline Complex<ComplexType> operator-(const NativeType& left, const Complex<ComplexType>& right) {
|
317
|
+
return Complex<ComplexType>(left) - right;
|
318
|
+
}
|
319
|
+
|
320
|
+
template <typename NativeType, typename ComplexType, typename = typename std::enable_if<std::is_arithmetic<NativeType>::value>::type>
|
321
|
+
inline Complex<ComplexType> operator*(const NativeType& left, const Complex<ComplexType>& right) {
|
322
|
+
return Complex<ComplexType>(left) * right;
|
323
|
+
}
|
324
|
+
|
325
|
+
template <typename NativeType, typename ComplexType, typename = typename std::enable_if<std::is_arithmetic<NativeType>::value>::type>
|
326
|
+
inline Complex<ComplexType> operator/(const NativeType& left, const Complex<ComplexType>& right) {
|
327
|
+
return Complex<ComplexType>(left) / right;
|
328
|
+
}
|
329
|
+
|
330
|
+
template <typename NativeType, typename ComplexType, typename = typename std::enable_if<std::is_arithmetic<NativeType>::value>::type>
|
331
|
+
inline bool operator<(const NativeType left, const Complex<ComplexType>& right) {
|
332
|
+
return Complex<ComplexType>(left) < right;
|
333
|
+
}
|
334
|
+
|
335
|
+
template <typename NativeType, typename ComplexType, typename = typename std::enable_if<std::is_arithmetic<NativeType>::value>::type>
|
336
|
+
inline bool operator>(const NativeType left, const Complex<ComplexType>& right) {
|
337
|
+
return Complex<ComplexType>(left) > right;
|
338
|
+
}
|
339
|
+
|
340
|
+
template <typename NativeType, typename ComplexType, typename = typename std::enable_if<std::is_arithmetic<NativeType>::value>::type>
|
341
|
+
inline bool operator==(const NativeType left, const Complex<ComplexType>& right) {
|
342
|
+
return Complex<ComplexType>(left) == right;
|
343
|
+
}
|
344
|
+
|
345
|
+
template <typename NativeType, typename ComplexType, typename = typename std::enable_if<std::is_arithmetic<NativeType>::value>::type>
|
346
|
+
inline bool operator!=(const NativeType left, const Complex<ComplexType>& right) {
|
347
|
+
return Complex<ComplexType>(left) != right;
|
348
|
+
}
|
349
|
+
|
350
|
+
template <typename NativeType, typename ComplexType, typename = typename std::enable_if<std::is_arithmetic<NativeType>::value>::type>
|
351
|
+
inline bool operator<=(const NativeType left, const Complex<ComplexType>& right) {
|
352
|
+
return Complex<ComplexType>(left) <= right;
|
353
|
+
}
|
354
|
+
|
355
|
+
template <typename NativeType, typename ComplexType, typename = typename std::enable_if<std::is_arithmetic<NativeType>::value>::type>
|
356
|
+
inline bool operator>=(const NativeType left, const Complex<ComplexType>& right) {
|
357
|
+
return Complex<ComplexType>(left) >= right;
|
358
|
+
}
|
359
|
+
|
360
|
+
template <typename Type>
|
361
|
+
inline std::ostream& operator<<(std::ostream& out, const Complex<Type>& rhs) {
|
362
|
+
out << "(" << rhs.r << "," << rhs.i << "i)" << std::flush;
|
363
|
+
return out;
|
364
|
+
}
|
365
|
+
|
366
|
+
// Negative operator
|
367
|
+
template <typename IntType, typename = typename std::enable_if<std::is_integral<IntType>::value>::type>
|
368
|
+
inline Complex<IntType> operator-(const Complex<IntType>& rhs) {
|
369
|
+
return Complex<IntType>(-rhs.r, -rhs.i);
|
370
|
+
}
|
371
|
+
|
372
|
+
} // end of namespace nm
|
373
|
+
|
374
|
+
namespace std {
|
375
|
+
template <typename FloatType, typename = typename std::enable_if<std::is_floating_point<FloatType>::value>::type>
|
376
|
+
nm::Complex<FloatType> piecewise_abs(const nm::Complex<FloatType>& value) {
|
377
|
+
return nm::Complex<FloatType>(value.r < 0 ? -value.r : value.r,
|
378
|
+
value.i < 0 ? -value.i : value.i);
|
379
|
+
}
|
380
|
+
|
381
|
+
template <typename FloatType, typename = typename std::enable_if<std::is_floating_point<FloatType>::value>::type>
|
382
|
+
nm::Complex<FloatType> real_abs(const nm::Complex<FloatType>& value) {
|
383
|
+
return nm::Complex<FloatType>(value.r < 0 ? -value.r : value.r,
|
384
|
+
value.i);
|
385
|
+
}
|
386
|
+
|
387
|
+
template <typename FloatType, typename = typename std::enable_if<std::is_floating_point<FloatType>::value>::type>
|
388
|
+
nm::Complex<FloatType> imag_abs(const nm::Complex<FloatType>& value) {
|
389
|
+
return nm::Complex<FloatType>(value.r,
|
390
|
+
value.i < 0 ? -value.i : value.i);
|
391
|
+
}
|
392
|
+
|
393
|
+
template <typename FloatType, typename = typename std::enable_if<std::is_floating_point<FloatType>::value>::type>
|
394
|
+
double abs(const nm::Complex<FloatType>& value) {
|
395
|
+
return std::sqrt(double(value.r)*double(value.r) + double(value.i)*double(value.i));
|
396
|
+
}
|
397
|
+
}
|
398
|
+
|
399
|
+
#endif // COMPLEX_H
|