libome-rs 0.0.1

Rust bindings for libome, a C++ library for massive QCD operator matrix elements in x-space.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
/******************************************************************************
 * This file is part of libome                                                *
 * Copyright (C) 2025 Arnd Behring, Kay Schoenwald                            *
 * SPDX-License-Identifier: GPL-3.0-or-later                                  *
 ******************************************************************************/

/**
 * \file
 * \brief Evaluatable (and nestable) Laurent polynomials
 */

#ifndef LIBOME_LAURENT_POLYNOMIAL_H
#define LIBOME_LAURENT_POLYNOMIAL_H

#include <utility>
#include <type_traits>
#include <initializer_list>
#include <iterator>
#include <vector>
#include <cmath>
#include <numeric>
#include <ome/traits.h>

namespace ome
{
  /**
   * \brief View on an evaluatable Laurent polynomial
   *
   * \details
   * This class provides a view on a Laurent polyonmial (i.e., it does not store
   * the Laurent polynomial itself, but it only refers to one). It can be nested
   * (see documentation of \ref laurent_polynomial) and it can be evaluated.
   *
   * \tparam Tnum Numerical data type. This is the type of the polynomial
   *         variable \f$x\f$, the type of the coefficients or the return type
   *         of evaluating the coefficients \f$c_i(\dots)\f$ and the type that
   *         the polynomial evaluates to.
   * \tparam Tcoeff Type of the coefficients \f$c_i\f$ of the polynomial. This
   *         can either be a numerical type that can be implicitly converted to
   *         Tnum or a callable that evaluates to Tnum when invoked.
   * \tparam Tcoefffargs Pack of types that specifies the types of the arguments
   *         when invoking Tcoeff. If Tcoeff is a numerical type (not a
   *         callable) this pack should be empty.
   */
  template<typename Tnum, typename Tcoeff, typename... Tcoeffargs>
  class laurent_polynomial_view
  {
    public:
      /// Type alias for the numerical type template parameter
      using numeric_type = Tnum;
      /// Type alias for the coefficient type template parameter
      using coefficient_type = Tcoeff;
      /// Boolean type alias for whether the coefficient_type has a view
      using coefficient_has_view = has_view<coefficient_type>;
      /// Boolean type alias indicating that this class has an eval_plus_int method
      using has_eval_plus_int = std::true_type;
      /// Type alias for the view of the coefficient type (if it exists, otherwise it is void)
      using coefficient_view_type = typename get_view_type<coefficient_type>::type;
      /// Type alias for the coefficient iterators
      using const_reverse_iterator = typename std::vector<coefficient_type>::const_reverse_iterator;

      /**
       * \brief Construct from const iterators
       *
       * \param crbegin Reverse iterator to last coefficient
       * \param crend Reverse iterator to behind first coefficient
       * \param min_power Exponent of the lowest-order monomial (\f$n_0\f$).
       */
      laurent_polynomial_view(
          const_reverse_iterator crbegin,
          const_reverse_iterator crend,
          int min_power = 0)
        : coeffs_crbegin_(crbegin),
          coeffs_crend_(crend),
          min_power_(min_power) {};

      /**
       * \brief Swap function
       */
      friend
      void swap(laurent_polynomial_view& first, laurent_polynomial_view& second)
      {
        using std::swap;
        swap(first.coeffs_crbegin_,second.coeffs_crbegin_);
        swap(first.coeffs_crend_,second.coeffs_crend_);
        swap(first.min_power_,second.min_power_);
      };

