i387-asm optimised code for Single, Double and Extended precision vector operations.

Tested with
  fPrint Virtual Pascal 2.0 (asm and pascal codes)
  Borland Pascal 7.0 and FPC 0.99.12 (generic pascal code)

Copyright (c) 1996-2000 by Jan Jeowicki,
              Department of Mathematics, Wrocaw University of Agriculture, Poland
              jasj@karnet.ar.wroc.pl
              jasj@ozi.ar.wroc.pl
              www.ar.wroc.pl/~jasj

In 1991 Wolfgang Lieff (Flinders Institute for Atmospheric and Marine Sciences,
mowl@cc.flinders.edu.au) has released his VMATH10 module for fast 2D and 3D
vector operations in Pascal assembler interface for BP. I have got it in 1996,
when I was writing 2D model for water flow computations, that have become
a part of my PhD.

At almost the same time, I have got a demo of the first VPascal release.
I am not high-quality assembler programmer, but these two facts made me
try to profile assembler code generated by VP compiler in order to speed
up my computations. I have successfully tested at least double-precision
part of libraries. Now I do not update them regularily, but I use them
up to now in several programs.

There is nothing very sophisticated or difficult in these routines,
and their mathematical foundations are obviously public domain.
There are guys who sell similar programs for money,
so I think it is better to put this code into PD sourceware...

Organization of the library:

mops.pas: memory management functions

scalars.pas: scalar types and math functions

vec2.pas: double precision 2D and 3D vector types and operations

vectors.pas: single, double and quadruple precision vector data types and operations.
Contains
  svectors (single precicion),
  dvectors (double precicion),
  qvectors (quadruple precicion),
  ivectors (integer-valued vectors),
  vecconv (data type conversion),
  vecband (elimination of band-structured linear equations system -- Pascal only).

Two trivial examples: DemoVec and DemoV2 have been included.

Compiler-specific files are located in complier-specific subdirectory (BP7 or VP2).
Copy them to the main directory.
*.PP files contain generic Pascal code.
*.ASM files contain almost eauivalent assembler code
(for VPascal only, since &saves-&uses mechanism has been applied).
ASM_MATH conditional switches between using Pascal and ASM source.
Results returned by ASM implementations may differ
to the standard ones due to reversed summation direction.

Routine names nad calling conventions are somewhat similar to BLAS libraries.

QVector routines are patched ugly, I am not going to improve them now.

How to use?

The best way is dynamic allocation of vectors. The encouraged way to do this is:
        var p: pvector;
        ...............
        p := nil;
        if vecalloc(1,n,p) then begin
          ... do something with p^
          ........................
          vecfree(1,n,p);
        end;
You must remember the size of your vector data. Since in many applications you need
a great number of identically sized vectors, this should not be a problem.


This is free source code. Use and have a joy! Please let me know about bugs.
Please do not remove my name from this file.
No guarantee is given etc...

The following subroutines are implemented in VECTORS.PAS:

{ conversion utilities }

  { Dense <--> Sparse data storage }
  { spv <-- v }
  procedure veccompress(const dim: index; var pattern: ivector; var v, cv: vector);
  { v <-- spv }
  procedure vecuncompress(const dim: index; var cv: vector; var pattern: ivector; var v: vector);

  { Y <-- X with data representation conversion }
  procedure dVec2qVec(const dim0,dim1: index; var x: dVector; var y: qVector);
  procedure qVec2dVec(const dim0,dim1: index; var x: qVector; var y: dVector);
  procedure dVec2sVec(const dim0,dim1: index; var x: dVector; var y: sVector);
  procedure sVec2dVec(const dim0,dim1: index; var x: sVector; var y: dVector);

{ norms and comparing functions }

