@Override
  public A multiply(A v, A[] m) {
    final int cols1 = arrayOps.getLength(v);
    final int rows2 = arrayOps.getRowCount(m);
    final int cols2 = arrayOps.getColumnCount(m);
    if (cols1 != rows2) {
      throw new IllegalArgumentException(
          "incompatible dimension for matrix multiplication: "
              + "1x"
              + cols1
              + " * "
              + rows2
              + "x"
              + cols2);
    }
    final TernaryOperator<N, A> mulAdd = expressionComposer.addToFree(expressionComposer.mul());

    final A res = numberArrayOps.newZeroVector(cols2);

    IntArray indices = null;
    final long[] rsup = numberArrayOps.getVectorSupportAsLongBits(v);
    for (int c = 0; c < cols2; c++) {
      final long[] csup = numberArrayOps.getMatrixColumnSupportAsLongBits(m, c);
      indices = toIndexArray(rsup, csup, indices);
      for (int i = 0; i < indices.length(); i++) {
        final int index = indices.get(i);
        // res[c] = res[c] + v[index]*m[index][c]*
        mulAdd.operate(res, c, v, index, m[index], c, res, c);
      }
    }
    return res;
  }
  @Override
  public A[] multiply(A[] m1, A[] m2) {
    final int rows1 = arrayOps.getRowCount(m1);
    final int cols1 = arrayOps.getColumnCount(m1);
    final int rows2 = arrayOps.getRowCount(m2);
    final int cols2 = arrayOps.getColumnCount(m2);
    if (cols1 != rows2) {
      throw new IllegalArgumentException(
          "incompatible dimension for matrix multiplication: "
              + rows1
              + "x"
              + cols1
              + " * "
              + rows2
              + "x"
              + cols2);
    }
    final TernaryOperator<N, A> mulAdd = expressionComposer.addToFree(expressionComposer.mul());

    final A[] res = numberArrayOps.newZeroMatrix(rows1, cols2);

    IntArray indices = null;
    final long[][] rsup = numberArrayOps.getMatrixSupportAsLongBits(m1);
    for (int c = 0; c < cols2; c++) {
      final long[] csup = numberArrayOps.getMatrixColumnSupportAsLongBits(m2, c);
      for (int r = 0; r < rows1; r++) {
        indices = toIndexArray(rsup[r], csup, indices);
        for (int i = 0; i < indices.length(); i++) {
          final int index = indices.get(i);
          // res[r][c] = res[r][c] + m1[r][index]*m2[index][c]
          mulAdd.operate(res[r], c, m1[r], index, m2[index], c, res[r], c);
        }
      }
    }
    return res;
  }
 public void operate(
     A operand1, int index1, A operand2, int index2, A operand3, int index3, A dst, int dstIndex) {
   operand.operate(operand1, index1, operand2, index2, operand3, index3, dst, dstIndex);
   operator.operate(dst, dstIndex, dst, dstIndex);
 }