[前][次][番号順一覧][スレッド一覧]

ruby-changes:36102

From: marcandre <ko1@a...>
Date: Wed, 29 Oct 2014 11:43:57 +0900 (JST)
Subject: [ruby-changes:36102] marcandRe: r48183 (trunk): * lib/matrix.rb: Generalize Vector#cross_product to arbitrary dimensions

marcandre	2014-10-29 11:43:52 +0900 (Wed, 29 Oct 2014)

  New Revision: 48183

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=48183

  Log:
    * lib/matrix.rb: Generalize Vector#cross_product to arbitrary dimensions
      based on a patch by gogo tanaka [#10074]

  Modified files:
    trunk/ChangeLog
    trunk/NEWS
    trunk/lib/matrix.rb
    trunk/test/matrix/test_vector.rb
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 48182)
+++ ChangeLog	(revision 48183)
@@ -1,3 +1,9 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Wed Oct 29 11:43:43 2014  Marc-Andre Lafortune  <ruby-core@m...>
+
+	* lib/matrix.rb: Generalize Vector#cross_product to arbitrary
+	  dimensions
+	  based on a patch by gogo tanaka [#10074]
+
 Wed Oct 29 11:43:11 2014  Marc-Andre Lafortune  <ruby-core@m...>
 
 	* lib/matrix.rb: Add Matrix#adjucate
Index: lib/matrix.rb
===================================================================
--- lib/matrix.rb	(revision 48182)
+++ lib/matrix.rb	(revision 48183)
@@ -1962,14 +1962,36 @@ class Vector https://github.com/ruby/ruby/blob/trunk/lib/matrix.rb#L1962
   alias_method :dot, :inner_product
 
   #
-  # Returns the cross product of this vector with the other.
+  # Returns the cross product of this vector with the others.
   #   Vector[1, 0, 0].cross_product Vector[0, 1, 0]   => Vector[0, 0, 1]
   #
-  def cross_product(v)
-    Vector.Raise ErrDimensionMismatch unless size == v.size && v.size == 3
-    Vector[ v[2]*@elements[1] - v[1]*@elements[2],
-            v[0]*@elements[2] - v[2]*@elements[0],
-            v[1]*@elements[0] - v[0]*@elements[1] ]
+  # It is generalized to other dimensions to return a vector perpendicular
+  # to the arguments.
+  #   Vector[1, 2].cross_product # => Vector[-2, 1]
+  #   Vector[1, 0, 0, 0].cross_product(
+  #      Vector[0, 1, 0, 0],
+  #      Vector[0, 0, 1, 0]
+  #   )  #=> Vector[0, 0, 0, 1]
+  #
+  def cross_product(*vs)
+    raise ErrOperationNotDefined, "cross product is not defined on vectors of dimension #{size}" unless size >= 2
+    raise ArgumentError, "wrong number of arguments (#{vs.size} for #{size - 2})" unless vs.size == size - 2
+    vs.each do |v|
+      raise TypeError, "expected Vector, got #{v.class}" unless v.is_a? Vector
+      Vector.Raise ErrDimensionMismatch unless v.size == size
+    end
+    case size
+    when 2
+      Vector[-@elements[1], @elements[0]]
+    when 3
+      v = vs[0]
+      Vector[ v[2]*@elements[1] - v[1]*@elements[2],
+        v[0]*@elements[2] - v[2]*@elements[0],
+        v[1]*@elements[0] - v[0]*@elements[1] ]
+    else
+      rows = self, *vs, Array.new(size) {|i| Vector.basis(size: size, index: i) }
+      Matrix.rows(rows).laplace_expansion(row: size - 1)
+    end
   end
   alias_method :cross, :cross_product
 
Index: NEWS
===================================================================
--- NEWS	(revision 48182)
+++ NEWS	(revision 48183)
@@ -155,6 +155,7 @@ with all sufficient information, see the https://github.com/ruby/ruby/blob/trunk/NEWS#L155
       along the +num+ -th row or column.
     * Vector.basis(size:, index:) returns the specified basis vector
     * Unary - and + added for Vector and Matrix
+    * Vector#cross_product generalized to arbitrary dimensions
     * Vector#dot and #cross are aliases for #inner_product and #cross_product
 
 * Pathname
Index: test/matrix/test_vector.rb
===================================================================
--- test/matrix/test_vector.rb	(revision 48182)
+++ test/matrix/test_vector.rb	(revision 48183)
@@ -169,7 +169,17 @@ class TestVector < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/matrix/test_vector.rb#L169
   def test_cross_product
     v = Vector[1, 0, 0].cross_product Vector[0, 1, 0]
     assert_equal(Vector[0, 0, 1], v)
-    v = Vector[1, 0, 0].cross Vector[0, 1, 0]
-    assert_equal(Vector[0, 0, 1], v)
+    v2 = Vector[1, 2].cross_product
+    assert_equal(Vector[-2, 1], v2)
+    v3 = Vector[3, 5, 2, 1].cross(Vector[4, 3, 1, 8], Vector[2, 9, 4, 3])
+    assert_equal(Vector[16, -65, 139, -1], v3)
+    assert_equal Vector[0, 0, 0, 1],
+      Vector[1, 0, 0, 0].cross(Vector[0, 1, 0, 0], Vector[0, 0, 1, 0])
+    assert_equal Vector[0, 0, 0, 0, 1],
+      Vector[1, 0, 0, 0, 0].cross(Vector[0, 1, 0, 0, 0], Vector[0, 0, 1, 0, 0], Vector[0, 0, 0, 1, 0])
+    assert_raise(Vector::ErrDimensionMismatch) { Vector[1, 2, 3].cross_product(Vector[1, 4]) }
+    assert_raise(TypeError) { Vector[1, 2, 3].cross_product(42) }
+    assert_raise(ArgumentError) { Vector[1, 2].cross_product(Vector[2, -1]) }
+    assert_raise(Vector::ErrOperationNotDefined) { Vector[1].cross_product }
   end
 end

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]