LCOV - code coverage report
Current view: top level - include/utils - CartesianProduct.h (source / functions) Hit Total Coverage
Test: idaholab/moose stochastic_tools: #32971 (54bef8) with base c6cf66 Lines: 37 38 97.4 %
Date: 2026-05-29 20:40:35 Functions: 12 12 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //* This file is part of the MOOSE framework
       2             : //* https://mooseframework.inl.gov
       3             : //*
       4             : //* All rights reserved, see COPYRIGHT for full restrictions
       5             : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
       6             : //*
       7             : //* Licensed under LGPL 2.1, please see LICENSE for details
       8             : //* https://www.gnu.org/licenses/lgpl-2.1.html
       9             : #pragma once
      10             : 
      11             : #include "MooseError.h"
      12             : #include <numeric>
      13             : #include <vector>
      14             : #include <deque>
      15             : #include "libmesh/libmesh_common.h"
      16             : 
      17             : using namespace libMesh;
      18             : 
      19             : namespace StochasticTools
      20             : {
      21             : /* Compute the Cartesian Product of the supplied vectors.
      22             :  * http://phrogz.net/lazy-cartesian-product
      23             :  * https://github.com/iamtheburd/lazy-cartesian-product-python/blob/master/LazyCartesianProduct.py
      24             :  */
      25             : template <class T>
      26             : class CartesianProduct
      27             : {
      28             : public:
      29             :   CartesianProduct(const std::vector<std::vector<T>> & items);
      30             : 
      31             :   /// Compute the complete Cartesian product matrix
      32             :   std::vector<std::vector<T>> computeMatrix() const;
      33             : 
      34             :   /// Compute specified row of Cartesian product matrix
      35             :   std::vector<T> computeRow(std::size_t row) const;
      36             : 
      37             :   /// Compute specific value, given row and column, of the Cartesian product matrix
      38             :   T computeValue(std::size_t row, std::size_t col) const;
      39             : 
      40             :   /// Total number of rows in the complete matrix
      41      728720 :   std::size_t numRows() const { return _n_rows; }
      42             : 
      43             :   /// Total number of columns in the complete matrix
      44        1102 :   std::size_t numCols() const { return _n_cols; }
      45             : 
      46             : protected:
      47             :   /// Number of rows/columns
      48             :   const std::size_t _n_rows;
      49             :   const std::size_t _n_cols;
      50             : 
      51             : private:
      52             :   /// Data used to create Cartesian product
      53             :   /// use a copy because a temporary can be supplied, as is the case in the CartesianProductSampler
      54             :   const std::vector<std::vector<T>> _items;
      55             : 
      56             :   /// Containers for lazy Cartesian product calculation
      57             :   std::deque<unsigned int> _denomenators;
      58             :   std::deque<unsigned int> _moduli;
      59             : 
      60             :   /// Helper to compute the rows in initialization list to allow _n_rows to be const
      61             :   static std::size_t computeRowCount(const std::vector<std::vector<T>> & items);
      62             : };
      63             : 
      64             : template <typename T>
      65        4315 : CartesianProduct<T>::CartesianProduct(const std::vector<std::vector<T>> & items)
      66        4315 :   : _n_rows(computeRowCount(items)), _n_cols(items.size()), _items(items)
      67             : {
      68             :   dof_id_type d = 1;
      69             :   for (typename std::vector<std::vector<T>>::const_reverse_iterator iter = _items.rbegin();
      70       24373 :        iter != _items.rend();
      71             :        ++iter)
      72             :   {
      73             :     std::size_t n = iter->size();
      74       20058 :     _denomenators.push_front(d);
      75       20058 :     _moduli.push_front(n);
      76       20058 :     d *= n;
      77             :   }
      78        4315 : }
      79             : 
      80             : template <typename T>
      81             : std::vector<std::vector<T>>
      82           1 : CartesianProduct<T>::computeMatrix() const
      83             : {
      84           1 :   std::vector<std::vector<T>> output(_n_rows, std::vector<T>(_n_cols));
      85          25 :   for (std::size_t row = 0; row < _n_rows; ++row)
      86          96 :     for (std::size_t col = 0; col < _n_cols; ++col)
      87          72 :       output[row][col] = computeValue(row, col);
      88           1 :   return output;
      89             : }
      90             : 
      91             : template <typename T>
      92             : std::vector<T>
      93     1229888 : CartesianProduct<T>::computeRow(std::size_t row) const
      94             : {
      95     1229888 :   std::vector<T> output(_n_cols);
      96     6608886 :   for (std::size_t col = 0; col < _n_cols; ++col)
      97     5378998 :     output[col] = computeValue(row, col);
      98     1229888 :   return output;
      99             : }
     100             : 
     101             : template <typename T>
     102             : T
     103     7429885 : CartesianProduct<T>::computeValue(std::size_t row, std::size_t col) const
     104             : {
     105             :   mooseAssert(row < _n_rows, "Row index out of range.");
     106             :   mooseAssert(col < _n_cols, "Column index out of range.");
     107     7429885 :   return _items[col][(row / _denomenators[col]) % _moduli[col]];
     108             : }
     109             : 
     110             : template <typename T>
     111             : std::size_t
     112             : CartesianProduct<T>::computeRowCount(const std::vector<std::vector<T>> & items)
     113             : {
     114             :   std::size_t n_rows = 1;
     115       24373 :   for (const auto & inner : items)
     116       20058 :     n_rows *= inner.size();
     117             :   return n_rows;
     118             : }
     119             : 
     120             : /*
     121             :  * Add ability to compute weighting values with the Cartesian Product
     122             :  */
     123             : template <class T, class W>
     124        1595 : class WeightedCartesianProduct : public CartesianProduct<T>
     125             : {
     126             : public:
     127             :   WeightedCartesianProduct(const std::vector<std::vector<T>> & items,
     128             :                            const std::vector<std::vector<W>> & weights);
     129             : 
     130             :   /// Compute complete vector of weights
     131             :   std::vector<W> computeWeightVector() const;
     132             : 
     133             :   /// Compute specific weight value, given row
     134             :   W computeWeight(std::size_t row) const;
     135             : 
     136             : private:
     137             :   /// Data used to create Cartesian product; use a copy because a temporary can be supplied
     138             :   const CartesianProduct<W> _weight;
     139             : };
     140             : 
     141             : template <typename T, typename W>
     142        1539 : WeightedCartesianProduct<T, W>::WeightedCartesianProduct(
     143             :     const std::vector<std::vector<T>> & items, const std::vector<std::vector<W>> & weights)
     144        1539 :   : CartesianProduct<T>(items), _weight(weights)
     145             : {
     146             :   mooseAssert(items.size() == weights.size(),
     147             :               "The supplied items and weights must be the same size.");
     148             :   for (std::size_t i = 0; i < items.size(); ++i)
     149             :     mooseAssert(items[i].size() == weights[i].size(),
     150             :                 "Internal vector of the supplied items and weights must be the same size.");
     151        1539 : }
     152             : 
     153             : template <typename T, typename W>
     154             : std::vector<W>
     155           1 : WeightedCartesianProduct<T, W>::computeWeightVector() const
     156             : {
     157           1 :   std::vector<W> output(this->_n_rows);
     158          25 :   for (std::size_t i = 0; i < output.size(); ++i)
     159          24 :     output[i] = computeWeight(i);
     160           1 :   return output;
     161           0 : }
     162             : 
     163             : template <typename T, typename W>
     164             : W
     165      503804 : WeightedCartesianProduct<T, W>::computeWeight(std::size_t row) const
     166             : {
     167      503804 :   std::vector<W> vec = _weight.computeRow(row);
     168      503804 :   return std::accumulate(vec.begin(), vec.end(), static_cast<W>(1), std::multiplies<W>());
     169      503804 : }
     170             : } // namespace

Generated by: LCOV version 1.14