All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.enterprisemath.math.algebra.Vector Maven / Gradle / Ivy

The newest version!
package com.enterprisemath.math.algebra;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;

import com.enterprisemath.utils.DomainUtils;
import com.enterprisemath.utils.ValidationUtils;

/**
 * This class represents vector in R^n space.
 *
 * @author radek.hecl
 *
 */
public final class Vector {

    /**
     * Builder object.
     *
     * @author radek.hecl
     *
     */
    public static class Builder {

        /**
         * Components.
         */
        private List components = new ArrayList();

        /**
         * Sets vector components.
         *
         * @param components vector components
         * @return this instance
         */
        public Builder setComponents(List components) {
            this.components = DomainUtils.softCopyList(components);
            return this;
        }

        /**
         * Adds vector component.
         *
         * @param component component
         * @return this instance
         */
        public Builder addComponent(double component) {
            this.components.add(component);
            return this;
        }

        /**
         * Builds the result object.
         *
         * @return created object
         */
        public Vector build() {
            return new Vector(this);
        }
    }

    /**
     * Components of this vector.
     */
    private double[] components;

    /**
     * Constructor which can be called only from inside.
     *
     */
    private Vector() {
    }

    /**
     * Creates new instance.
     *
     * @param builder builder object
     */
    public Vector(Builder builder) {
        List defRef = builder.components;
        components = new double[defRef.size()];
        for (int i = 0; i < components.length; ++i) {
            components[i] = defRef.get(i);
        }
        guardInvariants();
    }

    /**
     * Guards this object to be consistent. Throws exception if this is not the case.
     */
    private void guardInvariants() {
        ValidationUtils.guardNotNull(components, "components cannot be null");
    }

    /**
     * Returns the dimension of this vector.
     *
     * @return dimension of this vector
     */
    public int getDimension() {
        return components.length;
    }

    /**
     * Returns the value of the specified component.
     *
     * @param index index of the component
     * @return value of the specified component
     */
    public double getComponent(int index) {
        return components[index];
    }

    /**
     * Returns the magnitude of this vector.
     * Magnitude is returned in L_2 (Euclidean) norm.
     *
     * @return magnitude of this vector
     */
    public double getMagnitude() {
        double d = 0;
        for (int i = 0; i < components.length; ++i) {
            d = d + components[i] * components[i];
        }
        return Math.sqrt(d);
    }

    @Override
    public int hashCode() {
        return HashCodeBuilder.reflectionHashCode(this);
    }

    @Override
    public boolean equals(Object obj) {
        return EqualsBuilder.reflectionEquals(this, obj);
    }

    @Override
    public String toString() {
        StringBuilder res = new StringBuilder();
        res.append("[");
        for (int i = 0; i < components.length - 1; ++i) {
            res.append(components[i]);
            res.append(", ");
        }
        res.append(components[components.length - 1]);
        res.append("]");
        return res.toString();
    }

    public static Vector create(double... x) {
        Vector res = new Vector();
        res.components = Arrays.copyOf(x, x.length);
        res.guardInvariants();
        return res;
    }

    /**
     * Creates 1D vector.
     *
     * @param x component
     * @return created vector
     */
    public static Vector create1D(double x) {
        Vector res = new Vector();
        res.components = new double[]{x};
        res.guardInvariants();
        return res;
    }

    /**
     * Creates 2D vector.
     *
     * @param x x component
     * @param y y component
     * @return created vector
     */
    public static Vector create2D(double x, double y) {
        Vector res = new Vector();
        res.components = new double[]{x, y};
        res.guardInvariants();
        return res;
    }

    /**
     * Creates 3D vector.
     *
     * @param x x component
     * @param y y component
     * @param z z component
     * @return created vector
     */
    public static Vector create3D(double x, double y, double z) {
        Vector res = new Vector();
        res.components = new double[]{x, y, z};
        res.guardInvariants();
        return res;
    }

    /**
     * Creates 4D vector.
     *
     * @param x x component
     * @param y y component
     * @param z z component
     * @param u u component
     * @return created vector
     */
    public static Vector create4D(double x, double y, double z, double u) {
        Vector res = new Vector();
        res.components = new double[]{x, y, z, u};
        res.guardInvariants();
        return res;
    }

    /**
     * Creates the vector which is minimum boundary of the two specified.
     * This means the vector which contains the minimum of all components.
     * For example for vector [1, 2] and [2, 1] the result will be [1, 1].
     *
     * @param v1 vector 1
     * @param v2 vector 2
     * @return boundary minimum vector
     * @throws IllegalArgumentException if input vectors have different dimension
     */
    public static Vector createBoundaryMin(Vector v1, Vector v2) {
        ValidationUtils.guardEquals(v1.getDimension(), v2.getDimension(), "v1 and v2 must have same dimension");
        double[] comps = new double[v1.getDimension()];
        for (int i = 0; i < comps.length; ++i) {
            comps[i] = Math.min(v1.getComponent(i), v2.getComponent(i));
        }
        Vector res = new Vector();
        res.components = comps;
        res.guardInvariants();
        return res;
    }

