@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;
  }
 private static IntArray toIndexArray(long[] supportA, long[] supportB, IntArray indices) {
   if (indices == null) {
     indices = new IntArray();
   } else {
     indices.clear();
   }
   for (int i = 0; i < supportA.length; i++) {
     long commonSupport = supportA[i] & supportB[i];
     while (commonSupport != 0) {
       final int index = Long.numberOfTrailingZeros(commonSupport);
       indices.add(index + i * 64);
       commonSupport ^= (1L << index);
     }
   }
   return indices;
 }
  @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;
  }