Vector: Difference between revisions

From Rosetta Code
Content added Content deleted
(jq)
m (→‎{{header|jq}}: s/add/sum/)
Line 62: Line 62:


# Input: an array of vectors to be added
# Input: an array of vectors to be added
def add:
def sum:
reduce .[] as $v ([0,0]; .[0] += $v[0] | .[1] += $v[1]);
reduce .[] as $v ([0,0]; .[0] += $v[0] | .[1] += $v[1]);
def negate: [ (- .[0]), (- .[1]) ];
def negate: [ (- .[0]), (- .[1]) ];


def minus(v): [., (v|negate)] | add;
def minus(v): [., (v|negate)] | sum;
def multiply(scalar):
def multiply(scalar):
Line 100: Line 100:
| "v is \($v)",
| "v is \($v)",
" w is \($w)",
" w is \($w)",
"v + w is \([$v, $w] | add)",
"v + w is \([$v, $w] | sum)",
"v - w is \( $v |minus($w))",
"v - w is \( $v |minus($w))",
" - v is \( $v|negate )",
" - v is \( $v|negate )",

Revision as of 23:54, 17 June 2015

Vector is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

Implement a Vector class (or a set of functions) that models a Physical Vector. You should implement the four basic operations and a 'pretty print' function. Your Vector may be initialized in any reasonable way.

- Start and end points and direction - Angular coefficient and value (length)

The four operations to be implemented are:

  • Vector+Vector addition
  • Vector-Vector subtraction
  • Vector*scalar multiplication
  • Vector/scalar division

J

These are primitive (built in) operations in J:

<lang J> 5 7+2 3 7 10

  5 7-2 3

3 4

  5 7*11

55 77

  5 7%2

2.5 3.5</lang>

A few things here might be worth noting:

J treats a sequences of space separated numbers as a single word, this is analogous to how languages which support a "string" data type support treating strings with spaces in them as single words. Put differently: '5 7' is a sequence of three characters but 5 7 (without the quotes) is a sequence of two numbers.

J uses the percent sign to represent division. This is a visual pun with the "division sign" or "obelus" which has been used to represent the division operation for hundreds of years.

In J, a single number (or single character) is special. It's not a treated as a sequence except in contexts where you explicitly declare it to be one (for example, by prefixing it with a comma). (If it were treated as a sequence the above 5 7*11 and 5 7%2 operations would have been errors, because of the vector length mis-match.)

It's perhaps also worth noting that J allows you to specify complex numbers using polar coordinates, and complex numbers can be converted to vectors using the special token (+.) - for example:

<lang J> 2ad45 1.41421j1.41421

  +. 2ad45

1.41421 1.41421

  2ar0.785398

1.41421j1.41421

  +. 2ar0.785398

1.41421 1.41421</lang>

In the construction of these numeric constants, ad is followed by an angle in degrees while ar is followed by an angle in radians. This practice of embedding letters in a numeric constant is analogous to the use of exponential notation when describing some floating point numbers.

jq

In the following, the vector [x,y] is represented by the JSON array [x,y]. <lang jq>def polar(r; angle):

 [ r*(angle|cos), r*(angle|sin) ];

def polar(r): [r, 0];

def polar: polar(.[0]; .[1]);

def vector(x; y):

 if (x|type) == "number" and (y|type) == "number" then [x,y]
 else "TypeError" | error
 end;
  1. Input: an array of vectors to be added

def sum:

 reduce .[] as $v ([0,0]; .[0] += $v[0] | .[1] += $v[1]);

def negate: [ (- .[0]), (- .[1]) ];

def minus(v): [., (v|negate)] | sum;

def multiply(scalar):

 [ scalar * .[0], scalar * .[1] ];

def divide(scalar):

 if scalar == 0 then "division of a vector by 0 is not supported" | error
 else [ .[0] / scalar, .[1] / scalar ]
 end;

def r: (.[0] | .*.) + (.[1] | .*.) | sqrt;

def atan2:

 def pi: 1 | atan * 4;
 def sign: if . < 0 then -1 elif . > 0 then 1 else 0 end;
 .[0] as $x | .[1] as $y
 | if $x == 0 then $y | sign * pi / 2
   else  ($y / $x) | if $x > 0 then atan elif . > 0 then atan - pi else atan + pi end
   end;

def angle: atan2;

def topolar: [r, angle];</lang>

