Program Listing for File misc.h

Return to documentation for file (include/amici/misc.h)

#ifndef AMICI_MISC_H
#define AMICI_MISC_H

#include "amici/defines.h"
#include "amici/exception.h"
#include "amici/vector.h"
#include <sunmatrix/sunmatrix_sparse.h> // SUNMatrixContent_Sparse

#include <algorithm>
#include <ctime>
#include <functional>
#include <regex>
#include <vector>

#ifdef HAS_BOOST_CHRONO
#include <boost/chrono/thread_clock.hpp>
#endif

#include <gsl/gsl-lite.hpp>

namespace amici {

template <class T>
gsl::span<T> slice(std::vector<T>& data, int index, unsigned size) {
    if ((index + 1) * size > data.size())
        throw std::out_of_range("requested slice is out of data range");
    if (size > 0)
        return gsl::make_span(&data.at(index * size), size);

    return gsl::make_span(static_cast<T*>(nullptr), 0);
}

template <class T>
gsl::span<T const> slice(std::vector<T> const& data, int index, unsigned size) {
    if ((index + 1) * size > data.size())
        throw std::out_of_range("requested slice is out of data range");
    if (size > 0)
        return gsl::make_span(&data.at(index * size), size);

    return gsl::make_span(static_cast<T*>(nullptr), 0);
}

template <class T>
void checkBufferSize(
    gsl::span<T> buffer, typename gsl::span<T>::index_type expected_size
) {
    if (buffer.size() != expected_size)
        throw AmiException(
            "Incorrect buffer size! Was %u, expected %u.", buffer.size(),
            expected_size
        );
}

/* TODO: templating writeSlice breaks implicit conversion between vector & span
 not sure whether this is fixable */

template <class T>
void writeSlice(gsl::span<T const> const slice, gsl::span<T> buffer) {
    checkBufferSize(buffer, slice.size());
    std::copy(slice.begin(), slice.end(), buffer.data());
};

template <class T>
void addSlice(gsl::span<T const> const slice, gsl::span<T> buffer) {
    checkBufferSize(buffer, slice.size());
    std::transform(
        slice.begin(), slice.end(), buffer.begin(), buffer.begin(),
        std::plus<T>()
    );
};

template <class T> void writeSlice(std::vector<T> const& s, std::vector<T>& b) {
    writeSlice(
        gsl::make_span(s.data(), s.size()), gsl::make_span(b.data(), b.size())
    );
};

template <class T> void writeSlice(std::vector<T> const& s, gsl::span<T> b) {
    writeSlice(gsl::make_span(s.data(), s.size()), b);
};

template <class T> void addSlice(std::vector<T> const& s, gsl::span<T> b) {
    addSlice(gsl::make_span(s.data(), s.size()), b);
};

void writeSlice(AmiVector const& s, gsl::span<realtype> b);

void unscaleParameters(
    gsl::span<realtype const> bufferScaled,
    gsl::span<ParameterScaling const> pscale, gsl::span<realtype> bufferUnscaled
);

double getUnscaledParameter(double scaledParameter, ParameterScaling scaling);

double getScaledParameter(double unscaledParameter, ParameterScaling scaling);

void scaleParameters(
    gsl::span<realtype const> bufferUnscaled,
    gsl::span<ParameterScaling const> pscale, gsl::span<realtype> bufferScaled
);

std::string backtraceString(int maxFrames, int const first_frame = 0);

std::string regexErrorToString(std::regex_constants::error_type err_type);

std::string printfToString(char const* fmt, va_list ap);

class ContextManager {
  public:
    ContextManager() = default;
    ContextManager(ContextManager& other) = delete;
    ContextManager(ContextManager&& other) = delete;
};

auto unravel_index(size_t flat_idx, size_t num_cols)
    -> std::pair<size_t, size_t>;

template <class T> bool is_equal(T const& a, T const& b) {
    if (a.size() != b.size())
        return false;

    auto a_data = a.data();
    auto b_data = b.data();
    for (typename T::size_type i = 0; i < a.size(); ++i) {
        if (a_data[i] != b_data[i]
            && !(std::isnan(a_data[i]) && std::isnan(b_data[i])))
            return false;
    }
    return true;
}

#ifdef BOOST_CHRONO_HAS_THREAD_CLOCK
class CpuTimer {
    using clock = boost::chrono::thread_clock;
    using time_point = clock::time_point;
    using d_seconds = boost::chrono::duration<double>;
    using d_milliseconds = boost::chrono::duration<double, boost::milli>;

  public:
    CpuTimer()
        : start_(clock::now()) {}

    void reset() { start_ = clock::now(); }

    double elapsed_seconds() const {
        return d_seconds(clock::now() - start_).count();
    }

    double elapsed_milliseconds() const {
        return d_milliseconds(clock::now() - start_).count();
    }

    static bool const uses_thread_clock = true;

  private:
    time_point start_;
};
#else
class CpuTimer {
  public:
    CpuTimer()
        : start_(std::clock()) {}

    void reset() { start_ = std::clock(); }

    double elapsed_seconds() const {
        return static_cast<double>(std::clock() - start_) / CLOCKS_PER_SEC;
    }

    double elapsed_milliseconds() const {
        return static_cast<double>(std::clock() - start_) * 1000.0
               / CLOCKS_PER_SEC;
    }

    static bool const uses_thread_clock = false;

  private:
    std::clock_t start_;
};
#endif

} // namespace amici

#endif // AMICI_MISC_H