nmatrix-gemv 0.0.3

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.
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