(* vector operations *)

  { @ = |R| }
  function vecnorml1(const dim0,dim1: index; var r: dVector): qFloat; far;
  function vecnorml2(const dim0,dim1: index; var r: dVector): qFloat; far;
  function vecnormlp(const dim0,dim1: index; var r: dVector): qFloat; far;
  function vecnormlsup(const dim0,dim1: index; var r: dVector): qFloat; far;

  function spvecnorml1(const dim: index; var pattern: ivector; var r: dVector): qFloat; far;
  function spvecnorml2(const dim: index; var pattern: ivector; var r: dVector): qFloat; far;
  function spvecnormlp(const dim: index; var pattern: ivector; var r: dVector): qFloat; far;
  function spvecnormlsup(const dim: index; var pattern: ivector; var r: dVector): qFloat; far;

  function qvecnorml1(const dim0,dim1: index; var r: qVector): qFloat; far;
  function qvecnorml2(const dim0,dim1: index; var r: qVector): qFloat; far;
  function qvecnormlp(const dim0,dim1: index; var r: qVector): qFloat; far;
  function qvecnormlsup(const dim0,dim1: index; var r: qVector): qFloat; far;

  function spqvecnorml1(const dim: index; var pattern: ivector; var r: qVector): qFloat; far;
  function spqvecnorml2(const dim: index; var pattern: ivector; var r: qVector): qFloat; far;
  function spqvecnormlp(const dim: index; var pattern: ivector; var r: qVector): qFloat; far;
  function spqvecnormlsup(const dim: index; var pattern: ivector; var r: qVector): qFloat; far;

  { @ = |X-Y| }
  function vecdistl1(const dim0,dim1: index; var x,y: dVector): qFloat; far;
  function vecdistl2(const dim0,dim1: index; var x,y: dVector): qFloat; far;
  function vecdistlp(const dim0,dim1: index; var x,y: dVector): qFloat; far;
  function vecdistlsup(const dim0,dim1: index; var x,y: dVector): qFloat; far;

  function qvecdistl1(const dim0,dim1: index; var x,y: qVector): qFloat; far;
  function qvecdistl2(const dim0,dim1: index; var x,y: qVector): qFloat; far;
  function qvecdistlp(const dim0,dim1: index; var x,y: qVector): qFloat; far;
  function qvecdistlsup(const dim0,dim1: index; var x,y: qVector): qFloat; far;

  { @ = (Y==X), exact logical comparison }
  function veccmp0(const dim0,dim1: index; var x,y: dVector; const dummy: qFloat): boolean; far;
  { @ = (Y==X) up to Threshold with INorm }
  function veccmpl1(const dim0,dim1: index; var x,y: dVector; const threshold: qFloat): boolean; far;
  function veccmpl2(const dim0,dim1: index; var x,y: dVector; const threshold: qFloat): boolean; far;
  function veccmplp(const dim0,dim1: index; var x,y: dVector; const threshold: qFloat): boolean; far;
  function veccmplsup(const dim0,dim1: index; var x,y: dVector; const threshold: qFloat): boolean; far;

  { @ = (Y==X), exact logical comparison }
  function qveccmp0(const dim0,dim1: index; var x,y: qVector; const dummy: qFloat): boolean; far;
  { @ = (Y==X) up to Threshold with INorm }
  function qveccmpl1(const dim0,dim1: index; var x,y: qVector; const threshold: qFloat): boolean; far;
  function qveccmpl2(const dim0,dim1: index; var x,y: qVector; const threshold: qFloat): boolean; far;
  function qveccmplp(const dim0,dim1: index; var x,y: qVector; const threshold: qFloat): boolean; far;
  function qveccmplsup(const dim0,dim1: index; var x,y: qVector; const threshold: qFloat): boolean; far;

  { compare sparse vectors }
  function spveccmp0(const dim: index; var pattern: ivector; var x,y: dVector; const threshold: qFloat): boolean; far;
  function spveccmpl1(const dim: index; var pattern: ivector; var x,y: dVector; const threshold: qFloat): boolean; far;
  function spveccmpl2(const dim: index; var pattern: ivector; var x,y: dVector; const threshold: qFloat): boolean; far;
  function spveccmplp(const dim: index; var pattern: ivector; var x,y: dVector; const threshold: qFloat): boolean; far;
  function spveccmplsup(const dim: index; var pattern: ivector; var x,y: dVector; const threshold: qFloat): boolean; far;

  function spqveccmp0(const dim: index; var pattern: ivector; var x,y: qVector; const threshold: qFloat): boolean; far;
  function spqveccmpl1(const dim: index; var pattern: ivector; var x,y: qVector; const threshold: qFloat): boolean; far;
  function spqveccmpl2(const dim: index; var pattern: ivector; var x,y: qVector; const threshold: qFloat): boolean; far;
  function spqveccmplp(const dim: index; var pattern: ivector; var x,y: qVector; const threshold: qFloat): boolean; far;
  function spqveccmplsup(const dim: index; var pattern: ivector; var x,y: qVector; const threshold: qFloat): boolean; far;

  { R = X/|X|}
  function vecnormalize(const dim0,dim1: index; var x,r: dVector): qFloat;
  function qvecnormalize(const dim0,dim1: index; var x,r: qVector): qFloat;

  { X = 0 }
  procedure veczero(const dim0,dim1: index; var x: dVector);
  procedure qveczero(const dim0,dim1: index; var x: qVector);
  procedure sveczero(const dim0,dim1: index; var x: sVector);
  procedure spveczero(const dim: index; var pattern: ivector; var x: dVector);
  procedure spqveczero(const dim: index; var pattern: ivector; var x: qVector);

  { R = E_i }
  procedure vecei(const dim, i: index; var r: dVector);
  procedure qvecei(const dim, i: index; var r: qVector);

  { R = [c] }
  procedure vecfill(const dim0,dim1: index; var r: dVector; const c: qFloat);
  procedure qvecfill(const dim0,dim1: index; var r: qVector; const c: qFloat);
  procedure spvecfill(const dim: index; var pattern: ivector; var r: dVector; const c: qFloat);
  procedure spqvecfill(const dim: index; var pattern: ivector; var r: qVector; const c: qFloat);

  { R[i] = c0 + (i-1) c }
  procedure vecenum(const dim0,dim1: index; var r: dVector; const c0,c: qFloat);
  procedure qvecenum(const dim0,dim1: index; var r: qVector; const c0,c: qFloat);
  procedure spvecenum(const dim: index; var pattern: ivector; var r: dVector; const c0,c: qFloat);
  procedure spqvecenum(const dim: index; var pattern: ivector; var r: qVector; const c0,c: qFloat);

  { @ = |R| }
  function vecsum(const dim0,dim1: index; var r: dVector): qFloat;
  function spvecsum(const dim: index; var pattern: ivector; var r: dVector): qFloat;
  function qvecsum(const dim0,dim1: index; var r: qVector): qFloat;
  function spqvecsum(const dim: index; var pattern: ivector; var r: qVector): qFloat;

  { @ = P.Q }
  function vecdot(const dim0,dim1: index; var p,q: dVector): qFloat;
  function spvecdot(const dim: index; var pattern: ivector; var p,q: dVector): qFloat;
  function qvecdot(const dim0,dim1: index; var p,q: qVector): qFloat;
  function spqvecdot(const dim: index; var pattern: ivector; var p,q: qVector): qFloat;

  { @ = P.P }
  function vecsqr(const dim0,dim1: index; var p: dVector): qFloat;
  function spvecsqr(const dim: index; var pattern: ivector; var p: dVector): qFloat;
  function qvecsqr(const dim0,dim1: index; var p: qVector): qFloat;
  function spqvecsqr(const dim: index; var pattern: ivector; var p: qVector): qFloat;

  { R = P*Q pointwise }
  procedure vectimes(const dim0,dim1: index; var p,q, r: dVector);
  procedure spvectimes(const dim: index; var pattern: ivector; var p,q, r: dVector);
  procedure qvectimes(const dim0,dim1: index; var p,q, r: qVector);
  procedure spqvectimes(const dim: index; var pattern: ivector; var p,q, r: qVector);

  { Y = X }
  procedure veccopy(const dim0,dim1: index; var x,y: dVector);
  procedure spveccopy(const dim: index; var pattern: ivector; var x,y: dVector);
  procedure qveccopy(const dim0,dim1: index; var x,y: qVector);
  procedure spqveccopy(const dim: index; var pattern: ivector; var x,y: qVector);

  { Y = -X }
  procedure vecmcopy(const dim0,dim1: index; var x,y: dVector);
  procedure spvecmcopy(const dim: index; var pattern: ivector; var x,y: dVector);
  procedure qvecmcopy(const dim0,dim1: index; var x,y: qVector);
  procedure spqvecmcopy(const dim: index; var pattern: ivector; var x,y: qVector);

  { R = X + a }
  procedure vecaddc(const dim0,dim1: index; var x: dVector; const a: qFloat; var r: dVector);
  procedure spvecaddc(const dim: index; var pattern: ivector; var x: dVector; const a: qFloat; var r: dVector);
  procedure qvecaddc(const dim0,dim1: index; var x: qVector; const a: qFloat; var r: qVector);
  procedure spqvecaddc(const dim: index; var pattern: ivector; var x: qVector; const a: qFloat; var r: qVector);

  { R = a X }
  procedure vecscale(const dim0,dim1: index; var x: dVector; const a: qFloat; var r: dVector);
  procedure spvecscale(const dim: index; var pattern: ivector; var x: dVector; const a: qFloat; var r: dVector);
  procedure qvecscale(const dim0,dim1: index; var x: qVector; const a: qFloat; var r: qVector);
  procedure spqvecscale(const dim: index; var pattern: ivector; var x: qVector; const a: qFloat; var r: qVector);

  { R = X + Y }
  procedure vecadd(const dim0,dim1: index; var x,y: dVector; var r: dVector);
  procedure spvecadd(const dim: index; var pattern: ivector; var x,y: dVector; var r: dVector);
  procedure qvecadd(const dim0,dim1: index; var x,y: qVector; var r: qVector);
  procedure spqvecadd(const dim: index; var pattern: ivector; var x,y: qVector; var r: qVector);

  { R = X - Y }
  procedure vecsub(const dim0,dim1: index; var x,y: dVector; var r: dVector);
  procedure spvecsub(const dim: index; var pattern: ivector; var x,y: dVector; var r: dVector);
  procedure qvecsub(const dim0,dim1: index; var x,y: qVector; var r: qVector);
  procedure spqvecsub(const dim: index; var pattern: ivector; var x,y: qVector; var r: qVector);

  { R = p(X + Y) }
  procedure vecpadd(const dim0,dim1: index; const p: qFloat; var x,y: dVector; var r: dVector);
  procedure spvecpadd(const dim: index; var pattern: ivector; const p: qFloat; var x,y: dVector; var r: dVector);
  procedure qvecpadd(const dim0,dim1: index; const p: qFloat; var x,y: qVector; var r: qVector);
  procedure spqvecpadd(const dim: index; var pattern: ivector; const p: qFloat; var x,y: qVector; var r: qVector);

  { R = p(X - Y) }
  procedure vecpsub(const dim0,dim1: index; const p: qFloat; var x,y: dVector; var r: dVector);
  procedure spvecpsub(const dim: index; var pattern: ivector; const p: qFloat; var x,y: dVector; var r: dVector);
  procedure qvecpsub(const dim0,dim1: index; const p: qFloat; var x,y: qVector; var r: qVector);
  procedure spqvecpsub(const dim: index; var pattern: ivector; const p: qFloat; var x,y: qVector; var r: qVector);

  { R = p X + Y }
  procedure vecaddpxy(const dim0,dim1: index; const p: qFloat; var x: dVector; var y: dVector; var r: dVector);
  procedure spvecaddpxy(const dim: index; var pattern: ivector; const p: qFloat;
                        var x: dVector; var y: dVector; var r: dVector);
  procedure qvecaddpxy(const dim0,dim1: index; const p: qFloat; var x: qVector; var y: qVector; var r: qVector);
  procedure spqvecaddpxy(const dim: index; var pattern: ivector; const p: qFloat;
                        var x: qVector; var y: qVector; var r: qVector);

  { R = p X - Y }
  procedure vecsubpxy(const dim0,dim1: index; const p: qFloat; var x: dVector; var y: dVector; var r: dVector);
  procedure spvecsubpxy(const dim: index; var pattern: ivector;
                        const p: qFloat; var x: dVector; var y: dVector; var r: dVector);
  procedure qvecsubpxy(const dim0,dim1: index; const p: qFloat; var x: qVector; var y: qVector; var r: qVector);
  procedure spqvecsubpxy(const dim: index; var pattern: ivector;
                        const p: qFloat; var x: qVector; var y: qVector; var r: qVector);

  { R = p X + q Y }
  procedure vecaddpxqy(const dim0,dim1: index;
                       const p: qFloat; var x: dVector; const q: qFloat; var y: dVector; var r: dVector);
  procedure spvecaddpxqy(const dim: index; var pattern: ivector; const p: qFloat; var x: dVector;
                                                                 const q: qFloat; var y: dVector; var r: dVector);
  procedure qvecaddpxqy(const dim0,dim1: index;
                       const p: qFloat; var x: qVector; const q: qFloat; var y: qVector; var r: qVector);
  procedure spqvecaddpxqy(const dim: index; var pattern: ivector; const p: qFloat; var x: qVector;
                                                                 const q: qFloat; var y: qVector; var r: qVector);

  { Y = f(X) componentwise }
  procedure vectransform(const dim0,dim1: index; var x: dVector; f: realfunction; p: pointer; var y: dVector);
  procedure spvectransform(const dim: index; var pattern: ivector;
                           var x: dVector; f: realfunction; p: pointer; var y: dVector);
  procedure qvectransform(const dim0,dim1: index; var x: qVector; f: realfunction; p: pointer; var y: qVector);
  procedure spqvectransform(const dim: index; var pattern: ivector;
                           var x: qVector; f: realfunction; p: pointer; var y: qVector);

  { @ = max/min(R_i) }
  function vecmin(const dim0,dim1: index; var r: dVector): dFloat;
  function spvecmin(const dim: index; var pattern: ivector; var r: dVector): dFloat;
  function qvecmin(const dim0,dim1: index; var r: qVector): qFloat;
  function spqvecmin(const dim: index; var pattern: ivector; var r: qVector): qFloat;

  function vecmax(const dim0,dim1: index; var r: dVector): dFloat;
  function spvecmax(const dim: index; var pattern: ivector; var r: dVector): dFloat;
  function qvecmax(const dim0,dim1: index; var r: qVector): qFloat;
  function spqvecmax(const dim: index; var pattern: ivector; var r: qVector): qFloat;

  procedure vecminmax(const dim0,dim1: index; var r: dVector; var min,max: dFloat);
  procedure spvecminmax(const dim: index; var pattern: ivector; var r: dVector; var min,max: dFloat);
  procedure qvecminmax(const dim0,dim1: index; var r: qVector; var min,max: qFloat);
  procedure spqvecminmax(const dim: index; var pattern: ivector; var r: qVector; var min,max: qFloat);

  function ivecmin(const dim0,dim1: index; var r: ivector): index;
  function ivecmax(const dim0,dim1: index; var r: ivector): index;
  procedure ivecminmax(const dim0,dim1: index; var r: ivector; var min,max: index);

  { @ = i: (R_i=max/min(R_j)) }
  function vecimin(const dim0,dim1: index; var r: dVector): index;
  function vecimax(const dim0,dim1: index; var r: dVector): index;
  function qvecimin(const dim0,dim1: index; var r: qVector): index;
  function qvecimax(const dim0,dim1: index; var r: qVector): index;

  function ivecimin(const dim0,dim1: index; var r: ivector): index;
  function ivecimax(const dim0,dim1: index; var r: ivector): index;

  { @ = i: (R_i=max/min(abs(R_j))) }
  function veciamin(const dim0,dim1: index; var r: dVector): index;
  function veciamax(const dim0,dim1: index; var r: dVector): index;
  function qveciamin(const dim0,dim1: index; var r: qVector): index;
  function qveciamax(const dim0,dim1: index; var r: qVector): index;

  function iveciamin(const dim0,dim1: index; var r: ivector): index;
  function iveciamax(const dim0,dim1: index; var r: ivector): index;