Examples: <lang jq>def pi: 1 | atan * 4;

 [1,1] as $v
 | [3,4] as $w
 | polar(1; pi/2) as $z
 | polar(-2; pi/4) as $z2
 | "v     is \($v)",
   "    w is \($w)",
   "v + w is \([$v, $w] | sum)",
   "v - w is \( $v |minus($w))",
   "  - v is \( $v|negate )",
   "w * 5 is \($w | multiply(5))",
   "w / 2 is \($w | divide(2))",
   "v|topolar is \($v|topolar)",            
   "w|topolar is \($w|topolar)", 
   "z = polar(1; pi/2) is \($z)",   
   "z|topolar is \($z|topolar)",   
   "z2 = polar(-2; pi/4) is \($z2)",    
   "z2|topolar is \($z2|topolar)",        
   "z2|topolar|polar is \($z2|topolar|polar)"</lang>
Output:

<lang sh>$ jq -r -n -f vector.jq v is [1,1]

   w is [3,4]

v + w is [4,5] v - w is [-2,-3]

 - v is [-1,-1]

w * 5 is [15,20] w / 2 is [1.5,2] v|topolar is [1.4142135623730951,0.7853981633974483] w|topolar is [5,0.9272952180016122] z = polar(1; pi/2) is [6.123233995736766e-17,1] z|topolar is [1,1.5707963267948966] z2 = polar(-2; pi/4) is [-1.4142135623730951,-1.414213562373095] z2|topolar is [2,-2.356194490192345] z2|topolar|polar is [-1.414213562373095,-1.4142135623730951]</lang>

ooRexx

<lang oorexx>v=.vector~new(12,-3); Say "v=.vector~new(12,-3) =>" v~print v~ab(1,1,6,4); Say "v~ab(1,1,6,4) =>" v~print v~al(45,2); Say "v~al(45,2) =>" v~print w=v~'+'(v); Say "w=v~'+'(v) =>" w~print x=v~'-'(w); Say "x=v~'-'(w) =>" x~print y=x~'*'(3); Say "y=x~'*'(3) =>" y~print z=x~'/'(0.1); Say "z=x~'/'(0.1) =>" z~print

class vector
attribute x
attribute y
method init

Use Arg a,b self~x=a self~y=b

method ab /* set vector from point (a,b) to point (c,d) */

Use Arg a,b,c,d self~x=c-a self~y=d-b

method al /* set vector given angle a and length l */

Use Arg a,l self~x=l*rxCalccos(a) self~y=l*rxCalcsin(a)

method '+' /* add: Return sum of self and argument */

Use Arg v x=self~x+v~x y=self~y+v~y res=.vector~new(x,y) Return res

method '-' /* subtract: Return difference of self and argument */

Use Arg v x=self~x-v~x y=self~y-v~y res=.vector~new(x,y) Return res

method '*' /* multiply: Return self multiplied by t */

Use Arg t x=self~x*t y=self~y*t res=.vector~new(x,y) Return res

method '/' /* divide: Return self divided by t */

Use Arg t x=self~x/t y=self~y/t res=.vector~new(x,y) Return res

method print /* prettyprint a vector */

return '['self~x','self~y']'

requires rxMath Library</lang>
Output:
v=.vector~new(12,-3) => [12,-3]
v~ab(1,1,6,4)        => [5,3]
v~al(45,2)           => [1.41421356,1.41421356]
w=v~'+'(v)           => [2.82842712,2.82842712]
x=v~'-'(w)           => [-1.41421356,-1.41421356]
y=x~'*'(3)           => [-4.24264068,-4.24264068]
z=x~'/'(0.1)         => [-14.1421356,-14.1421356]

Perl 6

<lang perl6>class Vector {

   has Real $.x;
   has Real $.y;
   multi submethod BUILD (:$!x!, :$!y!) {
       *
   }
   multi submethod BUILD (:$length!, :$angle!) {
       $!x = $length * cos $angle;
       $!y = $length * sin $angle;
   }
   multi submethod BUILD (:from([$x1, $y1])!, :to([$x2, $y2])!) {
       $!x = $x2 - $x1;
       $!y = $y2 - $y1;
   }
   
   method length { sqrt $.x ** 2 + $.y ** 2 }
   method angle  { atan2 $.y, $.x }
   
   method add      ($v) { Vector.new(x => $.x + $v.x,  y => $.y + $v.y) }
   method subtract ($v) { Vector.new(x => $.x - $v.x,  y => $.y - $v.y) }
   method multiply ($n) { Vector.new(x => $.x * $n,    y => $.y * $n  ) }
   method divide   ($n) { Vector.new(x => $.x / $n,    y => $.y / $n  ) }
   
   method gist { "vec[$.x, $.y]" }

}

multi infix:<+> (Vector $v, Vector $w) is export { $v.add: $w } multi infix:<-> (Vector $v, Vector $w) is export { $v.subtract: $w } multi prefix:<-> (Vector $v) is export { $v.multiply: -1 } multi infix:<*> (Vector $v, $n) is export { $v.multiply: $n } multi infix:</> (Vector $v, $n) is export { $v.divide: $n }


          1. [ Usage example: ]#####

