/*
* Fatrop - A fast trajectory optimization solver
* Copyright (C) 2022 - 2024 Lander Vanroye, KU Leuven. All rights reserved.
*
* This file is part of Fatrop.
*
* Fatrop is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Fatrop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Fatrop. If not, see . */
#ifndef FATROP_BLASFEO_INCLUDED
#define FATROP_BLASFEO_INCLUDED
// macros
extern "C"
{
void blasfeo_ref_drowpe(int kmax, int *ipiv, struct blasfeo_dmat *sA);
void blasfeo_ref_drowpei(int kmax, int *ipiv, struct blasfeo_dmat *sA);
}
#define MAT blasfeo_dmat
#define VEC blasfeo_dvec
#define MEMSIZE_MAT blasfeo_memsize_dmat
#define CREATE_MAT blasfeo_create_dmat
// #define ROWPE blasfeo_drowpe
#define ROWPE blasfeo_ref_drowpe
#define VECPE blasfeo_dvecpe
#define VECPEI blasfeo_dvecpei
// #define ROWPEI blasfeo_drowpei
#define ROWPEI blasfeo_ref_drowpei
#define COLPE blasfeo_dcolpe
#define COLPEI blasfeo_dcolpei
#define CREATE_MAT blasfeo_create_dmat
#define MATEL BLASFEO_DMATEL
#define ROWSW blasfeo_drowsw
#define COLSW blasfeo_dcolsw
#define GEAD blasfeo_dgead
#define GECP blasfeo_dgecp
#define GESC blasfeo_dgesc
#define VECCP blasfeo_dveccp
#define VECCPSC blasfeo_dveccpsc
// #define TRSM_LLNN blasfeo_dtrsm_llnn
#define TRSM_RLTN blasfeo_dtrsm_rltn
#define VECEL BLASFEO_DVECEL
#define MEMSIZE_VEC blasfeo_memsize_dvec
#define CREATE_VEC blasfeo_create_dvec
#define GEMM_NT blasfeo_dgemm_nt
#define GEAD blasfeo_dgead
#define SYRK_LN_MN blasfeo_dsyrk_ln_mn
#define SYRK_LN blasfeo_dsyrk_ln
#define GETR blasfeo_dgetr
#define TRTR_L blasfeo_dtrtr_l
#define POTRF_L_MN blasfeo_dpotrf_l_mn
#define ROWEX blasfeo_drowex
#define ROWIN blasfeo_drowin
#define COLIN blasfeo_dcolin
#define ROWAD fatrop_drowad
#define TRSV_LTN blasfeo_dtrsv_ltn
#define TRSV_LNN blasfeo_dtrsv_lnn
#define TRSV_UTN blasfeo_dtrsv_utn
#define GEMV_T blasfeo_dgemv_t
#define GEMV_N blasfeo_dgemv_n
#define VECSE blasfeo_dvecse
#define VECSC blasfeo_dvecsc
#define PACKMAT blasfeo_pack_dmat
#define UNPACKVEC blasfeo_unpack_dvec
#define PACKVEC blasfeo_pack_dvec
#define PMAT PermMat
#define AXPY blasfeo_daxpy
#define AXPBY blasfeo_daxpby
#define DOT blasfeo_ddot
#define GESE blasfeo_dgese
#define DIARE blasfeo_ddiare
#define COLSC blasfeo_dcolsc
#define VECMUL blasfeo_dvecmul
#define VECMULACC blasfeo_dvecmulacc
#define GER blasfeo_dger
// functions not implemented by blasfeo_hp
#define GEADTR fatrop_dgead_transposed
#define VECCPR fatrop_dveccp_reversed
#define ROWAD fatrop_drowad
#define TRSV_UNU fatrop_dtrsv_unu
#define TRSV_UTU fatrop_dtrsv_utu
#if defined(BLASFEO_REF_API)
#define TRSM_RLNN blasfeo_dtrsm_rlnn
#else
void blasfeo_ref_dtrsm_rlnn_copy(int m, int n, double alpha, struct MAT *sA, int ai, int aj, struct MAT *sB, int bi, int bj, struct MAT *sD, int di, int dj);
#define TRSM_RLNN blasfeo_ref_dtrsm_rlnn_copy
#endif
#ifndef __GNUC__
#define MAX(a, b) max(a, b)
#define MIN(a, b) min(a, b)
#else
#define MAX(a, b) \
( \
{ \
__typeof__(a) _a = (a); \
__typeof__(b) _b = (b); \
_a > _b ? _a : _b; \
})
#define MIN(a, b) \
( \
{ \
__typeof__(a) _a = (a); \
__typeof__(b) _b = (b); \
_a < _b ? _a : _b; \
})
#endif
#include
extern "C"
{
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include
}
#include "fatrop/auxiliary/LinearAlgebra.hpp"
#include "fatrop/auxiliary/FatropVector.hpp"
#include "fatrop/auxiliary/Common.hpp"
#include
#if DEBUG
#include
#endif
namespace fatrop
{
void fatrop_dcolsc(fatrop_int kmax, double alpha, struct blasfeo_dmat *sA, fatrop_int ai, fatrop_int aj);
// copy elements from sx to sy but in reversed order to avoid aliasing issues in recursion
void fatrop_dveccp_reversed(fatrop_int m, struct blasfeo_dvec *sx, fatrop_int xi, struct blasfeo_dvec *sy, fatrop_int yi);
// for debugging purposes
// void fatrop_potrf_l_mn(fatrop_int m, fatrop_int n, struct blasfeo_dmat *sC, fatrop_int ci, fatrop_int cj, struct blasfeo_dmat *sD, fatrop_int di, fatrop_int dj);
void test();
/** \brief D <= alpha * B * A^{-1} , with A lower triangular employing explicit inverse of diagonal, fatrop uses its own (naive) implementation since it not implemented yet in blasfeo */
void fatrop_dtrsm_rlnn(fatrop_int m, fatrop_int n, double alpha, MAT *sA, fatrop_int offs_ai, fatrop_int offs_aj, MAT *sB, fatrop_int offs_bi, fatrop_int offs_bj, MAT *sD, fatrop_int offs_di, fatrop_int offs_dj);
/** \brief D <= alpha * B * A^{-1} , with A lower triangular employing explicit inverse of diagonal, fatrop uses its own (naive) implementation since it not implemented yet in blasfeo */
void fatrop_dtrsm_rlnn_alt(fatrop_int m, fatrop_int n, double alpha, MAT *sA, fatrop_int offs_ai, fatrop_int offs_aj, MAT *sB, fatrop_int offs_bi, fatrop_int offs_bj, MAT *sD, fatrop_int offs_di, fatrop_int offs_dj);
/** \brief B <= B + alpha*A^T (B is mxn) */
void fatrop_dgead_transposed(fatrop_int m, fatrop_int n, double alpha, struct blasfeo_dmat *sA, fatrop_int offs_ai, fatrop_int offs_aj, struct blasfeo_dmat *sB, fatrop_int offs_bi, fatrop_int offs_bj);
void fatrop_identity(const fatrop_int m, MAT *sA, const fatrop_int ai, const fatrop_int aj);
void fatrop_drowad(fatrop_int kmax, double alpha, struct blasfeo_dvec *sx, fatrop_int xi, struct blasfeo_dmat *sA, fatrop_int ai, fatrop_int aj);
/** \brief this class is used for blasfeo matrices*/
class FatropMatBF : public FatropMat
{
public:
/** \brief constructor memory still has to be allocated*/
FatropMatBF(const fatrop_int nrows, const fatrop_int ncols, const fatrop_int row_offset, const fatrop_int col_offset);
/** \brief constructor memory already allocated*/
FatropMatBF(const fatrop_int nrows, const fatrop_int ncols, const fatrop_int row_offset, const fatrop_int col_offset, MAT *matbf);
/** \brief constructor memory already allocated*/
FatropMatBF(MAT *matbf);
/** \brief type conversion to blasfeo matrix pointer*/
inline explicit operator MAT *() const
{
return this->mat_;
}
/** \brief acces to element of matrix */
inline double &at(const fatrop_int ai, const fatrop_int aj) const
{
#if DEBUG
assert(ai < nrows_);
assert(aj < ncols_);
#endif
return MATEL(mat_, ai + row_offset_, aj + col_offset_);
};
/** \brief get element of matrix */
inline double get_el(const fatrop_int ai, const fatrop_int aj) const { return this->at(ai, aj); };
/** \brief get number of rows */
inline fatrop_int nrows() const { return nrows_; };
/** \brief get number of cols */
inline fatrop_int ncols() const { return ncols_; };
/** \brief copies all elements from a given fatrop_matrix to this matrix*/
void operator=(const FatropMat &fm);
/** \brief set data pointer*/
void set_datap(MAT *matbf)
{
mat_ = matbf;
}
/** \brief take a block of size (p,q), starting at (i,j)*/
FatropMatBF block(const fatrop_int i, const fatrop_int j, const fatrop_int p, const fatrop_int q) const
{
return FatropMatBF(p, q, row_offset_ + i, col_offset_ + j, this->mat_);
}
private:
MAT *mat_ = NULL;
const fatrop_int row_offset_;
const fatrop_int col_offset_;
const fatrop_int nrows_;
const fatrop_int ncols_;
};
class MATBF
{
public:
MATBF(const int m, const int n) : m_(m), n_(n)
{
blasfeo_allocate_dmat(m_, n_, &mat_);
}
MATBF(MATBF &&other) : m_(other.m_), n_(other.n_)
{
mat_ = other.mat_;
other.mat_.pA = nullptr;
other.mat_.mem = nullptr;
other.mat_.dA = nullptr;
}
~MATBF()
{
blasfeo_free_dmat(&mat_);
}
operator MAT *()
{
return &mat_;
}
MAT mat_;
const int m_;
const int n_;
};
class VECBF
{
public:
VECBF(const int m) : m_(m)
{
blasfeo_allocate_dvec(m_, &vec_);
// zero out vector
blasfeo_dvecse(m_, 0.0, &vec_, 0);
}
VECBF(VECBF &&other) : m_(other.m_)
{
vec_ = other.vec_;
other.vec_.pa = nullptr;
other.vec_.mem = nullptr;
}
~VECBF()
{
blasfeo_free_dvec(&vec_);
}
operator VEC *()
{
return &vec_;
}
bool has_inf()
{
for (int i = 0; i < m_; i++)
{
if (std::isinf(VECEL(&vec_, i)))
{
return true;
}
}
return false;
}
VEC vec_;
const int m_;
};
/** \brief this class is used for the allocation of a blasfeo matrix, the dimsensions are set from a vector */
class FatropMemoryMatBF
{
public:
/** \brief constuction for allocation on fatrop_memory_allocator*/
FatropMemoryMatBF(const FatropVector &nrows, const FatropVector &ncols, fatrop_int N);
// TODO: if rvalue-reference is used -> unecessary copy, use move sementics instead.;
FatropMemoryMatBF(const fatrop_int nrows, const fatrop_int ncols, fatrop_int N);
/** \brief calculate memory size*/
fatrop_int memory_size() const;
/** \brief set up memory element and advance pointer */
void set_up();
/** \brief get fatrop matrix bf */
FatropMatBF operator[](const fatrop_int N) const;
/** \brief get first blasfeo_xmat* struct */
explicit operator MAT *() const
{
return mat;
}
FatropMemoryMatBF(const FatropMemoryMatBF &cpy) = delete;
FatropMemoryMatBF &operator=(const FatropMemoryMatBF &) = delete;
~FatropMemoryMatBF();
private:
void *mem = NULL;
MAT *mat;
const fatrop_int N_;
const FatropVector nrows_;
const FatropVector ncols_;
};
/** this class is used for blasfeo vectors*/
class FatropVecBF : public FatropVec
{
public:
/** \brief constructor memory still has to be allocated*/
FatropVecBF(const fatrop_int nels, const fatrop_int offset);
/** \brief constructor memory already allocated*/
FatropVecBF(const fatrop_int nels, const fatrop_int offset, VEC *vecbf);
/** \brief type conversion to blasfeo vector pointer*/
explicit operator VEC *() const;
/** \brief access to element of matrix */
inline double &at(const fatrop_int ai) const
{
#if DEBUG
assert(ai < nels_);
#endif
return VECEL(vec_, ai + offset_);
};
/** \brief get element of vector */
double get_el(const fatrop_int ai) const;
/** \brief get number of elements */
fatrop_int nels() const;
/** \brief get offset */
fatrop_int offset() const;
/** \brief copies all elements from a given fatrop_vector to this vector*/
void operator=(const FatropVec &fm);
void operator=(const double &val)
{
blasfeo_dvecse(nels(), val, vec_, offset());
}
void copy(const FatropVecBF &fm) const;
void copyto(std::vector &dest) const;
void operator=(const std::vector &fm);
/** \brief set data pointer*/
void set_datap(VEC *vecbf);
/** \brief take a block of size (p), starting at (i)*/
FatropVecBF block(const fatrop_int i, const fatrop_int p) const;
void SwapWith(FatropVecBF &vb);
void SetConstant(double constant) const;
friend double sum(const FatropVecBF &va)
{
double ret = 0.0;
for (int i = 0; i < va.nels(); i++)
{
ret += va.at(i);
}
return ret;
}
bool has_inf() const
{
for (int i = 0; i < nels(); i++)
{
if (std::isinf(VECEL(vec_, i)))
{
return true;
}
}
return false;
}
bool has_nan() const
{
for (int i = 0; i < nels(); i++)
{
if (std::isnan(VECEL(vec_, i)))
{
return true;
}
}
return false;
}
protected:
VEC *vec_ = NULL;
const fatrop_int offset_;
const fatrop_int nels_;
};
void axpy(const double alpha, const FatropVecBF &va, const FatropVecBF &vb, const FatropVecBF &vc);
void copy(const FatropVecBF &va, const FatropVecBF &vb);
void axpby(const double alpha, const FatropVecBF &va, const double beta, const FatropVecBF &vb, const FatropVecBF &vc);
double dot(const FatropVecBF &va, FatropVecBF &vb);
double Linf(const FatropVecBF &va);
double LinfScaled(const FatropVecBF &va, const FatropVecBF &scales);
double minabs(const FatropVecBF &va);
double L1(const FatropVecBF &va);
double sumsqr(const FatropVecBF &va);
/** \brief this class is used for the allocation of a blasfeo vector, the dimsensions are set from a vector */
class FatropMemoryVecBF
{
public:
/** \brief constuction for allocation on MemoryAllocator*/
FatropMemoryVecBF(const FatropVector &nels, fatrop_int N);
// TODO: if rvalue-reference is used -> unecessary copy, use move sementics instead.;
FatropMemoryVecBF(const fatrop_int nels, fatrop_int N = 1);
/** \brief calculate memory size*/
fatrop_int memory_size() const;
/** \brief set up memory element and advance pointer */
void set_up();
/** \brief get fatrop matrix bf */
FatropVecBF operator[](const fatrop_int N) const;
/** \brief get first blasfeo_xmat* struct */
explicit operator VEC *() const
{
return vec;
}
FatropMemoryVecBF(const FatropMemoryVecBF &cpy) = delete;
FatropMemoryVecBF &operator=(const FatropMemoryVecBF &) = delete;
~FatropMemoryVecBF();
private:
void *mem = NULL;
VEC *vec;
const fatrop_int N_;
const FatropVector nels_;
};
/** \brief this class represents a permutation matrix */
class PermMat : public FatropMat
{
public:
/** \brief constructor memory still has to be allocated */
PermMat(const fatrop_int dim);
;
/** \brief constructor memory already allocated */
PermMat(const fatrop_int dim, fatrop_int *data);
;
/** \brief get number of rows */
fatrop_int nrows() const { return dim_; };
/** \brief get number of columns */
fatrop_int ncols() const { return dim_; };
/** \brief get element of matrix represented by this permutation matrix - only used for debugging and testing purposes */
double get_el(const fatrop_int ai, const fatrop_int aj) const;
void print(const fatrop_int kmax) const;
/** \brief set data pointer*/
void set_datap(fatrop_int *data);
/** \brief set data point*/
void set_datap(const fatrop_int i, const fatrop_int val);
/** \brief apply row permutation*/
void PM(const fatrop_int kmax, MAT *M) const;
/** \brief apply vec permutation*/
void PV(const fatrop_int kmax, VEC *V, const fatrop_int offs) const;
/** \brief apply vec permutation*/
void PtV(const fatrop_int kmax, VEC *V, const fatrop_int offs) const;
/** \brief apply row permutation on partial matrix*/
void PM(const fatrop_int kmax, const fatrop_int n, MAT *M, const fatrop_int ai, const fatrop_int aj) const;
/** \brief apply inverse row permutation*/
void
PtM(const fatrop_int kmax, MAT *M) const;
/** \brief apply inverse col permutation*/
void MP(const fatrop_int kmax, MAT *M) const;
/** \brief apply col permutation*/
void MPt(const fatrop_int kmax, MAT *M) const;
/** fatrop_int pointer of permutation vector */
explicit operator fatrop_int *() { return data_; };
// private:
const fatrop_int dim_;
fatrop_int *data_ = NULL;
};
/** \brief this class is used for the allocation of a permutation matrix */
class MemoryPermMat : public PermMat
{
public:
/** \brief constructor */
MemoryPermMat(const fatrop_int dim, const fatrop_int N);
/** \brief calculate needed memory size*/
fatrop_int memory_size() const;
/** \brief set up memory*/
void set_up();
explicit operator PermMat *()
{
return perm_p;
};
MemoryPermMat(const MemoryPermMat &cpy) = delete;
MemoryPermMat &operator=(const MemoryPermMat &) = delete;
~MemoryPermMat();
private:
void *mem = NULL;
const fatrop_int dim_;
const fatrop_int N_;
PermMat *perm_p;
};
MatrixInd max_el(fatrop_int m, fatrop_int n, MAT *matr, fatrop_int ai, fatrop_int aj);
/** \brief Function to calculate LU factorization result is saved in A, L is lower unitriangular */
void LU_FACT(const fatrop_int m, const fatrop_int n, const fatrop_int n_max, fatrop_int &rank, MAT *A, PMAT *Pl_p, PMAT *Pr_p, double tol = 1e-8);
/** \brief Function to calculate LU factorization but A, and result (L and U) are transposed, all indices refer to the dimensions of the original A matrix (and not the transposed one) */
void LU_FACT_transposed(const fatrop_int m, const fatrop_int n, const fatrop_int n_max, fatrop_int &rank, MAT *At, PMAT *Pl_p, PMAT *Pr_p, double tol = 1e-5);
void fatrop_dtrsv_unu(const fatrop_int m, const fatrop_int n, blasfeo_dmat *sA, const fatrop_int ai, const fatrop_int aj, blasfeo_dvec *sx, const fatrop_int xi, blasfeo_dvec *sz, const fatrop_int zi);
void fatrop_dtrsv_utu(const fatrop_int m, blasfeo_dmat *sA, const fatrop_int ai, const fatrop_int aj, blasfeo_dvec *sx, const fatrop_int xi, blasfeo_dvec *sz, const fatrop_int zi);
} // namespace fatrop
#endif // FATROP_BLASFEO_INCLUDED