(* cyclic shift C cells right *)
  procedure vecshift(const dim0,dim1: index; var x: dvector; const c: integer; var y: dvector);
  procedure spvecshift(const dim: index; var pattern: ivector; var x: dvector; const c: integer; var y: dvector);
  procedure ivecshift(const dim0,dim1: index; var x: ivector; const c: integer; var y: ivector);
  procedure svecshift(const dim0,dim1: index; var x: svector; const c: integer; var y: svector);
  procedure qvecshift(const dim0,dim1: index; var x: qvector; const c: integer; var y: qvector);

(* invert element ordering *)
  procedure vecreflect(const dim0,dim1: index; var x: dvector; var y: dvector);
  procedure ivecreflect(const dim0,dim1: index; var x: ivector; var y: ivector);
  procedure svecreflect(const dim0,dim1: index; var x: svector; var y: svector);
  procedure qvecreflect(const dim0,dim1: index; var x: qvector; var y: qvector);

(* sorting/indexing algorithms *)

  { QuickSort }
  procedure vecqsort(il,ir:index; var a: dVector);
  procedure qvecqsort(il,ir:index; var a: qVector);
  { HeapSort }
  procedure vechsort(il,ir:index; var a: dVector);
  procedure qvechsort(il,ir:index; var a: qVector);

