【问题标题】:Utilizing delegate pattern for matrices使用矩阵的委托模式
【发布时间】:2020-09-29 07:56:44
【问题描述】:

根据this,我实现了一个委托模式来隐藏我想要进行基准测试的线性代数库,请参阅:

public interface Matrix<M> {

    /**
     * Cols or this matrix
     *
     * @return columns
     */
    int rows();

    /**
     * Rows of this matrix
     *
     * @return rows
     */
    int cols();

    /**
     * Matrix multiplication, should throw if cols and rows do not match.
     * Contract is This X in, i.e. this_rows*this_cols X in_cols*in_rows
     *
     * @param otherMatrix right operand
     * @return new matrix multiplied
     */
    M multiply(M otherMatrix);

    /**
     * Multiply each element with this scalar
     *
     * @param scalar to multiply with
     * @return scaled with scalar
     */
    M multiply(double scalar);

    /**
     * Add in to this matrix
     *
     * @param in right operand
     * @return this + in
     */
    M add(M in);

    /**
     * Add in to all elements of this.
     *
     * @param in scalar operand
     * @return this.map(e - > e + in)
     */
    M add(double in);

    /**
     * Subtract in from all elements of this
     *
     * @param in scalar operand
     * @return this.map(e - > e - in);
     */
    M subtract(double in);

    /**
     * Substract in from this matrix
     *
     * @param in right operand
     * @return this[i][j] -= in[i][j]
     */
    M subtract(M in);

    /**
     * Divide all elements by in
     *
     * @param in scalar operand
     * @return in.map(e - > e / in);
     */
    M divide(double in);

    /**
     * Map this matrix to a double, useful for reduce or trace implementations
     *
     * @param mapping f: This -> double
     * @return a double value
     */
    double map(Function<M, Double> mapping);

    /**
     * Map each element with this function
     *
     * @param mapping f: Double -> Double each element
     * @return this.map(e - > mapping ( e));
     */
    M mapElements(Function<Double, Double> mapping);

    /**
     * Sum this matrix over all entries.
     *
     * @return sum of this
     */
    double sum();

    /**
     * Max of this matrix over all entries.
     *
     * @return max of this
     */
    double max();

    /**
     * Index along a column of max, should only be used for vectors.
     *
     * @return index of max
     */
    int argMax();

    /**
     * Transpose this matrix.
     *
     * @return transpose.
     */
    M transpose();

    enum MatrixType {
        VECTOR, SQUARE
    }
}

使用这个类:

public class UJMPMatrix implements Matrix<UJMPMatrix> {
    
    private org.ujmp.core.Matrix delegate;        

    public UJMPMatrix(UJMPMatrix in) { this.delegate = in.delegate; }
    public UJMPMatrix(org.ujmp.core.Matrix in) { this.delegate = in; }
   
    public int rows() {
        return (int) this.delegate.getRowCount();
    }

    public int cols() {
        return (int) this.delegate.getColumnCount();
    }

    @Override
    public UJMPMatrix multiply(UJMPMatrix otherMatrix) {
        return new UJMPMatrix(this.delegate.mtimes(otherMatrix.delegate));
    }


    @Override
    public UJMPMatrix multiply(double scalar) {
        return new UJMPMatrix(this.delegate.times(scalar));
    }

    @Override
    public UJMPMatrix add(UJMPMatrix in) {
        return new UJMPMatrix(this.delegate.plus(in.delegate));
    }

    @Override
    public UJMPMatrix add(double in) {
        return new UJMPMatrix(this.delegate.plus(in));
    }

    @Override
    public UJMPMatrix subtract(double in) {
        return new UJMPMatrix(this.delegate.minus(in));
    }

    @Override
    public UJMPMatrix subtract(UJMPMatrix in) {
        return new UJMPMatrix(this.delegate.minus(in.delegate));
    }

    @Override
    public UJMPMatrix divide(double in) {
        return new UJMPMatrix(this.delegate.divide(in));
    }

    @Override
    public double map(Function<UJMPMatrix, Double> mapping) {
        return mapping.apply(this);
    }

    @Override
    public UJMPMatrix mapElements(Function<Double, Double> mapping) {
        double[][] elements = this.delegate.toDoubleArray();
        double[][] out = new double[elements.length][elements[0].length];
        for (int i = 0; i < elements.length; i++) {
            for (int j = 0; j < elements[0].length; i++) {
                out[i][j] = mapping.apply(elements[i][j]);
            }
        }
        return new UJMPMatrix(out, rows(), cols());
    }