    /**
     * Creates the vector which is maximum boundary of the two specified.
     * This means the vector which contains the maximum of all components.
     * For example for vector [1, 2] and [2, 1] the result will be [2, 2].
     *
     * @param v1 vector 1
     * @param v2 vector 2
     * @return boundary minimum vector
     * @throws IllegalArgumentException if input vectors have different dimension
     */
    public static Vector createBoundaryMax(Vector v1, Vector v2) {
        ValidationUtils.guardEquals(v1.getDimension(), v2.getDimension(), "v1 and v2 must have same dimension");
        double[] comps = new double[v1.getDimension()];
        for (int i = 0; i < comps.length; ++i) {
            comps[i] = Math.max(v1.getComponent(i), v2.getComponent(i));
        }
        Vector res = new Vector();
        res.components = comps;
        res.guardInvariants();
        return res;
    }

    /**
     * Creates vector by addition x + y.
     *
     * @param x vector x
     * @param y vector y
     * @return added vector
     */
    public static Vector add(Vector x, Vector y) {
        ValidationUtils.guardEquals(x.getDimension(), y.getDimension(), "x and y must have same dimension");
        double[] comps = new double[x.getDimension()];
        for (int i = 0; i < x.getDimension(); ++i) {
            comps[i] = x.getComponent(i) + y.getComponent(i);
        }
        Vector res = new Vector();
        res.components = comps;
        res.guardInvariants();
        return res;
    }

    /**
     * Creates vector by subtracting x - y.
     *
     * @param x vector x
     * @param y vector y
     * @return subtracted vector
     */
    public static Vector sub(Vector x, Vector y) {
        ValidationUtils.guardEquals(x.getDimension(), y.getDimension(), "x and y must have same dimension");
        double[] comps = new double[x.getDimension()];
        for (int i = 0; i < x.getDimension(); ++i) {
            comps[i] = x.getComponent(i) - y.getComponent(i);
        }
        Vector res = new Vector();
        res.components = comps;
        res.guardInvariants();
        return res;
    }

    /**
     * Creates vector averaging the two other.
     *
     * @param x vector x
     * @param y vector y
     * @return average vector
     */
    public static Vector avg(Vector x, Vector y) {
        ValidationUtils.guardEquals(x.getDimension(), y.getDimension(), "x and y must have same dimension");
        double[] comps = new double[x.getDimension()];
        for (int i = 0; i < x.getDimension(); ++i) {
            comps[i] = (x.getComponent(i) + y.getComponent(i)) / 2;
        }
        Vector res = new Vector();
        res.components = comps;
        res.guardInvariants();
        return res;
    }

    /**
     * Creates the diagonal vector. Diagonal vector have all the components same.
     *
     * @param dimension dimension
     * @param scalar value for all the components
     * @return created diagonal vector
     * @throws IllegalArgumentException if dimension is <= 0
     */
    public static Vector diagonal(int dimension, double scalar) {
        ValidationUtils.guardPositiveInt(dimension, "dimension must be at least 1");
        double[] comps = new double[dimension];
        for (int i = 0; i < comps.length; ++i) {
            comps[i] = scalar;
        }
        Vector res = new Vector();
        res.components = comps;
        res.guardInvariants();
        return res;
    }

    /**
     * Creates vector which is the scale * x.
     *
     * @param x original vector
     * @param scale scale factor
     * @return scaled vector
     */
    public static Vector scale(Vector x, double scale) {
        double[] comps = new double[x.getDimension()];
        for (int i = 0; i < x.getDimension(); ++i) {
            comps[i] = x.getComponent(i) * scale;
        }
        Vector res = new Vector();
        res.components = comps;
        res.guardInvariants();
        return res;
    }

    /**
     * Creates vector which has same direction, but L_2 (euclidean) magnitude is 1.
     *
     * @param x source vector
     * @return normalized vector
     */
    public static Vector normalize(Vector x) {
        return Vector.scale(x, 1 / x.getMagnitude());
    }

    /**
     * Creates vector which is cross product of 2 vectors.
     * Both input vector must be 3D.
     *
     * @param a first vector for product
     * @param b second vector for product
     * @return cross product
     */
    public static Vector cross(Vector a, Vector b) {
        ValidationUtils.guardEquals(3, a.getDimension(), "dimension of vector a must be 3");
        ValidationUtils.guardEquals(3, b.getDimension(), "dimension of vector b must be 3");
        return Vector.create3D(a.getComponent(1) * b.getComponent(2) - a.getComponent(2) * b.getComponent(1),
                a.getComponent(2) * b.getComponent(0) - a.getComponent(0) * b.getComponent(2),
                a.getComponent(0) * b.getComponent(1) - a.getComponent(1) * b.getComponent(0));
    }

    /**
     * Creates vector from a list of components. Size determines the dimension.
     *
     * @param components components
     * @return created vector
     */
    public static Vector create(List components) {
        double comps[] = new double[components.size()];
        for (int i = 0; i < components.size(); ++i) {
            comps[i] = components.get(i);
        }
        Vector res = new Vector();
        res.components = comps;
        res.guardInvariants();
        return res;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy