nsphere 0.1.0 → 0.2.0

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 (3) hide show
  1. checksums.yaml +7 -0
  2. data/lib/nsphere.rb +93 -19
  3. metadata +6 -8
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1d92024f76898a3e73d06ddcd095735d40bbc3f8
4
+ data.tar.gz: cfb5fa03364c9c89c3901605b3761a3368b57e16
5
+ SHA512:
6
+ metadata.gz: 9ead903c0cfe27d7d5115e4686a9eda710ac78fd73370e7665bf27b3dffb96c0a5925c051363207d52a74326483f1f1f1d9340d75c34ab3aab7d9512e002f924
7
+ data.tar.gz: ba084b8222f84c80dc25eb0150a2ea1abb7484f11e6d65ba972b204f08422bcef8e5c950d4228d7c7064cb6eb8b9f13e34f957880b56cd3a5b505e83a5f8c881
@@ -1,7 +1,28 @@
1
1
  # encoding: utf-8
2
2
 
3
+ # The program define the NSphere in any dimensional
4
+ # space, and offer the +, -, *, / operator for vector
5
+ # operation in the space.
6
+ #
7
+ # Author:: m00nlight (mailto:dot_wangyushi@yeah.net)
8
+ # Copyright:: Copyright(c) 2014 m00nlight
9
+ # License:: Distributed under the MIT-License
10
+
11
+
3
12
  class NSphere
4
- attr_reader :radius, :thetas, :coordinates
13
+ attr_reader :radius, :thetas, :coordinates, :dim
14
+
15
+ # A implementation of the n-sphere in any dimensional space
16
+ # In two dimensional, it is a circle to origin point(0, 0), in
17
+ # three dimensional space, it is a sphere to origin(0, 0, 0).
18
+ #
19
+ # === Attributes
20
+ #
21
+ # * +radius+ - Radius of the object
22
+ # * +thetas+ - angles value in radians
23
+ # * +coordinates+ - coordinates of the object
24
+ # * +dim+ - dimension of the space
25
+
5
26
 
6
27
  def initialize(args)
7
28
  if not (args[:radius].nil? or args[:thetas].nil?)
@@ -19,6 +40,8 @@ class NSphere
19
40
  end
20
41
  end
21
42
 
43
+ # Check argument of radius and thetas, the last theta must in range [0, 2PI],
44
+ # while the rest thetas values must be in the range of [0, PI]
22
45
  def check_argument(radius, thetas)
23
46
  radius >= 0.0 and thetas[0..-2].all? { |x| x >= 0 and x <= Math::PI} and
24
47
  thetas[-1] >= 0 and thetas[-1] <= 2 * Math::PI
@@ -27,9 +50,9 @@ class NSphere
27
50
  def build_by_radius_thetas(radius, thetas)
28
51
  @radius = radius
29
52
  @thetas = thetas
30
- dim = @thetas.size + 1
31
- @coordinates = [0.0] * dim
32
- (0..(dim - 2)).to_a.each do |idx|
53
+ @dim = @thetas.size + 1
54
+ @coordinates = [0.0] * @dim
55
+ (0..(@dim - 2)).to_a.each do |idx|
33
56
  tmp = @radius
34
57
  (0..(idx - 1)).to_a { |j| tmp = tmp * Math.sin(@thetas[j])}
35
58
  @coordinates[idx] = tmp * Math.cos(@thetas[idx])
@@ -39,20 +62,34 @@ class NSphere
39
62
 
40
63
  def build_by_coordinate(coordinates)
41
64
  @coordinates = coordinates
42
- dim = @coordinates.size
65
+ @dim = @coordinates.size
43
66
  coord_square = coordinates.map { |x| x ** 2}
44
67
  @radius = Math.sqrt(coord_square.inject(:+))
45
- sum = [0] * (dim + 1)
68
+ sum = [0] * (@dim + 1)
46
69
  coord_square.each_with_index do |elem, idx|
47
70
  sum[idx + 1] = sum[idx] + elem
48
71
  end
49
- @thetas = [0.0] * (dim - 1)
50
- @thetas[dim - 2] = Math.atan2(coordinates[dim - 1], coordinates[dim - 2])
51
- (0..(dim - 3)).to_a.reverse.each do |idx|
52
- @thetas[idx] = atan((sum[dim - 1] - sum[idx]) , coordinates[idx])
72
+ @thetas = [0.0] * (@dim - 1)
73
+ @thetas[@dim - 2] = normalize_angle(Math.atan2(coordinates[@dim - 1],
74
+ coordinates[@dim - 2]),
75
+ 2 * Math::PI)
76
+ (0..(@dim - 3)).to_a.reverse.each do |idx|
77
+ @thetas[idx] = normalize_angle(atan((sum[@dim - 1] - sum[idx]) ,
78
+ coordinates[idx]),
79
+ Math::PI)
53
80
  end
54
81
  end
55
82
 
