chromium/third_party/eigen3/src/Eigen/src/Core/ProductEvaluators.h

// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2006-2008 Benoit Jacob <[email protected]>
// Copyright (C) 2008-2010 Gael Guennebaud <[email protected]>
// Copyright (C) 2011 Jitse Niesen <[email protected]>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.

#ifndef EIGEN_PRODUCTEVALUATORS_H
#define EIGEN_PRODUCTEVALUATORS_H

// IWYU pragma: private
#include "./InternalHeaderCheck.h"

namespace Eigen {

namespace internal {

/** \internal
 * Evaluator of a product expression.
 * Since products require special treatments to handle all possible cases,
 * we simply defer the evaluation logic to a product_evaluator class
 * which offers more partial specialization possibilities.
 *
 * \sa class product_evaluator
 */
evaluator<Product<Lhs, Rhs, Options>>;

// Catch "scalar * ( A * B )" and transform it to "(A*scalar) * B"
// TODO we should apply that rule only if that's really helpful
evaluator_assume_aliasing<CwiseBinaryOp<internal::scalar_product_op<Scalar1, Scalar2>, const CwiseNullaryOp<internal::scalar_constant_op<Scalar1>, Plain1>, const Product<Lhs, Rhs, DefaultProduct>>>;
evaluator<CwiseBinaryOp<internal::scalar_product_op<Scalar1, Scalar2>, const CwiseNullaryOp<internal::scalar_constant_op<Scalar1>, Plain1>, const Product<Lhs, Rhs, DefaultProduct>>>;

evaluator<Diagonal<const Product<Lhs, Rhs, DefaultProduct>, DiagIndex>>;

// Helper class to perform a matrix product with the destination at hand.
// Depending on the sizes of the factors, there are different evaluation strategies
// as controlled by internal::product_type.
template <typename Lhs, typename Rhs, typename LhsShape = typename evaluator_traits<Lhs>::Shape,
          typename RhsShape = typename evaluator_traits<Rhs>::Shape,
          int ProductType = internal::product_type<Lhs, Rhs>::value>
struct generic_product_impl;

evaluator_assume_aliasing<Product<Lhs, Rhs, DefaultProduct>>;

// This is the default evaluator implementation for products:
// It creates a temporary and call generic_product_impl
product_evaluator<Product<Lhs, Rhs, Options>, ProductTag, LhsShape, RhsShape>;

// The following three shortcuts are enabled only if the scalar types match exactly.
// TODO: we could enable them for different scalar types when the product is not vectorized.

// Dense = Product
Assignment<DstXprType, Product<Lhs, Rhs, Options>, internal::assign_op<Scalar, Scalar>, Dense2Dense, std::enable_if_t<(Options == DefaultProduct || Options == AliasFreeProduct)>>;

// Dense += Product
Assignment<DstXprType, Product<Lhs, Rhs, Options>, internal::add_assign_op<Scalar, Scalar>, Dense2Dense, std::enable_if_t<(Options == DefaultProduct || Options == AliasFreeProduct)>>;

// Dense -= Product
Assignment<DstXprType, Product<Lhs, Rhs, Options>, internal::sub_assign_op<Scalar, Scalar>, Dense2Dense, std::enable_if_t<(Options == DefaultProduct || Options == AliasFreeProduct)>>;

// Dense ?= scalar * Product
// TODO we should apply that rule if that's really helpful
// for instance, this is not good for inner products
Assignment<DstXprType, CwiseBinaryOp<internal::scalar_product_op<ScalarBis, Scalar>, const CwiseNullaryOp<internal::scalar_constant_op<ScalarBis>, Plain>, const Product<Lhs, Rhs, DefaultProduct>>, AssignFunc, Dense2Dense>;

//----------------------------------------
// Catch "Dense ?= xpr + Product<>" expression to save one temporary
// FIXME we could probably enable these rules for any product, i.e., not only Dense and DefaultProduct

evaluator_assume_aliasing<CwiseBinaryOp<internal::scalar_sum_op<typename OtherXpr::Scalar, typename Product<Lhs, Rhs, DefaultProduct>::Scalar>, const OtherXpr, const Product<Lhs, Rhs, DefaultProduct>>, DenseShape>;

evaluator_assume_aliasing<CwiseBinaryOp<internal::scalar_difference_op<typename OtherXpr::Scalar, typename Product<Lhs, Rhs, DefaultProduct>::Scalar>, const OtherXpr, const Product<Lhs, Rhs, DefaultProduct>>, DenseShape>;

template <typename DstXprType, typename OtherXpr, typename ProductType, typename Func1, typename Func2>
struct assignment_from_xpr_op_product {};

#define EIGEN_CATCH_ASSIGN_XPR_OP_PRODUCT(ASSIGN_OP, BINOP, ASSIGN_OP2)

EIGEN_CATCH_ASSIGN_XPR_OP_PRODUCT();
EIGEN_CATCH_ASSIGN_XPR_OP_PRODUCT();
EIGEN_CATCH_ASSIGN_XPR_OP_PRODUCT();

EIGEN_CATCH_ASSIGN_XPR_OP_PRODUCT();
EIGEN_CATCH_ASSIGN_XPR_OP_PRODUCT();
EIGEN_CATCH_ASSIGN_XPR_OP_PRODUCT();

//----------------------------------------

generic_product_impl<Lhs, Rhs, DenseShape, DenseShape, InnerProduct>;

/***********************************************************************
 *  Implementation of outer dense * dense vector product
 ***********************************************************************/

// Column major result
template <typename Dst, typename Lhs, typename Rhs, typename Func>
void EIGEN_DEVICE_FUNC outer_product_selector_run(Dst& dst, const Lhs& lhs, const Rhs& rhs, const Func& func,
                                                  const false_type&) {}

// Row major result
template <typename Dst, typename Lhs, typename Rhs, typename Func>
void EIGEN_DEVICE_FUNC outer_product_selector_run(Dst& dst, const Lhs& lhs, const Rhs& rhs, const Func& func,
                                                  const true_type&) {}

generic_product_impl<Lhs, Rhs, DenseShape, DenseShape, OuterProduct>;

// This base class provides default implementations for evalTo, addTo, subTo, in terms of scaleAndAddTo
template <typename Lhs, typename Rhs, typename Derived>
struct generic_product_impl_base {};

generic_product_impl<Lhs, Rhs, DenseShape, DenseShape, GemvProduct>;

generic_product_impl<Lhs, Rhs, DenseShape, DenseShape, CoeffBasedProductMode>;

// This specialization enforces the use of a coefficient-based evaluation strategy
generic_product_impl<Lhs, Rhs, DenseShape, DenseShape, LazyCoeffBasedProductMode>;

// Case 2: Evaluate coeff by coeff
//
// This is mostly taken from CoeffBasedProduct.h
// The main difference is that we add an extra argument to the etor_product_*_impl::run() function
// for the inner dimension of the product, because evaluator object do not know their size.

template <int Traversal, int UnrollingIndex, typename Lhs, typename Rhs, typename RetScalar>
struct etor_product_coeff_impl;

template <int StorageOrder, int UnrollingIndex, typename Lhs, typename Rhs, typename Packet, int LoadMode>
struct etor_product_packet_impl;

product_evaluator<Product<Lhs, Rhs, LazyProduct>, ProductTag, DenseShape, DenseShape>;

product_evaluator<Product<Lhs, Rhs, DefaultProduct>, LazyCoeffBasedProductMode, DenseShape, DenseShape>;

/****************************************
*** Coeff based product, Packet path  ***
****************************************/

etor_product_packet_impl<RowMajor, UnrollingIndex, Lhs, Rhs, Packet, LoadMode>;

etor_product_packet_impl<ColMajor, UnrollingIndex, Lhs, Rhs, Packet, LoadMode>;

etor_product_packet_impl<RowMajor, 1, Lhs, Rhs, Packet, LoadMode>;

etor_product_packet_impl<ColMajor, 1, Lhs, Rhs, Packet, LoadMode>;

etor_product_packet_impl<RowMajor, 0, Lhs, Rhs, Packet, LoadMode>;

etor_product_packet_impl<ColMajor, 0, Lhs, Rhs, Packet, LoadMode>;

etor_product_packet_impl<RowMajor, Dynamic, Lhs, Rhs, Packet, LoadMode>;

etor_product_packet_impl<ColMajor, Dynamic, Lhs, Rhs, Packet, LoadMode>;

/***************************************************************************
 * Triangular products
 ***************************************************************************/
template <int Mode, bool LhsIsTriangular, typename Lhs, bool LhsIsVector, typename Rhs, bool RhsIsVector>
struct triangular_product_impl;

generic_product_impl<Lhs, Rhs, TriangularShape, DenseShape, ProductTag>;

generic_product_impl<Lhs, Rhs, DenseShape, TriangularShape, ProductTag>;

/***************************************************************************
 * SelfAdjoint products
 ***************************************************************************/
template <typename Lhs, int LhsMode, bool LhsIsVector, typename Rhs, int RhsMode, bool RhsIsVector>
struct selfadjoint_product_impl;

generic_product_impl<Lhs, Rhs, SelfAdjointShape, DenseShape, ProductTag>;

generic_product_impl<Lhs, Rhs, DenseShape, SelfAdjointShape, ProductTag>;

/***************************************************************************
 * Diagonal products
 ***************************************************************************/

template <typename MatrixType, typename DiagonalType, typename Derived, int ProductOrder>
struct diagonal_product_evaluator_base : evaluator_base<Derived> {};

// diagonal * dense
product_evaluator<Product<Lhs, Rhs, ProductKind>, ProductTag, DiagonalShape, DenseShape>;

// dense * diagonal
product_evaluator<Product<Lhs, Rhs, ProductKind>, ProductTag, DenseShape, DiagonalShape>;

/***************************************************************************
 * Products with permutation matrices
 ***************************************************************************/

/** \internal
 * \class permutation_matrix_product
 * Internal helper class implementing the product between a permutation matrix and a matrix.
 * This class is specialized for DenseShape below and for SparseShape in SparseCore/SparsePermutation.h
 */
template <typename ExpressionType, int Side, bool Transposed, typename ExpressionShape>
struct permutation_matrix_product;

permutation_matrix_product<ExpressionType, Side, Transposed, DenseShape>;

generic_product_impl<Lhs, Rhs, PermutationShape, MatrixShape, ProductTag>;

generic_product_impl<Lhs, Rhs, MatrixShape, PermutationShape, ProductTag>;

generic_product_impl<Inverse<Lhs>, Rhs, PermutationShape, MatrixShape, ProductTag>;

generic_product_impl<Lhs, Inverse<Rhs>, MatrixShape, PermutationShape, ProductTag>;

/***************************************************************************
 * Products with transpositions matrices
 ***************************************************************************/

// FIXME could we unify Transpositions and Permutation into a single "shape"??

/** \internal
 * \class transposition_matrix_product
 * Internal helper class implementing the product between a permutation matrix and a matrix.
 */
template <typename ExpressionType, int Side, bool Transposed, typename ExpressionShape>
struct transposition_matrix_product {};

generic_product_impl<Lhs, Rhs, TranspositionsShape, MatrixShape, ProductTag>;

generic_product_impl<Lhs, Rhs, MatrixShape, TranspositionsShape, ProductTag>;

generic_product_impl<Transpose<Lhs>, Rhs, TranspositionsShape, MatrixShape, ProductTag>;

generic_product_impl<Lhs, Transpose<Rhs>, MatrixShape, TranspositionsShape, ProductTag>;

/***************************************************************************
 * skew symmetric products
 * for now we just call the generic implementation
 ***************************************************************************/
generic_product_impl<Lhs, Rhs, SkewSymmetricShape, MatrixShape, ProductTag>;

generic_product_impl<Lhs, Rhs, MatrixShape, SkewSymmetricShape, ProductTag>;

generic_product_impl<Lhs, Rhs, SkewSymmetricShape, SkewSymmetricShape, ProductTag>;

}  // end namespace internal

}  // end namespace Eigen

#endif  // EIGEN_PRODUCT_EVALUATORS_H