      /**
       * \brief Evaluate Laurent polynomial
       *
       * \details
       * Evaluate the polynomial for a given set of values of the variables. The
       * first argument is the value for the variable \f$x\f$. If there are more
       * arguments, they are passed on to the evaluation of each coefficient.
       *
       * \param x Value for the polynomial variable \f$x\f$.
       * \param rest Pack of function arguments that are passed to the
       *        evaluation of the coefficients \f$c_i(\dots)\f$.
       *
       * \return Numerical value for the Laurent polynomial evaluated at the
       *         given point.
       */
      numeric_type operator()(numeric_type x, Tcoeffargs... rest) const
      {
        using std::pow;
        const numeric_type prefactor = (min_power_ != 0) ? pow(x, min_power_) : static_cast<numeric_type>(1);
        
        if constexpr(sizeof...(rest) > 0)
        {
          if(std::next(coeffs_crbegin_) == coeffs_crend_)
          {
            return(prefactor*(*coeffs_crbegin_)(rest...));
          }
          else
          {
            return(prefactor*std::accumulate(
              coeffs_crbegin_,
              coeffs_crend_,
              static_cast<numeric_type>(0),
              [&x, &rest...] (const numeric_type& acc, const coefficient_type& next)
              {
                return(x*acc + next(rest...));
              }
            ));
          }
        }
        else
        {
          if(std::next(coeffs_crbegin_) == coeffs_crend_)
          {
            return(prefactor*(*coeffs_crbegin_));
          }
          else
          {
            return(prefactor*std::accumulate(
              coeffs_crbegin_,
              coeffs_crend_,
              static_cast<numeric_type>(0),
              [&x] (const numeric_type& acc, const coefficient_type& next)
              {
                return(x*acc + next);
              }
            ));
          }
        }
      };

      /**
       * \brief Evaluate polynomial with precomputed monomials
       *
       * \details
       * Evaluate the Laurent polynomial, but instead of the \f$x^i\f$, the
       * monomials are taken from the input vector subst. Effectively this method computes the inner product between subst and the vector of polynomial coefficients.
       *
       * \param subst Vector of precomputed monomials. The caller has to
       *        ensure that it has the same length as the vector of
       *        polynomial coefficients
       * \param rest Pack of function arguments that are passed to the
       *        evaluation of the coefficients \f$c_i(\dots)\f$.
       *
       * \return Numerical value for the Laurent polynomial evaluated with the
       *         given monomials.
       */
      numeric_type eval_subst(const std::vector<numeric_type>& subst, Tcoeffargs... rest) const
      {
        if constexpr(sizeof...(rest) > 0)
        {
          return(std::transform_reduce(
            coeffs_crbegin_,
            coeffs_crend_,
            subst.crbegin(),
            static_cast<numeric_type>(0),
            std::plus<>(),
            [&rest...] (const coefficient_type& c, const numeric_type& s)
            {
              return(c(rest...) * s);
            }
          ));
        }
        else
        {
          return(std::transform_reduce(
            coeffs_crbegin_,
            coeffs_crend_,
            subst.crbegin(),
            static_cast<numeric_type>(0)
          ));
        }
      };

      /**
       * \brief Evaluate polynomial, but call eval_plus_int on wrapped type
       *
       * \details
       * This is meant to be used in conjunction with func_plusfunc_omx, which
       * allows to calculate the "extra" integral of plus functions over
       * \f$[0,x]\f$ analytically. This method exposes that functionality if
       * func_plusfunc_omx is wrapped into further laurent_polynomials.
       *
       * \param x Value for the polynomial variable \f$x\f$.
       * \param rest Pack of function arguments that are passed to the
       *        evaluation of the coefficients \f$c_i(\dots)\f$.
       *
       * \return Numerical value for the Laurent polynomial evaluated for the
       *         given values of the variables, but with eval_plus_int called
       *         on the wrapped callable.
       */
      numeric_type eval_plus_int(numeric_type x, Tcoeffargs... rest) const
      {
        using std::pow;
        const numeric_type prefactor = (min_power_ != 0) ? pow(x, min_power_) : static_cast<numeric_type>(1);

        if(std::next(coeffs_crbegin_) == coeffs_crend_)
        {
          return(prefactor * coeffs_crbegin_->eval_plus_int(rest...));
        }
        else
        {
          return(prefactor*std::accumulate(
            coeffs_crbegin_,
            coeffs_crend_,
            static_cast<numeric_type>(0),
            [&x, &rest...] (const numeric_type& acc, const coefficient_type& next)
            {
              return(x*acc + next.eval_plus_int(rest...));
            }
          ));
        }
      };