83
+ # atan wrapper for the Math.atan method to avoid produce 0 / 0 as NaN
84
+ #
85
+ # ==== Attributes
86
+ #
87
+ # * +y+ - denominator of the atan function
88
+ # * +x+ - numerator of the atan function
89
+ #
90
+ # ==== Example
91
+ # atan(0, 0) => 0.0
92
+ # atan(3, 4) => 0.6435011087932844
56
93
  def atan(y, x)
57
94
  if x.abs <= 10e-6 && y.abs <= 10e-6
58
95
  return 0.0
@@ -61,38 +98,70 @@ class NSphere
61
98
  end
62
99
  end
63
100
 
101
+
102
+ # normalize an angle value to [0..range]
103
+ def normalize_angle(angle, range)
104
+ (angle + range) % range
105
+ end
106
+
107
+ # negate the object
64
108
  def negate
65
- NSphere.new(radius: -self.radius,
66
- thetas: self.thetas.map { |x| -x})
109
+ NSphere.new(coord: @coordinates.map { |x| -x})
67
110
  end
68
111
 
112
+ # help function for doing vector multiplication and division
113
+ def add_angles(thetas1, thetas2)
114
+
115
+ res = []
116
+ res = thetas1[0..-2].zip(thetas2[0..-2]) { |x|
117
+ (x.inject(:+) + Math::PI) % Math::PI
118
+ } || res
119
+
120
+ res << ((thetas1[-1] + thetas2[-1] + 2 * Math::PI) % (2 * Math::PI))
121
+ res
122
+ end
123
+
124
+ # add operator for two vectors
69
125
  def +(a)
126
+ raise "Dimension not match" if @dim != a.dim
70
127
  tmp = self.coordinates.zip(a.coordinates).map { |x|
71
128
  x.inject(:+)
72
129
  }
73
130
  NSphere.new(coord: tmp)
74
131
  end
75
132
 
133
+ # minus operator for two vectors
76
134
  def -(a)
135
+ raise "Dimension not match" if @dim != a.dim
77
136
  self + a.negate
78
137
  end
79
138
 
139
+ # multiply operator for two vectors
80
140
  def *(a)
81
- tmp = self.coordinates.zip(a.coordinates).map { |x|
82
- x.inject(:+)
83
- }
141
+ tmp = add_angles(@thetas, a.thetas)
84
142
  NSphere.new(radius: self.radius * a.radius,
85
143
  thetas: tmp)
86
144
  end
87
145
 
146
+ # divide operator for two vectors
88
147
  def /(a)
89
- tmp = self.coordinates.zip(a.coordinates).map { |x|
90
- x[0] - x[1]
91
- }
92
- NSphere.new(radius: self.radius / a.radius,
148
+ tmp = add_angles(@thetas, a.thetas.map { |x| -x})
149
+
150
+ p @thetas
151
+ p a.thetas.map { |x| -x}
152
+ p tmp
153
+ NSphere.new(radius: @radius / a.radius,
93
154
  thetas: tmp)
94
155
  end
95
156
 
157
+ # Class method, generate a random vector in any dimensional space
158
+ #
159
+ # ==== Attributes
160
+ #
161
+ # * +dim+ - dimension of the generate vector
162
+ # * +radius+ - radius with default value set to 1.0
163
+ #
164
+ # An random NSphere object is returned as result.
96
165
  def self.random_vector(dim, radius = 1.0)
97
166
  thetas = [0.0] * (dim - 1)
98
167
  thetas[-1] = Random.rand(0..(2 * Math::PI))
@@ -102,4 +171,9 @@ class NSphere
102
171
  NSphere.new(radius: radius,
103
172
  thetas: thetas)
104
173
  end
174
+
175
+ # override to string method of NSphere object
176
+ def to_s
177
+ "radius: #{radius}, thetas: #{thetas}, coordinates: #{coordinates}"
178
+ end
105
179
  end
metadata CHANGED
@@ -1,8 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nsphere
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
5
- prerelease:
4
+ version: 0.2.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - m00nlight
@@ -21,26 +20,25 @@ files:
21
20
  homepage: https://github.com/m00nlight/nsphere
22
21
  licenses:
23
22
  - MIT
23
+ metadata: {}
24
24
  post_install_message:
25
25
  rdoc_options: []
26
26
  require_paths:
27
27
  - lib
28
28
  required_ruby_version: !ruby/object:Gem::Requirement
29
- none: false
30
29
  requirements:
31
- - - ! '>='
30
+ - - ">="
32
31
  - !ruby/object:Gem::Version
33
32
  version: '0'
34
33
  required_rubygems_version: !ruby/object:Gem::Requirement
35
- none: false
36
34
  requirements:
37
- - - ! '>='
35
+ - - ">="
38
36
  - !ruby/object:Gem::Version
39
37
  version: '0'
40
38
  requirements: []
41
39
  rubyforge_project:
42
- rubygems_version: 1.8.23
40
+ rubygems_version: 2.2.2
43
41
  signing_key:
44
- specification_version: 3
42
+ specification_version: 4
45
43
  summary: NSphere
46
44
  test_files: []