package recunn.autodiff;
import java.util.ArrayList;
import java.util.List;

import recunn.matrix.Matrix;
import recunn.model.Nonlinearity;


public class Graph {
	boolean applyBackprop;
	
	List backprop = new ArrayList<>();
	
	public Graph() {
		this.applyBackprop = true;
	}
	
	public Graph(boolean applyBackprop) {
		this.applyBackprop = applyBackprop;
	}
	
	public void backward() {
		for (int i = backprop.size()-1; i >= 0; i--) {
			backprop.get(i).run();
		}
	}
	
	public Matrix concatVectors(final Matrix m1, final Matrix m2) throws Exception {
		if (m1.cols > 1 || m2.cols > 1) {
			throw new Exception("Expected column vectors");
		}
		final Matrix out = new Matrix(m1.rows + m2.rows);
		int loc = 0;
		for (int i = 0; i < m1.w.length; i++) {
			out.w[loc] = m1.w[i];
			out.dw[loc] = m1.dw[i];
			out.stepCache[loc] = m1.stepCache[i];
			loc++;
		}
		for (int i = 0; i < m2.w.length; i++) {
			out.w[loc] = m2.w[i];
			out.dw[loc] = m2.dw[i];
			out.stepCache[loc] = m2.stepCache[i];
			loc++;
		}
		if (this.applyBackprop) {
			Runnable bp = new Runnable() {
				public void run() {
					int loc = 0;
					for (int i = 0; i < m1.w.length; i++) {
						m1.w[i] = out.w[loc];
						m1.dw[i] = out.dw[loc];
						m1.stepCache[i] = out.stepCache[loc];
						loc++;
					}
					for (int i = 0; i < m2.w.length; i++) {
						m2.w[i] = out.w[loc];
						m2.dw[i] = out.dw[loc];
						m2.stepCache[i] = out.stepCache[loc];
						loc++;
					}
				}
			};
			backprop.add(bp);
		}
		return out;
	}
	
	public Matrix nonlin(final Nonlinearity neuron, final Matrix m) throws Exception {
		final Matrix out = new Matrix(m.rows, m.cols);
		final int n = m.w.length;
		for (int i = 0; i < n; i++) {
			out.w[i] = neuron.forward(m.w[i]);
		}
		if (this.applyBackprop) {
			Runnable bp = new Runnable() {
				public void run() {
					for (int i = 0; i < n; i++) {
						m.dw[i] += neuron.backward(m.w[i]) * out.dw[i];
					}
				}
			};
			backprop.add(bp);
		}
		return out;
	}
	
	public Matrix mul(final Matrix m1, final Matrix m2) throws Exception {
		if (m1.cols != m2.rows) {
			throw new Exception("matrix dimension mismatch");
		}
		
		final int m1rows = m1.rows;
		final int m1cols = m1.cols;
		final int m2cols = m2.cols;
		final Matrix out = new Matrix(m1rows, m2cols);
		final int outcols = m2cols;
		for (int i = 0; i < m1rows; i++) {
			int m1col = m1cols*i;
			for (int j = 0; j < m2cols; j++) {
				double dot = 0;
				for (int k = 0; k < m1cols; k++) {
					dot +=  m1.w[m1col + k] * m2.w[m2cols*k + j];
				}
				out.w[outcols*i + j] = dot;
			}
		}
		if (this.applyBackprop) {
			Runnable bp = new Runnable() {
				public void run() {
					for (int i = 0; i < m1.rows; i++) {
						int outcol = outcols*i;
						for (int j = 0; j < m2.cols; j++) {
							double b = out.dw[outcol + j];
							for (int k = 0; k < m1.cols; k++) {
								m1.dw[m1cols*i + k] += m2.w[m2cols*k + j] * b;
								m2.dw[m2cols*k + j] += m1.w[m1cols*i + k] * b;
							}
						}
					}
				}
			};
			backprop.add(bp);
		}
		return out;
	}
	
	public Matrix add(final Matrix m1, final Matrix m2) throws Exception {
		if (m1.rows != m2.rows || m1.cols != m2.cols) {
			throw new Exception("matrix dimension mismatch");
		}
		final Matrix out = new Matrix(m1.rows, m1.cols);
		for (int i = 0; i < m1.w.length; i++) {
			out.w[i] = m1.w[i] + m2.w[i];
		}
		if (this.applyBackprop) {
			Runnable bp = new Runnable() {
				public void run() {
					for (int i = 0; i < m1.w.length; i++) {
						m1.dw[i] += out.dw[i];
						m2.dw[i] += out.dw[i];
					}
				}
			};
			backprop.add(bp);
		}
		return out;
	}
	
	public Matrix oneMinus(final Matrix m) throws Exception {
		Matrix ones = Matrix.ones(m.rows, m.cols);
		Matrix out = sub(ones, m);
		return out;
	}
	
	public Matrix sub(final Matrix m1, final Matrix m2) throws Exception {
		Matrix out = add(m1, neg(m2));
		return out;
	}
	
	public Matrix smul(final Matrix m, final double s) throws Exception {
		Matrix m2 = Matrix.uniform(m.rows, m.cols, s);
		Matrix out = elmul(m, m2);
		return out;
	}
	
	public Matrix smul(final double s, final Matrix m) throws Exception {
		Matrix out = smul(m, s);
		return out;
	}
	
	public Matrix neg(final Matrix m) throws Exception {
		Matrix negones = Matrix.negones(m.rows, m.cols);
		Matrix out = elmul(negones, m);
		return out;
	}
	
	public Matrix elmul(final Matrix m1, final Matrix m2) throws Exception {
		if (m1.rows != m2.rows || m1.cols != m2.cols) {
			throw new Exception("matrix dimension mismatch");
		}
		final Matrix out = new Matrix(m1.rows, m1.cols);
		for (int i = 0; i < m1.w.length; i++) {
			out.w[i] = m1.w[i] * m2.w[i];
		}
		if (this.applyBackprop) {
			Runnable bp = new Runnable() {
				public void run() {
					for (int i = 0; i < m1.w.length; i++) {
						m1.dw[i] += m2.w[i] * out.dw[i];
						m2.dw[i] += m1.w[i] * out.dw[i];
					}
				}
			};
			backprop.add(bp);
		}
		return out;
	}
}

 

Ads help maintain this website.