(* memory allocation service *)

  { static vectors }
  function vecalloc(const dim0,dim1: index; var p: pdVector): boolean;
  procedure vecfree(const dim0,dim1: index; var p: pdVector);
  function vecrealloc(const dim0,olddim1,newdim1: index; var p: pdVector): boolean;

  function qvecalloc(const dim0,dim1: index; var p: pqVector): boolean;
  procedure qvecfree(const dim0,dim1: index; var p: pqVector);
  function qvecrealloc(const dim0,olddim1,newdim1: index; var p: pqVector): boolean;

  function svecalloc(const dim0,dim1: index; var p: psVector): boolean;
  procedure svecfree(const dim0,dim1: index; var p: psVector);
  function svecrealloc(const dim0,olddim1,newdim1: index; var p: psVector): boolean;

  { swap vector pointers }
  procedure svecswap(var x,y: psVector);
  procedure vecswap(var x,y: pdVector);
  procedure qvecswap(var x,y: pqVector);

  { interface to text stream }
  procedure vecread(const dim0,dim1: index; var v: dVector; var f: text; msg: string; const col: index);
  procedure vecwrite(const dim0,dim1: index; var v: dVector; var f: text; msg: string; const col: index);
  procedure spvecread(const dim: index; var pattern: ivector; var v: dVector; var f: text; msg: string; const col: index);
  procedure spvecwrite(const dim: index; var pattern: ivector; var v: dVector; var f: text; msg: string; const col: index);
  procedure qvecread(const dim0,dim1: index; var v: qVector; var f: text; msg: string; const col: index);
  procedure qvecwrite(const dim0,dim1: index; var v: qVector; var f: text; msg: string; const col: index);
  procedure spqvecread(const dim: index; var pattern: ivector; var v: qVector; var f: text; msg: string; const col: index);
  procedure spqvecwrite(const dim: index; var pattern: ivector; var v: qVector; var f: text; msg: string; const col: index);

  function pfvecalloc(const dim0,dim1: integer; var p: ppfvector): boolean;
  procedure pfvecfree(const dim0,dim1: integer; var p: ppfvector);
  procedure pfveczero(const dim0,dim1: integer; var p: pfvector);

