diff --git a/.github/workflows/build-external-lib-tests.yml b/.github/workflows/build-external-lib-tests.yml index ebe21dac..3e880ed4 100644 --- a/.github/workflows/build-external-lib-tests.yml +++ b/.github/workflows/build-external-lib-tests.yml @@ -59,7 +59,7 @@ jobs: -DCMAKE_CXX_STANDARD=17 \ -DCMAKE_INSTALL_PREFIX=$GITHUB_WORKSPACE/KOKKOS_INSTALL/ \ ../ - sudo make -j2 install + sudo make -j$(nproc) install - name: Install Conda Dependencies shell: bash -l {0} @@ -74,7 +74,7 @@ jobs: - name: Build MParT shell: bash -l {0} - run: cd $GITHUB_WORKSPACE/mpart/build; make -j2 + run: cd $GITHUB_WORKSPACE/mpart/build; make -j$(nproc) - name: Run Tests shell: bash -l {0} diff --git a/MParT/AffineMap.h b/MParT/AffineMap.h index e69bd131..42fcd10e 100644 --- a/MParT/AffineMap.h +++ b/MParT/AffineMap.h @@ -59,6 +59,8 @@ class AffineMap : public ConditionalMapBase void LogDeterminantInputGradImpl(StridedMatrix const& pts, StridedMatrix output) override; + std::shared_ptr> Slice(int a, int b) override; + /** Computes an LU factorization of the matrix A_ */ void Factorize(); diff --git a/MParT/ComposedMap.h b/MParT/ComposedMap.h index ebac1ead..c1da168c 100644 --- a/MParT/ComposedMap.h +++ b/MParT/ComposedMap.h @@ -102,6 +102,8 @@ class ComposedMap : public ConditionalMapBase void GradientImpl(StridedMatrix const& pts, StridedMatrix const& sens, StridedMatrix output) override; + + std::shared_ptr> Slice(int a, int b) override; private: unsigned int maxChecks_; diff --git a/MParT/ConditionalMapBase.h b/MParT/ConditionalMapBase.h index 3689bf3a..9fbab75b 100644 --- a/MParT/ConditionalMapBase.h +++ b/MParT/ConditionalMapBase.h @@ -149,6 +149,11 @@ namespace mpart { virtual void LogDeterminantInputGradImpl(StridedMatrix const& pts, StridedMatrix output) = 0; + + virtual std::shared_ptr> Slice(int a, int b) { + throw std::runtime_error("Slice not implemented for this map type."); + } + #if defined(MPART_HAS_CEREAL) template void serialize(Archive& ar) { diff --git a/MParT/IdentityMap.h b/MParT/IdentityMap.h index 0a9d9fad..bafea491 100644 --- a/MParT/IdentityMap.h +++ b/MParT/IdentityMap.h @@ -57,6 +57,10 @@ class IdentityMap : public ConditionalMapBase void LogDeterminantInputGradImpl(StridedMatrix const& pts, StridedMatrix output) override; + // This only slices the tail of the map due to how IdentityMap is defined. + // i.e. this is invariant on identical shifting of a,b. + std::shared_ptr> Slice(int a, int b) override; + }; // class IdentityMap } diff --git a/MParT/MapFactory.h b/MParT/MapFactory.h index 64001aef..d8e38248 100644 --- a/MParT/MapFactory.h +++ b/MParT/MapFactory.h @@ -4,6 +4,7 @@ #include "MParT/MapOptions.h" #include "MParT/ConditionalMapBase.h" +#include "MParT/TriangularMap.h" #include "MParT/SummarizedMap.h" //#include "MParT/DebugMap.h" #include "MParT/MultiIndices/FixedMultiIndexSet.h" diff --git a/MParT/MonotoneComponent.h b/MParT/MonotoneComponent.h index 251deb5c..0812e5ae 100644 --- a/MParT/MonotoneComponent.h +++ b/MParT/MonotoneComponent.h @@ -1,6 +1,8 @@ #ifndef MPART_MONOTONECOMPONENT_H #define MPART_MONOTONECOMPONENT_H +#include + #include "MParT/MultiIndices/FixedMultiIndexSet.h" #include "MParT/MultiIndices/MultiIndexSet.h" @@ -37,7 +39,7 @@ T(x_1, x_2, ..., x_D) = f(x_1,x_2,..., x_{D-1}, 0) + \int_0^{x_D} g\left( \part @tparam QuadratureType A class defining the integration scheme used to approximate \f$\int_0^{x_N} g\left( \frac{\partial f}{\partial x_d}(x_1,x_2,..., x_{N-1}, t) \right) dt\f$. The type must have a function `Integrate(f,lb,ub)` that accepts a functor `f`, a double lower bound `lb`, a double upper bound `ub`, and returns a double with an estimate of the integral. The MParT::AdaptiveSimpson and MParT::RecursiveQuadrature classes provide this interface. */ template -class MonotoneComponent : public ConditionalMapBase +class MonotoneComponent : public ConditionalMapBase, public std::enable_shared_from_this> { public: @@ -1078,6 +1080,11 @@ class MonotoneComponent : public ConditionalMapBase return 0.5*(xub+xlb); } + std::shared_ptr> Slice(int a, int b) override { + assert(a == 0 && b == 1); + return MonotoneComponent::shared_from_this(); + } + /** Give access to the underlying FixedMultiIndexSet * @return The FixedMultiIndexSet */ diff --git a/MParT/TriangularMap.h b/MParT/TriangularMap.h index 086ff3f8..95a2b6dc 100644 --- a/MParT/TriangularMap.h +++ b/MParT/TriangularMap.h @@ -60,6 +60,18 @@ class TriangularMap : public ConditionalMapBase{ void WrapCoeffs(Kokkos::View coeffs) override; #endif + std::shared_ptr> Slice(int a, int b) override; + + /** @brief Returns a subsection of the map according to index of components + * @details This function returns a subsection (or "slice") of a block triangular map by simply just taking a subset of the blocks. + * The returned map will have the same number of inputs as the original map, and this is equivalent to {@link #Slice Slice} when + * the number of outputs of each component is 1. + * @param a The first component block to take + * @param b The index AFTER the last component block to take + * @return A shared pointer to a new ConditionalMapBase object containing the subsection of the map. + */ + virtual std::shared_ptr> BlockSlice(int a, int b); + virtual std::shared_ptr> GetComponent(unsigned int i){ return comps_.at(i);} /** @brief Computes the log determinant of the Jacobian matrix of this map. diff --git a/bindings/julia/src/ConditionalMapBase.cpp b/bindings/julia/src/ConditionalMapBase.cpp index c1f727e5..56ce235a 100644 --- a/bindings/julia/src/ConditionalMapBase.cpp +++ b/bindings/julia/src/ConditionalMapBase.cpp @@ -39,6 +39,7 @@ void mpart::binding::ConditionalMapBaseWrapper(jlcxx::Module &mod) { map.InverseImpl(JuliaToKokkos(x1), JuliaToKokkos(r), JuliaToKokkos(output)); return output; }) + .method("Slice", [](ConditionalMapBase& map, int begin, int end){ return map.Slice(begin-1, end); }) ; jlcxx::stl::apply_stl*>(mod); } \ No newline at end of file diff --git a/bindings/julia/src/TriangularMap.cpp b/bindings/julia/src/TriangularMap.cpp index 7ac54973..defb643d 100644 --- a/bindings/julia/src/TriangularMap.cpp +++ b/bindings/julia/src/TriangularMap.cpp @@ -14,6 +14,6 @@ void mpart::binding::TriangularMapWrapper(jlcxx::Module &mod) { .method("InverseInplace", [](TriangularMap &map, jlcxx::ArrayRef x, jlcxx::ArrayRef r){ map.InverseInplace(JuliaToKokkos(x), JuliaToKokkos(r)); }) - .method("GetComponent", &TriangularMap::GetComponent) + .method("GetComponent", [](TriangularMap& map, int i){ return map.GetComponent(i-1); }) ; } \ No newline at end of file diff --git a/bindings/python/src/ConditionalMapBase.cpp b/bindings/python/src/ConditionalMapBase.cpp index 22267d66..a44fc8d2 100644 --- a/bindings/python/src/ConditionalMapBase.cpp +++ b/bindings/python/src/ConditionalMapBase.cpp @@ -23,6 +23,12 @@ void mpart::binding::ConditionalMapBaseWrapper(py::module &m) .def("LogDeterminantCoeffGrad", static_cast::*)(Eigen::Ref const&)>(&ConditionalMapBase::LogDeterminantCoeffGrad)) .def("LogDeterminantInputGrad", static_cast::*)(Eigen::Ref const&)>(&ConditionalMapBase::LogDeterminantInputGrad)) .def("GetBaseFunction", &ConditionalMapBase::GetBaseFunction) + .def("__getitem__", [](ConditionalMapBase &m, const py::slice &s) { + size_t start = 0, stop = 0, step = 0, slicelength = 0; + s.compute(m.outputDim, &start, &stop, &step, &slicelength); + if(step != 1) throw std::runtime_error("Map slice step size must be 1"); + return m.Slice(start, stop); + }) ; } diff --git a/bindings/python/src/TriangularMap.cpp b/bindings/python/src/TriangularMap.cpp index 8ab340c9..f3a3ceff 100644 --- a/bindings/python/src/TriangularMap.cpp +++ b/bindings/python/src/TriangularMap.cpp @@ -20,6 +20,8 @@ void mpart::binding::TriangularMapWrapper(py::module &m) py::class_, ConditionalMapBase, std::shared_ptr>>(m, tName.c_str()) .def(py::init>>, bool>(), py::arg("comps"), py::arg("moveCoeffs") = false) .def("GetComponent", &TriangularMap::GetComponent) + .def("Slice", &TriangularMap::Slice) + .def("__getitem__", &TriangularMap::GetComponent) ; } diff --git a/src/AffineMap.cpp b/src/AffineMap.cpp index 90b81e9d..d5427991 100644 --- a/src/AffineMap.cpp +++ b/src/AffineMap.cpp @@ -3,13 +3,13 @@ #include "MParT/Utilities/ArrayConversions.h" #include "MParT/Initialization.h" - + using namespace mpart; template -AffineMap::AffineMap(StridedVector b) : ConditionalMapBase(b.size(),b.size(),0), - b_("b",b.layout()), +AffineMap::AffineMap(StridedVector b) : ConditionalMapBase(b.size(),b.size(),0), + b_("b",b.layout()), logDet_(0.0) { Kokkos::deep_copy(b_, b); @@ -30,7 +30,7 @@ AffineMap::AffineMap(StridedMatrix A, StridedVector b) : ConditionalMapBase(A.extent(1),A.extent(0),0), A_("A", A.layout()), b_("b",b.layout()) -{ +{ Kokkos::deep_copy(A_, A); Kokkos::deep_copy(b_, b); assert(A_.extent(0)<=A_.extent(1)); @@ -91,7 +91,7 @@ void AffineMap::InverseImpl(StridedMatrix0){ @@ -99,7 +99,7 @@ void AffineMap::InverseImpl(StridedMatrix::InverseImpl(StridedMatrix xsub = Kokkos::subview(x1, std::make_pair(0,ncols-nrows), Kokkos::ALL()); StridedMatrix Asub = Kokkos::subview(A_, Kokkos::ALL(), std::make_pair(0,ncols-nrows)); @@ -129,13 +129,13 @@ void AffineMap::InverseImpl(StridedMatrix -void AffineMap::LogDeterminantCoeffGradImpl(StridedMatrix const& pts, +void AffineMap::LogDeterminantCoeffGradImpl(StridedMatrix const& pts, StridedMatrix output) { return; @@ -151,7 +151,7 @@ void AffineMap::EvaluateImpl(StridedMatrix0){ @@ -165,22 +165,22 @@ void AffineMap::EvaluateImpl(StridedMatrix -void AffineMap::CoeffGradImpl(StridedMatrix const& pts, +void AffineMap::CoeffGradImpl(StridedMatrix const& pts, StridedMatrix const& sens, StridedMatrix output) { return; } -template -void AffineMap::LogDeterminantInputGradImpl(StridedMatrix const& pts, +template +void AffineMap::LogDeterminantInputGradImpl(StridedMatrix const& pts, StridedMatrix output) { return; } template -void AffineMap::GradientImpl(StridedMatrix const& pts, +void AffineMap::GradientImpl(StridedMatrix const& pts, StridedMatrix const& sens, StridedMatrix output) { @@ -192,8 +192,16 @@ void AffineMap::GradientImpl(StridedMatrix +std::shared_ptr> AffineMap::Slice(int a, int b) { + StridedMatrix A_new; + StridedVector b_new; + if(A_.extent(0) > 0) A_new = Kokkos::subview(A_, std::make_pair(a,b), Kokkos::ALL()); + if(b_.size() > 0) b_new = Kokkos::subview(b_, std::make_pair(a,b)); + return std::make_shared>(A_new, b_new); +} template class mpart::AffineMap; #if defined(MPART_ENABLE_GPU) template class mpart::AffineMap; -#endif +#endif diff --git a/src/ComposedMap.cpp b/src/ComposedMap.cpp index c2eb0aca..381a1a98 100644 --- a/src/ComposedMap.cpp +++ b/src/ComposedMap.cpp @@ -8,7 +8,7 @@ using namespace mpart; template -ComposedMap::Checkpointer::Checkpointer(unsigned int maxSaves, +ComposedMap::Checkpointer::Checkpointer(unsigned int maxSaves, StridedMatrix initialPts, std::vector>>& comps) : maxSaves_(maxSaves), maps_(comps) @@ -23,7 +23,7 @@ ComposedMap::Checkpointer::Checkpointer(unsigned int maxSaves, checkpointLayers_.push_back(0); - // Allocate the workspace + // Allocate the workspace workspace1_ = Kokkos::View("xi", initialPts.extent(0), initialPts.extent(1)); workspace2_ = Kokkos::View("xj", initialPts.extent(0), initialPts.extent(1)); } @@ -37,7 +37,7 @@ int ComposedMap::Checkpointer::GetNextCheckpoint(unsigned int layer int currLayer = checkpointLayers_.back(); int oldLayer = currLayer; - + //ds = snaps - *check; int availSaves = int(maxSaves_) - checkpoints_.size(); if(availSaves==0){ @@ -46,12 +46,12 @@ int ComposedMap::Checkpointer::GetNextCheckpoint(unsigned int layer int reps = 0; int range = 1; - - while(range < layerInd+1 - currLayer) { + + while(range < layerInd+1 - currLayer) { reps += 1; - range = range*(reps + availSaves)/reps; + range = range*(reps + availSaves)/reps; } - + int bino1, bino2, bino3, bino4, bino5; bino1 = range*reps/(availSaves+reps); bino2 = (availSaves > 1) ? bino1*availSaves/(availSaves+reps-1) : 1; @@ -71,15 +71,15 @@ int ComposedMap::Checkpointer::GetNextCheckpoint(unsigned int layer if(layerInd-currLayer <= bino1 + bino3){ currLayer = currLayer + bino4; }else{ - if(layerInd-currLayer >= range - bino5){ - currLayer = currLayer + bino1; + if(layerInd-currLayer >= range - bino5){ + currLayer = currLayer + bino1; }else{ currLayer = layerInd-bino2-bino3; } } - if (currLayer == oldLayer) - currLayer = oldLayer + 1; + if (currLayer == oldLayer) + currLayer = oldLayer + 1; return currLayer; } @@ -87,7 +87,7 @@ int ComposedMap::Checkpointer::GetNextCheckpoint(unsigned int layer template Kokkos::View ComposedMap::Checkpointer::GetLayerInput(unsigned int layerInd) -{ +{ // Check if the layer asked for is the last checkpoint if(layerInd==checkpointLayers_.back()){ return checkpoints_.back(); @@ -99,21 +99,21 @@ Kokkos::View ComposedMap return GetLayerInput(layerInd); }else{ - - + + // Figure out how many more checkpoints we can make ("available saves") - - // Figure out the index of the next checkpoint + + // Figure out the index of the next checkpoint int nextCheckLayer = GetNextCheckpoint(layerInd); - + // Compute the input by reevaluating from the last checkpoint int i = checkpointLayers_.back(); maps_.at(i)->EvaluateImpl(checkpoints_.back(), workspace1_); ++i; for(; i("xi", workspace1_.extent(0), workspace1_.extent(1))); Kokkos::deep_copy(checkpoints_.back(),workspace1_); @@ -133,7 +133,7 @@ Kokkos::View ComposedMap template ComposedMap::ComposedMap(std::vector>> const& maps, bool moveCoeffs, - int maxChecks) : ConditionalMapBase(maps.front()->inputDim, + int maxChecks) : ConditionalMapBase(maps.front()->inputDim, maps.front()->inputDim, std::accumulate(maps.begin(), maps.end(), 0, [](size_t sum, std::shared_ptr> const& comp){ return sum + comp->numCoeffs; })), maps_(maps), @@ -159,7 +159,7 @@ ComposedMap::ComposedMap(std::vector coeffs("coeffs", this->numCoeffs); unsigned int cumNumCoeffs = 0; - + for(unsigned int i=0; iCheckCoefficients()){ @@ -241,14 +241,14 @@ void ComposedMap::LogDeterminantImpl(StridedMatrix intPts1("intermediate points 1", pts.extent(0), pts.extent(1)); Kokkos::View intPts2("intermediate points 2", pts.extent(0), pts.extent(1)); Kokkos::deep_copy(intPts1, pts); Kokkos::View compDetIncrement("Log Determinant", output.extent(0)); for(unsigned int i=1; iEvaluateImpl(intPts1, intPts2); @@ -271,7 +271,7 @@ void ComposedMap::EvaluateImpl(StridedMatrix intPts1("intermediate points 1", pts.extent(0), pts.extent(1)); Kokkos::View intPts2("intermediate points 2", pts.extent(0), pts.extent(1)); - + maps_.at(0)->EvaluateImpl(pts, intPts1); for(int j = 1; j::EvaluateImpl(StridedMatrix -void ComposedMap::GradientImpl(StridedMatrix const& pts, +void ComposedMap::GradientImpl(StridedMatrix const& pts, StridedMatrix const& sens, StridedMatrix output) { @@ -296,14 +296,14 @@ void ComposedMap::GradientImpl(StridedMatrix intSens1("intermediate Sens", sens.extent(0), sens.extent(1)); Kokkos::View intSens2("intermediate Sens", sens.extent(0), sens.extent(1)); - Kokkos::deep_copy(intSens1,sens); - + Kokkos::deep_copy(intSens1,sens); + Checkpointer checker(maxChecks_, pts, maps_); for(int i = maps_.size() - 1; i>=0; --i){ - + // x* = T_{i-1} o ... o T_1(x) - auto input = checker.GetLayerInput(i); + auto input = checker.GetLayerInput(i); //s_{i-1}^T = s_{i}^T J_i(x*) maps_.at(i)->GradientImpl(input, intSens1, intSens2); @@ -320,7 +320,7 @@ void ComposedMap::InverseImpl(StridedMatrix output) { // We assume each component of the composed map is square, so the x1 input is not used. - // We can just loop backward through the layers + // We can just loop backward through the layers // intermediate vals Kokkos::View intR1("intermediate r1", r.extent(0), r.extent(1)); @@ -330,7 +330,7 @@ void ComposedMap::InverseImpl(StridedMatrix=0; --i){ - + maps_.at(i)->InverseImpl(x1, intR1, intR2); // <- Note the x1 doesn't matter here because the layer is square simple_swap(intR1,intR2); } @@ -339,13 +339,13 @@ void ComposedMap::InverseImpl(StridedMatrix -void ComposedMap::CoeffGradImpl(StridedMatrix const& pts, +void ComposedMap::CoeffGradImpl(StridedMatrix const& pts, StridedMatrix const& sens, StridedMatrix output) { // T(x) = T_{n} o ... o T_1(x), T_i coeffs w_i - // s^T \nabla_{w_i} T(x) = s^T J_n * J_{n-1} *...*J_{i-1}* \nabla_w_i T_i + // s^T \nabla_{w_i} T(x) = s^T J_n * J_{n-1} *...*J_{i-1}* \nabla_w_i T_i Kokkos::View intSens1("intermediate sens 1", sens.extent(0), sens.extent(1)); Kokkos::View intSens2("intermediate sens 2", sens.extent(0), sens.extent(1)); Kokkos::deep_copy(intSens1, sens); @@ -353,15 +353,15 @@ void ComposedMap::CoeffGradImpl(StridedMatrix subOut; - int endParamDim = this->numCoeffs; + int endParamDim = this->numCoeffs; for(int i = maps_.size() - 1; i>=0; --i){ - // intPts1 = T_{i-1} o ... o T_1(x) + // intPts1 = T_{i-1} o ... o T_1(x) auto input = checker.GetLayerInput(i); // finish g_i = s^T \nabla_{w_i} T(x) - subOut = Kokkos::subview(output, - std::make_pair(int(endParamDim-maps_.at(i)->numCoeffs), endParamDim), + subOut = Kokkos::subview(output, + std::make_pair(int(endParamDim-maps_.at(i)->numCoeffs), endParamDim), Kokkos::ALL()); @@ -381,43 +381,43 @@ void ComposedMap::CoeffGradImpl(StridedMatrix -void ComposedMap::LogDeterminantCoeffGradImpl(StridedMatrix const& pts, +void ComposedMap::LogDeterminantCoeffGradImpl(StridedMatrix const& pts, StridedMatrix output) { StridedMatrix subOut; Kokkos::View intSens1("intermediate Sens", pts.extent(0), pts.extent(1)); Kokkos::View intSens2("intermediate Sens", pts.extent(0), pts.extent(1)); - + // Get the gradient of the log determinant contribution from the last component Checkpointer checker(maxChecks_, pts, maps_); - auto input = checker.GetLayerInput(maps_.size()-1); - + auto input = checker.GetLayerInput(maps_.size()-1); + int endParamDim = this->numCoeffs; - subOut = Kokkos::subview(output, - std::make_pair(int(endParamDim-maps_.back()->numCoeffs), endParamDim), + subOut = Kokkos::subview(output, + std::make_pair(int(endParamDim-maps_.back()->numCoeffs), endParamDim), Kokkos::ALL()); maps_.back()->LogDeterminantCoeffGradImpl(input, subOut); // Get the sensitivity of this log determinant term wrt changes in the input maps_.back()->LogDeterminantInputGradImpl(input, intSens1); - - endParamDim -= maps_.back()->numCoeffs; + + endParamDim -= maps_.back()->numCoeffs; for(int i = maps_.size() - 2; i>=0; --i){ - + // Compute input to this layer input = checker.GetLayerInput(i); // Gradient for direct contribution of these parameters on the log determinant - subOut = Kokkos::subview(output, - std::make_pair(int(endParamDim-maps_.at(i)->numCoeffs), endParamDim), + subOut = Kokkos::subview(output, + std::make_pair(int(endParamDim-maps_.at(i)->numCoeffs), endParamDim), Kokkos::ALL()); - + maps_.at(i)->LogDeterminantCoeffGradImpl(input, subOut); - // Gradient of later log determinant terms on the coefficients of this layer + // Gradient of later log determinant terms on the coefficients of this layer Kokkos::View subOut2("temp", maps_.at(i)->numCoeffs, pts.extent(1)); maps_.at(i)->CoeffGradImpl(input, intSens1, subOut2); subOut += subOut2; @@ -428,31 +428,31 @@ void ComposedMap::LogDeterminantCoeffGradImpl(StridedMatrix(intSens1, intSens2); // Add sensitivity of log determinant to input - maps_.at(i)->LogDeterminantInputGradImpl(input, intSens2); - - intSens1 += intSens2; + maps_.at(i)->LogDeterminantInputGradImpl(input, intSens2); + + intSens1 += intSens2; } - endParamDim -= maps_.at(i)->numCoeffs; + endParamDim -= maps_.at(i)->numCoeffs; } } template -void ComposedMap::LogDeterminantInputGradImpl(StridedMatrix const& pts, +void ComposedMap::LogDeterminantInputGradImpl(StridedMatrix const& pts, StridedMatrix output) { Kokkos::View intSens1("intermediate Sens", pts.extent(0), pts.extent(1)); Kokkos::View intSens2("intermediate Sens", pts.extent(0), pts.extent(1)); - + // Get the gradient of the log determinant contribution from the last component Checkpointer checker(maxChecks_, pts, maps_); auto input = checker.GetLayerInput(maps_.size()-1); - + maps_.back()->LogDeterminantInputGradImpl(input, intSens1); for(int i = maps_.size() - 2; i>=0; --i){ - + // reset intPts1 to initial pts input = checker.GetLayerInput(i); @@ -460,13 +460,27 @@ void ComposedMap::LogDeterminantInputGradImpl(StridedMatrixGradientImpl(input, intSens1, intSens2); simple_swap(intSens1, intSens2); - maps_.at(i)->LogDeterminantInputGradImpl(input, intSens2); - intSens1 += intSens2; + maps_.at(i)->LogDeterminantInputGradImpl(input, intSens2); + intSens1 += intSens2; } Kokkos::deep_copy(output, intSens1); } +template +std::shared_ptr> ComposedMap::Slice(int a, int b) { + assert(a < b && 0 <= a && b <= this->outputDim); + std::shared_ptr> lastMap = maps_[maps_.size()-1]; + if (lastMap->outputDim == b-a) { + return std::shared_ptr>(this); + } else { + std::vector>> newMaps; + newMaps = maps_; + newMaps[maps_.size()-1] = lastMap->Slice(a, b); + return std::make_shared>(newMaps); + } +} + // Explicit template instantiation template class mpart::ComposedMap; #if defined(MPART_ENABLE_GPU) diff --git a/src/ConditionalMapBase.cpp b/src/ConditionalMapBase.cpp index fcf0193a..ff09ddc0 100644 --- a/src/ConditionalMapBase.cpp +++ b/src/ConditionalMapBase.cpp @@ -40,27 +40,27 @@ Kokkos::View ConditionalMapBase template<> template<> Kokkos::View ConditionalMapBase::LogDeterminant(StridedMatrix const& pts) -{ +{ return ToHost( this->LogDeterminant( ToDevice(pts) )); } template<> template<> Kokkos::View ConditionalMapBase::LogDeterminant(StridedMatrix const& pts) -{ +{ return ToDevice( this->LogDeterminant( ToHost(pts) )); } template<> Eigen::VectorXd ConditionalMapBase::LogDeterminant(Eigen::Ref const& pts) -{ +{ StridedMatrix pts_view = ConstRowMatToKokkos(pts); Kokkos::View outView = ToHost( this->LogDeterminant( ToDevice(pts_view) )); return KokkosToVec(outView); } -#endif +#endif template<> template<> @@ -138,7 +138,7 @@ Eigen::RowMatrixXd ConditionalMapBase::Inverse(Eigen::Ref template<> @@ -177,10 +177,10 @@ template<> template<> StridedMatrix ConditionalMapBase::LogDeterminantCoeffGrad(StridedMatrix const& pts) { - // Copy the points to the device space + // Copy the points to the device space StridedMatrix pts_device = ToDevice(pts); - // Evaluate on the device space + // Evaluate on the device space StridedMatrix evals_device = this->LogDeterminantCoeffGrad(pts_device); // Copy back to the host space @@ -191,10 +191,10 @@ template<> template<> StridedMatrix ConditionalMapBase::LogDeterminantCoeffGrad(StridedMatrix const& pts) { - // Copy the points to the host + // Copy the points to the host StridedMatrix pts_host = ToHost(pts); - // Evaluate on the host + // Evaluate on the host StridedMatrix evals_host = this->LogDeterminantCoeffGrad(pts_host); // Copy back to the device @@ -254,10 +254,10 @@ template<> template<> StridedMatrix ConditionalMapBase::LogDeterminantInputGrad(StridedMatrix const& pts) { - // Copy the points to the device space + // Copy the points to the device space StridedMatrix pts_device = ToDevice(pts); - // Evaluate on the device space + // Evaluate on the device space StridedMatrix evals_device = this->LogDeterminantInputGrad(pts_device); // Copy back to the host space @@ -268,10 +268,10 @@ template<> template<> StridedMatrix ConditionalMapBase::LogDeterminantInputGrad(StridedMatrix const& pts) { - // Copy the points to the host + // Copy the points to the host StridedMatrix pts_host = ToHost(pts); - // Evaluate on the host + // Evaluate on the host StridedMatrix evals_host = this->LogDeterminantInputGrad(pts_host); // Copy back to the device diff --git a/src/IdentityMap.cpp b/src/IdentityMap.cpp index 01c6297c..538351ed 100644 --- a/src/IdentityMap.cpp +++ b/src/IdentityMap.cpp @@ -49,7 +49,7 @@ void IdentityMap::InverseImpl(StridedMatrix -void IdentityMap::CoeffGradImpl(StridedMatrix const& pts, +void IdentityMap::CoeffGradImpl(StridedMatrix const& pts, StridedMatrix const& sens, StridedMatrix output) { @@ -57,7 +57,7 @@ void IdentityMap::CoeffGradImpl(StridedMatrix -void IdentityMap::GradientImpl(StridedMatrix const& pts, +void IdentityMap::GradientImpl(StridedMatrix const& pts, StridedMatrix const& sens, StridedMatrix output) { @@ -77,16 +77,16 @@ void IdentityMap::GradientImpl(StridedMatrix -void IdentityMap::LogDeterminantCoeffGradImpl(StridedMatrix const& pts, +void IdentityMap::LogDeterminantCoeffGradImpl(StridedMatrix const& pts, StridedMatrix output) { assert(false); } template -void IdentityMap::LogDeterminantInputGradImpl(StridedMatrix const& pts, +void IdentityMap::LogDeterminantInputGradImpl(StridedMatrix const& pts, StridedMatrix output) -{ +{ Kokkos::MDRangePolicy, typename MemoryToExecution::Space> zeroPolicy({0, 0}, {output.extent(0), output.extent(1)}); Kokkos::parallel_for(zeroPolicy, KOKKOS_LAMBDA(const int& i, const int& j) { output(i,j) = 0.0; @@ -94,6 +94,14 @@ void IdentityMap::LogDeterminantInputGradImpl(StridedMatrix +std::shared_ptr> IdentityMap::Slice(int a, int b) { + assert(a >= 0); + assert(b <= this->outputDim); + assert(a < b); + return std::make_shared>(this->inputDim, b-a); +} + // Explicit template instantiation template class mpart::IdentityMap; #if defined(KOKKOS_ENABLE_CUDA ) || defined(KOKKOS_ENABLE_SYCL) diff --git a/src/MapFactory.cpp b/src/MapFactory.cpp index 70df3ec0..47dc1032 100644 --- a/src/MapFactory.cpp +++ b/src/MapFactory.cpp @@ -100,9 +100,9 @@ std::shared_ptr> mpart::MapFactory::CreateSingle template std::shared_ptr> mpart::MapFactory::CreateTriangular(unsigned int inputDim, - unsigned int outputDim, - unsigned int totalOrder, - MapOptions options) + unsigned int outputDim, + unsigned int totalOrder, + MapOptions options) { std::vector>> comps(outputDim); diff --git a/src/TriangularMap.cpp b/src/TriangularMap.cpp index 5203719e..f3126db6 100644 --- a/src/TriangularMap.cpp +++ b/src/TriangularMap.cpp @@ -12,10 +12,10 @@ TriangularMap::TriangularMap(std::vector> const& comp){ return sum + comp->numCoeffs; })), comps_(components) { - + // Check the sizes of all the inputs - + for(unsigned int i=0; ioutputDim > comps_.at(i)->inputDim){ std::stringstream msg; @@ -42,7 +42,7 @@ TriangularMap::TriangularMap(std::vector coeffs("coeffs", this->numCoeffs); unsigned int cumNumCoeffs = 0; - + for(unsigned int i=0; iCheckCoefficients()){ @@ -281,7 +281,7 @@ void TriangularMap::CoeffGradImpl(StridedMatrixnumCoeffs)), Kokkos::ALL()); comps_.at(i)->CoeffGradImpl(subPts, subSens, subOut); - + startParamDim += comps_.at(i)->numCoeffs; } @@ -345,6 +345,63 @@ void TriangularMap::LogDeterminantInputGradImpl(StridedMatrix +std::shared_ptr> TriangularMap::Slice(int a, int b) { + std::vector>> components; + // TODO: Handle empty case + if( a < 0 || a >= b || b > this->outputDim ) { + throw std::invalid_argument("TriangularMap::Slice: 0 <= a < b <= outputDim must be satisfied."); + } + // Special cases if the slice is at the end of the map + if( b <= this->comps_[0]->outputDim) { + return this->comps_[0]->Slice(a, b); + } + if( a >= this->outputDim - this->comps_[this->comps_.size()-1]->outputDim) { + unsigned int rest_of_output = this->outputDim - this->comps_[this->comps_.size()-1]->outputDim; + return this->comps_[this->comps_.size()-1]->Slice(a - rest_of_output, b - rest_of_output); + } + + int accum_a = 0; // Accumulated output dimension before a + int k_a = 0; // Index of component containing a + //TODO: Check that this is correct + while(k_a < this->comps_.size()){ + if(accum_a + this->comps_[k_a]->outputDim > a) + break; + accum_a += this->comps_[k_a]->outputDim; + k_a++; + } + + int accum_b = accum_a; // Accumulated output dimension before b + int k_b = k_a; // Index of component containing b + //TODO: Check that this is correct + while(k_b < this->comps_.size()){ + if(accum_b + this->comps_[k_b]->outputDim >= b) + break; + accum_b += this->comps_[k_b]->outputDim; + k_b++; + } + + if(k_a == k_b){ + components.push_back(this->comps_[k_a]->Slice(a-accum_a, b-accum_b)); + } else { + components = std::vector>>(this->comps_.begin()+k_a, this->comps_.begin()+k_b+1); + components[0] = this->comps_[k_a]->Slice(a-accum_a, this->comps_[k_a]->outputDim); + components[components.size()-1] = this->comps_[k_b]->Slice(0, b-accum_b); + } + auto output = std::make_shared>(components); + output->SetCoeffs(Kokkos::View("Component Coefficients", output->numCoeffs)); + return output; +} + +template +std::shared_ptr> TriangularMap::BlockSlice(int a, int b) { + std::vector>> components; + for(int k = a; k < b; k++){ + components.push_back(this->comps_[k]); + } + return std::make_shared>(components); +} + // Explicit template instantiation template class mpart::TriangularMap; #if defined(MPART_ENABLE_GPU) diff --git a/tests/Test_AffineMap.cpp b/tests/Test_AffineMap.cpp index b6dbffa5..554af1c1 100644 --- a/tests/Test_AffineMap.cpp +++ b/tests/Test_AffineMap.cpp @@ -9,7 +9,7 @@ using namespace Catch; TEST_CASE( "Testing Shift-only AffineMap", "[ShiftMap]" ) { Kokkos::View b("b", 2); - + b(0) = 1.0; b(1) = 2.0; @@ -46,7 +46,7 @@ TEST_CASE( "Testing Shift-only AffineMap", "[ShiftMap]" ) { TEST_CASE( "Testing Linear-only AffineMap", "[LinearMap]" ) { Kokkos::View A("A", 2,2); - + A(0,0) = 2.0; A(1,0) = 1.0; A(0,1) = 1.0; @@ -85,8 +85,8 @@ TEST_CASE( "Testing Linear-only AffineMap", "[LinearMap]" ) { TEST_CASE( "Testing Rectangular AffineMap", "[RectangularLinearMap]" ) { Kokkos::View A("A", 2,3); - - /* + + /* A = [[2.0, 3.0, 1.0], [1.0, 1.0, 4.0]] */ @@ -96,7 +96,7 @@ TEST_CASE( "Testing Rectangular AffineMap", "[RectangularLinearMap]" ) { A(1,1) = 1.0; A(0,2) = 1.0; A(1,2) = 4.0; - + auto map = std::make_shared>(A); @@ -139,7 +139,7 @@ TEST_CASE( "Testing Full AffineMap", "[FullAffineMap]" ) { Kokkos::View A("A", 2,2); Kokkos::View b("b", 2); - + A(0,0) = 2.0; A(1,0) = 1.0; A(0,1) = 1.0; @@ -178,13 +178,70 @@ TEST_CASE( "Testing Full AffineMap", "[FullAffineMap]" ) { } +TEST_CASE( "Testing AffineMap::Slice", "[AffineMapSlice]" ) { + Kokkos::View A("A", 3,3); + Kokkos::View b("b", 3); + std::fill(A.data(), A.data()+A.extent(0)*A.extent(1), 0.0); + + A(0,0) = 2.0; + A(1,0) = 1.0; + A(0,1) = 1.0; + A(1,1) = 4.0; + A(0,2) = 1.0; + A(1,2) = 4.0; + + A(2,0) = 2.0; + A(2,1) = 1.0; + A(2,2) = 3.0; + + b(0) = 1.0; + b(1) = 2.0; + b(2) = 3.0; + + auto map = std::make_shared>(A,b); + auto slice = map->Slice(0,2); + REQUIRE(slice->inputDim==3); + REQUIRE(slice->outputDim==2); + + unsigned int numPts = 3; + Kokkos::View pts("Point", A.extent(1), numPts); + for(unsigned int i=0; i logDet = slice->LogDeterminant(pts); + for(unsigned int i=0; i evals = slice->Evaluate(pts); + REQUIRE(evals.extent(0)==2); + REQUIRE(evals.extent(1)==pts.extent(1)); + + Kokkos::View pts2 = slice->Inverse(pts, evals); + REQUIRE(pts2.extent(0)==2); + REQUIRE(pts2.extent(1)==pts.extent(1)); + + for(unsigned int i=0; i hb("b", 2); - + hb(0) = 1.0; hb(1) = 2.0; @@ -193,7 +250,7 @@ TEST_CASE( "Testing Shift-only AffineMap on Device", "[DeviceShiftMap]" ) { auto map = std::make_shared>(db); - + unsigned int numPts = 10; Kokkos::View hpts("Point", 2, numPts); for(unsigned int i=0; i hA("A", 2,2); - + hA(0,0) = 2.0; hA(1,0) = 1.0; hA(0,1) = 1.0; @@ -263,7 +320,7 @@ TEST_CASE( "Testing Linear-only AffineMap on Device", "[DeviceLinearMap]" ) { auto dpts2 = map->Inverse(dpts, devals); auto hpts2 = ToHost(dpts2); - + for(unsigned int i=0; i hA("A", 2,3); - - /* + + /* A = [[2.0, 3.0, 1.0], [1.0, 1.0, 4.0]] */ @@ -290,7 +347,7 @@ TEST_CASE( "Testing Rectangular AffineMap on Device", "[DeviceRectangularLinearM hA(1,1) = 1.0; hA(0,2) = 1.0; hA(1,2) = 4.0; - + auto dA = ToDevice(hA); auto map = std::make_shared>(dA); @@ -338,7 +395,7 @@ TEST_CASE( "Testing Full AffineMap on Device", "[DeviceFullAffineMap]" ) { Kokkos::View hA("A", 2,2); Kokkos::View hb("b", 2); - + hA(0,0) = 2.0; hA(1,0) = 1.0; hA(0,1) = 1.0; @@ -349,7 +406,7 @@ TEST_CASE( "Testing Full AffineMap on Device", "[DeviceFullAffineMap]" ) { auto dA = ToDevice(hA); auto db = ToDevice(hb); - + auto map = std::make_shared>(dA,db); unsigned int numPts = 10; @@ -374,7 +431,7 @@ TEST_CASE( "Testing Full AffineMap on Device", "[DeviceFullAffineMap]" ) { auto dpts2 = map->Inverse(dpts, devals); auto hpts2 = ToHost(dpts2); - + for(unsigned int i=0; i{ public: - MyIdentityMap(unsigned int dim, unsigned int numCoeffs) : ConditionalMapBase(dim,dim,numCoeffs){}; + MyIdentityMap(unsigned int dim, unsigned int numCoeffs, unsigned int dimOut = 0) : ConditionalMapBase(dim,!dimOut? dim : dimOut,numCoeffs){}; virtual ~MyIdentityMap() = default; virtual void EvaluateImpl(StridedMatrix const& pts, - StridedMatrix output) override{Kokkos::deep_copy(output,pts);}; + StridedMatrix output) override{ + int a = this->inputDim - this->outputDim; + auto pts_view = Kokkos::subview(pts, std::make_pair(a, int(this->inputDim)), Kokkos::ALL()); + Kokkos::deep_copy(output,pts_view); + }; - virtual void GradientImpl(StridedMatrix const& pts, + virtual void GradientImpl(StridedMatrix const& pts, StridedMatrix const& sens, StridedMatrix output) override { - assert(false); + assert(false); } virtual void LogDeterminantImpl(StridedMatrix const&, @@ -32,25 +36,30 @@ class MyIdentityMap : public ConditionalMapBase{ StridedMatrix const& r, StridedMatrix output) override{Kokkos::deep_copy(output,r);}; - virtual void CoeffGradImpl(StridedMatrix const& pts, + virtual void CoeffGradImpl(StridedMatrix const& pts, StridedMatrix const& sens, StridedMatrix output) override { - assert(false); + assert(false); } - virtual void LogDeterminantCoeffGradImpl(StridedMatrix const& pts, + virtual void LogDeterminantCoeffGradImpl(StridedMatrix const& pts, StridedMatrix output) override - { + { assert(false); } - virtual void LogDeterminantInputGradImpl(StridedMatrix const& pts, + virtual void LogDeterminantInputGradImpl(StridedMatrix const& pts, StridedMatrix output) override - { + { assert(false); } + + // Only creates a slice of the tail of the input + std::shared_ptr> Slice(int a, int b) override{ + return std::make_shared(this->inputDim, 0, b-a); + } }; @@ -241,5 +250,47 @@ TEST_CASE( "Testing inverse evaluation of an identity conditional map", "[Condit } } } +} + +TEST_CASE( "Testing slicing evaluation of an identity conditional map", "[ConditionalMapBaseSlice]" ) { + unsigned int dim = 7; + unsigned int numPts = 5; + MyIdentityMap map(dim,0); + + int a = 2; + int b = 5; + std::shared_ptr> mapSlice = map.Slice(a,b); + + int sliceOutdim = b-a; + + CHECK(map.inputDim == dim); + CHECK(map.outputDim == dim); + + CHECK(mapSlice->inputDim == dim); + CHECK(mapSlice->outputDim == sliceOutdim); + + SECTION("Using Kokkos"){ + + Kokkos::View pts("pts", dim, numPts); + + for(unsigned int i=0; i output = mapSlice->Evaluate(pts); + + REQUIRE(output.extent(0)==sliceOutdim); + REQUIRE(output.extent(1)==numPts); + + int idx_start = map.inputDim - (b-a); + + for(unsigned int i=0; i(mset, options); } - std::shared_ptr> triMap = std::make_shared>(blocks); + std::shared_ptr> triMap = std::make_shared>(blocks); CHECK(triMap->outputDim == numBlocks); CHECK(triMap->inputDim == numBlocks+extraInputs); @@ -37,9 +37,9 @@ TEST_CASE( "Testing 3d triangular map from MonotoneComponents with moveCoeffs=fa Kokkos::View coeffs("Coefficients", triMap->numCoeffs); for(unsigned int i=0; inumCoeffs; ++i) coeffs(i) = 0.1*(i+1); - + SECTION("Coefficients"){ - + // Set the coefficients of the triangular map triMap->SetCoeffs(coeffs); @@ -65,11 +65,11 @@ TEST_CASE( "Testing 3d triangular map from MonotoneComponents with moveCoeffs=fa triMap->SetCoeffs(coeffs); auto out = triMap->Evaluate(in); - + SECTION("Evaluation"){ for(unsigned int i=0; iEvaluate(Kokkos::subview(in, std::make_pair(0,int(i+1+extraInputs)), Kokkos::ALL())); REQUIRE(outBlock.extent(1)==numSamps); @@ -134,16 +134,16 @@ TEST_CASE( "Testing 3d triangular map from MonotoneComponents with moveCoeffs=fa evals2 = triMap->Evaluate(in); for(unsigned int ptInd=0; ptIndoutputDim; ++j) fdDeriv += sens(j,ptInd) * (evals2(j,ptInd)-evals(j,ptInd))/fdstep; - CHECK( coeffGrad(i,ptInd) == Approx(fdDeriv).margin(1e-3)); + CHECK( coeffGrad(i,ptInd) == Approx(fdDeriv).margin(1e-3)); } coeffs(i) -= fdstep; } - + } @@ -173,18 +173,18 @@ TEST_CASE( "Testing 3d triangular map from MonotoneComponents with moveCoeffs=fa evals2 = triMap->Evaluate(in); for(unsigned int ptInd=0; ptIndoutputDim; ++j) fdDeriv += sens(j,ptInd) * (evals2(j,ptInd)-evals(j,ptInd))/fdstep; - CHECK( inputGrad(i,ptInd) == Approx(fdDeriv).margin(1e-3)); + CHECK( inputGrad(i,ptInd) == Approx(fdDeriv).margin(1e-3)); } for(unsigned int ptInd=0; ptInd detGrad = triMap->LogDeterminantCoeffGrad(in); REQUIRE(detGrad.extent(0)==triMap->numCoeffs); REQUIRE(detGrad.extent(1)==numSamps); - + Kokkos::View logDet = triMap->LogDeterminant(in); Kokkos::View logDet2; @@ -212,8 +212,8 @@ TEST_CASE( "Testing 3d triangular map from MonotoneComponents with moveCoeffs=fa logDet2 = triMap->LogDeterminant(in); for(unsigned int ptInd=0; ptInd>> blocks(numBlocks); std::vector> coeffs_(numBlocks); for(unsigned int i=0;i mset(i+extraInputs+1,maxDegree); coeffSize += mset.Size(); @@ -248,9 +248,9 @@ TEST_CASE( "Testing 3d triangular map from MonotoneComponents with moveCoeffs=tr for(unsigned int j=0; jnumCoeffs; ++j) coeffs_.at(i)(j) = 0.1*(j+1); - + blocks.at(i)->SetCoeffs(coeffs_.at(i)); - + } bool moveCoeffs=true; std::shared_ptr> triMap = std::make_shared>(blocks, moveCoeffs); @@ -269,7 +269,7 @@ TEST_CASE( "Testing 3d triangular map from MonotoneComponents with moveCoeffs=tr for(unsigned int i=0; inumCoeffs; ++j){ CHECK(blocks.at(i)->Coeffs()(j) == coeffs(cumCoeffInd)); // Values of coefficients should be equal - CHECK(blocks.at(i)->Coeffs()(j) == coeffs_.at(i)(j)); + CHECK(blocks.at(i)->Coeffs()(j) == coeffs_.at(i)(j)); CHECK(&blocks.at(i)->Coeffs()(j) == &coeffs(cumCoeffInd)); // Memory location should also be the same (no copy) cumCoeffInd++; } @@ -286,13 +286,13 @@ TEST_CASE( "Testing 3d triangular map from MonotoneComponents with moveCoeffs=tr } - + auto out = triMap->Evaluate(in); - + SECTION("Evaluation"){ for(unsigned int i=0; iEvaluate(Kokkos::subview(in, std::make_pair(0,int(i+1+extraInputs)), Kokkos::ALL())); REQUIRE(outBlock.extent(1)==numSamps); @@ -357,16 +357,16 @@ TEST_CASE( "Testing 3d triangular map from MonotoneComponents with moveCoeffs=tr evals2 = triMap->Evaluate(in); for(unsigned int ptInd=0; ptIndoutputDim; ++j) fdDeriv += sens(j,ptInd) * (evals2(j,ptInd)-evals(j,ptInd))/fdstep; - CHECK( coeffGrad(i,ptInd) == Approx(fdDeriv).margin(1e-3)); + CHECK( coeffGrad(i,ptInd) == Approx(fdDeriv).margin(1e-3)); } coeffs(i) -= fdstep; } - + } @@ -396,18 +396,18 @@ TEST_CASE( "Testing 3d triangular map from MonotoneComponents with moveCoeffs=tr evals2 = triMap->Evaluate(in); for(unsigned int ptInd=0; ptIndoutputDim; ++j) fdDeriv += sens(j,ptInd) * (evals2(j,ptInd)-evals(j,ptInd))/fdstep; - CHECK( inputGrad(i,ptInd) == Approx(fdDeriv).margin(1e-3)); + CHECK( inputGrad(i,ptInd) == Approx(fdDeriv).margin(1e-3)); } for(unsigned int ptInd=0; ptInd detGrad = triMap->LogDeterminantCoeffGrad(in); REQUIRE(detGrad.extent(0)==triMap->numCoeffs); REQUIRE(detGrad.extent(1)==numSamps); - + Kokkos::View logDet = triMap->LogDeterminant(in); Kokkos::View logDet2; @@ -435,8 +435,8 @@ TEST_CASE( "Testing 3d triangular map from MonotoneComponents with moveCoeffs=tr logDet2 = triMap->LogDeterminant(in); for(unsigned int ptInd=0; ptInd coeffs("Coefficients", triMap->numCoeffs); for(unsigned int i=0; inumCoeffs; ++i) coeffs(i) = 0.1*(i+1); - + SECTION("Coefficients"){ - + // Set the coefficients of the triangular map triMap->SetCoeffs(coeffs); @@ -505,18 +505,18 @@ TEST_CASE( "Testing TriangularMap made from smaller TriangularMaps with moveCoef triMap->SetCoeffs(coeffs); auto out = triMap->Evaluate(in); - + SECTION("Evaluation"){ unsigned int start = 0; for(unsigned int b=0; binputDim)), Kokkos::ALL()); auto subOut = Kokkos::subview(out, std::make_pair(int(start), int(start + blocks.at(b)->outputDim)), Kokkos::ALL()); auto outBlock = blocks.at(b)->Evaluate(subIn); - + REQUIRE(outBlock.extent(1)==subOut.extent(1)); REQUIRE(outBlock.extent(0)==subOut.extent(0)); @@ -584,16 +584,16 @@ TEST_CASE( "Testing TriangularMap made from smaller TriangularMaps with moveCoef evals2 = triMap->Evaluate(in); for(unsigned int ptInd=0; ptIndoutputDim; ++j) fdDeriv += sens(j,ptInd) * (evals2(j,ptInd)-evals(j,ptInd))/fdstep; - CHECK( coeffGrad(i,ptInd) == Approx(fdDeriv).margin(1e-3)); + CHECK( coeffGrad(i,ptInd) == Approx(fdDeriv).margin(1e-3)); } coeffs(i) -= fdstep; } - + } @@ -623,18 +623,18 @@ TEST_CASE( "Testing TriangularMap made from smaller TriangularMaps with moveCoef evals2 = triMap->Evaluate(in); for(unsigned int ptInd=0; ptIndoutputDim; ++j) fdDeriv += sens(j,ptInd) * (evals2(j,ptInd)-evals(j,ptInd))/fdstep; - CHECK( inputGrad(i,ptInd) == Approx(fdDeriv).epsilon(1e-3)); + CHECK( inputGrad(i,ptInd) == Approx(fdDeriv).epsilon(1e-3)); } for(unsigned int ptInd=0; ptInd detGrad = triMap->LogDeterminantCoeffGrad(in); REQUIRE(detGrad.extent(0)==triMap->numCoeffs); REQUIRE(detGrad.extent(1)==numSamps); - + Kokkos::View logDet = triMap->LogDeterminant(in); Kokkos::View logDet2; @@ -662,8 +662,8 @@ TEST_CASE( "Testing TriangularMap made from smaller TriangularMaps with moveCoef logDet2 = triMap->LogDeterminant(in); for(unsigned int ptInd=0; ptIndnumCoeffs == coeffSize); - + SECTION("Coefficients"){ - + // Now make sure that the coefficients of each block were set unsigned int cumCoeffInd = 0; for(unsigned int i=0; inumCoeffs; ++j){ CHECK(blocks.at(i)->Coeffs()(j) == triMap->Coeffs()(cumCoeffInd)); // Values of coefficients should be equal - CHECK(blocks.at(i)->Coeffs()(j) == coeffs_.at(i)(j)); + CHECK(blocks.at(i)->Coeffs()(j) == coeffs_.at(i)(j)); CHECK(&blocks.at(i)->Coeffs()(j) == &triMap->Coeffs()(cumCoeffInd)); // Memory location should also be the same (no copy) cumCoeffInd++; } @@ -736,18 +736,18 @@ TEST_CASE( "Testing TriangularMap made from smaller TriangularMaps with moveCoef } auto out = triMap->Evaluate(in); - + SECTION("Evaluation"){ unsigned int start = 0; for(unsigned int b=0; binputDim)), Kokkos::ALL()); auto subOut = Kokkos::subview(out, std::make_pair(int(start), int(start + blocks.at(b)->outputDim)), Kokkos::ALL()); auto outBlock = blocks.at(b)->Evaluate(subIn); - + REQUIRE(outBlock.extent(1)==subOut.extent(1)); REQUIRE(outBlock.extent(0)==subOut.extent(0)); @@ -815,16 +815,16 @@ TEST_CASE( "Testing TriangularMap made from smaller TriangularMaps with moveCoef evals2 = triMap->Evaluate(in); for(unsigned int ptInd=0; ptIndoutputDim; ++j) fdDeriv += sens(j,ptInd) * (evals2(j,ptInd)-evals(j,ptInd))/fdstep; - CHECK( coeffGrad(i,ptInd) == Approx(fdDeriv).margin(1e-3)); + CHECK( coeffGrad(i,ptInd) == Approx(fdDeriv).margin(1e-3)); } coeffs(i) -= fdstep; } - + } @@ -854,18 +854,18 @@ TEST_CASE( "Testing TriangularMap made from smaller TriangularMaps with moveCoef evals2 = triMap->Evaluate(in); for(unsigned int ptInd=0; ptIndoutputDim; ++j) fdDeriv += sens(j,ptInd) * (evals2(j,ptInd)-evals(j,ptInd))/fdstep; - CHECK( inputGrad(i,ptInd) == Approx(fdDeriv).epsilon(1e-3)); + CHECK( inputGrad(i,ptInd) == Approx(fdDeriv).epsilon(1e-3)); } for(unsigned int ptInd=0; ptInd detGrad = triMap->LogDeterminantCoeffGrad(in); REQUIRE(detGrad.extent(0)==triMap->numCoeffs); REQUIRE(detGrad.extent(1)==numSamps); - + Kokkos::View logDet = triMap->LogDeterminant(in); Kokkos::View logDet2; @@ -893,16 +893,36 @@ TEST_CASE( "Testing TriangularMap made from smaller TriangularMaps with moveCoef logDet2 = triMap->LogDeterminant(in); for(unsigned int ptInd=0; ptIndSlice(sliceBegin, sliceEnd); + REQUIRE(slice->inputDim == sliceEnd); + REQUIRE(slice->outputDim == sliceEnd-sliceBegin); + + auto outSlice = slice->Evaluate(in); + auto outFull = triMap->Evaluate(in); + + // Just test the evaluation + for(unsigned int i=sliceBegin; i>(slice); + } +} TEST_CASE( "Testing TriangularMap made using CreateSingleEntryMap", "[TriangularMap_CreateSingleEntryMap]" ) { @@ -925,9 +945,9 @@ TEST_CASE( "Testing TriangularMap made using CreateSingleEntryMap", "[Triangular Kokkos::View coeffs("Coefficients", triMap->numCoeffs); for(unsigned int i=0; inumCoeffs; ++i) coeffs(i) = 0.1*(i+1); - + SECTION("Coefficients"){ - + // Set the coefficients of the triangular map triMap->SetCoeffs(coeffs); @@ -937,7 +957,7 @@ TEST_CASE( "Testing TriangularMap made using CreateSingleEntryMap", "[Triangular CHECK(comp->Coeffs()(i) == triMap->Coeffs()(i)); // Values of coefficients should be equal CHECK(&comp->Coeffs()(i) == &triMap->Coeffs()(i)); // Memory location should also be the same (no copy) } - + } unsigned int numSamps = 10; @@ -950,7 +970,7 @@ TEST_CASE( "Testing TriangularMap made using CreateSingleEntryMap", "[Triangular triMap->SetCoeffs(coeffs); auto out = triMap->Evaluate(in); - + SECTION("Evaluation"){ unsigned int start = 0; @@ -991,9 +1011,9 @@ TEST_CASE( "Testing TriangularMap made using CreateSingleEntryMap", "[Triangular } SECTION("LogDeterminant"){ - + auto inTopAndMid = Kokkos::subview(in, std::make_pair(0, int(activeInd)), Kokkos::ALL()); - + auto logDet = triMap->LogDeterminant(in); auto logDet_ = comp->LogDeterminant(inTopAndMid); @@ -1030,16 +1050,16 @@ TEST_CASE( "Testing TriangularMap made using CreateSingleEntryMap", "[Triangular evals2 = triMap->Evaluate(in); for(unsigned int ptInd=0; ptIndoutputDim; ++j) fdDeriv += sens(j,ptInd) * (evals2(j,ptInd)-evals(j,ptInd))/fdstep; - CHECK( coeffGrad(i,ptInd) == Approx(fdDeriv).margin(1e-3)); + CHECK( coeffGrad(i,ptInd) == Approx(fdDeriv).margin(1e-3)); } coeffs(i) -= fdstep; } - + } @@ -1069,18 +1089,18 @@ TEST_CASE( "Testing TriangularMap made using CreateSingleEntryMap", "[Triangular evals2 = triMap->Evaluate(in); for(unsigned int ptInd=0; ptIndoutputDim; ++j) fdDeriv += sens(j,ptInd) * (evals2(j,ptInd)-evals(j,ptInd))/fdstep; - CHECK( inputGrad(i,ptInd) == Approx(fdDeriv).margin(1e-3)); + CHECK( inputGrad(i,ptInd) == Approx(fdDeriv).margin(1e-3)); } for(unsigned int ptInd=0; ptInd detGrad = triMap->LogDeterminantCoeffGrad(in); REQUIRE(detGrad.extent(0)==triMap->numCoeffs); REQUIRE(detGrad.extent(1)==numSamps); - + Kokkos::View logDet = triMap->LogDeterminant(in); Kokkos::View logDet2; @@ -1108,8 +1128,8 @@ TEST_CASE( "Testing TriangularMap made using CreateSingleEntryMap", "[Triangular logDet2 = triMap->LogDeterminant(in); for(unsigned int ptInd=0; ptInd