nmatrix-gemv 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +29 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +14 -0
  5. data/Gemfile +7 -0
  6. data/README.md +29 -0
  7. data/Rakefile +225 -0
  8. data/ext/nmatrix_gemv/binary_format.txt +53 -0
  9. data/ext/nmatrix_gemv/data/complex.h +399 -0
  10. data/ext/nmatrix_gemv/data/data.cpp +298 -0
  11. data/ext/nmatrix_gemv/data/data.h +771 -0
  12. data/ext/nmatrix_gemv/data/meta.h +70 -0
  13. data/ext/nmatrix_gemv/data/rational.h +436 -0
  14. data/ext/nmatrix_gemv/data/ruby_object.h +471 -0
  15. data/ext/nmatrix_gemv/extconf.rb +254 -0
  16. data/ext/nmatrix_gemv/math.cpp +1639 -0
  17. data/ext/nmatrix_gemv/math/asum.h +143 -0
  18. data/ext/nmatrix_gemv/math/geev.h +82 -0
  19. data/ext/nmatrix_gemv/math/gemm.h +271 -0
  20. data/ext/nmatrix_gemv/math/gemv.h +212 -0
  21. data/ext/nmatrix_gemv/math/ger.h +96 -0
  22. data/ext/nmatrix_gemv/math/gesdd.h +80 -0
  23. data/ext/nmatrix_gemv/math/gesvd.h +78 -0
  24. data/ext/nmatrix_gemv/math/getf2.h +86 -0
  25. data/ext/nmatrix_gemv/math/getrf.h +240 -0
  26. data/ext/nmatrix_gemv/math/getri.h +108 -0
  27. data/ext/nmatrix_gemv/math/getrs.h +129 -0
  28. data/ext/nmatrix_gemv/math/idamax.h +86 -0
  29. data/ext/nmatrix_gemv/math/inc.h +47 -0
  30. data/ext/nmatrix_gemv/math/laswp.h +165 -0
  31. data/ext/nmatrix_gemv/math/long_dtype.h +52 -0
  32. data/ext/nmatrix_gemv/math/math.h +1069 -0
  33. data/ext/nmatrix_gemv/math/nrm2.h +181 -0
  34. data/ext/nmatrix_gemv/math/potrs.h +129 -0
  35. data/ext/nmatrix_gemv/math/rot.h +141 -0
  36. data/ext/nmatrix_gemv/math/rotg.h +115 -0
  37. data/ext/nmatrix_gemv/math/scal.h +73 -0
  38. data/ext/nmatrix_gemv/math/swap.h +73 -0
  39. data/ext/nmatrix_gemv/math/trsm.h +387 -0
  40. data/ext/nmatrix_gemv/nm_memory.h +60 -0
  41. data/ext/nmatrix_gemv/nmatrix_gemv.cpp +90 -0
  42. data/ext/nmatrix_gemv/nmatrix_gemv.h +374 -0
  43. data/ext/nmatrix_gemv/ruby_constants.cpp +153 -0
  44. data/ext/nmatrix_gemv/ruby_constants.h +107 -0
  45. data/ext/nmatrix_gemv/ruby_nmatrix.c +84 -0
  46. data/ext/nmatrix_gemv/ttable_helper.rb +122 -0
  47. data/ext/nmatrix_gemv/types.h +54 -0
  48. data/ext/nmatrix_gemv/util/util.h +78 -0
  49. data/lib/nmatrix-gemv.rb +43 -0
  50. data/lib/nmatrix_gemv/blas.rb +85 -0
  51. data/lib/nmatrix_gemv/nmatrix_gemv.rb +35 -0
  52. data/lib/nmatrix_gemv/rspec.rb +75 -0
  53. data/nmatrix-gemv.gemspec +31 -0
  54. data/spec/blas_spec.rb +154 -0
  55. data/spec/spec_helper.rb +128 -0
  56. metadata +186 -0
@@ -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
@@ -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
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format RSpec::Longrun::Formatter
@@ -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
@@ -0,0 +1,7 @@
1
+ # Gemfile
2
+ source 'http://ruby.taobao.org/'
3
+ gemspec
4
+
5
+ group :development do
6
+ gem 'rspec-longrun'
7
+ end
@@ -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
+ ```
@@ -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