The following subroutines are implemented in Vec2.PAS:

(* V2 operations *)

  { R = 0 }
  function v2zero(var V: Vector2): PVector2;
  { V1 ?= V2 }
  function v2eqzero(var V: Vector2): boolean;
  function v2equal(var V1,V2: Vector2): boolean;
  function v2cmp0(var x,y: vector2): boolean;
  function v2cmp(var x,y: vector2; const threshold: qFloat): boolean;
  { R = V }
  function v2copy(var V: Vector2; var R: Vector2): PVector2;
  { R = -V }
  function v2mcopy(var V: Vector2; var R: Vector2): PVector2;
  { R = x V }
  function v2scale(var V: Vector2; X: dFloat; var R: Vector2): PVector2;
  { R = (P2-P1)/|P2-P1|}
  function v2dir(var P1,P2: Vector2; var R: Vector2): PVector2;
  { R = V1 V2 componentwise }
  function v2mult(var V1,V2: Vector2; var R: Vector2): PVector2;
  { R = V1*V2 }
  function v2dot(var V1,V2: Vector2): qFloat;
  { R = V1 x V2 }
  function v2cross(var V1,V2: Vector2): qFloat;
  { R  V }
  function v2normalto(V: Vector2; var R: Vector2): PVector2;
  { R = V/|V|, @Result = |V| }
  function v2normalize(var V: Vector2; var R: Vector2): qFloat;
  { v2abs = |V| }
  function v2abs(var V: Vector2): qFloat;
  function v2sqr(var V: Vector2): qFloat;
  function v2absl1(var V: Vector2): qFloat;
  { R = V1/V2 componentwise }
  function v2div(var V1,V2: Vector2; var R: Vector2): PVector2;
  { R = x V1 + y V2 }
  function v2addpxqy(const x: dFloat; var V1: Vector2; const y: dFloat; var V2: Vector2; var R: Vector2): PVector2;
  { R = V1 + x V2 }
  function v2addxpy(var V1: Vector2; const x: dFloat; var V2: Vector2; var R: Vector2): PVector2;
  { R = V1 + V2 }
  function v2add(var V1,V2: Vector2; var R: Vector2): PVector2;
  { R = x (V1 + V2) }
  function v2padd(const x: dFloat; var V1,V2: Vector2; var R: Vector2): PVector2;
  { R = V + s }
  function v2shift(var V: Vector2; const s: dFloat; var R: Vector2): PVector2;
  { R = V1 - V2 }
  function v2sub(var V1,V2: Vector2; var R: Vector2): PVector2;
  { R = x (V1 - V2) }
  function v2psub(const x: dFloat; var V1,V2: Vector2; var R: Vector2): PVector2;
  { R = [x,y] }
  function FltoV2(const X,Y: dFloat; var V: Vector2): PVector2;
  { [x,y] = R }
  procedure V2toFl(var V: Vector2; var X,Y: dFloat);
  { |X-Y| }
  function v2dist(var X,Y: Vector2): qFloat;
  function v2distl1(var X,Y: Vector2): qFloat;
  { Y = X rotated in R basis }
  function v2rot(X,R: vector2; var Y: vector2): PVector2;
  { Y = X inversly rotated in R basis }
  function v2unrot(X,R: vector2; var Y: vector2): PVector2;

(* M2 operations *)

  { Y = M X }
  function M2TimesV2(var a: matrix2; var x,y: vector2): pvector2;
  { Y = X M }
  function M2TTimesV2(var a: matrix2; var x,y: vector2): pvector2;
  { M = a1 a2 }
  function M2TimesM2(var a1,a2,m: matrix2): pmatrix2;
  { M = M^T }
  procedure M2Tran(var a,b: matrix2);
  { B = A^(-1) }
  function M2Inv(var a: matrix2; var b: matrix2): boolean;
  { @ = |A| }
  function M2Det(var a: matrix2): qFloat;
  { X <-- solution, @ <-- exists }
  function M2Solve(var m: matrix2; var r,x: vector2): boolean;

(* V3 operations *)

  { R = 0 }
  function v3zero(var V: vector3): Pvector3;
  { V1 ?= V2 }
  function v3eqzero(var V: Vector3): boolean;
  function v3equal(var V1,V2: Vector3): boolean;
  function v3cmp0(var x,y: vector3): boolean;
  function v3cmp(var x,y: vector3; const threshold: qFloat): boolean;
  { R = V }
  function v3copy(var V: vector3; var R: vector3): Pvector3;
  { R = -V }
  function v3mcopy(var V: vector3; var R: vector3): Pvector3;
  { R = x V }
  function v3scale(var V: vector3; X: dFloat; var R: vector3): Pvector3;
  { R = (P2-P1)/|P2-P1|}
  function v3dir(var P1,P2: vector3; var R: vector3): Pvector3;
  { R = V1 V2 componentwise }
  function v3mult(var V1,V2: vector3; var R: vector3): Pvector3;
  { R = V1*V2 }
  function v3dot(var V1,V2: Vector3): qFloat;
  { R = V1 x V2 }
  function v3cross(var V1,V2,R: vector3): pvector3;
  { R = V/|V|, @Result = |V| }
  function v3normalize(var V: vector3; var R: vector3): qFloat;
  { v3abs = |V| }
  function v3abs(var V: vector3): qFloat;
  function v3sqr(var V: vector3): qFloat;
  function v3absl1(var V: vector3): qFloat;
  { R = V1/V2 componentwise }
  function v3div(var V1,V2: vector3; var R: vector3): Pvector3;
  { R = x V1 + y V2 }
  function v3addpxqy(const x: dFloat; var V1: vector3; const y: dFloat; var V2: vector3; var R: vector3): Pvector3;
  { R = V1 + x V2 }
  function v3addxpy(var V1: vector3; const x: dFloat; var V2: vector3; var R: vector3): Pvector3;
  { R = V1 + V2 }
  function v3add(var V1,V2: vector3; var R: vector3): Pvector3;
  { R = x (V1 + V2) }
  function v3padd(const x: dFloat; var V1,V2: vector3; var R: vector3): Pvector3;
  { R = V + s }
  function v3shift(var V: vector3; const s: dFloat; var R: vector3): Pvector3;
  { R = V1 - V2 }
  function v3sub(var V1,V2: vector3; var R: vector3): Pvector3;
  { R = x (V1 - V2) }
  function v3psub(const x: dFloat; var V1,V2: vector3; var R: vector3): Pvector3;
  { R = [x,y] }
  function FltoV3(const X,Y,Z: dFloat; var V: vector3): Pvector3;
  { [x,y] = R }
  procedure V3toFl(var V: vector3; var X,Y,Z: dFloat);
  { |X-Y| }
  function v3dist(var X,Y: vector3): qFloat;
  function v3distl1(var X,Y: vector3): qFloat;

(* M3 operations *)

  { Y = M X }
  function M3TimesV3(var a: matrix3; var x,y: vector3): pvector3;
  { Y = X M }
  function M3TTimesV3(var a: matrix3; var x,y: vector3): pvector3;
  { M = a1 a2 }
  function M3TimesM3(var a1,a2,m: matrix3): pmatrix3;
  { M = M^T }
  procedure M3Tran(var a,b: matrix3);
  { B = A^(-1) }
  function M3Inv(var a: matrix3; var b: matrix3): boolean;
  { @ = |A| }
  function M3Det(var a: matrix3): qFloat;
  { X <-- solution, @ <-- exists }
  function M3Solve(var m: matrix3; var r,x: vector3): boolean;

  {
    @ <-- x0 \in Quadrilateral(x1,x2,x3,x4)
    starshape method
  }
  function xyinquad(var x0,x1,x2,x3,x4: vector2): boolean;
  function xyintriangle(var x0,x1,x2,x3: vector2): boolean;


Jan Jeowicki
Wrocaw, December 2000

