Small Vectors Proposal

Andrei Alexandrescu (See Website For Email) SeeWebsiteForEmail at erdani.org
Tue Jan 30 17:44:15 PST 2007


Having read the proposal, I think it can likely be accommodated entirely 
with current and up-and-coming language features. To expand:

Mikola Lysenko wrote:
> It is important to make the distinction between low dimension vectors 
> and other higher order arrays.  This is crucial since the higher 
> dimensional arrays are often more tenuously connected with any sort of 
> geometric or physical interpretation.

Well I disagree here, but it's not important. Look outside your domain. 
There are people who think as well the future belongs to machine 
learning and statistical methods, which are ripe with large dimensional 
vectors. I think it's just shortsighted to claim that geometrical and 
physical interpretation is more special than others.

> Moreover, many architectures are 
> specially optimized for the lower dimensional cases, and offer special 
> registers which are virtually impossible to properly exploit using 
> libraries alone.  The situation is analogous to floating point 
> arithmetic, proper hardware support requires language level integration.

I don't see much of an analogy, but this is also a minor point. Floating 
point arithmetic was weird way before it was implemented in hardware, 
and the weirdness reflected in languages. But on many machines adding 
two floating point numbers required a routine call, which didn't add or 
subtract anything to the equation.

> 1. Additional primitive types

Let's try:

s/primitive types/types/ig

and see what happens, just for the sake of experiment.

> All numerical primitive types in the language will be supplemented with 
> 3 additional vector extensions.  Each vector extension will contain 2, 3 
> or 4 components since these are best supported by hardware, and the most 
> relevant geometrically.  The initial value for each component in each 
> type will be the same as that of its base type.  Each the size of each 
> vector component will be equal to the size of its base type times its 
> dimension.  Here is a complete list of the new types to be added:
> 
> Integer types:
> byte2, byte3, byte4, short2, short3, short4, int2, int3, int4, long2, 
> long3, long4, cent2, cent3, cent4, ubyte2, ubyte3, ubyte4, ushort2, 
> ushort3, ushort4, uint2, uint3, uint4, ulong2, ulong3, ulong4, ucent2, 
> ucent3, ucent4
> 
> Floating types:
> float2, float3, float4, double2, double3, double4, real2, real3, real4
> 
> Imaginary types:
> ifloat2, ifloat3, ifloat4, idouble2, idouble3, idouble4, ireal2, ireal3, 
> ireal4
> 
> Complex types:
> cfloat2, cfloat3, cfloat4, cdouble2, cdouble3, cdouble4, creal2, creal3, 
> creal4

My variant define vector_ops module:

struct small_vector(base, ubyte size)
{
   base[size] data;
   ...
}

alias small_vector!(byte, 2) byte2;
...

> All new vector types are pass-by-value, and may be used in combination 
> with any number of other types.

Check this one. Structs are passed by value, and various constructors 
and (up-and-coming) conversions will take care of the rest.

> The following expressions would all be 
> valid:
> 
> int2[] a;
> float4* b;
> char[][ucent4] c;

Check that one.

> 2. Vector literals
> 
> It must be possible to declare a vector literal with unambiguously as an 
> argument to a function, or any number of other situations.  This syntax 
> must be concise since it will be used often, and it must be flexible, 
> allowing vectors to be constructed via concatenation.  In this light, 
> the following is proposed:
> 
> float4(1, 2, 3, 4);
> int2(100, 200);
> creal3(1 + 2i, 3+4i, 5-6i);

Constructors. Check that one.

> Additionally, this syntax will also support the construction of vectors 
> from other sub vectors.  This can be useful for augmenting a 3-vector 
> with a fourth homogenous component for transformation amongst other 
> things.  Here are some examples:
> 
> float4(float3(x, y, z), 1);        // returns (x, y, z, 1)
> int3(0, int2(a, b));            // returns (0, a, b)
> creal4(ireal2(r, z), real2(p, q));    // returns (r, z, p, q)

Constructors. Check that one too.

> 3. Casting rules
> 
> Vector types will obey the same casting rules as their base type within 
> a single dimension.  It is not possible to use a cast to change the 
> dimension of a vector.
> 
> cast(float2)(int2(1, 2));    //ok
> cast(int)(float2(3, 4));    //error, int is not the same dimension as 
> float2
> real3(a, b) + ireal(c, d);    //ok, type of expression is creal3

opCast. Yup, check that sucker too.

> 4. Component-Wise Arithmetic
> 
> All of the arithmetic operators on primitive types will be extended such 
> that when applied to vectors they operate on each component 
> independently.  The size and types of the vectors must be compatible 
> with the operator.
> 
> float4(1, 2, 3, 4) + float4(3, 5, 6, 7);     // Vector-Vector operation, 
> returns (4, 7, 9, 11)
> float3(1, 5, 6) * float3(1, 0, 2);        // returns (1, 0, 12)
> uint2(0xFF00FF, 0x00FF88) & uint2(0xFF, 0xFF);    // returns (0xFF, 0x88)
> 
> int3(x, y, z) * int2(a, b);            // error, size of vectors does 
> not match

Overloaded operators. Check.

> Additionally, scalar vector operations will be supported.  Each 
> scalar-vector operator is applied per-component within the vector.
> 
> int2(0, 3) * 5;                    // Vector-Scalar operation, returns 
> (0, 15)
> byte2(2, 5) + 6;                // returns (8, 11)

Overloaded operators. Check.

> Note that the only two comparison operators allowed on vectors are == 
> and !=.  The problem with <, >, etc. is that there is no commonly agreed 
> upon definition for such things.  Therefore the operators are omitted to 
> avoid confusion.
 > int2(1, 2) == int2(1, 2);        //ok, evaluates to true
 > float3(1, 0, 0) < float3(0, 0, 1);    // error, < is undefined for 
vectors

Check :o).

> 5. Swizzle operations
> 
> In many vector applications, it is often necessary to reorder the 
> components.  In shader languages this is accomplished via 'swizzle' 
> properties in each vector type.  Each swizzle selects a set of 1-4 
> vector components and places them into a new vector of the given 
> dimension.  Conventionally these components have the following names:
> 
> x - first component
> y - second component
> z - third component
> w - fourth component
> 
> A swizzle is then given as a property consisting of 1-4 components in a 
> given order.

This is more interesting. Today's D can't do it. Fortunately, code 
generation techniques that Walter works on right now (possibly literally 
at the time I'm writing this and/or at the time you're reading this) 
will enable comfortable generation of combinatorial functions, of which 
swizzles is actually an excellent motivating example.

   Here are some examples:
> 
> float2(a, b).yx;        // evaluates to (b, a)
> float3(1, 2, 3).zzyx;        // evaluates to (3, 3, 2, 1)
> byte4('a', 'b', 'c', 'd').w;    // evaluates to 'd'
> creal3(1 + 2i, 0, 4i).zzzz;    // evaluates to (4i, 4i, 4i, 4i)
> 
> int2(1, 2).z;            // error, vector does not have 3 components

Check (for D 2.0).

> These can be useful when projecting homogenous vectors into a lower 
> dimension subspace, or when computing various products.  Here is an 
> example of a cross product implemented using swizzles:
> 
> float3 cross(float3 a, float3 b)
> {
>     return a.zxy * b.yzx - a.yzx * b.zxy;
> }
> 
> And here is a simple homogenous projection:
> 
> float3 project(float4 hg)
> {
>     return hg.xyz / hg.w;
> }

Yum. Love that.

> 6. Standard Library Additions
[snip]

Check by virtue of definition :o).


Andrei



More information about the Digitalmars-d mailing list