/**
   * Performs a transposed mass evaluation
   *
   * @param storage GridStorage object that contains the grid's points information
   * @param basis a reference to a class that implements a specific basis
   * @param source the coefficients of the grid points
   * @param x the d-dimensional vector with data points (row-wise)
   * @param result the result vector of the matrix vector multiplication
   */
  void mult_transpose(GridStorage* storage, BASIS& basis, DataVector& source,
                      DataMatrix& x, DataVector& result) {
    result.setAll(0.0);
    size_t source_size = source.getSize();

    #pragma omp parallel
    {
      DataVector privateResult(result.getSize());
      privateResult.setAll(0.0);

      DataVector line(x.getNcols());
      AlgorithmEvaluationTransposed<BASIS> AlgoEvalTrans(storage);

      privateResult.setAll(0.0);


      #pragma omp for schedule(static)

      for (size_t i = 0; i < source_size; i++) {
        x.getRow(i, line);

        AlgoEvalTrans(basis, line, source[i], privateResult);
      }

      #pragma omp critical
      {
        result.add(privateResult);
      }
    }
  }
  /**
   * Performs a mass evaluation
   *
   * @param storage GridStorage object that contains the grid's points information
   * @param basis a reference to a class that implements a specific basis
   * @param source the coefficients of the grid points
   * @param x the d-dimensional vector with data points (row-wise)
   * @param result the result vector of the matrix vector multiplication
   */
  void mult(GridStorage* storage, BASIS& basis, DataVector& source, DataMatrix& x,
            DataVector& result) {
    result.setAll(0.0);
    size_t result_size = result.getSize();


    #pragma omp parallel
    {
      DataVector line(x.getNcols());
      AlgorithmEvaluation<BASIS> AlgoEval(storage);

      #pragma omp for schedule(static)

      for (size_t i = 0; i < result_size; i++) {
        x.getRow(i, line);

        result[i] = AlgoEval(basis, line, source);
      }
    }
  }