One class for math vectors of arbitrary dimension

614 views Asked by At

I want to write a class for mathematical Vectors (holding real numbers). I figured that Vector operations are pretty much the same regardeless of the dimension of the vector, so instead of writing classes like Vector2D, Vector3D, Vector4D, ... I just want to write a Vector class.

Now the problem is that I can't multiply a 2D vector with a 4D one, so I thought about a field dimension. But now I had to check it for every operation so I asked myself if I can do better than that. This is were generics came to my mind. But then again I have to do something like Vector<? extends Dimension>, where Dimension is simply a base class of Dimension.One, Dimension.Two and so on, which means, I have to write a Dimension class for every dimension I want to use vectos in.

So my question:

Is there a way of writing one class for vectors of arbitrary dimension without having to check the dimension at runtime?

4

There are 4 answers

2
Jochen On BEST ANSWER

If I understand your question correctly, then the answer is that you can't have both. Either you use the type system to ensure correct dimensionality, and then you end up with a proliferation of explicit types (generics won't help you), or you use state to track the dimensions and perform dynamic checks every time you perform an operation. Since the "dimension" of a vector is how many elements it holds, this will be represented somehow in the underlying data structure. For example if you use a list to store the values in the vector, the list knows how many elements it contains. So doing a simple runtime check is cheap and you can throw an exception when dimensions don't match. That solution is much more flexible and easy to program with than a type based solution.

2
mmaag On

To make clear why I wanted to use generics (it works which is why I'm posting it as an answer):

Dimension.java:

public class Dimension {
    class ONE extends Dimension {}
    class TWO extends Dimension {}
    class THREE extends Dimension {}
    // [...]
}

Vector.java:

public class Vector<D extends Dimension> {
    private double[] elements;

    public Vector(double _elmts) {
        elements = _elmts;
    }

    public void add(Vector<D> v) { /*...*/ }
    public void subtract(Vector<D> v) { /*...*/ }
}

But as mentioned in my Question, I have to create several classes, which is what I wanted to prevent in the first place. Also it's rather ugly. And there's no way to make sure elements has the right dimension other than trusting the user.

I guess it's pretty similar to Eric's answer.

3
Eric On

You could write a Vector class with some interesting generics

public static class Vector<V extends Vector<V>>{
    protected double[] components;
    public final int dimensions;
    private Class<V> klass;

    protected Vector(int d, Class<V> klass) {
        this.klass = klass;
        this.components = new double[d];
    }

    public double get(int x) { return components[x] }
    protected void set(int x, double d) { components[x] = d }

    public V clone() {
        try {
            V c = klass.newInstance();
            c.components = this.components.clone();
            return c;
        }
        catch(InstantiationException e1) {}
        catch(IllegalAccessException e2) {}
        return null;
    }

    public V add(V that) {
        V sum = this.clone();
        for(int i = 0; i < dimensions; i++)
            sum.components[i] += that.components[i];
        return sum;
    }

}

Then derive each case:

   

public static class Vector2D extends Vector<Vector2D>{
    public Vector2D() { 
        super(2, Vector2D.class);
    }
    public Vector2D(double x, double y) { 
        this();
        set(0, x);
        set(1, y);
    }
}
public static class Vector3D extends Vector<Vector3D>{
    public Vector3D() { 
        super(3, Vector3D.class);
    }
    public Vector3D(double x, double y, double z) { 
        this();
        set(0, x);
        set(1, y);
        set(2, z);
    }
}
public static class Vector4D extends Vector<Vector4D>{
    public Vector4D() { 
        super(4, Vector4D.class);
    }
    public Vector4D(double w, double x, double y, double z) { 
        this();
        set(0, w);
        set(1, x);
        set(2, y);
        set(3, z);
    }
}

After all, there are special cases - for instance, a cross product only exists in 3 and 7 dimensions. Having an implementation for each solves this.

0
Tony Ennis On

You can embed in the Dimension class a method that performs the check and throws a Runtime Exception if the vectors are incompatible. Then have every method in Dimension invoke this method. Now the code that uses the Dimension class won't be littered with checks.