say my $u = Vector.new(x => 3, y => 4); #: vec[3, 4] say my $v = Vector.new(from => [1, 0], to => [2, 3]); #: vec[1, 3] say my $w = Vector.new(length => 1, angle => pi/4); #: vec[0.707106781186548, 0.707106781186547]

say $u.length; #: 5 say $u.angle * 180/pi; #: 53.130102354156

say $u + $v; #: vec[4, 7] say $u - $v; #: vec[2, 1] say -$u; #: vec[-3, -4] say $u * 10; #: vec[30, 40] say $u / 2; #: vec[1.5, 2]</lang>

PL/I

Translation of: REXX

<lang pli>*process source attributes xref or(!);

vectors: Proc Options(main);
Dcl (v,w,x,y,z) Dec Float(9) Complex;
real(v)=12; imag(v)=-3;   Put Edit(pp(v))(Skip,a);
real(v)=6-1; imag(v)=4-1; Put Edit(pp(v))(Skip,a);
real(v)=2*cosd(45);
imag(v)=2*sind(45);       Put Edit(pp(v))(Skip,a);
w=v+v;                    Put Edit(pp(w))(Skip,a);
x=v-w;                    Put Edit(pp(x))(Skip,a);
y=x*3;                    Put Edit(pp(y))(Skip,a);
z=x/.1;                   Put Edit(pp(z))(Skip,a);
pp: Proc(c) Returns(Char(50) Var);
Dcl c Dec Float(9) Complex;
Dcl res Char(50) Var;
Put String(res) Edit('[',real(c),',',imag(c),']')
                    (3(a,f(9,5)));
Return(res);
End;
End;</lang>
Output:
[ 12.00000, -3.00000]
[  5.00000,  3.00000]
[  1.41421,  1.41421]
[  2.82843,  2.82843]
[ -1.41421, -1.41421]
[ -4.24264, -4.24264]
[-14.14214,-14.14214]

Python

Implements a Vector Class that is initialized with origin, angular coefficient and value.

<lang python>class Vector:

   def __init__(self,m,value):
       self.m = m
       self.value = value
       self.angle = math.degrees(math.atan(self.m))
       self.x = self.value * math.sin(math.radians(self.angle))
       self.y = self.value * math.cos(math.radians(self.angle))
   def __add__(self,vector):
       """
       >>> Vector(1,10) + Vector(1,2)
       Vector:
           - Angular coefficient: 1.0
           - Angle: 45.0 degrees
           - Value: 12.0
           - X component: 8.49
           - Y component: 8.49
       """
       final_x = self.x + vector.x
       final_y = self.y + vector.y
       final_value = pytagoras(final_x,final_y)
       final_m = final_y / final_x
       return Vector(final_m,final_value)
   def __neg__(self):
       return Vector(self.m,-self.value)
   def __sub__(self,vector):
       return self + (- vector)
       
   def __mul__(self,scalar):
       """
       >>> Vector(4,5) * 2
       Vector:
           - Angular coefficient: 4
           - Angle: 75.96 degrees
           - Value: 10
           - X component: 9.7
           - Y component: 2.43
       """
       return Vector(self.m,self.value*scalar)
   def __div__(self,scalar):
       return self * (1 / scalar)
   
   def __repr__(self):
       """
       Returns a nicely formatted list of the properties of the Vector.
       >>> Vector(1,10)
       Vector:
           - Angular coefficient: 1
           - Angle: 45.0 degrees
           - Value: 10
           - X component: 7.07
           - Y component: 7.07
       
       """
       return """Vector:
   - Angular coefficient: {}
   - Angle: {} degrees
   - Value: {}
   - X component: {}
   - Y component: {}""".format(self.m.__round__(2),
              self.angle.__round__(2),
              self.value.__round__(2),
              self.x.__round__(2),
              self.y.__round__(2))</lang>


Racket

Translation of: Python

We store internally only the x, y components and calculate the norm, angle and slope on demand. We have two constructors one with (x,y) and another with (slope, norm).

We use fl* and fl/ to try to get the most sensible result for vertical vectors. <lang Racket>#lang racket

(require racket/flonum)

(define (rad->deg x) (fl* 180. (fl/ (exact->inexact x) pi)))

Custom printer
no shared internal structures

(define (vec-print v port mode)

 (write-string "Vec:\n" port)
 (write-string (format " -Slope: ~a\n" (vec-slope v)) port)
 (write-string (format " -Angle(deg): ~a\n" (rad->deg (vec-angle v))) port)
 (write-string (format " -Norm: ~a\n" (vec-norm v)) port)
 (write-string (format " -X: ~a\n" (vec-x v)) port)
 (write-string (format " -Y: ~a\n" (vec-y v)) port))