      /**
       * \brief Truncate the Laurent polynomial to a given order
       *
       * \details
       * Truncation means that the polynomial is only evaluated up to a certain
       * order, which can by lower than the highest available term. If the
       * requested truncation order is lower than the minimal exponent
       * (\f$n_0\f$), the resulting truncated polynomial will always evaluate to
       * zero. If the requested truncation order is higher than the maximal
       * exponent, no truncation will be performed.
       *
       * \param truncation_order Exponent of the last order to include
       *
       * \return A laurent_polynomial_view of the truncated polynomial
       */
      laurent_polynomial_view truncate(int truncation_order) const
      {
        const int requested_orders = truncation_order - min_power_ + 1;
        const int available_orders = coeffs_crend_ - coeffs_crbegin_;

        if(requested_orders <= 0)
        {
          return(laurent_polynomial_view(coeffs_crbegin_,
            coeffs_crbegin_, min_power_));
        }
        else if(requested_orders > available_orders)
        {
          return(laurent_polynomial_view(coeffs_crbegin_,
            coeffs_crend_, min_power_));
        }
        else
        {
          return(laurent_polynomial_view(
            coeffs_crbegin_ + (available_orders - requested_orders),
            coeffs_crend_,
            min_power_
          ));
        }
      };

      /**
       * \brief Clone the view on this Laurent polynomial
       *
       * \return A laurent_polynomial_view on this polynomial
       */
      laurent_polynomial_view get_view() const
      {
        return(laurent_polynomial_view(*this));
      };

      /**
       * \brief Get the minimum exponent \f$n_0\f$ of the polynomial
       *
       * \return Minimum exponent
       */
      int min_power() const
      {
        return(min_power_);
      };

      /**
       * \brief Get the maximum exponent \f$N\f$ of the polynomial
       *
       * \details
       * If the polynomial is empty (i.e. it doesn't have any coefficients)
       * it returns min_power - 1
       *
       * \return Maximum exponent
       */
      int max_power() const
      {
        return(min_power_ + (coeffs_crend_ - coeffs_crbegin_ - 1));
      };

      /**
       * \brief Access to the coefficients of the Laurent polynomial
       *
       * \param pow Index of the coefficient to access
       *
       * \return Constant reference to the coefficient of \f$x^\mathtt{pow}\f$.
       */
      const coefficient_type& operator[](int pow) const
      {
        const int requested_position = pow - min_power_;
        const int size = coeffs_crend_ - coeffs_crbegin_;
        if(requested_position < 0 || requested_position >= size)
          return zero_value_;
        else
          return *(coeffs_crbegin_ + ((size-1) - requested_position));
      };

    protected:
      /// Reverse iterator pointing to the beginning of the coefficient vector
      const_reverse_iterator coeffs_crbegin_;
      /// Reverse iterator pointing to the end of the coefficient vector
      const_reverse_iterator coeffs_crend_;

      /**
       * \brief Default constructor 
       */
      laurent_polynomial_view(int min_power = 0)
        : min_power_(min_power) {};

    private:
      int min_power_;

      inline const static coefficient_type zero_value_{};
  };

