/// <summary> /// 8 neighbor stencil transformationd For efficient finite difference operations. /// Applies a function to a moving <tt>3 x 3</tt> window. /// Does nothing if <tt>rows() < 3 || columns() < 3</tt>. /// </summary> /// <param name="b"> /// The matrix to hold the results. /// </param> /// <param name="function"> /// The function to be applied to the 9 cells. /// </param> /// <exception cref="ArgumentNullException"> /// If <tt>function==null</tt>. /// </exception> /// <exception cref="ArgumentOutOfRangeException"> /// If <tt>rows() != B.rows() || columns() != B.columns()</tt>. /// </exception> public virtual void ZAssign8Neighbors(DoubleMatrix2D b, Double9Function function) { if (function == null) { throw new ArgumentNullException("function", Cern.LocalizedResources.Instance().Exception_FuncionMustNotBeNull); } CheckShape(b); if (Rows < 3 || Columns < 3) { return; // nothing to do } int r = Rows - 1; int c = Columns - 1; for (int i = 1; i < r; i++) { double a00 = this[i - 1, 0]; double a01 = this[i - 1, 1]; double a10 = this[i, 0]; double a11 = this[i, 1]; double a20 = this[i + 1, 0]; double a21 = this[i + 1, 1]; for (int j = 1; j < c; j++) { // in each step six cells can be remembered in registers - they don't need to be reread from slow memory // in each step 3 instead of 9 cells need to be read from memory. double a02 = this[i - 1, j + 1]; double a12 = this[i, j + 1]; double a22 = this[i + 1, j + 1]; b[i, j] = function(a00, a01, a02, a10, a11, a12, a20, a21, a22); a00 = a01; a10 = a11; a20 = a21; a01 = a02; a11 = a12; a21 = a22; } } }
/// <summary> /// 8 neighbor stencil transformation. For efficient finite difference operations. /// Applies a function to a moving <tt>3 x 3</tt> window. /// Does nothing if <tt>rows() < 3 || columns() < 3</tt>. /// </summary> /// <param name="b"> /// The matrix to hold the results. /// </param> /// <param name="function"> /// The unction to be applied to the 9 cells. /// </param> /// <exception cref="ArgumentOutOfRangeException"> /// If <tt>rows() != B.rows() || columns() != B.columns()</tt>. /// </exception> public override void ZAssign8Neighbors(DoubleMatrix2D b, Double9Function function) { // 1. using only 4-5 out of the 9 cells in "function" is *not* the limiting factor for performance. // 2. if the "function" would be hardwired into the innermost loop, a speedup of 1.5-2.0 would be seen // but then the multi-purpose interface is gone... if (!(b is DenseDoubleMatrix2D)) { base.ZAssign8Neighbors(b, function); return; } CheckShape(b); int r = Rows - 1; int c = Columns - 1; if (Rows < 3 || Columns < 3) { return; // nothing to do } var bb = (DenseDoubleMatrix2D)b; int a_rs = RowStride; int b_rs = bb.RowStride; int a_cs = ColumnStride; int b_cs = bb.ColumnStride; double[] elems = Elements; double[] b_elems = bb.Elements; if (elems == null || b_elems == null) { throw new ApplicationException(); } int a_index = Index(1, 1); int b_index = bb.Index(1, 1); for (int i = 1; i < r; i++) { int b11 = b_index; int a02 = a_index - a_rs - a_cs; int a12 = a02 + a_rs; int a22 = a12 + a_rs; // in each step six cells can be remembered in registers - they don't need to be reread from slow memory double a00 = elems[a02]; a02 += a_cs; double a01 = elems[a02]; double a10 = elems[a12]; a12 += a_cs; double a11 = elems[a12]; double a20 = elems[a22]; a22 += a_cs; double a21 = elems[a22]; for (int j = 1; j < c; j++) { // in each step 3 instead of 9 cells need to be read from memory. double _a02 = elems[a02 += a_cs]; double _a12 = elems[a12 += a_cs]; double _a22 = elems[a22 += a_cs]; b_elems[b11] = function(a00, a01, _a02, a10, a11, _a12, a20, a21, _a22); b11 += b_cs; // move remembered cells a00 = a01; a01 = _a02; a10 = a11; a11 = _a12; a20 = a21; a21 = _a22; } a_index += a_rs; b_index += b_rs; } }