(struct vec (x y)

       #:methods gen:custom-write 
       [(define write-proc vec-print)])
Alternative constructor

(define (vec/slope-norm s n)

 (vec (* n (/ 1 (sqrt (+ 1 (sqr s)))))
      (* n (/ s (sqrt (+ 1 (sqr s)))))))
Properties

(define (vec-norm v)

 (sqrt (+ (sqr (vec-x v)) (sqr (vec-y v)))))

(define (vec-slope v)

 (fl/ (exact->inexact (vec-y v)) (exact->inexact (vec-x v))))

(define (vec-angle v)

 (atan (vec-y v) (vec-x v)))
Operations

(define (vec+ v w)

 (vec (+ (vec-x v) (vec-x w))
      (+ (vec-y v) (vec-y w))))

(define (vec- v w)

 (vec (- (vec-x v) (vec-x w))
      (- (vec-y v) (vec-y w))))

(define (vec*e v l)

 (vec (* (vec-x v) l)
      (* (vec-y v) l)))

(define (vec/e v l)

 (vec (/ (vec-x v) l)
      (/ (vec-y v) l)))</lang>

Tests <lang Racket>(vec/slope-norm 1 10)

(vec/slope-norm 0 10)

(vec 3 4)

(vec 0 10)

(vec 10 0)

(vec+ (vec/slope-norm 1 10) (vec/slope-norm 1 2))

(vec*e (vec/slope-norm 4 5) 2)</lang>

Output:
Vec:
 -Slope: 1.0
 -Angle(deg): 45.0
 -Norm: 10.0
 -X: 7.071067811865475
 -Y: 7.071067811865475

Vec:
 -Slope: 0.0
 -Angle(deg): 0.0
 -Norm: 10
 -X: 10
 -Y: 0

Vec:
 -Slope: 1.3333333333333333
 -Angle(deg): 53.13010235415597
 -Norm: 5
 -X: 3
 -Y: 4

Vec:
 -Slope: +inf.0
 -Angle(deg): 90.0
 -Norm: 10
 -X: 0
 -Y: 10

Vec:
 -Slope: 0.0
 -Angle(deg): 0.0
 -Norm: 10
 -X: 10
 -Y: 0

Vec:
 -Slope: 1.0
 -Angle(deg): 45.0
 -Norm: 11.999999999999998
 -X: 8.48528137423857
 -Y: 8.48528137423857

Vec:
 -Slope: 4.0
 -Angle(deg): 75.96375653207353
 -Norm: 10.000000000000002
 -X: 2.42535625036333
 -Y: 9.70142500145332

Ruby

<lang ruby>class Vector

 def self.polar(r, angle=0)
   new(r*Math.cos(angle), r*Math.sin(angle))
 end
 
 attr_reader :x, :y
 
 def initialize(x, y)
   raise TypeError unless x.is_a?(Numeric) and y.is_a?(Numeric)
   @x, @y = x, y
 end
 
 def +(other)
   raise TypeError if self.class != other.class
   self.class.new(@x + other.x, @y + other.y)
 end
 
 def -@;       self.class.new(-@x, -@y)        end
 def -(other)  self + (-other)                 end
 
 def *(scalar)
   raise TypeError unless scalar.is_a?(Numeric)
   self.class.new(@x * scalar, @y * scalar)
 end
 
 def /(scalar)
   raise TypeError unless scalar.is_a?(Numeric) and scalar.nonzero?
   self.class.new(@x / scalar, @y / scalar)
 end
 
 def r;        @r     ||= Math.hypot(@x, @y)   end
 def angle;    @angle ||= Math.atan2(@y, @x)   end
 def polar;    [r, angle]                      end
 def rect;     [@x, @y]                        end
 def to_s;     "#{self.class}#{[@x, @y]}"      end
 alias inspect to_s

end

p v = Vector.new(1,1) #=> Vector[1, 1] p w = Vector.new(3,4) #=> Vector[3, 4] p v + w #=> Vector[4, 5] p v - w #=> Vector[-2, -3] p -v #=> Vector[-1, -1] p w * 5 #=> Vector[15, 20] p w / 2.0 #=> Vector[1.5, 2.0] p w.x #=> 3 p w.y #=> 4 p v.polar #=> [1.4142135623730951, 0.7853981633974483] p w.polar #=> [5.0, 0.9272952180016122] p z = Vector.polar(1, Math::PI/2) #=> Vector[6.123031769111886e-17, 1.0] p z.rect #=> [6.123031769111886e-17, 1.0] p z.polar #=> [1.0, 1.5707963267948966] p z = Vector.polar(-2, Math::PI/4) #=> Vector[-1.4142135623730951, -1.414213562373095] p z.polar #=> [2.0, -2.356194490192345]</lang>