    @Override
    public double sum() {
        return this.delegate.getValueSum();
    }

    @Override
    public double max() {
        return this.delegate.max(Calculation.Ret.NEW, 0).doubleValue();
    }

    @Override
    public UJMPMatrix transpose() {
        return new UJMPMatrix(this.delegate.transpose());
    }

    @Override
    public int argMax() {
        double[] array = this.delegate.toDoubleArray()[0];
        int argMax = -1;
        double best = Double.MIN_VALUE;
        for (int i = 0; i < array.length; i++) {
            if (array[i] > best) {
                best = array[i];
                argMax = i;
            }
        }

        return argMax;

    }
}

但是,当我想使用这个抽象时,Java 告诉我不能使用这些方法中的任何一个,因为我需要使用通配符 (?) 来声明这些矩阵:

 private void feedForward(final Matrix<? extends Matrix<?>> starter, final List<Matrix<? extends Matrix<?>>> actives) {
        Matrix<? extends Matrix<?>> toPredict = starter;

        actives.add(toPredict);
        for (int i = 0; i < this.totalLayers - 1; i++) {
            final Matrix<? extends Matrix<?>> x = this.weights[i].multiply(toPredict).add(this.biases[i]);
            // Weights and Biases are also Matrix<? extends Matrix<?>>[].
            // error: cannot resolve method multiply(Matrix<capture ? extends Matrix<?>>)
            toPredict = this.functions[i + 1].function(x);
            actives.add(toPredict);
        }
    }

注意:在神经网络的构造函数中,我让调用者通过一个简单的枚举 { OJ_ALGO, UJMP } 来决定他们想要什么类型的矩阵,然后调用我实现的工厂来初始化这些矩阵。神经网络的字段如下所示:

// Weights and biases of the network
private volatile Matrix<? extends Matrix<?>>[] weights;
private volatile Matrix<? extends Matrix<?>>[] biases;
private volatile Matrix<? extends Matrix<?>>[] dW;
private volatile Matrix<? extends Matrix<?>>[] dB;

问题:如何声明、初始化和利用我在这个神经网络库中实现的矩阵抽象?

【问题讨论】:

    标签: java oop generics delegates


    【解决方案1】:

    您的 feedForward 方法需要一个泛型类型来表示两个参数必须是相同类型(注意 void 之前的 &lt;M&gt;):

    private <M> void feedForward(final Matrix<M> starter, final List<M> actives) {
    

    同样你的神经网络类应该声明它使用的矩阵类型(假设你不想同时使用不同的实现):

    public class NeuralNetwork<M> {
        private volatile Matrix<M>[] weights;
        private volatile Matrix<M>[] biases;
        private volatile Matrix<M>[] dW;
        private volatile Matrix<M>[] dB;
    

    附带说明一下,我不确定为什么将它们声明为 volatile。

    你的界面应该是这样的:

    public interface Matrix<M> {
        Matrix<M> multiply(Matrix<M> otherMatrix);
        M delegate();
    

    还有你的实现:

    public class UJMPMatrix implements Matrix<org.ujmp.core.Matrix> {
        
        private org.ujmp.core.Matrix delegate; 
    
        @Override
        public UJMPMatrix  multiply(Matrix<org.ujmp.core.Matrix> otherMatrix) {
            return new UJMPMatrix(this.delegate.mtimes(otherMatrix.delegate()));
        }
    
        @Override
        public org.ujmp.core.Matrix delegate() {
            return delegate();
        }
    

    【讨论】:

    • 嗨,再次。当我实现 Matrix 接口时,它变得笨拙。我无法按照帖子中的方式实现它,我不得不将Matrix&lt;M&gt;interface 更改为返回Mreturn Matrix&lt;M&gt;for all Matrix 方法,如下所示:Matrix&lt;M&gt; add(Matrix&lt;M&gt; other);。这导致我不得不实现一个返回矩阵类型的delegate() 方法,然后像这样访问实际的委托:Matrix&lt;UJMPMatrix&gt; add(Matrix&lt;UJMPMatrix&gt; other) { return new UJMPMatrix(this.delegate.add(other.delegate().delegate)); }。我哪里错了?
    • UJMPMatrix 应该实现 Matrix&lt;org.ujmp.core.Matrix&gt; 查看我编辑的答案
    猜你喜欢
    • 1970-01-01
    • 2019-10-07
    • 1970-01-01
    • 1970-01-01
    • 2011-02-10
    • 1970-01-01
    • 1970-01-01
    • 2020-12-04
    • 1970-01-01
    相关资源
    最近更新 更多