  /**
   * \brief Potentially nested, evaluatable Laurent polynomial
   *
   * \details
   * This class implements a Laurent polynomial \f$p(x, \dots)\f$ (i.e. it can
   * have monomials with negative degree).
   * \f[
   *    p(x, \dots) = \sum_{n=n_0}^N x^i c_i(\dots)
   * \f]
   * The polynomial can be nested, which means that its coefficients \f$c_i\f$
   * can be callables. In particular, they can be laurent_polynomials. This
   * allows to implement multivariate polynomials. Coefficients are specified
   * at the time of construction and cannot be modified.
   *
   * \tparam Tnum Numerical data type. This is the type of the polynomial
   *         variable \f$x\f$, the type of the coefficients or the return type
   *         of evaluating the coefficients \f$c_i(\dots)\f$ and the type that
   *         the polynomial evaluates to.
   * \tparam Tcoeff Type of the coefficients \f$c_i\f$ of the polynomial. This
   *         can either be a numerical type that can be implicitly converted to
   *         Tnum or a callable that evaluates to Tnum when invoked.
   * \tparam Tcoefffargs Pack of types that specifies the types of the arguments
   *         when invoking Tcoeff. If Tcoeff is a numerical type (not a
   *         callable) this pack should be empty.
   */
  template<typename Tnum, typename Tcoeff, typename... Tcoeffargs>
  class laurent_polynomial
    : public laurent_polynomial_view<Tnum, Tcoeff, Tcoeffargs...>
  {
    public:
      /// Type alias for the underlying view from which we inherit
      using view_type = laurent_polynomial_view<Tnum, Tcoeff, Tcoeffargs...>;
      // Make type aliases from base class usable here
      using typename view_type::numeric_type;
      using typename view_type::coefficient_type;


      /**
       * \brief Construct a null polynomial (always evaluates to zero)
       */
      laurent_polynomial()
        : view_type(0),
          coefficients_()
      {
        this->coeffs_crbegin_ = coefficients_.crbegin();
        this->coeffs_crend_ = coefficients_.crend();
      };

      /**
       * \brief Construct Laurent polynomial from a vector of coefficients
       *
       * \param coefficients Vector of coefficients \f$c_i(\dots)\f$ of the
       *        polynomial. The first element is the coefficient of the
       *        lowest-order monomial \f$x^{n_0}\f$ and subsequent elements are
       *        the coefficients of the higher powers.
       * \param min_power Exponent of the lowest-order monomial (\f$n_0\f$).
       */
      laurent_polynomial(const std::vector<coefficient_type>& coefficients,
          int min_power = 0)
        : view_type(min_power),
          coefficients_(coefficients)
      {
        this->coeffs_crbegin_ = coefficients_.crbegin();
        this->coeffs_crend_ = coefficients_.crend();
      };

      /**
       * \brief Helper to construct a Laurent polynomial directly from an
       *        initalizer list.
       *
       * \details
       * See \ref laurent_polynomial(const std::vector<coefficient_type>&, int) for details.
       */
      laurent_polynomial(std::initializer_list<coefficient_type> coefficients,
          int min_power = 0)
        : view_type(min_power),
          coefficients_(coefficients)
      {
        this->coeffs_crbegin_ = coefficients_.crbegin();
        this->coeffs_crend_ = coefficients_.crend();
      };

      /**
       * \brief Copy constructor
       */
      laurent_polynomial(const laurent_polynomial& other)
        : view_type(other),
          coefficients_(other.coefficients_)
      {
        this->coeffs_crbegin_ = coefficients_.crbegin();
        this->coeffs_crend_ = coefficients_.crend();
      };

      /**
       * \brief Swap function
       */
      friend
      void swap(laurent_polynomial& first, laurent_polynomial& second)
      {
        // enable proper ADL
        using std::swap;

        // swap base class members
        swap(static_cast<view_type&>(first),static_cast<view_type&>(second));

        // swap local data members
        swap(first.coefficients_,second.coefficients_);

        // update iterators
        first.coeffs_crbegin_ = first.coefficients_.crbegin();
        first.coeffs_crend_   = first.coefficients_.crend();
        second.coeffs_crbegin_ = second.coefficients_.crbegin();
        second.coeffs_crend_   = second.coefficients_.crend();
      };

      /**
       * \brief Assignment operator
       */
      laurent_polynomial& operator=(laurent_polynomial other)
      {
        swap(*this, other);
        return(*this);
      };

      /**
       * \brief Move operator
       */
      laurent_polynomial(laurent_polynomial&& other)
        : laurent_polynomial()
      {
        swap(*this, other);
      };

    private:
      std::vector<coefficient_type> coefficients_;
  };

}

#endif