From 85c5505315fd61d11ae5a136577d8a2c039746e7 Mon Sep 17 00:00:00 2001 From: "Fedorov, Andrey" Date: Thu, 17 Mar 2022 17:47:01 +0300 Subject: [PATCH 01/10] add data_fitting domain to onemkl --- .../source/architecture/api_design.inc.rst | 23 +- .../source/domains/data_fitting/cubic.rst | 90 +++++ .../domains/data_fitting/data-fitting.inc.rst | 30 ++ .../source/domains/data_fitting/examples.rst | 10 + .../domains/data_fitting/interpolate.rst | 106 ++++++ .../source/domains/data_fitting/linear.rst | 66 ++++ .../source/domains/data_fitting/splines.rst | 177 ++++++++++ .../source/domains/data_fitting/terms.rst | 324 ++++++++++++++++++ .../oneMKL/source/domains/domains.rst | 1 + source/elements/oneMKL/source/index.rst | 2 +- 10 files changed, 817 insertions(+), 12 deletions(-) create mode 100644 source/elements/oneMKL/source/domains/data_fitting/cubic.rst create mode 100644 source/elements/oneMKL/source/domains/data_fitting/data-fitting.inc.rst create mode 100644 source/elements/oneMKL/source/domains/data_fitting/examples.rst create mode 100644 source/elements/oneMKL/source/domains/data_fitting/interpolate.rst create mode 100644 source/elements/oneMKL/source/domains/data_fitting/linear.rst create mode 100644 source/elements/oneMKL/source/domains/data_fitting/splines.rst create mode 100644 source/elements/oneMKL/source/domains/data_fitting/terms.rst diff --git a/source/elements/oneMKL/source/architecture/api_design.inc.rst b/source/elements/oneMKL/source/architecture/api_design.inc.rst index c6a98490b6..18ddbf35d2 100644 --- a/source/elements/oneMKL/source/architecture/api_design.inc.rst +++ b/source/elements/oneMKL/source/architecture/api_design.inc.rst @@ -16,17 +16,18 @@ oneMKL namespaces The oneMKL library uses C++ namespaces to organize routines by mathematical domain. All oneMKL objects and routines shall be contained within the ``oneapi::mkl`` base namespace. The individual oneMKL domains use a secondary namespace layer as follows: -======================== ======================================================================================================= -namespace oneMKL domain or content -======================== ======================================================================================================= -``oneapi::mkl`` oneMKL base namespace, contains general oneMKL data types, objects, exceptions and routines -``oneapi::mkl::blas`` Dense linear algebra routines from BLAS and BLAS like extensions. The oneapi::mkl::blas namespace should contain two namespaces column_major and row_major to support both matrix layouts. See :ref:`onemkl_blas` -``oneapi::mkl::lapack`` Dense linear algebra routines from LAPACK and LAPACK like extensions. See :ref:`onemkl_lapack` -``oneapi::mkl::sparse`` Sparse linear algebra routines from Sparse BLAS and Sparse Solvers. See :ref:`onemkl_sparse_linear_algebra` -``oneapi::mkl::dft`` Discrete and fast Fourier transformations. See :ref:`onemkl_dft` -``oneapi::mkl::rng`` Random number generator routines. See :ref:`onemkl_rng` -``oneapi::mkl::vm`` Vector mathematics routines, e.g. trigonometric, exponential functions acting on elements of a vector. See :ref:`onemkl_vm` -======================== ======================================================================================================= +=========================================== ========================================================================= +namespace oneMKL domain or content +=========================================== ========================================================================= +``oneapi::mkl`` oneMKL base namespace, contains general oneMKL data types, objects, exceptions and routines +``oneapi::mkl::blas`` Dense linear algebra routines from BLAS and BLAS like extensions. The oneapi::mkl::blas namespace should contain two namespaces column_major and row_major to support both matrix layouts. See :ref:`onemkl_blas` +``oneapi::mkl::lapack`` Dense linear algebra routines from LAPACK and LAPACK like extensions. See :ref:`onemkl_lapack` +``oneapi::mkl::sparse`` Sparse linear algebra routines from Sparse BLAS and Sparse Solvers. See :ref:`onemkl_sparse_linear_algebra` +``oneapi::mkl::dft`` Discrete and fast Fourier transformations. See :ref:`onemkl_dft` +``oneapi::mkl::rng`` Random number generator routines. See :ref:`onemkl_rng` +``oneapi::mkl::vm`` Vector mathematics routines, e.g. trigonometric, exponential functions acting on elements of a vector. See :ref:`onemkl_vm` +``oneapi::mkl::experimental::data_fitting`` Data fitting routines, e.g. interpolate. See :ref:`data_fitting` +=========================================== ========================================================================= .. note:: :name: Implementation Requirement diff --git a/source/elements/oneMKL/source/domains/data_fitting/cubic.rst b/source/elements/oneMKL/source/domains/data_fitting/cubic.rst new file mode 100644 index 0000000000..395045d2db --- /dev/null +++ b/source/elements/oneMKL/source/domains/data_fitting/cubic.rst @@ -0,0 +1,90 @@ +.. _cubic: + +Cubic Splines +============= + +.. contents:: + :local: + :depth: 2 + +Cubic splines are splines whose degree is equal to 3. + +Cubic splines are described by the following polynomial + +.. math:: + P_i\left( x \right) = c_{1,i}+ c_{2,i}\left( x - x_i \right) + c_{3,i}{\left( x - x_i \right)}^2+ c_{4,i}{\left( x - x_i \right)}^3, + +where + +.. math:: + x \in \left[ x_i, x_{i+1} \right), + +.. math:: + i = 1,\cdots , n-1. + +There are a lot of different types of cubic splines: Hermite, natural, Akima, Bessel. +However, the current version of DPC++ API supports only one type: Hermite. + +Header File +----------- + +.. code:: cpp + + #include + +Namespace +--------- + +.. code:: cpp + + oneapi::mkl::experimental::data_fitiing + +Hermite Spline +-------------- + +Coefficients of Hermite spline are calculated using the following formulas: + +.. math:: + c_{1,i} = f\left( x_i \right), + +.. math:: + c_{2,i} = s_i, + +.. math:: + c_{3,i} = \left( \left[ x_i, x_{i+1} \right]f - s_i \right) / \left( \Delta x_i \right) - c_{4,i}\left( \Delta x_i \right), + +.. math:: + c_{4,i} = \left( s_i + s_{i+1} - 2\left[ x_i, x_{i+1} \right]f \right) / {\left( \Delta x_i \right)}^2, + +.. math:: + s_i = f^{\left( 1 \right)}\left( x_i \right). + +The following boundary conditions are supported for Hermite spline: + + - Free end (:math:`f^{(2)}(x_1) = f^{(2)}(x_n) = 0`). + - Periodic. + - First derivative. + - Second Derivative. + +Syntax +^^^^^^ + +.. code:: cpp + + namespace cubic_spline { + struct hermite {}; + } + +Example +^^^^^^^ + +To create a cubic Hermite spline object use the following: + +.. code:: cpp + + spline val( + /*SYCL queue object*/q, + /*number of spline functions*/ny + ); + +Follow the :ref:`examples` section to see more complicated examples. diff --git a/source/elements/oneMKL/source/domains/data_fitting/data-fitting.inc.rst b/source/elements/oneMKL/source/domains/data_fitting/data-fitting.inc.rst new file mode 100644 index 0000000000..4fef7fa8a8 --- /dev/null +++ b/source/elements/oneMKL/source/domains/data_fitting/data-fitting.inc.rst @@ -0,0 +1,30 @@ +.. _data-fitting: + +Data Fitting +============ + +|IONE-MKL| provides spline-based interpolation capabilities that can be used for +spline construction (Linear, Cubic, Quadratic etc.), +to perform cell-search operations, and to approximate functions, +function derivatives, or integrals. + +APIs are experimental. It means that no API or ABI backward compatibility are guaranteed. + +APIs are based on SYCL USM (Unfied Shared Memory) input data. + +Routines +-------- + +Splines: + :ref:`splines` +Interpolate function: + :ref:`interpolate` + +.. toctree:: + :maxdepth: 1 + :hidden: + + data_fitting/terms + data_fitting/splines + data_fitting/interpolate + data_fitting/examples diff --git a/source/elements/oneMKL/source/domains/data_fitting/examples.rst b/source/elements/oneMKL/source/domains/data_fitting/examples.rst new file mode 100644 index 0000000000..bd09b69d0c --- /dev/null +++ b/source/elements/oneMKL/source/domains/data_fitting/examples.rst @@ -0,0 +1,10 @@ +.. _examples: + +Examples +======== + +The following example demonstrates how to construct the linear spline and perform the interpolation. + +.. literalinclude:: /_examples/data_fitting_linear.cpp + :language: cpp + :linenos: diff --git a/source/elements/oneMKL/source/domains/data_fitting/interpolate.rst b/source/elements/oneMKL/source/domains/data_fitting/interpolate.rst new file mode 100644 index 0000000000..a53c925141 --- /dev/null +++ b/source/elements/oneMKL/source/domains/data_fitting/interpolate.rst @@ -0,0 +1,106 @@ +.. _interpolate: + +Interpolate Function +==================== + +.. contents:: + :local: + :depth: 1 + +Interpolate function performs computations of function and derivatives values at interpolation sites. + +If the sites do not belong to interpolation interval ``[a, b]``, the library uses: + + - interpolant :math:`I_0` coefficients computed for interval :math:`[x_0, x_1)` for the + computations at the sites to the left of ``a``. + - interpolant :math:`I_{n-2}` coefficients computed for interval + :math:`[x_{n-2}, x_{n-1})` for the computations at the sites to the right of ``b``. + +Interpolation algorithm depends on interpolant's type (e.g., for cubic spline +interpoilation evaluation of third-order polynomial is performed to obtain function values). + +Header File +----------- + +.. code:: cpp + + #include + +Namespace +--------- + +.. code:: cpp + + oneapi::mkl::experimental::data_fitiing + +Syntax +------ + +.. code:: cpp + + template + sycl::event interpolate( + Interpolant& interpolant, + typename Interpolant::fp_type* sites, + std::int64_t n_sites, + typename Interpolant::fp_type* results, + const std::vector& dependencies, + interpolate_hint ResultHint = interpolate_hint::funcs_sites_ders, + site_hint SiteHint = site_hint::non_uniform); // (1) + + template + sycl::event interpolate( + Interpolant& interpolant, + typename Interpolant::fp_type* sites, + std::int64_t n_sites, + typename Interpolant::fp_type* results, + std::bitset<32> der_indicator, + const std::vector& dependencies = {}, + interpolate_hint ResultHint = interpolate_hint::funcs_sites_ders, + site_hint SiteHint = site_hint::non_uniform); // (2) + + template + sycl::event interpolate( + sycl::queue& q, + const Interpolant& interpolant, + typename Interpolant::fp_type* sites, + std::int64_t n_sites, + typename Interpolant::fp_type* results, + const std::vector& dependencies, + interpolate_hint ResultHint = interpolate_hint::funcs_sites_ders, + site_hint SiteHint = site_hint::non_uniform); // (3) + + template + sycl::event interpolate( + sycl::queue& q, + const Interpolant& interpolant, + typename Interpolant::fp_type* sites, + std::int64_t n_sites, + typename Interpolant::fp_type* results, + std::bitset<32> der_indicator, + const std::vector& dependencies = {}, + interpolate_hint ResultHint = interpolate_hint::funcs_sites_ders, + site_hint SiteHint = site_hint::non_uniform); // (4) + +For all functions users can provide ``SiteHint`` and ``ResultHint`` to specify +the layout of ``sites`` and ``results`` respectively. +If ``results`` layout doesn't satisfy ``ResultHint`` and/or +``sites`` layout doesn't satisfy ``SiteHint``, behavior is undefined. +Returns the SYCL event of the submitted task. + +#. Performs computations of function values only using the SYCL queue + associated with ``interpolant``. +#. Performs computations of certain derivatives + (function values is considered as a zero derivative) which are indicated in + ``der_indicator`` (each bit corresponds to certain derivative starting from lower bit) + using the SYCL queue associated with ``interpolant``. +#. Performs computations of function values only using ``q`` as an input argument + that should be created from the same context and device as the SYCL queue + associated with ``interpolant``. +#. Performs computations of certain derivatives + (function values is considered as a zero derivative) which are indicated in + ``der_indicator`` (each bit corresponds to certain derivative starting from lower bit) + using ``q`` as an input argument that should be created from + the same context and device as the SYCL queue associated with ``interpolant``. + +Follow the :ref:`examples` section to see examples of the interpolation function usage. diff --git a/source/elements/oneMKL/source/domains/data_fitting/linear.rst b/source/elements/oneMKL/source/domains/data_fitting/linear.rst new file mode 100644 index 0000000000..8cd53780b4 --- /dev/null +++ b/source/elements/oneMKL/source/domains/data_fitting/linear.rst @@ -0,0 +1,66 @@ +.. _linear: + +Linear Spline +============= + +.. contents:: + :local: + :depth: 1 + +Linear spline is a spline whose degree is equal to 1. + +It's described by the following polynomial + +.. math:: + P_i\left( x \right) = c_{1,i} + c_{2,i}\left( x - x_i \right), + +where + +.. math:: + x \in \left[ x_i, x_{i+1} \right), + +.. math:: + c_{1,i} = f\left( x_i \right), + +.. math:: + c_{2,i} = \left[ x_i, x_{i+1} \right]f, + +.. math:: + i = 1, \cdots, n-1. + +Header File +----------- + +.. code:: cpp + + #include + +Namespace +--------- + +.. code:: cpp + + oneapi::mkl::experimental::data_fitiing + +Syntax +------ + +.. code:: cpp + + namespace linear_spline { + struct default_type {}; + } + +Example +------- + +To create a linear spline object use the following: + +.. code:: cpp + + spline val( + /*SYCL queue object*/q, + /*number of spline functions*/ny + ); + +Follow the :ref:`examples` section to see more complicated examples. diff --git a/source/elements/oneMKL/source/domains/data_fitting/splines.rst b/source/elements/oneMKL/source/domains/data_fitting/splines.rst new file mode 100644 index 0000000000..60d1afc1e1 --- /dev/null +++ b/source/elements/oneMKL/source/domains/data_fitting/splines.rst @@ -0,0 +1,177 @@ +.. _splines: + +Splines +======= + +.. contents:: + :local: + :depth: 1 + +Header File +----------- + +.. code:: cpp + + #include + +Namespace +--------- + +.. code:: cpp + + oneapi::mkl::experimental::data_fitiing + +Common API for All Spline Types +------------------------------- + +.. code:: cpp + + template < + typename FpType, + typename SplineType, + int Dimensions = 1> + class spline { + public: + using value_type = FpType; + using spline_type = SplineType; + + spline( + const sycl::queue& q, + std::int64_t ny = 1); + + spline( + const sycl::device& dev, + const sycl::context& ctx, + std::int64_t ny = 1); + + ~spline(); + + spline(const spline& other) = delete; + spline(spline&& other) = delete; + spline& operator=( + const spline& other) = delete; + spline& operator=( + spline&& other) = delete; + + spline& set_partitions( + FpType* input_data, + std::int64_t nx, + partition_hint PartitionHint = partition_hint::non_uniform); + + spline& set_function_values( + FpType* input_data, + function_hint FunctionHint = storage_hint::row_major); + + spline& set_coefficients( + FpType* data, + coefficient_hint CoeffHint = storage_hint::row_major); + + bool is_initialized() const; + + std::int64_t get_required_coeffs_size() const; + + sycl::event construct(const std::vector& dependencies = {}); + }; + +An instance of ``spline`` create the ``N``-dimensional spline +that operates with the ``T`` data type. ``ST`` is a type of spline. +``T`` can only be ``float`` or ``double``. + +.. list-table:: + :header-rows: 1 + + * - Constructor + - Description + * - ``spline(const sycl::queue& q, std::int64_t ny = 1);`` + - Create an object with the ``q`` SYCL queue and ``ny`` number of functions. + * - ``spline(const sycl::device& dev, const sycl::context& ctx, std::int64_t ny = 1);`` + - Create an object using the ``dev`` SYCL device, the ``ctx`` context + and ``ny`` number of functions. + +.. list-table:: + :header-rows: 1 + + * - Member function + - Description + * - ``spline& set_partitions(FpType* input_data, std::int64_t nx, partition_hint PartitionHint = partition_hint::non_uniform);`` + - Set partition values that are specified by the ``input_data`` memory pointer and ``nx`` partition values. + Users can provide ``PartitionHint`` to specify the layout of data. + Default layout is ``non_uniform``. + If ``uniform`` is specified, ``nx`` must equals to ``2`` and + ``input_data`` must contain only 2 values the left and the right borders of partition. + Otherwise, behavior is undefined. + If ``input_data`` layout doesn't satisfy ``PartitionHint``, behavior is undefined. + Returns a reference to the spline object for which partitions are set. + + Example, for ``uniform``. Let :math:`\left\{ i \right\}_{i=1,\cdots,n}` is a partition. + So, ``input_data`` must contain only 2 values: 1, ``n``. + * - ``spline& set_function_values(FpType* input_data, function_hint FunctionHint = storage_hint::row_major);`` + - Set function values that are specified by the ``input_data`` memory pointer. + Number of function values must equals to ``ny * nx`` elements. + Users can provide ``FunctionHint`` to specify the layout of data. + Default layout is ``row_major``. + If ``input_data`` layout doesn't satisfy ``FunctionHint``, behavior is undefined. + Returns a reference to the spline object for which function values are set. + * - ``spline& set_coefficients(FpType* data, coefficient_hint CoeffHint = storage_hint::row_major);`` + - Set coefficients that are specified by the ``data`` memory pointer. + Number of coefficients in the memory must equals to the return value of ``get_required_coeffs_size()``. + Users can provide ``CoeffHint`` to specify the layout of data. + Default layout is ``row_major``. + If ``data`` layout doesn't satisfy ``CoeffHint``, behavior is undefined. + Returns a reference to the spline object for which coefficients are set. + * - ``bool is_initialized() const;`` + - Returns ``true`` if all required data are set (for example, partitions, function values, coefficients). + * - ``std::int64_t get_required_coeffs_size() const;`` + - Returns amount of memory that is required for coefficients storage. + * - ``sycl::event construct(const std::vector& dependencies = {});`` + - Constructs the spline (calculates spline coefficients). + The function submits a SYCL kernel and returns the SYCL event to wait on to ensure computation is complete. + ``dependencies`` is a list of SYCL events to wait for before starting computations. + +There are some splines that requires internal conditions and boundary conditions to be set. +For such spline types, the following member functions must be called. + +.. code:: cpp + + spline& set_internal_conditions( + FpType* input_data); + + spline& set_boundary_conditions( + bc_type BCType = bc_type::free_end, + FpType input_value = {}); + +.. list-table:: + :header-rows: 1 + + * - Member function + - Description + * - ``spline& set_internal_conditions(FpType* input_data);`` + - Set internal conditions that are specified by the ``input_data`` memory pointer. + Number of internal condition values must equals to ``nx - 2``. + Returns a reference to the spline object for which internal conditions are set. + * - ``spline& set_boundary_conditions(bc_type BCType = bc_type::free_end, FpType input_value = {});`` + - Set the ``input_value`` boundary condition corresponding to ``BCType``. + Default value for ``input_value`` is empty since some boundary conditions doesn't require value to be provided. + Returns a reference to the spline object for which boundary condition value is set. + +.. note:: + copy/move constructor and copy/move assignment operators are deleted + since the ``spline`` class is just a wrapper over memory that users provide. + Memory management responsibility is on user's side. + +Supported Spline Types +---------------------- + +Currently, the DPC++ Data Fitting APIs support the following spline types +(follow the corresponding links to deep-dive into the details): + +:ref:`linear` + +:ref:`cubic` + +.. toctree:: + :maxdepth: 1 + :hidden: + + linear + cubic diff --git a/source/elements/oneMKL/source/domains/data_fitting/terms.rst b/source/elements/oneMKL/source/domains/data_fitting/terms.rst new file mode 100644 index 0000000000..3e48bf9329 --- /dev/null +++ b/source/elements/oneMKL/source/domains/data_fitting/terms.rst @@ -0,0 +1,324 @@ +.. _terms: + +Common Terms +============ + +.. contents:: + :local: + :depth: 2 + +Glossary +-------- + +Assume we need to interpolate a function ``f(x)`` on the ``[a, b)`` interval using splines. + +Let's break ``[a, b)`` into sub-intervals by ``n`` points :math:`x_i` +called partition points or simply **partition**. +**Function values** at these points (:math:`y_i = f(x_i), i=1,\cdots,n`) are also given. + +Spline has ``k`` degree if it can be expressed by the following polynomial: + +.. math:: + P\left( x \right) = + c_{1} + + c_{2}\left( x - x_i \right) + + c_{3}{\left( x - x_i \right)}^2 + \cdots + + c_{k-1}{\left( x - x_i \right)}^k. + +Splines are constructed on :math:`[x_i, x_{i+1}), i=1,\cdots,n-1` sub-intervals. +So, for each sub-interval there are following polynomials: + +.. math:: + P_i\left( x \right) = + c_{1,i} + + c_{2,i}\left( x - x_i \right) + + c_{3,i}{\left( x - x_i \right)}^2 + \cdots + + c_{k-1,i}{\left( x - x_i \right)}^k. + +:math:`c_{j,i}, j=1,\cdots,k, i=1,\cdots,n` are called spline **coefficients**. + +Function is interpolated at points of [a, b). +Such points are called interpolation sites or simply **sites**. Sites might or migtn't equals to partition points. + +Mathematical Notation in the Data Fitting Component +--------------------------------------------------- + +.. list-table:: + :header-rows: 1 + + * - Concept + - Mathematical Notation + * - Partition + - :math:`\left\{ x_i \right\}_{i=1,\cdots,n}`, + where :math:`a = x1 < x2< \cdots < xn = b`.. + * - Uniform partition + - Partition :math:`\left\{ x_i \right\}_{i=1,\cdots,n}` + which meets the following condition: + + :math:`x_{i+1} - x_i = x_i - x_{i-1}, i=2,\cdots,n-1` + * - Quasi-uniform partition + - Partition :math:`\left\{ x_i \right\}_{i=1,\cdots,n}` + which meets the constraint with a constant ``C`` defined as: + :math:`1 \le M / m \le C`, + + where + + :math:`M = max_{i=1,\cdots,n-1} (\Delta_i)`, + + :math:`m = min_{i=1,\cdots,n-1} (\Delta_i)`, + + :math:`\Delta_i = x_{i+1} - x_i` + * - Vector-valued function of dimension ``p`` being fit + - :math:`f(x) = (f_1(x),\cdots, f_p(x))`. + * - A ``k``-order derivative of function ``f(x)`` at point ``t`` + - :math:`f^{(k)}(t)`. + * - Function ``p`` agrees with function ``f`` at the points + :math:`\left\{ x_i \right\}_{i=1,\cdots,n}`. + - For every point :math:`\zeta` in sequence :math:`\left\{ x_i \right\}_{i=1,\cdots,n}` + that occurs ``m`` times, the equality :math:`p^{(i-1)}(\zeta) = f^{(i-1)}(\zeta)` + holds for all :math:`i=1,\cdots,m`. + * - The ``k``-th divided difference of function ``f`` at points :math:`x_i,..., x_{i+k}`. + This difference is the leading coefficient of the polynomial of order ``k+1`` + that agrees with ``f`` at :math:`x_i,\cdots, x_{i+k}`. + - :math:`\left[ x_i,\cdots, x_{i + k} \right]f`. + + In particular, + + :math:`\left[ x_1 \right]f = f(x_1)`, + + :math:`\left[ x_1, x_2 \right] f = (f(x_1) - f(x_2)) / (x_1 - x_2)`. + +Hints in the Data Fitting Component +----------------------------------- + +The |IONE-MKL| Data Fitting component provides ways to specify some "hints" +for partitions, function values, coefficients, interpolation sites. + +Partition Hints +^^^^^^^^^^^^^^^ + +The following are supported: + + - Non-uniform. + - Quasi-uniform. + - Uniform. + +**Syntax** + +.. code:: cpp + + enum class partition_hint { + non_uniform, + quasi_uniform, + uniform + }; + +Function Values Hints +^^^^^^^^^^^^^^^^^^^^^ + +Let :math:`\left\{ x_i \right\}_{i=1,\cdots,nx}` is a partition, +:math:`\left\{ f_j(x) \right\}_{j=1,\cdots,ny}` is a vector-valued function. +Function values are stored in the one-dimensional array with ``nx * ny`` elements. +2 different layouts are possible: row major and column major. + +- For row major layout function values are stored as the following: + + Let :math:`\left\{ f_{j,i} \right\}_{j=1,\cdots,ny, i=1,\cdots,nx}` + is the function value that corresponds to the ``i-th`` partition point and the ``j-th`` function. + +- For column major: + + Let :math:`\left\{ f_{i,j} \right\}_{i=1,\cdots,nx, j=1,\cdots,ny}` + is the function value that corresponds to the ``i-th`` partition point and the ``j-th`` function. + +The following hints are supported: + + - Row major. + - Column major. + +**Syntax** + +.. code:: cpp + + enum class function_hint { + row_major, + col_major + }; + +Coefficients Hints +^^^^^^^^^^^^^^^^^^ + +Let :math:`\left\{ x_i \right\}_{i=1,\cdots,nx}` is a partition, +:math:`\left\{ f_j(x) \right\}_{j=1,\cdots,ny}` is a vector-valued function. +Let cubic spline should be constructed. It means that it requires 4 coefficients +per each interpolation interval and function value. +Cofficients are stored in the one-dimensional array with ``4 * (nx - 1) * ny`` elements. + +- For row major: + + Let :math:`\left\{ c_{j,i,k} \right\}_{j=1,\cdots,ny, i=1,\cdots,nx-1, k=1,\cdots,4}` + is the coefficient value that corresponds to the ``i-th`` partition point, the ``j-th`` function. + +- For column major: + + Let :math:`\left\{ c_{i,j,k} \right\}_{i=1,\cdots,nx-1, j=1,\cdots,ny, k=1,\cdots,4}` + is the coefficient value that corresponds to the ``i-th`` partition point, the ``j-th`` function. + +The following is supported: + + - row major + +**Syntax** + +.. code:: cpp + + enum class coefficient_hint { + row_major + }; + +Sites Hints +^^^^^^^^^^^ + +The following are supported: + + - Non-uniform. + - Uniform. + - Sorted. + +**Syntax** + +.. code:: cpp + + enum class site_hint { + non_uniform, + uniform, + sorted + }; + +Interpolation Results Hints +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Let :math:`\left\{ f_j(x) \right\}_{j=1,\cdots,ny}` is a vector-valued function, +:math:`\left\{ s_i \right\}_{i=1,\cdots,ns}` are sites, ``d`` is a number of derivatives (including interpolation values) that needs to be calculated. +So, size of memory to store interpolation results is ``nsite * ny * d`` elements. + +6 different layouts are possible: + + - functions-sites-derivatives + + Let :math:`\left\{ r_{j,i,k} \right\}_{j=1,\cdots,ny, i=1,\cdots,nsite, k=1,\cdots,d}` + is an interpolation result that corresponds to the ``i-th`` site, + the ``j-th`` function, the ``k-th`` derivative. + + - functions-derivatives-sites + + Let :math:`\left\{ r_{j,k,i} \right\}_{j=1,\cdots,ny, k=1,\cdots,d, i=1,\cdots,nsite}` + is an interpolation result that corresponds to the ``i-th`` site, + the ``j-th`` function, the ``k-th`` derivative. + + - sites-functions-derivatives + + Let :math:`\left\{ r_{i,j,k} \right\}_{i=1,\cdots,nsite, j=1,\cdots,ny, k=1,\cdots,d}` + is an interpolation result that corresponds to the ``i-th`` site, + the ``j-th`` function, the ``k-th`` derivative. + + - sites-derivatives-functions + + Let :math:`\left\{ r_{i,k,j} \right\}_{i=1,\cdots,nsite, k=1,\cdots,d, j=1,\cdots,ny}` + is an interpolation result that corresponds to the ``i-th`` site, + the ``j-th`` function, the ``k-th`` derivative. + + - derivatives-functions-sites + + Let :math:`\left\{ r_{k,j,i} \right\}_{k=1,\cdots,d, j=1,\cdots,ny, i=1,\cdots,nsite}` + is an interpolation result that corresponds to the ``i-th`` site, + the ``j-th`` function, the ``k-th`` derivative. + + - derivatives-sites-functions + + Let :math:`\left\{ r_{k,i,j} \right\}_{k=1,\cdots,d, i=1,\cdots,nsite, j=1,\cdots,ny}` + is an interpolation result that corresponds to the ``i-th`` site, + the ``j-th`` function, the ``k-th`` derivative. + + +The following are supported: + + - functions-sites-derivatives + - functions-derivatives-sites + - sites-functions-derivatives + - sites-derivatives-functions + +**Syntax** + +.. code:: cpp + + enum class interpolate_hint { + funcs_sites_ders, + funcs_ders_sites, + sites_funcs_ders, + sites_ders_funcs + }; + +Derivatives Hints +^^^^^^^^^^^^^^^^^ + +Following hints are added to choose which derivtive orders +need to be computed during the ``interpolate`` function: + + - just compute interpolation values + - compute first derivative of the spline polynomial only + - compute second derivative of the spline polynomial only + - compute third derivative of the spline polynomial only + +**Syntax** + +.. code:: cpp + + enum class derivatives { + zero, + first, + second, + third + }; + +``operator|`` is overloaded to create combinations of derivative orders +to be computed by ``interpolate``. + +**Example** + +Assume that interpolation values, 1-st and 3-rd derivatives need to be computed. +To create a bit mask that is passed to ``interpolate`` it needs following: + +.. code:: cpp + + std::bitset<32> bit_mask = derivatives::zero | derivatives::first | derivatives::third; + +Boundary Condition Types +------------------------ + +Some type of splines requires boundary conditions to be set. +The following types are supported: + + - Free end (:math:`f^{(2)}(x_1) = f^{(2)}(x_n) = 0`). + - Periodic. + - First derivative. + - Second Derivative. + +**Syntax** + +.. code:: cpp + + enum class bc_type { + free_end, + first_left_der, + first_right_der, + second_left_der, + second_right_der, + periodic + }; + +.. note:: + + #. First derivative and second derivative types + must be set on the left and on the right borders. + #. Free end doesn't require any values to be set. diff --git a/source/elements/oneMKL/source/domains/domains.rst b/source/elements/oneMKL/source/domains/domains.rst index 1a4f04c337..c98ca19f62 100644 --- a/source/elements/oneMKL/source/domains/domains.rst +++ b/source/elements/oneMKL/source/domains/domains.rst @@ -15,4 +15,5 @@ This section describes the Data Parallel C++ (DPC++) interface. .. include:: rng/random_number_generators.inc.rst .. include:: stats/stats.inc.rst .. include:: vm/vector_math.inc.rst +.. include:: data_fitting/data-fitting.inc.rst diff --git a/source/elements/oneMKL/source/index.rst b/source/elements/oneMKL/source/index.rst index 2ca635aa05..840cb45759 100644 --- a/source/elements/oneMKL/source/index.rst +++ b/source/elements/oneMKL/source/index.rst @@ -8,7 +8,7 @@ oneMKL ====== -The |mkl_full_name| (oneMKL) defines a set of fundamental mathematical routines for use in high-performance computing and other applications. As part of oneAPI, oneMKL is designed to allow execution on a wide variety of computational devices: CPUs, GPUs, FPGAs, and other accelerators. The functionality is subdivided into several domains: dense linear algebra, sparse linear algebra, discrete Fourier transforms, random number generators and vector math. +The |mkl_full_name| (oneMKL) defines a set of fundamental mathematical routines for use in high-performance computing and other applications. As part of oneAPI, oneMKL is designed to allow execution on a wide variety of computational devices: CPUs, GPUs, FPGAs, and other accelerators. The functionality is subdivided into several domains: dense linear algebra, sparse linear algebra, discrete Fourier transforms, random number generators, vector math and data fitting. The general assumptions, design features and requirements for the oneMKL library and host-to-device computational routines will be described in :ref:`onemkl_architecture`. From 3bea0b8a099dc03bf7ffa2c0dc8aca44f5113d54 Mon Sep 17 00:00:00 2001 From: "Fedorov, Andrey" Date: Fri, 18 Mar 2022 16:41:04 +0300 Subject: [PATCH 02/10] address feedbacks --- .../source/architecture/api_design.inc.rst | 2 +- .../source/domains/data_fitting/cubic.rst | 10 +- .../domains/data_fitting/data-fitting.inc.rst | 2 +- .../domains/data_fitting/interpolate.rst | 20 ++- .../source/domains/data_fitting/linear.rst | 6 +- .../source/domains/data_fitting/splines.rst | 33 ++--- .../source/domains/data_fitting/terms.rst | 122 +++++++++--------- 7 files changed, 88 insertions(+), 107 deletions(-) diff --git a/source/elements/oneMKL/source/architecture/api_design.inc.rst b/source/elements/oneMKL/source/architecture/api_design.inc.rst index 18ddbf35d2..93ae50ec79 100644 --- a/source/elements/oneMKL/source/architecture/api_design.inc.rst +++ b/source/elements/oneMKL/source/architecture/api_design.inc.rst @@ -26,7 +26,7 @@ namespace oneMKL domain or content ``oneapi::mkl::dft`` Discrete and fast Fourier transformations. See :ref:`onemkl_dft` ``oneapi::mkl::rng`` Random number generator routines. See :ref:`onemkl_rng` ``oneapi::mkl::vm`` Vector mathematics routines, e.g. trigonometric, exponential functions acting on elements of a vector. See :ref:`onemkl_vm` -``oneapi::mkl::experimental::data_fitting`` Data fitting routines, e.g. interpolate. See :ref:`data_fitting` +``oneapi::mkl::experimental::data_fitting`` Data fitting routines, e.g. interpolation. See :ref:`data_fitting` =========================================== ========================================================================= .. note:: diff --git a/source/elements/oneMKL/source/domains/data_fitting/cubic.rst b/source/elements/oneMKL/source/domains/data_fitting/cubic.rst index 395045d2db..d3306c099e 100644 --- a/source/elements/oneMKL/source/domains/data_fitting/cubic.rst +++ b/source/elements/oneMKL/source/domains/data_fitting/cubic.rst @@ -3,10 +3,6 @@ Cubic Splines ============= -.. contents:: - :local: - :depth: 2 - Cubic splines are splines whose degree is equal to 3. Cubic splines are described by the following polynomial @@ -20,9 +16,9 @@ where x \in \left[ x_i, x_{i+1} \right), .. math:: - i = 1,\cdots , n-1. + i = 1,\dots , n-1. -There are a lot of different types of cubic splines: Hermite, natural, Akima, Bessel. +There are many different kinds of cubic splines: Hermite, natural, Akima, Bessel. However, the current version of DPC++ API supports only one type: Hermite. Header File @@ -42,7 +38,7 @@ Namespace Hermite Spline -------------- -Coefficients of Hermite spline are calculated using the following formulas: +The coefficients of Hermite spline are calculated using the following formulas: .. math:: c_{1,i} = f\left( x_i \right), diff --git a/source/elements/oneMKL/source/domains/data_fitting/data-fitting.inc.rst b/source/elements/oneMKL/source/domains/data_fitting/data-fitting.inc.rst index 4fef7fa8a8..5963942967 100644 --- a/source/elements/oneMKL/source/domains/data_fitting/data-fitting.inc.rst +++ b/source/elements/oneMKL/source/domains/data_fitting/data-fitting.inc.rst @@ -3,7 +3,7 @@ Data Fitting ============ -|IONE-MKL| provides spline-based interpolation capabilities that can be used for +oneMKL provides spline-based interpolation capabilities that can be used for spline construction (Linear, Cubic, Quadratic etc.), to perform cell-search operations, and to approximate functions, function derivatives, or integrals. diff --git a/source/elements/oneMKL/source/domains/data_fitting/interpolate.rst b/source/elements/oneMKL/source/domains/data_fitting/interpolate.rst index a53c925141..7b89e7faba 100644 --- a/source/elements/oneMKL/source/domains/data_fitting/interpolate.rst +++ b/source/elements/oneMKL/source/domains/data_fitting/interpolate.rst @@ -3,21 +3,17 @@ Interpolate Function ==================== -.. contents:: - :local: - :depth: 1 - Interpolate function performs computations of function and derivatives values at interpolation sites. -If the sites do not belong to interpolation interval ``[a, b]``, the library uses: +If the sites do not belong to interpolation interval ``[a, b)``, the library uses: - interpolant :math:`I_0` coefficients computed for interval :math:`[x_0, x_1)` for the computations at the sites to the left of ``a``. - interpolant :math:`I_{n-2}` coefficients computed for interval :math:`[x_{n-2}, x_{n-1})` for the computations at the sites to the right of ``b``. -Interpolation algorithm depends on interpolant's type (e.g., for cubic spline -interpoilation evaluation of third-order polynomial is performed to obtain function values). +Interpolation algorithm depends on interpolant's type (e.g., for a cubic spline, +the evaluation of a third-order polynomial is performed to obtain the resulting interpolant value). Header File ----------- @@ -31,7 +27,7 @@ Namespace .. code:: cpp - oneapi::mkl::experimental::data_fitiing + oneapi::mkl::experimental::data_fitting Syntax ------ @@ -61,7 +57,7 @@ Syntax template sycl::event interpolate( - sycl::queue& q, + sycl::queue& queue, const Interpolant& interpolant, typename Interpolant::fp_type* sites, std::int64_t n_sites, @@ -72,7 +68,7 @@ Syntax template sycl::event interpolate( - sycl::queue& q, + sycl::queue& queue, const Interpolant& interpolant, typename Interpolant::fp_type* sites, std::int64_t n_sites, @@ -94,13 +90,13 @@ Returns the SYCL event of the submitted task. (function values is considered as a zero derivative) which are indicated in ``der_indicator`` (each bit corresponds to certain derivative starting from lower bit) using the SYCL queue associated with ``interpolant``. -#. Performs computations of function values only using ``q`` as an input argument +#. Performs computations of function values only using ``queue`` as an input argument that should be created from the same context and device as the SYCL queue associated with ``interpolant``. #. Performs computations of certain derivatives (function values is considered as a zero derivative) which are indicated in ``der_indicator`` (each bit corresponds to certain derivative starting from lower bit) - using ``q`` as an input argument that should be created from + using ``queue`` as an input argument that should be created from the same context and device as the SYCL queue associated with ``interpolant``. Follow the :ref:`examples` section to see examples of the interpolation function usage. diff --git a/source/elements/oneMKL/source/domains/data_fitting/linear.rst b/source/elements/oneMKL/source/domains/data_fitting/linear.rst index 8cd53780b4..409b73828c 100644 --- a/source/elements/oneMKL/source/domains/data_fitting/linear.rst +++ b/source/elements/oneMKL/source/domains/data_fitting/linear.rst @@ -3,10 +3,6 @@ Linear Spline ============= -.. contents:: - :local: - :depth: 1 - Linear spline is a spline whose degree is equal to 1. It's described by the following polynomial @@ -26,7 +22,7 @@ where c_{2,i} = \left[ x_i, x_{i+1} \right]f, .. math:: - i = 1, \cdots, n-1. + i = 1, \dots, n-1. Header File ----------- diff --git a/source/elements/oneMKL/source/domains/data_fitting/splines.rst b/source/elements/oneMKL/source/domains/data_fitting/splines.rst index 60d1afc1e1..c7b6815972 100644 --- a/source/elements/oneMKL/source/domains/data_fitting/splines.rst +++ b/source/elements/oneMKL/source/domains/data_fitting/splines.rst @@ -3,10 +3,6 @@ Splines ======= -.. contents:: - :local: - :depth: 1 - Header File ----------- @@ -36,12 +32,12 @@ Common API for All Spline Types using spline_type = SplineType; spline( - const sycl::queue& q, + const sycl::queue& queue, std::int64_t ny = 1); spline( - const sycl::device& dev, - const sycl::context& ctx, + const sycl::device& device, + const sycl::context& context, std::int64_t ny = 1); ~spline(); @@ -82,10 +78,10 @@ that operates with the ``T`` data type. ``ST`` is a type of spline. * - Constructor - Description - * - ``spline(const sycl::queue& q, std::int64_t ny = 1);`` - - Create an object with the ``q`` SYCL queue and ``ny`` number of functions. - * - ``spline(const sycl::device& dev, const sycl::context& ctx, std::int64_t ny = 1);`` - - Create an object using the ``dev`` SYCL device, the ``ctx`` context + * - ``spline(const sycl::queue& queue, std::int64_t ny = 1);`` + - Create an object with the ``queue`` SYCL queue and ``ny`` number of functions. + * - ``spline(const sycl::device& device, const sycl::context& context, std::int64_t ny = 1);`` + - Create an object using the ``device`` SYCL device, the ``context`` context and ``ny`` number of functions. .. list-table:: @@ -97,26 +93,25 @@ that operates with the ``T`` data type. ``ST`` is a type of spline. - Set partition values that are specified by the ``input_data`` memory pointer and ``nx`` partition values. Users can provide ``PartitionHint`` to specify the layout of data. Default layout is ``non_uniform``. - If ``uniform`` is specified, ``nx`` must equals to ``2`` and - ``input_data`` must contain only 2 values the left and the right borders of partition. + If ``uniform`` is specified, ``nx`` must be equal to ``2`` and + ``input_data`` must contain only 2 values corresponding to the left and the right borders + of the sub-interval defined by the partition. Otherwise, behavior is undefined. If ``input_data`` layout doesn't satisfy ``PartitionHint``, behavior is undefined. Returns a reference to the spline object for which partitions are set. - Example, for ``uniform``. Let :math:`\left\{ i \right\}_{i=1,\cdots,n}` is a partition. + Example, for ``uniform``. Let :math:`\left\{ i \right\}_{i=1,\dots,n}` be a partition. So, ``input_data`` must contain only 2 values: 1, ``n``. * - ``spline& set_function_values(FpType* input_data, function_hint FunctionHint = storage_hint::row_major);`` - Set function values that are specified by the ``input_data`` memory pointer. - Number of function values must equals to ``ny * nx`` elements. - Users can provide ``FunctionHint`` to specify the layout of data. - Default layout is ``row_major``. + Number of function values must be ``ny * nx`` elements. + Users can provide a ``FunctionHint`` to specify the layout of data with a default value of ``row_major``. If ``input_data`` layout doesn't satisfy ``FunctionHint``, behavior is undefined. Returns a reference to the spline object for which function values are set. * - ``spline& set_coefficients(FpType* data, coefficient_hint CoeffHint = storage_hint::row_major);`` - Set coefficients that are specified by the ``data`` memory pointer. Number of coefficients in the memory must equals to the return value of ``get_required_coeffs_size()``. - Users can provide ``CoeffHint`` to specify the layout of data. - Default layout is ``row_major``. + Users can provide a ``CoeffHint`` to specify the layout of data with a default value of ``row_major``. If ``data`` layout doesn't satisfy ``CoeffHint``, behavior is undefined. Returns a reference to the spline object for which coefficients are set. * - ``bool is_initialized() const;`` diff --git a/source/elements/oneMKL/source/domains/data_fitting/terms.rst b/source/elements/oneMKL/source/domains/data_fitting/terms.rst index 3e48bf9329..980f210549 100644 --- a/source/elements/oneMKL/source/domains/data_fitting/terms.rst +++ b/source/elements/oneMKL/source/domains/data_fitting/terms.rst @@ -3,18 +3,14 @@ Common Terms ============ -.. contents:: - :local: - :depth: 2 - Glossary -------- Assume we need to interpolate a function ``f(x)`` on the ``[a, b)`` interval using splines. -Let's break ``[a, b)`` into sub-intervals by ``n`` points :math:`x_i` -called partition points or simply **partition**. -**Function values** at these points (:math:`y_i = f(x_i), i=1,\cdots,n`) are also given. +We define a **partition** of `[a, b)` to be a collection of :math:`n` points +(**partition points**) :math:`\left\{ x_{i}\right}, i = 1, \dots, n` such as +:math:`a = x_1 < x_2 < \dots < x_n = b`. Spline has ``k`` degree if it can be expressed by the following polynomial: @@ -22,23 +18,27 @@ Spline has ``k`` degree if it can be expressed by the following polynomial: P\left( x \right) = c_{1} + c_{2}\left( x - x_i \right) + - c_{3}{\left( x - x_i \right)}^2 + \cdots + + c_{3}{\left( x - x_i \right)}^2 + \dots + c_{k-1}{\left( x - x_i \right)}^k. -Splines are constructed on :math:`[x_i, x_{i+1}), i=1,\cdots,n-1` sub-intervals. +Splines are constructed on the partition subintervals +:math:`[x_i, x_{i+1}), i=1,\dots,n-1` sub-intervals. So, for each sub-interval there are following polynomials: .. math:: P_i\left( x \right) = c_{1,i} + c_{2,i}\left( x - x_i \right) + - c_{3,i}{\left( x - x_i \right)}^2 + \cdots + + c_{3,i}{\left( x - x_i \right)}^2 + \dots + c_{k-1,i}{\left( x - x_i \right)}^k. -:math:`c_{j,i}, j=1,\cdots,k, i=1,\cdots,n` are called spline **coefficients**. +The scalars :math:`c_{j,i}, j=1,\dots,k, i=1,\dots,n` are called spline **coefficients**. -Function is interpolated at points of [a, b). -Such points are called interpolation sites or simply **sites**. Sites might or migtn't equals to partition points. +Given an interpolant spline of :math:`f(x)` on a partition of :math:`[a,b)`, +the interpolant function can be evaluated at any point in the interval :math:`[a,b)` or +outside it (see :ref:`interpoate` for details). Such points to evaluate the interpolant at +will be referred to as **interpolation sites** or simply **sites**. +Sites can correspond to partition points, but are not required to be. Mathematical Notation in the Data Fitting Component --------------------------------------------------- @@ -49,38 +49,37 @@ Mathematical Notation in the Data Fitting Component * - Concept - Mathematical Notation * - Partition - - :math:`\left\{ x_i \right\}_{i=1,\cdots,n}`, - where :math:`a = x1 < x2< \cdots < xn = b`.. + - :math:`\left\{ x_i \right\}_{i=1,\dots,n}`, + where :math:`a = x1 < x2< \dots < xn = b`. * - Uniform partition - - Partition :math:`\left\{ x_i \right\}_{i=1,\cdots,n}` + - Partition :math:`\left\{ x_i \right\}_{i=1,\dots,n}` which meets the following condition: - :math:`x_{i+1} - x_i = x_i - x_{i-1}, i=2,\cdots,n-1` + :math:`x_{i+1} - x_i = x_i - x_{i-1}, i=2,\dots,n-1` * - Quasi-uniform partition - - Partition :math:`\left\{ x_i \right\}_{i=1,\cdots,n}` + - Partition :math:`\left\{ x_i \right\}_{i=1,\dots,n}` which meets the constraint with a constant ``C`` defined as: :math:`1 \le M / m \le C`, where - :math:`M = max_{i=1,\cdots,n-1} (\Delta_i)`, - - :math:`m = min_{i=1,\cdots,n-1} (\Delta_i)`, + :math:`M = \text{max}_{i=1,\dots,n-1} (x_{i+1} - x_i)`, - :math:`\Delta_i = x_{i+1} - x_i` - * - Vector-valued function of dimension ``p`` being fit - - :math:`f(x) = (f_1(x),\cdots, f_p(x))`. - * - A ``k``-order derivative of function ``f(x)`` at point ``t`` - - :math:`f^{(k)}(t)`. + :math:`m = \text{min}_{i=1,\dots,n-1} (x_{i+1} - x_i)`, + * - Vector-valued function of dimension ``m`` + - :math:`f(x) = (f_1(x),\dots, f_m(x))`. + * - A ``d``-order derivative of function ``f(x)`` at point ``t`` + - :math:`f^{(d)}(t)`. * - Function ``p`` agrees with function ``f`` at the points - :math:`\left\{ x_i \right\}_{i=1,\cdots,n}`. - - For every point :math:`\zeta` in sequence :math:`\left\{ x_i \right\}_{i=1,\cdots,n}` - that occurs ``m`` times, the equality :math:`p^{(i-1)}(\zeta) = f^{(i-1)}(\zeta)` - holds for all :math:`i=1,\cdots,m`. + :math:`\left\{ x_i \right\}_{i=1,\dots,n}`. + - For every point :math:`\zeta` in sequence :math:`\left\{ x_i \right\}_{i=1,\dots,n}` + the equality :math:`p^{(d)}(\zeta) = f^{(d)}(\zeta)` + holds for all :math:`d=0,\dots,s` if ``p`` and ``f`` + are ``s``-times differentiable. * - The ``k``-th divided difference of function ``f`` at points :math:`x_i,..., x_{i+k}`. This difference is the leading coefficient of the polynomial of order ``k+1`` - that agrees with ``f`` at :math:`x_i,\cdots, x_{i+k}`. - - :math:`\left[ x_i,\cdots, x_{i + k} \right]f`. + that agrees with ``f`` at :math:`x_i,\dots, x_{i+k}`. + - :math:`\left[ x_i,\dots, x_{i + k} \right]f`. In particular, @@ -91,7 +90,7 @@ Mathematical Notation in the Data Fitting Component Hints in the Data Fitting Component ----------------------------------- -The |IONE-MKL| Data Fitting component provides ways to specify some "hints" +The oneMKL Data Fitting component provides ways to specify some "hints" for partitions, function values, coefficients, interpolation sites. Partition Hints @@ -116,20 +115,20 @@ The following are supported: Function Values Hints ^^^^^^^^^^^^^^^^^^^^^ -Let :math:`\left\{ x_i \right\}_{i=1,\cdots,nx}` is a partition, -:math:`\left\{ f_j(x) \right\}_{j=1,\cdots,ny}` is a vector-valued function. +Let :math:`\left\{ x_i \right\}_{i=1,\dots,nx}` be a partition, +:math:`\left\{ f_j(x) \right\}_{j=1,\dots,ny}` be a vector-valued function. Function values are stored in the one-dimensional array with ``nx * ny`` elements. 2 different layouts are possible: row major and column major. - For row major layout function values are stored as the following: - Let :math:`\left\{ f_{j,i} \right\}_{j=1,\cdots,ny, i=1,\cdots,nx}` - is the function value that corresponds to the ``i-th`` partition point and the ``j-th`` function. + Let :math:`\left\{ f_{j,i} \right\}_{j=1,\dots,ny, i=1,\dots,nx}` + be the function value that corresponds to the ``i-th`` partition point and the ``j-th`` function. - For column major: - Let :math:`\left\{ f_{i,j} \right\}_{i=1,\cdots,nx, j=1,\cdots,ny}` - is the function value that corresponds to the ``i-th`` partition point and the ``j-th`` function. + Let :math:`\left\{ f_{i,j} \right\}_{i=1,\dots,nx, j=1,\dots,ny}` + be the function value that corresponds to the ``i-th`` partition point and the ``j-th`` function. The following hints are supported: @@ -148,21 +147,20 @@ The following hints are supported: Coefficients Hints ^^^^^^^^^^^^^^^^^^ -Let :math:`\left\{ x_i \right\}_{i=1,\cdots,nx}` is a partition, -:math:`\left\{ f_j(x) \right\}_{j=1,\cdots,ny}` is a vector-valued function. -Let cubic spline should be constructed. It means that it requires 4 coefficients -per each interpolation interval and function value. -Cofficients are stored in the one-dimensional array with ``4 * (nx - 1) * ny`` elements. +Let :math:`\left\{ x_i \right\}_{i=1,\dots,nx}` be a partition of :math:`[a,b)` and +:math:`f(x) = \left\{ f_j(x) \right\}_{j=1,\dots,ny}` be a vector-valued function +to be interpolated with a cubic spline on this partition. +To create a cubic spline, on each sub-interval in the partition, we require 4 coefficients per component :math:`f_j(x)` of :math:`f(x)`. The coefficients are stored in a one-dimensional array with :math:`4 * (nx - 1) * ny` elements. - For row major: - Let :math:`\left\{ c_{j,i,k} \right\}_{j=1,\cdots,ny, i=1,\cdots,nx-1, k=1,\cdots,4}` - is the coefficient value that corresponds to the ``i-th`` partition point, the ``j-th`` function. + Let :math:`\left\{ c_{j,i,k} \right\}_{j=1,\dots,ny, i=1,\dots,nx-1, k=1,\dots,4}` + be the coefficient value that corresponds to the ``i-th`` partition point, the ``j-th`` function. - For column major: - Let :math:`\left\{ c_{i,j,k} \right\}_{i=1,\cdots,nx-1, j=1,\cdots,ny, k=1,\cdots,4}` - is the coefficient value that corresponds to the ``i-th`` partition point, the ``j-th`` function. + Let :math:`\left\{ c_{i,j,k} \right\}_{i=1,\dots,nx-1, j=1,\dots,ny, k=1,\dots,4}` + be the coefficient value that corresponds to the ``i-th`` partition point, the ``j-th`` function. The following is supported: @@ -198,46 +196,46 @@ The following are supported: Interpolation Results Hints ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Let :math:`\left\{ f_j(x) \right\}_{j=1,\cdots,ny}` is a vector-valued function, -:math:`\left\{ s_i \right\}_{i=1,\cdots,ns}` are sites, ``d`` is a number of derivatives (including interpolation values) that needs to be calculated. +Let :math:`\left\{ f_j(x) \right\}_{j=1,\dots,ny}` be a vector-valued function, +:math:`\left\{ s_i \right\}_{i=1,\dots,ns}` are sites, ``d`` is a number of derivatives (including interpolation values) that needs to be calculated. So, size of memory to store interpolation results is ``nsite * ny * d`` elements. 6 different layouts are possible: - functions-sites-derivatives - Let :math:`\left\{ r_{j,i,k} \right\}_{j=1,\cdots,ny, i=1,\cdots,nsite, k=1,\cdots,d}` - is an interpolation result that corresponds to the ``i-th`` site, + Let :math:`\left\{ r_{j,i,k} \right\}_{j=1,\dots,ny, i=1,\dots,nsite, k=1,\dots,d}` + be an interpolation result that corresponds to the ``i-th`` site, the ``j-th`` function, the ``k-th`` derivative. - functions-derivatives-sites - Let :math:`\left\{ r_{j,k,i} \right\}_{j=1,\cdots,ny, k=1,\cdots,d, i=1,\cdots,nsite}` - is an interpolation result that corresponds to the ``i-th`` site, + Let :math:`\left\{ r_{j,k,i} \right\}_{j=1,\dots,ny, k=1,\dots,d, i=1,\dots,nsite}` + be an interpolation result that corresponds to the ``i-th`` site, the ``j-th`` function, the ``k-th`` derivative. - sites-functions-derivatives - Let :math:`\left\{ r_{i,j,k} \right\}_{i=1,\cdots,nsite, j=1,\cdots,ny, k=1,\cdots,d}` - is an interpolation result that corresponds to the ``i-th`` site, + Let :math:`\left\{ r_{i,j,k} \right\}_{i=1,\dots,nsite, j=1,\dots,ny, k=1,\dots,d}` + be an interpolation result that corresponds to the ``i-th`` site, the ``j-th`` function, the ``k-th`` derivative. - sites-derivatives-functions - Let :math:`\left\{ r_{i,k,j} \right\}_{i=1,\cdots,nsite, k=1,\cdots,d, j=1,\cdots,ny}` - is an interpolation result that corresponds to the ``i-th`` site, + Let :math:`\left\{ r_{i,k,j} \right\}_{i=1,\dots,nsite, k=1,\dots,d, j=1,\dots,ny}` + be an interpolation result that corresponds to the ``i-th`` site, the ``j-th`` function, the ``k-th`` derivative. - derivatives-functions-sites - Let :math:`\left\{ r_{k,j,i} \right\}_{k=1,\cdots,d, j=1,\cdots,ny, i=1,\cdots,nsite}` - is an interpolation result that corresponds to the ``i-th`` site, + Let :math:`\left\{ r_{k,j,i} \right\}_{k=1,\dots,d, j=1,\dots,ny, i=1,\dots,nsite}` + be an interpolation result that corresponds to the ``i-th`` site, the ``j-th`` function, the ``k-th`` derivative. - derivatives-sites-functions - Let :math:`\left\{ r_{k,i,j} \right\}_{k=1,\cdots,d, i=1,\cdots,nsite, j=1,\cdots,ny}` - is an interpolation result that corresponds to the ``i-th`` site, + Let :math:`\left\{ r_{k,i,j} \right\}_{k=1,\dots,d, i=1,\dots,nsite, j=1,\dots,ny}` + be an interpolation result that corresponds to the ``i-th`` site, the ``j-th`` function, the ``k-th`` derivative. From f0cad286c2d8223ed0d05591c06587286c4ff0b6 Mon Sep 17 00:00:00 2001 From: "Fedorov, Andrey" Date: Mon, 21 Mar 2022 12:52:16 +0300 Subject: [PATCH 03/10] applied more remarks --- .../oneMKL/source/domains/data_fitting/cubic.rst | 2 -- .../source/domains/data_fitting/data-fitting.inc.rst | 1 - .../oneMKL/source/domains/data_fitting/examples.rst | 10 ---------- .../source/domains/data_fitting/interpolate.rst | 10 ++++------ .../oneMKL/source/domains/data_fitting/linear.rst | 2 -- .../oneMKL/source/domains/data_fitting/terms.rst | 12 ++++++++---- 6 files changed, 12 insertions(+), 25 deletions(-) delete mode 100644 source/elements/oneMKL/source/domains/data_fitting/examples.rst diff --git a/source/elements/oneMKL/source/domains/data_fitting/cubic.rst b/source/elements/oneMKL/source/domains/data_fitting/cubic.rst index d3306c099e..1f03ffaba4 100644 --- a/source/elements/oneMKL/source/domains/data_fitting/cubic.rst +++ b/source/elements/oneMKL/source/domains/data_fitting/cubic.rst @@ -82,5 +82,3 @@ To create a cubic Hermite spline object use the following: /*SYCL queue object*/q, /*number of spline functions*/ny ); - -Follow the :ref:`examples` section to see more complicated examples. diff --git a/source/elements/oneMKL/source/domains/data_fitting/data-fitting.inc.rst b/source/elements/oneMKL/source/domains/data_fitting/data-fitting.inc.rst index 5963942967..f4afdaf5ed 100644 --- a/source/elements/oneMKL/source/domains/data_fitting/data-fitting.inc.rst +++ b/source/elements/oneMKL/source/domains/data_fitting/data-fitting.inc.rst @@ -27,4 +27,3 @@ Interpolate function: data_fitting/terms data_fitting/splines data_fitting/interpolate - data_fitting/examples diff --git a/source/elements/oneMKL/source/domains/data_fitting/examples.rst b/source/elements/oneMKL/source/domains/data_fitting/examples.rst deleted file mode 100644 index bd09b69d0c..0000000000 --- a/source/elements/oneMKL/source/domains/data_fitting/examples.rst +++ /dev/null @@ -1,10 +0,0 @@ -.. _examples: - -Examples -======== - -The following example demonstrates how to construct the linear spline and perform the interpolation. - -.. literalinclude:: /_examples/data_fitting_linear.cpp - :language: cpp - :linenos: diff --git a/source/elements/oneMKL/source/domains/data_fitting/interpolate.rst b/source/elements/oneMKL/source/domains/data_fitting/interpolate.rst index 7b89e7faba..15134de67c 100644 --- a/source/elements/oneMKL/source/domains/data_fitting/interpolate.rst +++ b/source/elements/oneMKL/source/domains/data_fitting/interpolate.rst @@ -50,7 +50,7 @@ Syntax typename Interpolant::fp_type* sites, std::int64_t n_sites, typename Interpolant::fp_type* results, - std::bitset<32> der_indicator, + std::bitset<32> derivatives_indicator, const std::vector& dependencies = {}, interpolate_hint ResultHint = interpolate_hint::funcs_sites_ders, site_hint SiteHint = site_hint::non_uniform); // (2) @@ -73,7 +73,7 @@ Syntax typename Interpolant::fp_type* sites, std::int64_t n_sites, typename Interpolant::fp_type* results, - std::bitset<32> der_indicator, + std::bitset<32> derivatives_indicator, const std::vector& dependencies = {}, interpolate_hint ResultHint = interpolate_hint::funcs_sites_ders, site_hint SiteHint = site_hint::non_uniform); // (4) @@ -88,15 +88,13 @@ Returns the SYCL event of the submitted task. associated with ``interpolant``. #. Performs computations of certain derivatives (function values is considered as a zero derivative) which are indicated in - ``der_indicator`` (each bit corresponds to certain derivative starting from lower bit) + ``derivatives_indicator`` (each bit corresponds to certain derivative starting from lower bit) using the SYCL queue associated with ``interpolant``. #. Performs computations of function values only using ``queue`` as an input argument that should be created from the same context and device as the SYCL queue associated with ``interpolant``. #. Performs computations of certain derivatives (function values is considered as a zero derivative) which are indicated in - ``der_indicator`` (each bit corresponds to certain derivative starting from lower bit) + ``derivatives_indicator`` (each bit corresponds to certain derivative starting from lower bit) using ``queue`` as an input argument that should be created from the same context and device as the SYCL queue associated with ``interpolant``. - -Follow the :ref:`examples` section to see examples of the interpolation function usage. diff --git a/source/elements/oneMKL/source/domains/data_fitting/linear.rst b/source/elements/oneMKL/source/domains/data_fitting/linear.rst index 409b73828c..a70ea67ebb 100644 --- a/source/elements/oneMKL/source/domains/data_fitting/linear.rst +++ b/source/elements/oneMKL/source/domains/data_fitting/linear.rst @@ -58,5 +58,3 @@ To create a linear spline object use the following: /*SYCL queue object*/q, /*number of spline functions*/ny ); - -Follow the :ref:`examples` section to see more complicated examples. diff --git a/source/elements/oneMKL/source/domains/data_fitting/terms.rst b/source/elements/oneMKL/source/domains/data_fitting/terms.rst index 980f210549..9e20cef6d3 100644 --- a/source/elements/oneMKL/source/domains/data_fitting/terms.rst +++ b/source/elements/oneMKL/source/domains/data_fitting/terms.rst @@ -11,6 +11,8 @@ Assume we need to interpolate a function ``f(x)`` on the ``[a, b)`` interval usi We define a **partition** of `[a, b)` to be a collection of :math:`n` points (**partition points**) :math:`\left\{ x_{i}\right}, i = 1, \dots, n` such as :math:`a = x_1 < x_2 < \dots < x_n = b`. +In general when there is no condition with respect to the distances between the :math:`x_i`, +the partition is referred to as a **non-uniform partition**. Spline has ``k`` degree if it can be expressed by the following polynomial: @@ -50,7 +52,7 @@ Mathematical Notation in the Data Fitting Component - Mathematical Notation * - Partition - :math:`\left\{ x_i \right\}_{i=1,\dots,n}`, - where :math:`a = x1 < x2< \dots < xn = b`. + where :math:`a = x_1 < x_2 < \dots < x_n = b`. * - Uniform partition - Partition :math:`\left\{ x_i \right\}_{i=1,\dots,n}` which meets the following condition: @@ -59,13 +61,13 @@ Mathematical Notation in the Data Fitting Component * - Quasi-uniform partition - Partition :math:`\left\{ x_i \right\}_{i=1,\dots,n}` which meets the constraint with a constant ``C`` defined as: - :math:`1 \le M / m \le C`, + :math:`1 \le M_max / M_min \le C`, where - :math:`M = \text{max}_{i=1,\dots,n-1} (x_{i+1} - x_i)`, + :math:`M_max = \text{max}_{i=1,\dots,n-1} (x_{i+1} - x_i)`, - :math:`m = \text{min}_{i=1,\dots,n-1} (x_{i+1} - x_i)`, + :math:`M_min = \text{min}_{i=1,\dots,n-1} (x_{i+1} - x_i)`, * - Vector-valued function of dimension ``m`` - :math:`f(x) = (f_1(x),\dots, f_m(x))`. * - A ``d``-order derivative of function ``f(x)`` at point ``t`` @@ -298,6 +300,7 @@ Some type of splines requires boundary conditions to be set. The following types are supported: - Free end (:math:`f^{(2)}(x_1) = f^{(2)}(x_n) = 0`). + - Not-a-knot. - Periodic. - First derivative. - Second Derivative. @@ -308,6 +311,7 @@ The following types are supported: enum class bc_type { free_end, + not_a_knot, first_left_der, first_right_der, second_left_der, From 204a15e74e90d08c21a38c35beb88a73fd7eed6f Mon Sep 17 00:00:00 2001 From: "Fedorov, Andrey" Date: Mon, 21 Mar 2022 12:58:23 +0300 Subject: [PATCH 04/10] fixed an issue --- source/elements/oneMKL/source/domains/data_fitting/terms.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/elements/oneMKL/source/domains/data_fitting/terms.rst b/source/elements/oneMKL/source/domains/data_fitting/terms.rst index 9e20cef6d3..6dd608dc0b 100644 --- a/source/elements/oneMKL/source/domains/data_fitting/terms.rst +++ b/source/elements/oneMKL/source/domains/data_fitting/terms.rst @@ -38,7 +38,7 @@ The scalars :math:`c_{j,i}, j=1,\dots,k, i=1,\dots,n` are called spline **coeffi Given an interpolant spline of :math:`f(x)` on a partition of :math:`[a,b)`, the interpolant function can be evaluated at any point in the interval :math:`[a,b)` or -outside it (see :ref:`interpoate` for details). Such points to evaluate the interpolant at +outside it (see :ref:`interpolate` for details). Such points to evaluate the interpolant at will be referred to as **interpolation sites** or simply **sites**. Sites can correspond to partition points, but are not required to be. From 9e6e933db34ee680f5ee4c2f5a54cba0ffe8f20c Mon Sep 17 00:00:00 2001 From: "Fedorov, Andrey" Date: Mon, 21 Mar 2022 13:03:59 +0300 Subject: [PATCH 05/10] add copyrights --- source/elements/oneMKL/source/domains/data_fitting/cubic.rst | 4 ++++ .../oneMKL/source/domains/data_fitting/data-fitting.inc.rst | 4 ++++ .../oneMKL/source/domains/data_fitting/interpolate.rst | 4 ++++ source/elements/oneMKL/source/domains/data_fitting/linear.rst | 4 ++++ .../elements/oneMKL/source/domains/data_fitting/splines.rst | 4 ++++ source/elements/oneMKL/source/domains/data_fitting/terms.rst | 4 ++++ 6 files changed, 24 insertions(+) diff --git a/source/elements/oneMKL/source/domains/data_fitting/cubic.rst b/source/elements/oneMKL/source/domains/data_fitting/cubic.rst index 1f03ffaba4..e6b5ebb2d6 100644 --- a/source/elements/oneMKL/source/domains/data_fitting/cubic.rst +++ b/source/elements/oneMKL/source/domains/data_fitting/cubic.rst @@ -1,3 +1,7 @@ +.. SPDX-FileCopyrightText: 2022 Intel Corporation +.. +.. SPDX-License-Identifier: CC-BY-4.0 + .. _cubic: Cubic Splines diff --git a/source/elements/oneMKL/source/domains/data_fitting/data-fitting.inc.rst b/source/elements/oneMKL/source/domains/data_fitting/data-fitting.inc.rst index f4afdaf5ed..c1d83ec614 100644 --- a/source/elements/oneMKL/source/domains/data_fitting/data-fitting.inc.rst +++ b/source/elements/oneMKL/source/domains/data_fitting/data-fitting.inc.rst @@ -1,3 +1,7 @@ +.. SPDX-FileCopyrightText: 2022 Intel Corporation +.. +.. SPDX-License-Identifier: CC-BY-4.0 + .. _data-fitting: Data Fitting diff --git a/source/elements/oneMKL/source/domains/data_fitting/interpolate.rst b/source/elements/oneMKL/source/domains/data_fitting/interpolate.rst index 15134de67c..1d5d2b7f53 100644 --- a/source/elements/oneMKL/source/domains/data_fitting/interpolate.rst +++ b/source/elements/oneMKL/source/domains/data_fitting/interpolate.rst @@ -1,3 +1,7 @@ +.. SPDX-FileCopyrightText: 2022 Intel Corporation +.. +.. SPDX-License-Identifier: CC-BY-4.0 + .. _interpolate: Interpolate Function diff --git a/source/elements/oneMKL/source/domains/data_fitting/linear.rst b/source/elements/oneMKL/source/domains/data_fitting/linear.rst index a70ea67ebb..ee1501b20f 100644 --- a/source/elements/oneMKL/source/domains/data_fitting/linear.rst +++ b/source/elements/oneMKL/source/domains/data_fitting/linear.rst @@ -1,3 +1,7 @@ +.. SPDX-FileCopyrightText: 2022 Intel Corporation +.. +.. SPDX-License-Identifier: CC-BY-4.0 + .. _linear: Linear Spline diff --git a/source/elements/oneMKL/source/domains/data_fitting/splines.rst b/source/elements/oneMKL/source/domains/data_fitting/splines.rst index c7b6815972..88011c6dc6 100644 --- a/source/elements/oneMKL/source/domains/data_fitting/splines.rst +++ b/source/elements/oneMKL/source/domains/data_fitting/splines.rst @@ -1,3 +1,7 @@ +.. SPDX-FileCopyrightText: 2022 Intel Corporation +.. +.. SPDX-License-Identifier: CC-BY-4.0 + .. _splines: Splines diff --git a/source/elements/oneMKL/source/domains/data_fitting/terms.rst b/source/elements/oneMKL/source/domains/data_fitting/terms.rst index 6dd608dc0b..a04cfb03e6 100644 --- a/source/elements/oneMKL/source/domains/data_fitting/terms.rst +++ b/source/elements/oneMKL/source/domains/data_fitting/terms.rst @@ -1,3 +1,7 @@ +.. SPDX-FileCopyrightText: 2022 Intel Corporation +.. +.. SPDX-License-Identifier: CC-BY-4.0 + .. _terms: Common Terms From 39147fc8ffd9f6280cc3fe613412d38bc2312ebf Mon Sep 17 00:00:00 2001 From: "Fedorov, Andrey" Date: Mon, 21 Mar 2022 13:11:13 +0300 Subject: [PATCH 06/10] fixed a label for the file --- .../oneMKL/source/architecture/api_design.inc.rst | 12 ++++++------ .../source/domains/data_fitting/data-fitting.inc.rst | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/source/elements/oneMKL/source/architecture/api_design.inc.rst b/source/elements/oneMKL/source/architecture/api_design.inc.rst index 93ae50ec79..9e4e4e1697 100644 --- a/source/elements/oneMKL/source/architecture/api_design.inc.rst +++ b/source/elements/oneMKL/source/architecture/api_design.inc.rst @@ -32,12 +32,12 @@ namespace oneMKL domain or content .. note:: :name: Implementation Requirement - Inside each oneMKL domain, there are many routines, classes, enums and objects defined which constitute the breadth and scope of that oneMKL domain. + Inside each oneMKL domain, there are many routines, classes, enums and objects defined which constitute the breadth and scope of that oneMKL domain. It is permitted for a library implementation of the oneMKL specification to implement either all, one or more than one of the domains in oneMKL. However, within an implementation of a specific domain, all relevant routines, classes, enums and objects (including those relevant enums and objects which live outside a particular domain in the general ``oneapi::mkl`` namespace must be both declared and defined in the library so that an application that uses that domain could build and link against that library implementation successfully. - It is however acceptable to throw the runtime exception :ref:`oneapi::mkl::unimplemented` inside of the routines or class member functions in that domain that have not been fully implemented. - For instance, a library may choose to implement the oneMKL BLAS functionality and in particular may choose to implement only the :ref:`onemkl_blas_gemm` api for their library, in which case they must also include all the other blas namespaced routines and throw the :ref:`oneapi::mkl::unimplemented` exception inside all the others. - + It is however acceptable to throw the runtime exception :ref:`oneapi::mkl::unimplemented` inside of the routines or class member functions in that domain that have not been fully implemented. + For instance, a library may choose to implement the oneMKL BLAS functionality and in particular may choose to implement only the :ref:`onemkl_blas_gemm` api for their library, in which case they must also include all the other blas namespaced routines and throw the :ref:`oneapi::mkl::unimplemented` exception inside all the others. + In such a case, the implemented routines in such a library should be communicated clearly and easily understood by users of that library. @@ -74,7 +74,7 @@ oneMKL uses the following DPC++ data types: oneMKL defined datatypes ++++++++++++++++++++++++ -oneMKL dense and sparse linear algebra routines use scoped enum types as type-safe replacements for the traditional character arguments used in C/Fortran implementations of BLAS and LAPACK. These types all belong to the ``oneapi::mkl`` namespace. +oneMKL dense and sparse linear algebra routines use scoped enum types as type-safe replacements for the traditional character arguments used in C/Fortran implementations of BLAS and LAPACK. These types all belong to the ``oneapi::mkl`` namespace. Each enumeration value comes with two names: A single-character name (the traditional BLAS/LAPACK character) and a longer, more descriptive name. The two names are exactly equivalent and may be used interchangeably. @@ -239,7 +239,7 @@ Each enumeration value comes with two names: A single-character name (the tradit :name: layout :class: sectiontitle - The ``layout`` type specifies how a dense matrix ``A`` with leading dimension ``lda`` is stored as one dimensional array in memory. + The ``layout`` type specifies how a dense matrix ``A`` with leading dimension ``lda`` is stored as one dimensional array in memory. The layouts are traditionally provided in one of two forms: C/C++-style using ``row_major`` layout, or Fortran-style using ``column_major`` layout. The ``layout`` type can take the following values: diff --git a/source/elements/oneMKL/source/domains/data_fitting/data-fitting.inc.rst b/source/elements/oneMKL/source/domains/data_fitting/data-fitting.inc.rst index c1d83ec614..d8e8d06b17 100644 --- a/source/elements/oneMKL/source/domains/data_fitting/data-fitting.inc.rst +++ b/source/elements/oneMKL/source/domains/data_fitting/data-fitting.inc.rst @@ -2,7 +2,7 @@ .. .. SPDX-License-Identifier: CC-BY-4.0 -.. _data-fitting: +.. _data_fitting: Data Fitting ============ From ddceee536ead10731a1226bbdb2fb694dafb42cb Mon Sep 17 00:00:00 2001 From: "Fedorov, Andrey" Date: Mon, 21 Mar 2022 13:22:09 +0300 Subject: [PATCH 07/10] add were_coeffs_computed parameter --- .../source/domains/data_fitting/splines.rst | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/source/elements/oneMKL/source/domains/data_fitting/splines.rst b/source/elements/oneMKL/source/domains/data_fitting/splines.rst index 88011c6dc6..7ca964b704 100644 --- a/source/elements/oneMKL/source/domains/data_fitting/splines.rst +++ b/source/elements/oneMKL/source/domains/data_fitting/splines.rst @@ -37,12 +37,14 @@ Common API for All Spline Types spline( const sycl::queue& queue, - std::int64_t ny = 1); + std::int64_t ny = 1, + bool were_coeffs_computed = false); spline( const sycl::device& device, const sycl::context& context, - std::int64_t ny = 1); + std::int64_t ny = 1, + bool were_coeffs_computed = false); ~spline(); @@ -82,11 +84,17 @@ that operates with the ``T`` data type. ``ST`` is a type of spline. * - Constructor - Description - * - ``spline(const sycl::queue& queue, std::int64_t ny = 1);`` + * - ``spline(const sycl::queue& queue, std::int64_t ny = 1, bool were_coeffs_computed = false);`` - Create an object with the ``queue`` SYCL queue and ``ny`` number of functions. - * - ``spline(const sycl::device& device, const sycl::context& context, std::int64_t ny = 1);`` + If spline coeficients were already computed, provide ``true`` as a 3-rd argument. + ``were_coeffs_computed == false`` by default. + It means that it needs to call ``construct`` to compute spline coefficients. + * - ``spline(const sycl::device& device, const sycl::context& context, std::int64_t ny = 1, bool were_coeffs_computed = false);`` - Create an object using the ``device`` SYCL device, the ``context`` context and ``ny`` number of functions. + If spline coeficients were already computed, provide ``true`` as a 3-rd argument. + ``were_coeffs_computed == false`` by default. + It means that it needs to call ``construct`` to compute spline coefficients. .. list-table:: :header-rows: 1 @@ -117,13 +125,14 @@ that operates with the ``T`` data type. ``ST`` is a type of spline. Number of coefficients in the memory must equals to the return value of ``get_required_coeffs_size()``. Users can provide a ``CoeffHint`` to specify the layout of data with a default value of ``row_major``. If ``data`` layout doesn't satisfy ``CoeffHint``, behavior is undefined. + If ``were_coeffs_computed == false``, ``data`` will be rewritten during ``construct``. Returns a reference to the spline object for which coefficients are set. * - ``bool is_initialized() const;`` - Returns ``true`` if all required data are set (for example, partitions, function values, coefficients). * - ``std::int64_t get_required_coeffs_size() const;`` - Returns amount of memory that is required for coefficients storage. * - ``sycl::event construct(const std::vector& dependencies = {});`` - - Constructs the spline (calculates spline coefficients). + - Constructs the spline (calculates spline coefficients if ``were_coeffs_computed == false``). The function submits a SYCL kernel and returns the SYCL event to wait on to ensure computation is complete. ``dependencies`` is a list of SYCL events to wait for before starting computations. From 10f36ac0ab920cbc14eefa10ee31210e4f227b9a Mon Sep 17 00:00:00 2001 From: "Fedorov, Andrey" Date: Mon, 21 Mar 2022 15:57:42 +0300 Subject: [PATCH 08/10] small fixes for interfaces --- .../source/domains/data_fitting/interpolate.rst | 16 ++++++++-------- .../source/domains/data_fitting/splines.rst | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/source/elements/oneMKL/source/domains/data_fitting/interpolate.rst b/source/elements/oneMKL/source/domains/data_fitting/interpolate.rst index 1d5d2b7f53..5daf3bb465 100644 --- a/source/elements/oneMKL/source/domains/data_fitting/interpolate.rst +++ b/source/elements/oneMKL/source/domains/data_fitting/interpolate.rst @@ -41,9 +41,9 @@ Syntax template sycl::event interpolate( Interpolant& interpolant, - typename Interpolant::fp_type* sites, + typename Interpolant::value_type* sites, std::int64_t n_sites, - typename Interpolant::fp_type* results, + typename Interpolant::value_type* results, const std::vector& dependencies, interpolate_hint ResultHint = interpolate_hint::funcs_sites_ders, site_hint SiteHint = site_hint::non_uniform); // (1) @@ -51,9 +51,9 @@ Syntax template sycl::event interpolate( Interpolant& interpolant, - typename Interpolant::fp_type* sites, + typename Interpolant::value_type* sites, std::int64_t n_sites, - typename Interpolant::fp_type* results, + typename Interpolant::value_type* results, std::bitset<32> derivatives_indicator, const std::vector& dependencies = {}, interpolate_hint ResultHint = interpolate_hint::funcs_sites_ders, @@ -63,9 +63,9 @@ Syntax sycl::event interpolate( sycl::queue& queue, const Interpolant& interpolant, - typename Interpolant::fp_type* sites, + typename Interpolant::value_type* sites, std::int64_t n_sites, - typename Interpolant::fp_type* results, + typename Interpolant::value_type* results, const std::vector& dependencies, interpolate_hint ResultHint = interpolate_hint::funcs_sites_ders, site_hint SiteHint = site_hint::non_uniform); // (3) @@ -74,9 +74,9 @@ Syntax sycl::event interpolate( sycl::queue& queue, const Interpolant& interpolant, - typename Interpolant::fp_type* sites, + typename Interpolant::value_type* sites, std::int64_t n_sites, - typename Interpolant::fp_type* results, + typename Interpolant::value_type* results, std::bitset<32> derivatives_indicator, const std::vector& dependencies = {}, interpolate_hint ResultHint = interpolate_hint::funcs_sites_ders, diff --git a/source/elements/oneMKL/source/domains/data_fitting/splines.rst b/source/elements/oneMKL/source/domains/data_fitting/splines.rst index 7ca964b704..37bb9fc92b 100644 --- a/source/elements/oneMKL/source/domains/data_fitting/splines.rst +++ b/source/elements/oneMKL/source/domains/data_fitting/splines.rst @@ -62,11 +62,11 @@ Common API for All Spline Types spline& set_function_values( FpType* input_data, - function_hint FunctionHint = storage_hint::row_major); + function_hint FunctionHint = function_hint::row_major); spline& set_coefficients( FpType* data, - coefficient_hint CoeffHint = storage_hint::row_major); + coefficient_hint CoeffHint = coefficient_hint::row_major); bool is_initialized() const; From 79582bfda7b2afb658473d4054cc9fb2e46e395a Mon Sep 17 00:00:00 2001 From: "Fedorov, Andrey" Date: Wed, 23 Mar 2022 20:06:13 +0300 Subject: [PATCH 09/10] fixed formulae --- source/elements/oneMKL/source/domains/data_fitting/terms.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/elements/oneMKL/source/domains/data_fitting/terms.rst b/source/elements/oneMKL/source/domains/data_fitting/terms.rst index a04cfb03e6..7f3e17534b 100644 --- a/source/elements/oneMKL/source/domains/data_fitting/terms.rst +++ b/source/elements/oneMKL/source/domains/data_fitting/terms.rst @@ -13,7 +13,7 @@ Glossary Assume we need to interpolate a function ``f(x)`` on the ``[a, b)`` interval using splines. We define a **partition** of `[a, b)` to be a collection of :math:`n` points -(**partition points**) :math:`\left\{ x_{i}\right}, i = 1, \dots, n` such as +(**partition points**) :math:`\left\{ x_{i}\right\}, i = 1, \dots, n` such as :math:`a = x_1 < x_2 < \dots < x_n = b`. In general when there is no condition with respect to the distances between the :math:`x_i`, the partition is referred to as a **non-uniform partition**. From 9139dc3650423b1c5bf9e1fd6476fef2cc779165 Mon Sep 17 00:00:00 2001 From: "Fedorov, Andrey" Date: Fri, 25 Mar 2022 11:32:08 +0300 Subject: [PATCH 10/10] add a picture + fixed a wording --- .../domains/data_fitting/img_data_fitting.png | Bin 0 -> 92127 bytes .../source/domains/data_fitting/interpolate.rst | 3 +++ .../source/domains/data_fitting/splines.rst | 2 ++ .../source/domains/data_fitting/terms.rst | 4 ++++ 4 files changed, 9 insertions(+) create mode 100644 source/elements/oneMKL/source/domains/data_fitting/img_data_fitting.png diff --git a/source/elements/oneMKL/source/domains/data_fitting/img_data_fitting.png b/source/elements/oneMKL/source/domains/data_fitting/img_data_fitting.png new file mode 100644 index 0000000000000000000000000000000000000000..e16ba7d60407acb3ded0abf287404218baee0632 GIT binary patch literal 92127 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%0A!_1DCk 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 nmzmL<6}z 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 literal 0 HcmV?d00001 diff --git a/source/elements/oneMKL/source/domains/data_fitting/interpolate.rst b/source/elements/oneMKL/source/domains/data_fitting/interpolate.rst index 5daf3bb465..ded7fe1be2 100644 --- a/source/elements/oneMKL/source/domains/data_fitting/interpolate.rst +++ b/source/elements/oneMKL/source/domains/data_fitting/interpolate.rst @@ -88,6 +88,9 @@ If ``results`` layout doesn't satisfy ``ResultHint`` and/or ``sites`` layout doesn't satisfy ``SiteHint``, behavior is undefined. Returns the SYCL event of the submitted task. +Interfaces (3) and (4) can be useful when users try to interpolate over different parts of ``sites`` +using different ``queue`` objects. + #. Performs computations of function values only using the SYCL queue associated with ``interpolant``. #. Performs computations of certain derivatives diff --git a/source/elements/oneMKL/source/domains/data_fitting/splines.rst b/source/elements/oneMKL/source/domains/data_fitting/splines.rst index 37bb9fc92b..6b0987968c 100644 --- a/source/elements/oneMKL/source/domains/data_fitting/splines.rst +++ b/source/elements/oneMKL/source/domains/data_fitting/splines.rst @@ -89,12 +89,14 @@ that operates with the ``T`` data type. ``ST`` is a type of spline. If spline coeficients were already computed, provide ``true`` as a 3-rd argument. ``were_coeffs_computed == false`` by default. It means that it needs to call ``construct`` to compute spline coefficients. + This constructor is useful when users want to pass SYCL queue, not SYCL device and SYCL context. * - ``spline(const sycl::device& device, const sycl::context& context, std::int64_t ny = 1, bool were_coeffs_computed = false);`` - Create an object using the ``device`` SYCL device, the ``context`` context and ``ny`` number of functions. If spline coeficients were already computed, provide ``true`` as a 3-rd argument. ``were_coeffs_computed == false`` by default. It means that it needs to call ``construct`` to compute spline coefficients. + This constructor is useful for cases mentioned in :ref:`interpolate`. .. list-table:: :header-rows: 1 diff --git a/source/elements/oneMKL/source/domains/data_fitting/terms.rst b/source/elements/oneMKL/source/domains/data_fitting/terms.rst index 7f3e17534b..acf32027d6 100644 --- a/source/elements/oneMKL/source/domains/data_fitting/terms.rst +++ b/source/elements/oneMKL/source/domains/data_fitting/terms.rst @@ -46,6 +46,10 @@ outside it (see :ref:`interpolate` for details). Such points to evaluate the int will be referred to as **interpolation sites** or simply **sites**. Sites can correspond to partition points, but are not required to be. +.. image:: img_data_fitting.png + :width: 600 + :alt: Data Fitting terminology picture + Mathematical Notation in the Data Fitting Component ---------------------------------------------------