public override DoubleMatrix1D ZMult(DoubleMatrix1D y, DoubleMatrix1D z, double alpha, double beta, Boolean transposeA)
        {
            int m = Rows;
            int n = Columns;

            if (transposeA)
            {
                m = Columns;
                n = Rows;
            }

            Boolean ignore = (z == null);

            if (z == null)
            {
                z = new DenseDoubleMatrix1D(m);
            }

            if (!(!this.IsView && y is DenseDoubleMatrix1D && z is DenseDoubleMatrix1D))
            {
                return(base.ZMult(y, z, alpha, beta, transposeA));
            }

            if (n != y.Size || m > z.Size)
            {
                throw new ArgumentException(String.Format(Cern.LocalizedResources.Instance().Exception_IncompatibleArgs, ((transposeA ? ViewDice() : this).ToStringShort()), y.ToStringShort(), z.ToStringShort()));
            }

            if (!ignore)
            {
                z.Assign(F1.Mult(beta / alpha));
            }

            DenseDoubleMatrix1D zz = (DenseDoubleMatrix1D)z;

            double[] zElements = zz.Elements;
            int      zStride   = zz.Stride;
            int      zi        = z.Index(0);

            DenseDoubleMatrix1D yy = (DenseDoubleMatrix1D)y;

            double[] yElements = yy.Elements;
            int      yStride   = yy.Stride;
            int      yi        = y.Index(0);

            if (yElements == null || zElements == null)
            {
                throw new NullReferenceException();
            }

            ForEachNonZero(
                new Cern.Colt.Function.IntIntDoubleFunction((i, j, value) =>
            {
                if (transposeA)
                {
                    int tmp = i; i = j; j = tmp;
                }
                zElements[zi + zStride * i] += value * yElements[yi + yStride * j];
                //z.setQuick(row,z.getQuick(row) + value * y.getQuick(column));
                //Console.WriteLine("["+i+","+j+"]-->"+value);
                return(value);
            }
                                                            ));

            if (alpha != 1)
            {
                z.Assign(F1.Mult(alpha));
            }
            return(z);
        }
        /// <summary>
        /// Linear algebraic matrix-vector multiplication; <tt>z = alpha * A * y + beta*z</tt>.
        /// </summary>
        /// <param name="y">
        /// The ource vector.
        /// </param>
        /// <param name="z">
        /// The vector where results are to be stored. Set this parameter to <tt>null</tt> to indicate that a new result vector shall be constructed.
        /// </param>
        /// <param name="alpha">
        /// The alpha.
        /// </param>
        /// <param name="beta">
        /// The beta.
        /// </param>
        /// <param name="transposeA">
        /// Whether A must be transposed.
        /// </param>
        /// <returns>
        /// z (for convenience only).
        /// </returns>
        /// <exception cref="ArgumentOutOfRangeException">
        /// If <tt>A.columns() != y.size() || A.rows() &gt; z.size())</tt>.
        /// </exception>
        public override DoubleMatrix1D ZMult(DoubleMatrix1D y, DoubleMatrix1D z, double alpha, double beta, bool transposeA)
        {
            if (transposeA)
            {
                return(ViewDice().ZMult(y, z, alpha, beta, false));
            }
            if (z == null)
            {
                z = new DenseDoubleMatrix1D(Rows);
            }
            if (!(y is DenseDoubleMatrix1D) && z is DenseDoubleMatrix1D)
            {
                return(base.ZMult(y, z, alpha, beta, false));
            }

            if (Columns != y.Size || Rows > z.Size)
            {
                throw new ArgumentException("Incompatible args: " + this + ", " + y + ", " + z);
            }

            var yy = (DenseDoubleMatrix1D)y;
            var zz = (DenseDoubleMatrix1D)z;

            double[] aElems = Elements;
            double[] yElems = yy.Elements;
            double[] zElems = zz.Elements;
            if (aElems == null || yElems == null || zElems == null)
            {
                throw new ApplicationException();
            }
            int _as = ColumnStride;
            int ys  = yy.Stride;
            int zs  = zz.Stride;

            int indexA = Index(0, 0);
            int indexY = yy.Index(0);
            int indexZ = zz.Index(0);

            int cols = Columns;

            for (int row = Rows; --row >= 0;)
            {
                double sum = 0;

                /*
                 * // not loop unrolled
                 * for (int i=indexA, j=indexY, column=columns; --column >= 0;) {
                 *  sum += AElems[i] * yElems[j];
                 *  i += As;
                 *  j += ys;
                 * }
                 */

                // loop unrolled
                int i = indexA - _as;
                int j = indexY - ys;
                for (int k = cols % 4; --k >= 0;)
                {
                    sum += aElems[i += _as] * yElems[j += ys];
                }
                for (int k = cols / 4; --k >= 0;)
                {
                    sum += (aElems[i += _as] * yElems[j += ys]) +
                           (aElems[i += _as] * yElems[j += ys]) +
                           (aElems[i += _as] * yElems[j += ys]) +
                           (aElems[i += _as] * yElems[j += ys]);
                }

                zElems[indexZ] = (alpha * sum) + (beta * zElems[indexZ]);
                indexA        += RowStride;
                indexZ        += zs;
            }

            return(z);
        }
        public override DoubleMatrix1D ZMult(DoubleMatrix1D y, DoubleMatrix1D z, double alpha, double beta, Boolean transposeA)
        {
            int m = Rows;
            int n = Columns;

            if (transposeA)
            {
                m = Columns;
                n = Rows;
            }

            Boolean ignore = (z == null || !transposeA);

            if (z == null)
            {
                z = new DenseDoubleMatrix1D(m);
            }

            if (!(y is DenseDoubleMatrix1D && z is DenseDoubleMatrix1D))
            {
                return(base.ZMult(y, z, alpha, beta, transposeA));
            }

            if (n != y.Size || m > z.Size)
            {
                throw new ArgumentException("Incompatible args: " + ((transposeA ? ViewDice() : this).ToStringShort()) + ", " + y.ToStringShort() + ", " + z.ToStringShort());
            }

            DenseDoubleMatrix1D zz = (DenseDoubleMatrix1D)z;

            double[] zElements = zz.Elements;
            int      zStride   = zz.Stride;
            int      zi        = z.Index(0);

            DenseDoubleMatrix1D yy = (DenseDoubleMatrix1D)y;

            double[] yElements = yy.Elements;
            int      yStride   = yy.Stride;
            int      yi        = y.Index(0);

            if (yElements == null || zElements == null)
            {
                throw new NullReferenceException();
            }

            /*
             * forEachNonZero(
             *  new Cern.Colt.Function.IntIntDoubleFunction() {
             *      public double apply(int i, int j, double value) {
             *          zElements[zi + zStride*i] += value * yElements[yi + yStride*j];
             *          //z.SetQuick(row,z.getQuick(row) + value * y.getQuick(column));
             *          //Console.WriteLine("["+i+","+j+"]-->"+value);
             *          return value;
             *      }
             *  }
             * );
             */


            int[]    idx  = Indexes.ToArray();
            double[] vals = Values.ToArray();
            int      s    = Starts.Length - 1;

            if (!transposeA)
            {
                for (int i = 0; i < s; i++)
                {
                    int    high = Starts[i + 1];
                    double sum  = 0;
                    for (int k = Starts[i]; k < high; k++)
                    {
                        int j = idx[k];
                        sum += vals[k] * yElements[yi + yStride * j];
                    }
                    zElements[zi] = alpha * sum + beta * zElements[zi];
                    zi           += zStride;
                }
            }
            else
            {
                if (!ignore)
                {
                    z.Assign(F1.Mult(beta));
                }
                for (int i = 0; i < s; i++)
                {
                    int    high  = Starts[i + 1];
                    double yElem = alpha * yElements[yi + yStride * i];
                    for (int k = Starts[i]; k < high; k++)
                    {
                        int j = idx[k];
                        zElements[zi + zStride * j] += vals[k] * yElem;
                    }
                }
            }

            return(z);
        }