mirror of
https://github.com/aportelli/LatAnalyze.git
synced 2025-06-17 14:57:05 +01:00
reintegration of LatCore & folder restructuration
This commit is contained in:
123
lib/Core/Eigen.hpp
Normal file
123
lib/Core/Eigen.hpp
Normal file
@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Eigen.hpp, part of LatAnalyze 3
|
||||
*
|
||||
* Copyright (C) 2013 - 2016 Antonin Portelli
|
||||
*
|
||||
* LatAnalyze 3 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LatAnalyze 3 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LatAnalyze 3. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Eigen inclusion
|
||||
#define EIGEN_DONT_PARALLELIZE
|
||||
#define EIGEN_MATRIXBASE_PLUGIN <LatAnalyze/Core/EigenPlugin.hpp>
|
||||
#include <LatAnalyze/Eigen/Dense>
|
||||
|
||||
// copy/assignement from Eigen expression
|
||||
#define EIGEN_EXPR_CTOR(ctorName, Class, Base, ExprType) \
|
||||
template <typename Derived>\
|
||||
ctorName(const ExprType<Derived> &m): Base(m) {}\
|
||||
template<typename Derived>\
|
||||
Class & operator=(const ExprType<Derived> &m)\
|
||||
{\
|
||||
this->Base::operator=(m);\
|
||||
return *this;\
|
||||
}
|
||||
|
||||
#define FOR_MAT(mat, i, j) \
|
||||
for (Latan::Index j = 0; j < mat.cols(); ++j)\
|
||||
for (Latan::Index i = 0; i < mat.rows(); ++i)
|
||||
|
||||
BEGIN_LATAN_NAMESPACE
|
||||
|
||||
const int dynamic = Eigen::Dynamic;
|
||||
|
||||
// array types
|
||||
template <typename Derived>
|
||||
using ArrayExpr = Eigen::ArrayBase<Derived>;
|
||||
|
||||
template <typename T, int nRow = dynamic, int nCol = dynamic>
|
||||
using Array = Eigen::Array<T, nRow, nCol>;
|
||||
|
||||
// matrix types
|
||||
template <typename Derived>
|
||||
using MatExpr = Eigen::MatrixBase<Derived>;
|
||||
|
||||
template <typename T, int nRow = dynamic, int nCol = dynamic>
|
||||
using MatBase = Eigen::Matrix<T, nRow, nCol>;
|
||||
|
||||
template <int nRow, int nCol>
|
||||
using SFMat = Eigen::Matrix<float, nRow, nCol>;
|
||||
|
||||
template <int nRow, int nCol>
|
||||
using SDMat = Eigen::Matrix<double, nRow, nCol>;
|
||||
|
||||
template <int nRow, int nCol>
|
||||
using SCMat = Eigen::Matrix<std::complex<double>, nRow, nCol>;
|
||||
|
||||
// vector types
|
||||
template <typename T, int size = dynamic>
|
||||
using Vec = MatBase<T, size, 1>;
|
||||
|
||||
template <int size>
|
||||
using SIVec = Vec<int, size>;
|
||||
|
||||
template <int size>
|
||||
using SUVec = Vec<unsigned int, size>;
|
||||
|
||||
template <int size>
|
||||
using SFVec = Vec<float, size>;
|
||||
|
||||
template <int size>
|
||||
using SDVec = Vec<double, size>;
|
||||
|
||||
template <int size>
|
||||
using SCVec = Vec<std::complex<double>, size>;
|
||||
|
||||
typedef SIVec<dynamic> IVec;
|
||||
typedef SUVec<dynamic> UVec;
|
||||
typedef SDVec<dynamic> DVec;
|
||||
typedef SCVec<dynamic> CVec;
|
||||
|
||||
// block types
|
||||
template <typename Derived>
|
||||
using Block = Eigen::Block<Derived>;
|
||||
template <typename Derived>
|
||||
using ConstBlock = const Eigen::Block<const Derived>;
|
||||
|
||||
template <typename Derived>
|
||||
using Row = typename Derived::RowXpr;
|
||||
template <typename Derived>
|
||||
using ConstRow = typename Derived::ConstRowXpr;
|
||||
|
||||
template <typename Derived>
|
||||
using Col = typename Derived::ColXpr;
|
||||
template <typename Derived>
|
||||
using ConstCol = typename Derived::ConstColXpr;
|
||||
|
||||
// map type
|
||||
template <int stride>
|
||||
using InnerStride = Eigen::InnerStride<stride>;
|
||||
template <int rowStride, int colStride>
|
||||
using Stride = Eigen::Stride<rowStride, colStride>;
|
||||
template <typename Derived, typename StrideType = Stride<0, 0>>
|
||||
using Map = Eigen::Map<Derived, Eigen::Unaligned, StrideType>;
|
||||
template <typename Derived, typename StrideType = Stride<0, 0>>
|
||||
using ConstMap = Eigen::Map<const Derived, Eigen::Unaligned, StrideType>;
|
||||
|
||||
// Index type //////////////////////////////////////////////////////////////////
|
||||
typedef MatBase<int>::Index Index;
|
||||
|
||||
#define FOR_VEC(vec, i) for (Latan::Index i = 0; i < (vec).size(); ++i)
|
||||
#define FOR_ARRAY(ar, i) FOR_VEC(ar, i)
|
||||
|
||||
END_LATAN_NAMESPACE
|
60
lib/Core/EigenPlugin.hpp
Normal file
60
lib/Core/EigenPlugin.hpp
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* EigenPlugin.hpp, part of LatAnalyze
|
||||
*
|
||||
* Copyright (C) 2015 Antonin Portelli
|
||||
*
|
||||
* LatAnalyze is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LatAnalyze 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LatAnalyze. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
Derived pInverse(const double tolerance = 1.0e-10)
|
||||
{
|
||||
auto svd = jacobiSvd(Eigen::ComputeThinU|Eigen::ComputeThinV);
|
||||
const auto u = svd.matrixU();
|
||||
const auto v = svd.matrixV();
|
||||
auto s = svd.singularValues();
|
||||
double maxsv = 0.;
|
||||
unsigned int elim = 0;
|
||||
|
||||
for (Index i = 0; i < s.rows(); ++i)
|
||||
{
|
||||
if (fabs(s(i)) > maxsv) maxsv = fabs(s(i));
|
||||
}
|
||||
for (Index i = 0; i < s.rows(); ++i)
|
||||
{
|
||||
if (fabs(s(i)) > maxsv*tolerance)
|
||||
{
|
||||
s(i) = 1./s(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
elim++;
|
||||
s(i) = 0.;
|
||||
}
|
||||
}
|
||||
if (elim)
|
||||
{
|
||||
std::cerr << "warning: pseudoinverse: " << elim << "/";
|
||||
std::cerr << s.rows() << " singular value(s) eliminated (tolerance= ";
|
||||
std::cerr << tolerance << ")" << std::endl;
|
||||
}
|
||||
|
||||
return v*s.asDiagonal()*u.transpose();
|
||||
}
|
||||
|
||||
Derived singularValues(void)
|
||||
{
|
||||
auto svd = jacobiSvd();
|
||||
|
||||
return svd.singularValues();
|
||||
}
|
51
lib/Core/Exceptions.cpp
Normal file
51
lib/Core/Exceptions.cpp
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Exceptions.cpp, part of LatAnalyze 3
|
||||
*
|
||||
* Copyright (C) 2013 - 2016 Antonin Portelli
|
||||
*
|
||||
* LatAnalyze 3 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LatAnalyze 3 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LatAnalyze 3. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <LatAnalyze/Core/Exceptions.hpp>
|
||||
#include <LatAnalyze/includes.hpp>
|
||||
|
||||
#ifndef ERR_SUFF
|
||||
#define ERR_SUFF " (" + loc + ")"
|
||||
#endif
|
||||
|
||||
#define CONST_EXC(name, init) \
|
||||
name::name(string msg, string loc)\
|
||||
:init\
|
||||
{}
|
||||
|
||||
using namespace std;
|
||||
using namespace Latan;
|
||||
using namespace Exceptions;
|
||||
|
||||
// logic errors
|
||||
CONST_EXC(Logic, logic_error(Env::msgPrefix + msg + ERR_SUFF))
|
||||
CONST_EXC(Definition, Logic("definition error: " + msg, loc))
|
||||
CONST_EXC(Implementation, Logic("implementation error: " + msg, loc))
|
||||
CONST_EXC(Range, Logic("range error: " + msg, loc))
|
||||
CONST_EXC(Size, Logic("size error: " + msg, loc))
|
||||
// runtime errors
|
||||
CONST_EXC(Runtime, runtime_error(Env::msgPrefix + msg + ERR_SUFF))
|
||||
CONST_EXC(Argument, Runtime("argument error: " + msg, loc))
|
||||
CONST_EXC(Compilation, Runtime("compilation error: " + msg, loc))
|
||||
CONST_EXC(Io, Runtime("IO error: " + msg, loc))
|
||||
CONST_EXC(Memory, Runtime("memory error: " + msg, loc))
|
||||
CONST_EXC(Parsing, Runtime(msg, loc))
|
||||
CONST_EXC(Program, Runtime(msg, loc))
|
||||
CONST_EXC(Syntax, Runtime("syntax error: " + msg, loc))
|
||||
CONST_EXC(System, Runtime("system error: " + msg, loc))
|
66
lib/Core/Exceptions.hpp
Normal file
66
lib/Core/Exceptions.hpp
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Exceptions.hpp, part of LatAnalyze 3
|
||||
*
|
||||
* Copyright (C) 2013 - 2016 Antonin Portelli
|
||||
*
|
||||
* LatAnalyze 3 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LatAnalyze 3 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LatAnalyze 3. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef Latan_Exceptions_hpp_
|
||||
#define Latan_Exceptions_hpp_
|
||||
|
||||
#include <stdexcept>
|
||||
#ifndef LATAN_GLOBAL_HPP_
|
||||
#include <LatAnalyze/Global.hpp>
|
||||
#endif
|
||||
|
||||
#define SRC_LOC strFrom(__FUNCTION__) + " at " + strFrom(__FILE__) + ":"\
|
||||
+ strFrom(__LINE__)
|
||||
#define LATAN_ERROR(exc,msg) throw(Exceptions::exc(msg, SRC_LOC))
|
||||
#define LATAN_WARNING(msg) \
|
||||
std::cerr << Env::msgPrefix << "warning: " << msg\
|
||||
<< " (" << SRC_LOC << ")" << std::endl
|
||||
|
||||
#define DECL_EXC(name, base) \
|
||||
class name: public base\
|
||||
{\
|
||||
public:\
|
||||
name(std::string msg, std::string loc);\
|
||||
}
|
||||
|
||||
BEGIN_LATAN_NAMESPACE
|
||||
|
||||
namespace Exceptions
|
||||
{
|
||||
// logic errors
|
||||
DECL_EXC(Logic, std::logic_error);
|
||||
DECL_EXC(Definition, Logic);
|
||||
DECL_EXC(Implementation, Logic);
|
||||
DECL_EXC(Range, Logic);
|
||||
DECL_EXC(Size, Logic);
|
||||
// runtime errors
|
||||
DECL_EXC(Runtime, std::runtime_error);
|
||||
DECL_EXC(Argument, Runtime);
|
||||
DECL_EXC(Compilation, Runtime);
|
||||
DECL_EXC(Io, Runtime);
|
||||
DECL_EXC(Memory, Runtime);
|
||||
DECL_EXC(Parsing, Runtime);
|
||||
DECL_EXC(Program, Runtime);
|
||||
DECL_EXC(Syntax, Runtime);
|
||||
DECL_EXC(System, Runtime);
|
||||
}
|
||||
|
||||
END_LATAN_NAMESPACE
|
||||
|
||||
#endif // Latan_Exceptions_hpp_
|
36
lib/Core/Mat.cpp
Normal file
36
lib/Core/Mat.cpp
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Mat.cpp, part of LatAnalyze 3
|
||||
*
|
||||
* Copyright (C) 2013 - 2016 Antonin Portelli
|
||||
*
|
||||
* LatAnalyze 3 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LatAnalyze 3 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LatAnalyze 3. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <LatAnalyze/Core/Mat.hpp>
|
||||
#include <LatAnalyze/includes.hpp>
|
||||
|
||||
using namespace std;
|
||||
|
||||
/******************************************************************************
|
||||
* DMat implementation *
|
||||
******************************************************************************/
|
||||
// IO //////////////////////////////////////////////////////////////////////////
|
||||
namespace Latan
|
||||
{
|
||||
template <>
|
||||
IoObject::IoType Mat<double>::getType(void) const
|
||||
{
|
||||
return IoType::dMat;
|
||||
}
|
||||
}
|
69
lib/Core/Mat.hpp
Normal file
69
lib/Core/Mat.hpp
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Mat.hpp, part of LatAnalyze 3
|
||||
*
|
||||
* Copyright (C) 2013 - 2016 Antonin Portelli
|
||||
*
|
||||
* LatAnalyze 3 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LatAnalyze 3 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LatAnalyze 3. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef Latan_Mat_hpp_
|
||||
#define Latan_Mat_hpp_
|
||||
|
||||
#include <LatAnalyze/Global.hpp>
|
||||
#include <LatAnalyze/Io/IoObject.hpp>
|
||||
|
||||
BEGIN_LATAN_NAMESPACE
|
||||
|
||||
/******************************************************************************
|
||||
* matrix type *
|
||||
******************************************************************************/
|
||||
template <typename T>
|
||||
class Mat: public MatBase<T>, public IoObject
|
||||
{
|
||||
public:
|
||||
// constructors
|
||||
Mat(void) = default;
|
||||
Mat(const Index nRow, const Index nCol);
|
||||
EIGEN_EXPR_CTOR(Mat, Mat<T>, MatBase<T>, MatExpr)
|
||||
// destructor
|
||||
virtual ~Mat(void) = default;
|
||||
// IO
|
||||
virtual IoType getType(void) const;
|
||||
};
|
||||
|
||||
// type aliases
|
||||
typedef Mat<int> IMat;
|
||||
typedef Mat<long int> LMat;
|
||||
typedef Mat<double> DMat;
|
||||
typedef Mat<std::complex<double>> CMat;
|
||||
|
||||
/******************************************************************************
|
||||
* Mat template implementation *
|
||||
******************************************************************************/
|
||||
// constructors ////////////////////////////////////////////////////////////////
|
||||
template <typename T>
|
||||
Mat<T>::Mat(const Index nRow, const Index nCol)
|
||||
: MatBase<T>(nRow, nCol)
|
||||
{}
|
||||
|
||||
// IO //////////////////////////////////////////////////////////////////////////
|
||||
template <typename T>
|
||||
IoObject::IoType Mat<T>::getType(void) const
|
||||
{
|
||||
return IoType::noType;
|
||||
}
|
||||
|
||||
END_LATAN_NAMESPACE
|
||||
|
||||
#endif // Latan_Mat_hpp_
|
114
lib/Core/Math.cpp
Normal file
114
lib/Core/Math.cpp
Normal file
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Math.cpp, part of LatAnalyze 3
|
||||
*
|
||||
* Copyright (C) 2013 - 2016 Antonin Portelli
|
||||
*
|
||||
* LatAnalyze 3 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LatAnalyze 3 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LatAnalyze 3. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <LatAnalyze/Core/Math.hpp>
|
||||
#include <LatAnalyze/includes.hpp>
|
||||
#include <gsl/gsl_cdf.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace Latan;
|
||||
|
||||
/******************************************************************************
|
||||
* Custom math functions *
|
||||
******************************************************************************/
|
||||
DMat MATH_NAMESPACE::varToCorr(const DMat &var)
|
||||
{
|
||||
DMat res = var, invDiag = res.diagonal();
|
||||
|
||||
invDiag = invDiag.cwiseInverse().cwiseSqrt();
|
||||
res = (invDiag*invDiag.transpose()).cwiseProduct(res);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Standard C functions *
|
||||
******************************************************************************/
|
||||
|
||||
#define DEF_STD_FUNC_1ARG(name) \
|
||||
auto name##VecFunc = [](const double arg[1]){return (name)(arg[0]);};\
|
||||
DoubleFunction STDMATH_NAMESPACE::name(name##VecFunc, 1);
|
||||
|
||||
#define DEF_STD_FUNC_2ARG(name) \
|
||||
auto name##VecFunc = [](const double arg[2]){return (name)(arg[0], arg[1]);};\
|
||||
DoubleFunction STDMATH_NAMESPACE::name(name##VecFunc, 2);
|
||||
|
||||
// Trigonometric functions
|
||||
DEF_STD_FUNC_1ARG(cos)
|
||||
DEF_STD_FUNC_1ARG(sin)
|
||||
DEF_STD_FUNC_1ARG(tan)
|
||||
DEF_STD_FUNC_1ARG(acos)
|
||||
DEF_STD_FUNC_1ARG(asin)
|
||||
DEF_STD_FUNC_1ARG(atan)
|
||||
DEF_STD_FUNC_2ARG(atan2)
|
||||
|
||||
// Hyperbolic functions
|
||||
DEF_STD_FUNC_1ARG(cosh)
|
||||
DEF_STD_FUNC_1ARG(sinh)
|
||||
DEF_STD_FUNC_1ARG(tanh)
|
||||
DEF_STD_FUNC_1ARG(acosh)
|
||||
DEF_STD_FUNC_1ARG(asinh)
|
||||
DEF_STD_FUNC_1ARG(atanh)
|
||||
|
||||
// Exponential and logarithmic functions
|
||||
DEF_STD_FUNC_1ARG(exp)
|
||||
DEF_STD_FUNC_1ARG(log)
|
||||
DEF_STD_FUNC_1ARG(log10)
|
||||
DEF_STD_FUNC_1ARG(exp2)
|
||||
DEF_STD_FUNC_1ARG(expm1)
|
||||
DEF_STD_FUNC_1ARG(log1p)
|
||||
DEF_STD_FUNC_1ARG(log2)
|
||||
|
||||
// Power functions
|
||||
DEF_STD_FUNC_2ARG(pow)
|
||||
DEF_STD_FUNC_1ARG(sqrt)
|
||||
DEF_STD_FUNC_1ARG(cbrt)
|
||||
DEF_STD_FUNC_2ARG(hypot)
|
||||
|
||||
// Error and gamma functions
|
||||
DEF_STD_FUNC_1ARG(erf)
|
||||
DEF_STD_FUNC_1ARG(erfc)
|
||||
DEF_STD_FUNC_1ARG(tgamma)
|
||||
DEF_STD_FUNC_1ARG(lgamma)
|
||||
|
||||
// Rounding and remainder functions
|
||||
DEF_STD_FUNC_1ARG(ceil)
|
||||
DEF_STD_FUNC_1ARG(floor)
|
||||
DEF_STD_FUNC_2ARG(fmod)
|
||||
DEF_STD_FUNC_1ARG(trunc)
|
||||
DEF_STD_FUNC_1ARG(round)
|
||||
DEF_STD_FUNC_1ARG(rint)
|
||||
DEF_STD_FUNC_1ARG(nearbyint)
|
||||
DEF_STD_FUNC_2ARG(remainder)
|
||||
|
||||
// Minimum, maximum, difference functions
|
||||
DEF_STD_FUNC_2ARG(fdim)
|
||||
DEF_STD_FUNC_2ARG(fmax)
|
||||
DEF_STD_FUNC_2ARG(fmin)
|
||||
|
||||
// Absolute value
|
||||
DEF_STD_FUNC_1ARG(fabs)
|
||||
|
||||
// p-value
|
||||
auto chi2PValueVecFunc = [](const double arg[2])
|
||||
{
|
||||
return gsl_cdf_chisq_Q(arg[0], arg[1]);
|
||||
};
|
||||
|
||||
DoubleFunction MATH_NAMESPACE::chi2PValue(chi2PValueVecFunc, 2);
|
159
lib/Core/Math.hpp
Normal file
159
lib/Core/Math.hpp
Normal file
@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Math.hpp, part of LatAnalyze 3
|
||||
*
|
||||
* Copyright (C) 2013 - 2016 Antonin Portelli
|
||||
*
|
||||
* LatAnalyze 3 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LatAnalyze 3 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LatAnalyze 3. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef Latan_Math_hpp_
|
||||
#define Latan_Math_hpp_
|
||||
|
||||
#include <LatAnalyze/Global.hpp>
|
||||
#include <LatAnalyze/Functional/Function.hpp>
|
||||
#include <LatAnalyze/Core/MathInterpreter.hpp>
|
||||
|
||||
BEGIN_LATAN_NAMESPACE
|
||||
|
||||
/******************************************************************************
|
||||
* Custom math functions *
|
||||
******************************************************************************/
|
||||
#define MATH_NAMESPACE Math
|
||||
|
||||
namespace MATH_NAMESPACE
|
||||
{
|
||||
// integer power function
|
||||
template <unsigned int n, typename T>
|
||||
typename std::enable_if<(n == 0), T>::type pow(const T x __dumb)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
template <unsigned int n, typename T>
|
||||
typename std::enable_if<(n == 1), T>::type pow(const T x)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
template <unsigned int n, typename T>
|
||||
typename std::enable_if<(n > 1), T>::type pow(const T x)
|
||||
{
|
||||
return x*pow<n-1>(x);
|
||||
}
|
||||
|
||||
// integral factorial function
|
||||
template <typename T>
|
||||
T factorial(const T n)
|
||||
{
|
||||
static_assert(std::is_integral<T>::value,
|
||||
"factorial must me used with an integral argument");
|
||||
|
||||
T res = n;
|
||||
for (T i = n - 1; i != 0; --i)
|
||||
{
|
||||
res *= i;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// convert variance matrix to correlation matrix
|
||||
DMat varToCorr(const DMat &var);
|
||||
|
||||
// Constants
|
||||
constexpr double pi = 3.1415926535897932384626433832795028841970;
|
||||
constexpr double e = 2.7182818284590452353602874713526624977572;
|
||||
constexpr double inf = std::numeric_limits<double>::infinity();
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* Standard C functions *
|
||||
******************************************************************************/
|
||||
#define STDMATH_NAMESPACE StdMath
|
||||
|
||||
#define DECL_STD_FUNC(name) \
|
||||
namespace STDMATH_NAMESPACE\
|
||||
{\
|
||||
extern DoubleFunction name;\
|
||||
}
|
||||
|
||||
// Trigonometric functions
|
||||
DECL_STD_FUNC(cos)
|
||||
DECL_STD_FUNC(sin)
|
||||
DECL_STD_FUNC(tan)
|
||||
DECL_STD_FUNC(acos)
|
||||
DECL_STD_FUNC(asin)
|
||||
DECL_STD_FUNC(atan)
|
||||
DECL_STD_FUNC(atan2)
|
||||
|
||||
// Hyperbolic functions
|
||||
DECL_STD_FUNC(cosh)
|
||||
DECL_STD_FUNC(sinh)
|
||||
DECL_STD_FUNC(tanh)
|
||||
DECL_STD_FUNC(acosh)
|
||||
DECL_STD_FUNC(asinh)
|
||||
DECL_STD_FUNC(atanh)
|
||||
|
||||
// Exponential and logarithmic functions
|
||||
DECL_STD_FUNC(exp)
|
||||
DECL_STD_FUNC(log)
|
||||
DECL_STD_FUNC(log10)
|
||||
DECL_STD_FUNC(exp2)
|
||||
DECL_STD_FUNC(expm1)
|
||||
DECL_STD_FUNC(log1p)
|
||||
DECL_STD_FUNC(log2)
|
||||
|
||||
// Power functions
|
||||
DECL_STD_FUNC(pow)
|
||||
DECL_STD_FUNC(sqrt)
|
||||
DECL_STD_FUNC(cbrt)
|
||||
DECL_STD_FUNC(hypot)
|
||||
|
||||
// Error and gamma functions
|
||||
DECL_STD_FUNC(erf)
|
||||
DECL_STD_FUNC(erfc)
|
||||
DECL_STD_FUNC(tgamma)
|
||||
DECL_STD_FUNC(lgamma)
|
||||
|
||||
// Rounding and remainder functions
|
||||
DECL_STD_FUNC(ceil)
|
||||
DECL_STD_FUNC(floor)
|
||||
DECL_STD_FUNC(fmod)
|
||||
DECL_STD_FUNC(trunc)
|
||||
DECL_STD_FUNC(round)
|
||||
DECL_STD_FUNC(rint)
|
||||
DECL_STD_FUNC(nearbyint)
|
||||
DECL_STD_FUNC(remainder)
|
||||
|
||||
// Minimum, maximum, difference functions
|
||||
DECL_STD_FUNC(fdim)
|
||||
DECL_STD_FUNC(fmax)
|
||||
DECL_STD_FUNC(fmin)
|
||||
|
||||
// Absolute value
|
||||
DECL_STD_FUNC(fabs)
|
||||
|
||||
/******************************************************************************
|
||||
* Other functions *
|
||||
******************************************************************************/
|
||||
// p-value
|
||||
namespace MATH_NAMESPACE
|
||||
{
|
||||
extern DoubleFunction chi2PValue;
|
||||
}
|
||||
|
||||
END_LATAN_NAMESPACE
|
||||
|
||||
#endif // Latan_Math_hpp_
|
745
lib/Core/MathInterpreter.cpp
Normal file
745
lib/Core/MathInterpreter.cpp
Normal file
@ -0,0 +1,745 @@
|
||||
/*
|
||||
* MathInterpreter.cpp, part of LatAnalyze 3
|
||||
*
|
||||
* Copyright (C) 2013 - 2016 Antonin Portelli
|
||||
*
|
||||
* LatAnalyze 3 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LatAnalyze 3 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LatAnalyze 3. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <LatAnalyze/Core/MathInterpreter.hpp>
|
||||
#include <LatAnalyze/includes.hpp>
|
||||
#include <LatAnalyze/Core/Math.hpp>
|
||||
|
||||
using namespace std;
|
||||
using namespace Latan;
|
||||
|
||||
/******************************************************************************
|
||||
* RunContext implementation *
|
||||
******************************************************************************/
|
||||
// access //////////////////////////////////////////////////////////////////////
|
||||
unsigned int RunContext::addFunction(const string &name, DoubleFunction *init)
|
||||
{
|
||||
try
|
||||
{
|
||||
setFunction(name, init);
|
||||
|
||||
return getFunctionAddress(name);
|
||||
}
|
||||
catch (Exceptions::Definition)
|
||||
{
|
||||
unsigned int address = fTable_.size();
|
||||
|
||||
fMem_.push_back(init);
|
||||
fTable_[name] = address;
|
||||
|
||||
return address;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int RunContext::addVariable(const string &name, double init)
|
||||
{
|
||||
try
|
||||
{
|
||||
setVariable(name, init);
|
||||
|
||||
return getVariableAddress(name);
|
||||
}
|
||||
catch (Exceptions::Definition)
|
||||
{
|
||||
unsigned int address = vTable_.size();
|
||||
|
||||
vMem_.push_back(init);
|
||||
vTable_[name] = address;
|
||||
|
||||
return address;
|
||||
}
|
||||
}
|
||||
|
||||
DoubleFunction * RunContext::getFunction(const string &name) const
|
||||
{
|
||||
return getFunction(getFunctionAddress(name));
|
||||
}
|
||||
|
||||
DoubleFunction * RunContext::getFunction(const unsigned int address) const
|
||||
{
|
||||
if (address >= fTable_.size())
|
||||
{
|
||||
LATAN_ERROR(Range, "function address " + strFrom(address)
|
||||
+ " out of range");
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
return fMem_[address];
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int RunContext::getFunctionAddress(const string &name) const
|
||||
{
|
||||
try
|
||||
{
|
||||
return fTable_.at(name);
|
||||
}
|
||||
catch (out_of_range)
|
||||
{
|
||||
LATAN_ERROR(Definition, "undefined function '" + name + "'");
|
||||
}
|
||||
}
|
||||
|
||||
const RunContext::AddressTable & RunContext::getFunctionTable(void) const
|
||||
{
|
||||
return fTable_;
|
||||
}
|
||||
|
||||
unsigned int RunContext::getInsIndex(void) const
|
||||
{
|
||||
return insIndex_;
|
||||
}
|
||||
|
||||
double RunContext::getVariable(const string &name) const
|
||||
{
|
||||
return getVariable(getVariableAddress(name));
|
||||
}
|
||||
|
||||
double RunContext::getVariable(const unsigned int address) const
|
||||
{
|
||||
if (address >= vTable_.size())
|
||||
{
|
||||
LATAN_ERROR(Range, "variable address " + strFrom(address)
|
||||
+ " out of range");
|
||||
|
||||
return 0.;
|
||||
}
|
||||
else
|
||||
{
|
||||
return vMem_[address];
|
||||
}
|
||||
}
|
||||
|
||||
const RunContext::AddressTable & RunContext::getVariableTable(void) const
|
||||
{
|
||||
return vTable_;
|
||||
}
|
||||
|
||||
unsigned int RunContext::getVariableAddress(const string &name) const
|
||||
{
|
||||
try
|
||||
{
|
||||
return vTable_.at(name);
|
||||
}
|
||||
catch (out_of_range)
|
||||
{
|
||||
LATAN_ERROR(Definition, "undefined variable '" + name + "'");
|
||||
}
|
||||
}
|
||||
|
||||
void RunContext::incrementInsIndex(const unsigned int inc)
|
||||
{
|
||||
setInsIndex(getInsIndex() + inc);
|
||||
}
|
||||
|
||||
void RunContext::setFunction(const string &name, DoubleFunction *f)
|
||||
{
|
||||
|
||||
setFunction(getFunctionAddress(name), f);
|
||||
}
|
||||
|
||||
void RunContext::setFunction(const unsigned int address, DoubleFunction *f)
|
||||
{
|
||||
if (address >= fTable_.size())
|
||||
{
|
||||
LATAN_ERROR(Range, "function address " + strFrom(address)
|
||||
+ " out of range");
|
||||
}
|
||||
else
|
||||
{
|
||||
fMem_[address] = f;
|
||||
}
|
||||
}
|
||||
|
||||
void RunContext::setInsIndex(const unsigned index)
|
||||
{
|
||||
insIndex_ = index;
|
||||
}
|
||||
|
||||
void RunContext::setVariable(const string &name, const double value)
|
||||
{
|
||||
setVariable(getVariableAddress(name), value);
|
||||
}
|
||||
|
||||
void RunContext::setVariable(const unsigned int address, const double value)
|
||||
{
|
||||
if (address >= vTable_.size())
|
||||
{
|
||||
LATAN_ERROR(Range, "variable address " + strFrom(address)
|
||||
+ " out of range");
|
||||
}
|
||||
else
|
||||
{
|
||||
vMem_[address] = value;
|
||||
}
|
||||
}
|
||||
|
||||
stack<double> & RunContext::stack(void)
|
||||
{
|
||||
return dStack_;
|
||||
}
|
||||
|
||||
// reset ///////////////////////////////////////////////////////////////////////
|
||||
void RunContext::reset(void)
|
||||
{
|
||||
insIndex_ = 0;
|
||||
while (!dStack_.empty())
|
||||
{
|
||||
dStack_.pop();
|
||||
}
|
||||
vMem_.clear();
|
||||
fMem_.clear();
|
||||
vTable_.clear();
|
||||
fTable_.clear();
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Instruction set *
|
||||
******************************************************************************/
|
||||
#define CODE_WIDTH 6
|
||||
#define CODE_MOD setw(CODE_WIDTH) << left
|
||||
|
||||
// Instruction operator ////////////////////////////////////////////////////////
|
||||
ostream &Latan::operator<<(ostream& out, const Instruction& ins)
|
||||
{
|
||||
ins.print(out);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
// Push constructors ///////////////////////////////////////////////////////////
|
||||
Push::Push(const double val)
|
||||
: type_(ArgType::Constant)
|
||||
, val_(val)
|
||||
, address_(0)
|
||||
, name_("")
|
||||
{}
|
||||
|
||||
Push::Push(const unsigned int address, const string &name)
|
||||
: type_(ArgType::Variable)
|
||||
, val_(0.0)
|
||||
, address_(address)
|
||||
, name_(name)
|
||||
{}
|
||||
|
||||
// Push execution //////////////////////////////////////////////////////////////
|
||||
void Push::operator()(RunContext &context) const
|
||||
{
|
||||
if (type_ == ArgType::Constant)
|
||||
{
|
||||
context.stack().push(val_);
|
||||
}
|
||||
else
|
||||
{
|
||||
context.stack().push(context.getVariable(address_));
|
||||
}
|
||||
context.incrementInsIndex();
|
||||
}
|
||||
|
||||
// Push print //////////////////////////////////////////////////////////////////
|
||||
void Push::print(ostream &out) const
|
||||
{
|
||||
out << CODE_MOD << "push";
|
||||
if (type_ == ArgType::Constant)
|
||||
{
|
||||
out << CODE_MOD << val_;
|
||||
}
|
||||
else
|
||||
{
|
||||
out << CODE_MOD << name_ << " @v" << address_;
|
||||
}
|
||||
}
|
||||
|
||||
// Pop constructor /////////////////////////////////////////////////////////////
|
||||
Pop::Pop(const unsigned int address, const string &name)
|
||||
: address_(address)
|
||||
, name_(name)
|
||||
{}
|
||||
|
||||
// Pop execution ///////////////////////////////////////////////////////////////
|
||||
void Pop::operator()(RunContext &context) const
|
||||
{
|
||||
if (!name_.empty())
|
||||
{
|
||||
context.setVariable(address_, context.stack().top());
|
||||
}
|
||||
context.stack().pop();
|
||||
context.incrementInsIndex();
|
||||
}
|
||||
|
||||
// Pop print ///////////////////////////////////////////////////////////////////
|
||||
void Pop::print(ostream &out) const
|
||||
{
|
||||
out << CODE_MOD << "pop" << CODE_MOD << name_ << " @v" << address_;
|
||||
}
|
||||
|
||||
// Store constructor ///////////////////////////////////////////////////////////
|
||||
Store::Store(const unsigned int address, const string &name)
|
||||
: address_(address)
|
||||
, name_(name)
|
||||
{}
|
||||
|
||||
// Store execution /////////////////////////////////////////////////////////////
|
||||
void Store::operator()(RunContext &context) const
|
||||
{
|
||||
if (!name_.empty())
|
||||
{
|
||||
context.setVariable(address_, context.stack().top());
|
||||
}
|
||||
context.incrementInsIndex();
|
||||
}
|
||||
|
||||
// Store print /////////////////////////////////////////////////////////////////
|
||||
void Store::print(ostream &out) const
|
||||
{
|
||||
out << CODE_MOD << "store" << CODE_MOD << name_ << " @v" << address_;
|
||||
}
|
||||
|
||||
// Call constructor ////////////////////////////////////////////////////////////
|
||||
Call::Call(const unsigned int address, const string &name)
|
||||
: address_(address)
|
||||
, name_(name)
|
||||
{}
|
||||
|
||||
// Call execution //////////////////////////////////////////////////////////////
|
||||
void Call::operator()(RunContext &context) const
|
||||
{
|
||||
context.stack().push((*context.getFunction(address_))(context.stack()));
|
||||
context.incrementInsIndex();
|
||||
}
|
||||
|
||||
// Call print //////////////////////////////////////////////////////////////////
|
||||
void Call::print(ostream &out) const
|
||||
{
|
||||
out << CODE_MOD << "call" << CODE_MOD << name_ << " @f" << address_;
|
||||
}
|
||||
|
||||
// Math operations /////////////////////////////////////////////////////////////
|
||||
#define DEF_OP(name, nArg, exp, insName)\
|
||||
void name::operator()(RunContext &context) const\
|
||||
{\
|
||||
double x[nArg];\
|
||||
for (int i = 0; i < nArg; ++i)\
|
||||
{\
|
||||
x[nArg-1-i] = context.stack().top();\
|
||||
context.stack().pop();\
|
||||
}\
|
||||
context.stack().push(exp);\
|
||||
context.incrementInsIndex();\
|
||||
}\
|
||||
void name::print(ostream &out) const\
|
||||
{\
|
||||
out << CODE_MOD << insName;\
|
||||
}
|
||||
|
||||
DEF_OP(Neg, 1, -x[0], "neg")
|
||||
DEF_OP(Add, 2, x[0] + x[1], "add")
|
||||
DEF_OP(Sub, 2, x[0] - x[1], "sub")
|
||||
DEF_OP(Mul, 2, x[0]*x[1], "mul")
|
||||
DEF_OP(Div, 2, x[0]/x[1], "div")
|
||||
DEF_OP(Pow, 2, pow(x[0],x[1]), "pow")
|
||||
|
||||
/******************************************************************************
|
||||
* ExprNode implementation *
|
||||
******************************************************************************/
|
||||
// ExprNode constructors ///////////////////////////////////////////////////////
|
||||
ExprNode::ExprNode(const string &name)
|
||||
: name_(name)
|
||||
, parent_(nullptr)
|
||||
{}
|
||||
|
||||
// ExprNode access /////////////////////////////////////////////////////////////
|
||||
const string &ExprNode::getName(void) const
|
||||
{
|
||||
return name_;
|
||||
}
|
||||
|
||||
Index ExprNode::getNArg(void) const
|
||||
{
|
||||
return static_cast<Index>(arg_.size());
|
||||
}
|
||||
|
||||
const ExprNode * ExprNode::getParent(void) const
|
||||
{
|
||||
return parent_;
|
||||
}
|
||||
|
||||
Index ExprNode::getLevel(void) const
|
||||
{
|
||||
if (getParent())
|
||||
{
|
||||
return getParent()->getLevel() + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void ExprNode::setName(const std::string &name)
|
||||
{
|
||||
name_ = name;
|
||||
}
|
||||
|
||||
void ExprNode::pushArg(ExprNode *node)
|
||||
{
|
||||
if (node)
|
||||
{
|
||||
node->parent_ = this;
|
||||
arg_.push_back(unique_ptr<ExprNode>(node));
|
||||
}
|
||||
}
|
||||
|
||||
// ExprNode operators //////////////////////////////////////////////////////////
|
||||
const ExprNode &ExprNode::operator[](const Index i) const
|
||||
{
|
||||
return *arg_[i];
|
||||
}
|
||||
|
||||
ostream &Latan::operator<<(ostream &out, const ExprNode &n)
|
||||
{
|
||||
Index level = n.getLevel();
|
||||
|
||||
for (Index i = 0; i <= level; ++i)
|
||||
{
|
||||
if (i == level)
|
||||
{
|
||||
out << "_";
|
||||
}
|
||||
else if (i == level - 1)
|
||||
{
|
||||
out << "|";
|
||||
}
|
||||
else
|
||||
{
|
||||
out << " ";
|
||||
}
|
||||
}
|
||||
out << " " << n.getName() << endl;
|
||||
for (Index i = 0; i < n.getNArg(); ++i)
|
||||
{
|
||||
out << n[i];
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
#define PUSH_INS(program, type, ...)\
|
||||
program.push_back(unique_ptr<type>(new type(__VA_ARGS__)))
|
||||
#define GET_ADDRESS(address, table, name)\
|
||||
try\
|
||||
{\
|
||||
address = (table).at(name);\
|
||||
}\
|
||||
catch (out_of_range)\
|
||||
{\
|
||||
address = (table).size();\
|
||||
(table)[(name)] = address;\
|
||||
}\
|
||||
|
||||
// VarNode compile /////////////////////////////////////////////////////////////
|
||||
void VarNode::compile(Program &program, RunContext &context) const
|
||||
{
|
||||
PUSH_INS(program, Push, context.getVariableAddress(getName()), getName());
|
||||
}
|
||||
|
||||
// CstNode compile /////////////////////////////////////////////////////////////
|
||||
void CstNode::compile(Program &program, RunContext &context __dumb) const
|
||||
{
|
||||
PUSH_INS(program, Push, strTo<double>(getName()));
|
||||
}
|
||||
|
||||
// SemicolonNode compile ///////////////////////////////////////////////////////
|
||||
void SemicolonNode::compile(Program &program, RunContext &context) const
|
||||
{
|
||||
auto &n = *this;
|
||||
|
||||
for (Index i = 0; i < getNArg(); ++i)
|
||||
{
|
||||
bool isAssign = isDerivedFrom<AssignNode>(&n[i]);
|
||||
bool isSemiColumn = isDerivedFrom<SemicolonNode>(&n[i]);
|
||||
bool isKeyword = isDerivedFrom<KeywordNode>(&n[i]);
|
||||
|
||||
if (isAssign or isSemiColumn or isKeyword)
|
||||
{
|
||||
n[i].compile(program, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// AssignNode compile //////////////////////////////////////////////////////////
|
||||
void AssignNode::compile(Program &program, RunContext &context) const
|
||||
{
|
||||
auto &n = *this;
|
||||
|
||||
if (isDerivedFrom<VarNode>(&n[0]))
|
||||
{
|
||||
bool hasSemicolonParent = isDerivedFrom<SemicolonNode>(getParent());
|
||||
unsigned int address;
|
||||
|
||||
n[1].compile(program, context);
|
||||
address = context.addVariable(n[0].getName());
|
||||
if (hasSemicolonParent)
|
||||
{
|
||||
PUSH_INS(program, Pop, address, n[0].getName());
|
||||
}
|
||||
else
|
||||
{
|
||||
PUSH_INS(program, Store, address, n[0].getName());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LATAN_ERROR(Compilation, "invalid LHS for '='");
|
||||
}
|
||||
}
|
||||
|
||||
// MathOpNode compile //////////////////////////////////////////////////////////
|
||||
#define IFNODE(name, nArg) if ((n.getName() == (name)) and (n.getNArg() == nArg))
|
||||
#define ELIFNODE(name, nArg) else IFNODE(name, nArg)
|
||||
#define ELSE else
|
||||
|
||||
void MathOpNode::compile(Program &program, RunContext &context) const
|
||||
{
|
||||
auto &n = *this;
|
||||
|
||||
for (Index i = 0; i < n.getNArg(); ++i)
|
||||
{
|
||||
n[i].compile(program, context);
|
||||
}
|
||||
IFNODE("-", 1) PUSH_INS(program, Neg,);
|
||||
ELIFNODE("+", 2) PUSH_INS(program, Add,);
|
||||
ELIFNODE("-", 2) PUSH_INS(program, Sub,);
|
||||
ELIFNODE("*", 2) PUSH_INS(program, Mul,);
|
||||
ELIFNODE("/", 2) PUSH_INS(program, Div,);
|
||||
ELIFNODE("^", 2) PUSH_INS(program, Pow,);
|
||||
ELSE LATAN_ERROR(Compilation, "unknown operator '" + getName() + "'");
|
||||
}
|
||||
|
||||
// FuncNode compile ////////////////////////////////////////////////////////////
|
||||
void FuncNode::compile(Program &program, RunContext &context) const
|
||||
{
|
||||
auto &n = *this;
|
||||
|
||||
for (Index i = 0; i < n.getNArg(); ++i)
|
||||
{
|
||||
n[i].compile(program, context);
|
||||
}
|
||||
PUSH_INS(program, Call, context.getFunctionAddress(getName()), getName());
|
||||
}
|
||||
|
||||
// ReturnNode compile ////////////////////////////////////////////////////////////
|
||||
void ReturnNode::compile(Program &program, RunContext &context) const
|
||||
{
|
||||
auto &n = *this;
|
||||
|
||||
n[0].compile(program, context);
|
||||
program.push_back(nullptr);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* MathInterpreter implementation *
|
||||
******************************************************************************/
|
||||
// MathParserState constructor /////////////////////////////////////////////////
|
||||
MathInterpreter::MathParserState::MathParserState
|
||||
(istream *stream, string *name, std::unique_ptr<ExprNode> *data)
|
||||
: ParserState<std::unique_ptr<ExprNode>>(stream, name, data)
|
||||
{
|
||||
initScanner();
|
||||
}
|
||||
|
||||
// MathParserState destructor //////////////////////////////////////////////////
|
||||
MathInterpreter::MathParserState::~MathParserState(void)
|
||||
{
|
||||
destroyScanner();
|
||||
}
|
||||
|
||||
// constructors ////////////////////////////////////////////////////////////////
|
||||
MathInterpreter::MathInterpreter(const std::string &code)
|
||||
: codeName_("<string>")
|
||||
{
|
||||
setCode(code);
|
||||
}
|
||||
|
||||
// access //////////////////////////////////////////////////////////////////////
|
||||
const Instruction * MathInterpreter::operator[](const Index i) const
|
||||
{
|
||||
return program_[i].get();
|
||||
}
|
||||
|
||||
const ExprNode * MathInterpreter::getAST(void) const
|
||||
{
|
||||
return root_.get();
|
||||
}
|
||||
|
||||
void MathInterpreter::push(const Instruction *i)
|
||||
{
|
||||
program_.push_back(unique_ptr<const Instruction>(i));
|
||||
}
|
||||
|
||||
// initialization //////////////////////////////////////////////////////////////
|
||||
void MathInterpreter::setCode(const std::string &code)
|
||||
{
|
||||
if (status_)
|
||||
{
|
||||
reset();
|
||||
}
|
||||
code_.reset(new stringstream(code));
|
||||
codeName_ = "<string>";
|
||||
state_.reset(new MathParserState(code_.get(), &codeName_, &root_));
|
||||
program_.clear();
|
||||
status_ = Status::initialised;
|
||||
}
|
||||
|
||||
void MathInterpreter::reset(void)
|
||||
{
|
||||
code_.reset();
|
||||
codeName_ = "<no_code>";
|
||||
state_.reset();
|
||||
root_.reset();
|
||||
program_.clear();
|
||||
status_ = 0;
|
||||
}
|
||||
|
||||
// parser //////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Bison/Flex parser declaration
|
||||
int _math_parse(MathInterpreter::MathParserState *state);
|
||||
|
||||
void MathInterpreter::parse(void)
|
||||
{
|
||||
_math_parse(state_.get());
|
||||
}
|
||||
|
||||
// interpreter /////////////////////////////////////////////////////////////////
|
||||
#define ADD_FUNC(context, func)\
|
||||
(context).addFunction(#func, &STDMATH_NAMESPACE::func);\
|
||||
|
||||
#define ADD_STDMATH_FUNCS(context)\
|
||||
ADD_FUNC(context, cos);\
|
||||
ADD_FUNC(context, sin);\
|
||||
ADD_FUNC(context, tan);\
|
||||
ADD_FUNC(context, acos);\
|
||||
ADD_FUNC(context, asin);\
|
||||
ADD_FUNC(context, atan);\
|
||||
ADD_FUNC(context, atan2);\
|
||||
ADD_FUNC(context, cosh);\
|
||||
ADD_FUNC(context, sinh);\
|
||||
ADD_FUNC(context, tanh);\
|
||||
ADD_FUNC(context, acosh);\
|
||||
ADD_FUNC(context, asinh);\
|
||||
ADD_FUNC(context, atanh);\
|
||||
ADD_FUNC(context, exp);\
|
||||
ADD_FUNC(context, log);\
|
||||
ADD_FUNC(context, log10);\
|
||||
ADD_FUNC(context, exp2);\
|
||||
ADD_FUNC(context, expm1);\
|
||||
ADD_FUNC(context, log1p);\
|
||||
ADD_FUNC(context, log2);\
|
||||
ADD_FUNC(context, pow);\
|
||||
ADD_FUNC(context, sqrt);\
|
||||
ADD_FUNC(context, cbrt);\
|
||||
ADD_FUNC(context, hypot);\
|
||||
ADD_FUNC(context, erf);\
|
||||
ADD_FUNC(context, erfc);\
|
||||
ADD_FUNC(context, tgamma);\
|
||||
ADD_FUNC(context, lgamma);\
|
||||
ADD_FUNC(context, ceil);\
|
||||
ADD_FUNC(context, floor);\
|
||||
ADD_FUNC(context, fmod);\
|
||||
ADD_FUNC(context, trunc);\
|
||||
ADD_FUNC(context, round);\
|
||||
ADD_FUNC(context, rint);\
|
||||
ADD_FUNC(context, nearbyint);\
|
||||
ADD_FUNC(context, remainder);\
|
||||
ADD_FUNC(context, fdim);\
|
||||
ADD_FUNC(context, fmax);\
|
||||
ADD_FUNC(context, fmin);\
|
||||
ADD_FUNC(context, fabs);
|
||||
|
||||
void MathInterpreter::compile(RunContext &context)
|
||||
{
|
||||
bool gotReturn = false;
|
||||
|
||||
if (!(status_ & Status::parsed))
|
||||
{
|
||||
parse();
|
||||
status_ |= Status::parsed;
|
||||
status_ -= status_ & Status::compiled;
|
||||
}
|
||||
if (!(status_ & Status::compiled))
|
||||
{
|
||||
if (root_)
|
||||
{
|
||||
context.addVariable("pi", Math::pi);
|
||||
context.addVariable("inf", Math::inf);
|
||||
ADD_STDMATH_FUNCS(context);
|
||||
root_->compile(program_, context);
|
||||
for (unsigned int i = 0; i < program_.size(); ++i)
|
||||
{
|
||||
if (!program_[i])
|
||||
{
|
||||
gotReturn = true;
|
||||
program_.resize(i);
|
||||
program_.shrink_to_fit();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!root_ or !gotReturn)
|
||||
{
|
||||
LATAN_ERROR(Syntax, "expected 'return' in program '" + codeName_
|
||||
+ "'");
|
||||
}
|
||||
status_ |= Status::compiled;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// execution ///////////////////////////////////////////////////////////////////
|
||||
void MathInterpreter::operator()(RunContext &context)
|
||||
{
|
||||
if (!(status_ & Status::compiled))
|
||||
{
|
||||
compile(context);
|
||||
}
|
||||
execute(context);
|
||||
}
|
||||
|
||||
void MathInterpreter::execute(RunContext &context) const
|
||||
{
|
||||
context.setInsIndex(0);
|
||||
while (context.getInsIndex() != program_.size())
|
||||
{
|
||||
(*(program_[context.getInsIndex()]))(context);
|
||||
}
|
||||
}
|
||||
|
||||
// IO //////////////////////////////////////////////////////////////////////////
|
||||
ostream &Latan::operator<<(ostream &out, const MathInterpreter &program)
|
||||
{
|
||||
for (unsigned int i = 0; i < program.program_.size(); ++i)
|
||||
{
|
||||
out << *(program.program_[i]) << endl;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
313
lib/Core/MathInterpreter.hpp
Normal file
313
lib/Core/MathInterpreter.hpp
Normal file
@ -0,0 +1,313 @@
|
||||
/*
|
||||
* MathInterpreter.hpp, part of LatAnalyze 3
|
||||
*
|
||||
* Copyright (C) 2013 - 2016 Antonin Portelli
|
||||
*
|
||||
* LatAnalyze 3 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LatAnalyze 3 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LatAnalyze 3. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef Latan_MathInterpreter_hpp_
|
||||
#define Latan_MathInterpreter_hpp_
|
||||
|
||||
#include <LatAnalyze/Functional/Function.hpp>
|
||||
#include <LatAnalyze/Global.hpp>
|
||||
#include <LatAnalyze/Core/ParserState.hpp>
|
||||
|
||||
#define MAXIDLENGTH 256
|
||||
|
||||
BEGIN_LATAN_NAMESPACE
|
||||
|
||||
/******************************************************************************
|
||||
* Class for runtime context *
|
||||
******************************************************************************/
|
||||
class RunContext
|
||||
{
|
||||
public:
|
||||
typedef std::map<std::string, unsigned int> AddressTable;
|
||||
public:
|
||||
// constructor
|
||||
RunContext(void) = default;
|
||||
// destructor
|
||||
~RunContext(void) = default;
|
||||
// access
|
||||
unsigned int addFunction(const std::string &name,
|
||||
DoubleFunction *init = nullptr);
|
||||
unsigned int addVariable(const std::string &name,
|
||||
const double init = 0.);
|
||||
DoubleFunction * getFunction(const std::string &name) const;
|
||||
DoubleFunction * getFunction(const unsigned int address) const;
|
||||
unsigned int getFunctionAddress(const std::string &name) const;
|
||||
const AddressTable & getFunctionTable(void) const;
|
||||
unsigned int getInsIndex(void) const;
|
||||
double getVariable(const std::string &name) const;
|
||||
double getVariable(const unsigned int address) const;
|
||||
unsigned int getVariableAddress(const std::string &name) const;
|
||||
const AddressTable & getVariableTable(void) const;
|
||||
void incrementInsIndex(const unsigned int inc = 1);
|
||||
void setFunction(const std::string &name,
|
||||
DoubleFunction *f);
|
||||
void setFunction(const unsigned int address,
|
||||
DoubleFunction *f);
|
||||
void setInsIndex(const unsigned index);
|
||||
void setVariable(const std::string &name,
|
||||
const double value);
|
||||
void setVariable(const unsigned int address,
|
||||
const double value);
|
||||
std::stack<double> & stack(void);
|
||||
// reset
|
||||
void reset(void);
|
||||
private:
|
||||
unsigned int insIndex_;
|
||||
std::stack<double> dStack_;
|
||||
std::vector<double> vMem_;
|
||||
std::vector<DoubleFunction *> fMem_;
|
||||
AddressTable vTable_, fTable_;
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
* Instruction classes *
|
||||
******************************************************************************/
|
||||
// Abstract base
|
||||
class Instruction
|
||||
{
|
||||
public:
|
||||
// destructor
|
||||
virtual ~Instruction(void) = default;
|
||||
// instruction execution
|
||||
virtual void operator()(RunContext &context) const = 0;
|
||||
friend std::ostream & operator<<(std::ostream &out, const Instruction &ins);
|
||||
private:
|
||||
virtual void print(std::ostream &out) const = 0;
|
||||
};
|
||||
|
||||
std::ostream & operator<<(std::ostream &out, const Instruction &ins);
|
||||
|
||||
// Instruction container
|
||||
typedef std::vector<std::unique_ptr<const Instruction>> Program;
|
||||
|
||||
// Push
|
||||
class Push: public Instruction
|
||||
{
|
||||
private:
|
||||
enum class ArgType
|
||||
{
|
||||
Constant = 0,
|
||||
Variable = 1
|
||||
};
|
||||
public:
|
||||
//constructors
|
||||
explicit Push(const double val);
|
||||
explicit Push(const unsigned int address, const std::string &name);
|
||||
// instruction execution
|
||||
virtual void operator()(RunContext &context) const;
|
||||
private:
|
||||
virtual void print(std::ostream& out) const;
|
||||
private:
|
||||
ArgType type_;
|
||||
double val_;
|
||||
unsigned int address_;
|
||||
std::string name_;
|
||||
};
|
||||
|
||||
// Pop
|
||||
class Pop: public Instruction
|
||||
{
|
||||
public:
|
||||
//constructor
|
||||
explicit Pop(const unsigned int address, const std::string &name);
|
||||
// instruction execution
|
||||
virtual void operator()(RunContext &context) const;
|
||||
private:
|
||||
virtual void print(std::ostream& out) const;
|
||||
private:
|
||||
unsigned int address_;
|
||||
std::string name_;
|
||||
};
|
||||
|
||||
// Store
|
||||
class Store: public Instruction
|
||||
{
|
||||
public:
|
||||
//constructor
|
||||
explicit Store(const unsigned int address, const std::string &name);
|
||||
// instruction execution
|
||||
virtual void operator()(RunContext &context) const;
|
||||
private:
|
||||
virtual void print(std::ostream& out) const;
|
||||
private:
|
||||
unsigned int address_;
|
||||
std::string name_;
|
||||
};
|
||||
|
||||
// Call function
|
||||
class Call: public Instruction
|
||||
{
|
||||
public:
|
||||
//constructor
|
||||
explicit Call(const unsigned int address, const std::string &name);
|
||||
// instruction execution
|
||||
virtual void operator()(RunContext &context) const;
|
||||
private:
|
||||
virtual void print(std::ostream& out) const;
|
||||
private:
|
||||
unsigned int address_;
|
||||
std::string name_;
|
||||
};
|
||||
|
||||
// Floating point operations
|
||||
#define DECL_OP(name)\
|
||||
class name: public Instruction\
|
||||
{\
|
||||
public:\
|
||||
virtual void operator()(RunContext &context) const;\
|
||||
private:\
|
||||
virtual void print(std::ostream &out) const;\
|
||||
}
|
||||
|
||||
DECL_OP(Neg);
|
||||
DECL_OP(Add);
|
||||
DECL_OP(Sub);
|
||||
DECL_OP(Mul);
|
||||
DECL_OP(Div);
|
||||
DECL_OP(Pow);
|
||||
|
||||
/******************************************************************************
|
||||
* Expression node classes *
|
||||
******************************************************************************/
|
||||
class ExprNode
|
||||
{
|
||||
public:
|
||||
// constructors
|
||||
explicit ExprNode(const std::string &name);
|
||||
// destructor
|
||||
virtual ~ExprNode() = default;
|
||||
// access
|
||||
const std::string& getName(void) const;
|
||||
Index getNArg(void) const;
|
||||
const ExprNode * getParent(void) const;
|
||||
Index getLevel(void) const;
|
||||
void setName(const std::string &name);
|
||||
void pushArg(ExprNode *node);
|
||||
// operator
|
||||
const ExprNode &operator[](const Index i) const;
|
||||
// compile
|
||||
virtual void compile(Program &program, RunContext &context) const = 0;
|
||||
private:
|
||||
std::string name_;
|
||||
std::vector<std::unique_ptr<ExprNode>> arg_;
|
||||
const ExprNode * parent_;
|
||||
};
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, const ExprNode &n);
|
||||
|
||||
#define DECL_NODE(base, name) \
|
||||
class name: public base\
|
||||
{\
|
||||
public:\
|
||||
using base::base;\
|
||||
virtual void compile(Program &program, RunContext &context) const;\
|
||||
}
|
||||
|
||||
DECL_NODE(ExprNode, VarNode);
|
||||
DECL_NODE(ExprNode, CstNode);
|
||||
DECL_NODE(ExprNode, SemicolonNode);
|
||||
DECL_NODE(ExprNode, AssignNode);
|
||||
DECL_NODE(ExprNode, MathOpNode);
|
||||
DECL_NODE(ExprNode, FuncNode);
|
||||
|
||||
class KeywordNode: public ExprNode
|
||||
{
|
||||
public:
|
||||
using ExprNode::ExprNode;
|
||||
virtual void compile(Program &program, RunContext &context) const = 0;
|
||||
};
|
||||
|
||||
DECL_NODE(KeywordNode, ReturnNode);
|
||||
|
||||
/******************************************************************************
|
||||
* Interpreter class *
|
||||
******************************************************************************/
|
||||
class MathInterpreter
|
||||
{
|
||||
public:
|
||||
// parser state
|
||||
class MathParserState: public ParserState<std::unique_ptr<ExprNode>>
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
explicit MathParserState(std::istream *stream, std::string *name,
|
||||
std::unique_ptr<ExprNode> *data);
|
||||
// destructor
|
||||
virtual ~MathParserState(void);
|
||||
private:
|
||||
// allocation/deallocation functions defined in MathLexer.lpp
|
||||
virtual void initScanner(void);
|
||||
virtual void destroyScanner(void);
|
||||
};
|
||||
private:
|
||||
// status flags
|
||||
class Status
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
none = 0,
|
||||
initialised = 1 << 0,
|
||||
parsed = 1 << 1,
|
||||
compiled = 1 << 2
|
||||
};
|
||||
};
|
||||
public:
|
||||
// constructors
|
||||
MathInterpreter(void) = default;
|
||||
MathInterpreter(const std::string &code);
|
||||
// destructor
|
||||
~MathInterpreter(void) = default;
|
||||
// access
|
||||
const Instruction * operator[](const Index i) const;
|
||||
const ExprNode * getAST(void) const;
|
||||
// initialization
|
||||
void setCode(const std::string &code);
|
||||
// interpreter
|
||||
void compile(RunContext &context);
|
||||
// execution
|
||||
void operator()(RunContext &context);
|
||||
// IO
|
||||
friend std::ostream & operator<<(std::ostream &out,
|
||||
const MathInterpreter &program);
|
||||
private:
|
||||
// initialization
|
||||
void reset(void);
|
||||
// access
|
||||
void push(const Instruction *i);
|
||||
// parser
|
||||
void parse(void);
|
||||
// interpreter
|
||||
void compileNode(const ExprNode &node);
|
||||
// execution
|
||||
void execute(RunContext &context) const;
|
||||
private:
|
||||
std::unique_ptr<std::istream> code_{nullptr};
|
||||
std::string codeName_{"<no_code>"};
|
||||
std::unique_ptr<MathParserState> state_{nullptr};
|
||||
std::unique_ptr<ExprNode> root_{nullptr};
|
||||
Program program_;
|
||||
unsigned int status_{Status::none};
|
||||
};
|
||||
|
||||
std::ostream & operator<<(std::ostream &out, const MathInterpreter &program);
|
||||
|
||||
END_LATAN_NAMESPACE
|
||||
|
||||
#endif // Latan_MathInterpreter_hpp_
|
89
lib/Core/MathLexer.lpp
Normal file
89
lib/Core/MathLexer.lpp
Normal file
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* MathLexer.lpp, part of LatAnalyze 3
|
||||
*
|
||||
* Copyright (C) 2013 - 2016 Antonin Portelli
|
||||
*
|
||||
* LatAnalyze 3 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LatAnalyze 3 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LatAnalyze 3. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
%option reentrant
|
||||
%option prefix="_math_"
|
||||
%option bison-bridge
|
||||
%option bison-locations
|
||||
%option noyywrap
|
||||
%option yylineno
|
||||
|
||||
%{
|
||||
#include <LatAnalyze/Core/MathInterpreter.hpp>
|
||||
#include "MathParser.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace Latan;
|
||||
|
||||
#define YY_EXTRA_TYPE MathInterpreter::MathParserState *
|
||||
#define YY_USER_ACTION \
|
||||
yylloc->first_line = yylloc->last_line = yylineno;\
|
||||
yylloc->first_column = yylloc->last_column + 1;\
|
||||
yylloc->last_column = yylloc->first_column + yyleng - 1;
|
||||
|
||||
#define YY_INPUT(buf, result, max_size) \
|
||||
{ \
|
||||
(*yyextra->stream).read(buf, max_size);\
|
||||
result = (*yyextra->stream).gcount();\
|
||||
}
|
||||
|
||||
#define YY_DEBUG 0
|
||||
#if (YY_DEBUG == 1)
|
||||
#define RET(var) cout << (var) << "(" << yytext << ")" << endl; return (var)
|
||||
#define RETTOK(tok) cout << #tok << "(" << yytext << ")" << endl; return tok
|
||||
#else
|
||||
#define RET(var) return (var)
|
||||
#define RETTOK(tok) return tok
|
||||
#endif
|
||||
%}
|
||||
|
||||
DIGIT [0-9]
|
||||
ALPHA [a-zA-Z_]
|
||||
FLOAT (({DIGIT}+(\.{DIGIT}*)?)|({DIGIT}*\.{DIGIT}+))([eE][+-]?{DIGIT}+)?
|
||||
SPECIAL [;,()+\-*/^={}]
|
||||
BLANK [ \t]
|
||||
|
||||
%%
|
||||
|
||||
{FLOAT} {
|
||||
strncpy(yylval->val_str,yytext,MAXIDLENGTH);
|
||||
RETTOK(FLOAT);
|
||||
}
|
||||
{SPECIAL} {RET(*yytext);}
|
||||
return {RETTOK(RETURN);}
|
||||
{ALPHA}({ALPHA}|{DIGIT})* {
|
||||
strncpy(yylval->val_str,yytext,MAXIDLENGTH);
|
||||
RETTOK(ID);
|
||||
}
|
||||
<*>\n {yylloc->last_column = 0;}
|
||||
<*>{BLANK}
|
||||
<*>. {yylval->val_char = yytext[0]; RETTOK(ERR);}
|
||||
|
||||
%%
|
||||
|
||||
void MathInterpreter::MathParserState::initScanner()
|
||||
{
|
||||
yylex_init(&scanner);
|
||||
yyset_extra(this, scanner);
|
||||
}
|
||||
|
||||
void MathInterpreter::MathParserState::destroyScanner()
|
||||
{
|
||||
yylex_destroy(scanner);
|
||||
}
|
142
lib/Core/MathParser.ypp
Normal file
142
lib/Core/MathParser.ypp
Normal file
@ -0,0 +1,142 @@
|
||||
/*
|
||||
* MathParser.ypp, part of LatAnalyze 3
|
||||
*
|
||||
* Copyright (C) 2013 - 2016 Antonin Portelli
|
||||
*
|
||||
* LatAnalyze 3 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LatAnalyze 3 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LatAnalyze 3. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
%{
|
||||
#include <LatAnalyze/Global.hpp>
|
||||
#include <LatAnalyze/Core/MathInterpreter.hpp>
|
||||
|
||||
using namespace std;
|
||||
using namespace Latan;
|
||||
%}
|
||||
|
||||
%pure-parser
|
||||
%name-prefix "_math_"
|
||||
%locations
|
||||
%defines
|
||||
%error-verbose
|
||||
%parse-param { Latan::MathInterpreter::MathParserState *state }
|
||||
%initial-action {yylloc.last_column = 0;}
|
||||
%lex-param { void* scanner }
|
||||
|
||||
%union
|
||||
{
|
||||
double val_double;
|
||||
char val_char;
|
||||
char val_str[MAXIDLENGTH];
|
||||
Latan::ExprNode *val_node;
|
||||
}
|
||||
|
||||
%token <val_char> ERR
|
||||
%token <val_str> FLOAT
|
||||
%token <val_str> ID
|
||||
%token RETURN
|
||||
|
||||
%left '='
|
||||
%left '+' '-'
|
||||
%left '*' '/'
|
||||
%nonassoc UMINUS
|
||||
%left '^'
|
||||
|
||||
%type <val_node> stmt stmt_list expr func_args
|
||||
|
||||
%{
|
||||
int _math_lex(YYSTYPE *lvalp, YYLTYPE *llocp, void *scanner);
|
||||
|
||||
void _math_error(YYLTYPE *locp, MathInterpreter::MathParserState *state,
|
||||
const char *err)
|
||||
{
|
||||
stringstream buf;
|
||||
|
||||
buf << *(state->streamName) << ":" << locp->first_line << ":"\
|
||||
<< locp->first_column << ": " << err;
|
||||
LATAN_ERROR(Parsing, buf.str());
|
||||
}
|
||||
|
||||
void _math_warning(YYLTYPE *locp, MathInterpreter::MathParserState *state,
|
||||
const char *err)
|
||||
{
|
||||
stringstream buf;
|
||||
|
||||
buf << *(state->streamName) << ":" << locp->first_line << ":"\
|
||||
<< locp->first_column << ": " << err;
|
||||
LATAN_WARNING(buf.str());
|
||||
}
|
||||
|
||||
#define scanner state->scanner
|
||||
%}
|
||||
|
||||
%%
|
||||
|
||||
program:
|
||||
/* empty string */
|
||||
| stmt_list {(*(state->data)).reset($1);}
|
||||
;
|
||||
|
||||
stmt:
|
||||
';'
|
||||
{$$ = new SemicolonNode(";");}
|
||||
| expr ';'
|
||||
{$$ = nullptr; _math_warning(&yylloc, state, "useless statement removed");}
|
||||
| ID '=' expr ';'
|
||||
{$$ = new AssignNode("="); $$->pushArg(new VarNode($1)); $$->pushArg($3);}
|
||||
| RETURN expr ';'
|
||||
{$$ = new ReturnNode("return"); $$->pushArg($2);}
|
||||
| '{' stmt_list '}'
|
||||
{$$ = $2;}
|
||||
;
|
||||
|
||||
stmt_list:
|
||||
stmt
|
||||
{$$ = $1;}
|
||||
| stmt_list stmt
|
||||
{$$ = new SemicolonNode(";"); $$->pushArg($1); $$->pushArg($2);}
|
||||
;
|
||||
|
||||
expr:
|
||||
FLOAT
|
||||
{$$ = new CstNode($1);}
|
||||
| ID
|
||||
{$$ = new VarNode($1);}
|
||||
| '-' expr %prec UMINUS
|
||||
{$$ = new MathOpNode("-"); $$->pushArg($2);}
|
||||
| expr '+' expr
|
||||
{$$ = new MathOpNode("+"); $$->pushArg($1); $$->pushArg($3);}
|
||||
| expr '-' expr
|
||||
{$$ = new MathOpNode("-"); $$->pushArg($1); $$->pushArg($3);}
|
||||
| expr '*' expr
|
||||
{$$ = new MathOpNode("*"); $$->pushArg($1); $$->pushArg($3);}
|
||||
| expr '/' expr
|
||||
{$$ = new MathOpNode("/"); $$->pushArg($1); $$->pushArg($3);}
|
||||
| expr '^' expr
|
||||
{$$ = new MathOpNode("^"); $$->pushArg($1); $$->pushArg($3);}
|
||||
| '(' expr ')'
|
||||
{$$ = $2;}
|
||||
| ID '(' func_args ')'
|
||||
{$$ = $3; $$->setName($1);}
|
||||
;
|
||||
|
||||
func_args:
|
||||
/* empty string */
|
||||
{$$ = new FuncNode("");}
|
||||
| expr
|
||||
{$$ = new FuncNode(""); $$->pushArg($1);}
|
||||
| func_args ',' expr
|
||||
{$$ = $1; $$->pushArg($3);}
|
||||
;
|
||||
|
272
lib/Core/OptParser.cpp
Normal file
272
lib/Core/OptParser.cpp
Normal file
@ -0,0 +1,272 @@
|
||||
/*
|
||||
* OptParser.cpp, part of LatAnalyze
|
||||
*
|
||||
* Copyright (C) 2016 Antonin Portelli
|
||||
*
|
||||
* LatAnalyze is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LatAnalyze 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LatAnalyze. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <LatAnalyze/Core/OptParser.hpp>
|
||||
#include <LatAnalyze/includes.hpp>
|
||||
|
||||
using namespace std;
|
||||
using namespace Latan;
|
||||
|
||||
static char optRegex[] = "(-([a-zA-Z])(.+)?)|(--([a-zA-Z_-]+)=?(.+)?)";
|
||||
|
||||
/******************************************************************************
|
||||
* OptParser implementation *
|
||||
******************************************************************************/
|
||||
// regular expressions /////////////////////////////////////////////////////////
|
||||
const regex OptParser::optRegex_(optRegex);
|
||||
|
||||
// access //////////////////////////////////////////////////////////////////////
|
||||
void OptParser::addOption(const std::string shortName,
|
||||
const std::string longName,
|
||||
const OptType type, const bool optional,
|
||||
const std::string helpMessage,
|
||||
const std::string defaultVal)
|
||||
{
|
||||
OptPar par;
|
||||
|
||||
par.shortName = shortName;
|
||||
par.longName = longName;
|
||||
par.defaultVal = defaultVal;
|
||||
par.helpMessage = helpMessage;
|
||||
par.type = type;
|
||||
par.optional = optional;
|
||||
opt_.push_back(par);
|
||||
}
|
||||
|
||||
bool OptParser::gotOption(const std::string name) const
|
||||
{
|
||||
int i = optIndex(name);
|
||||
|
||||
if (result_.size() != opt_.size())
|
||||
{
|
||||
throw(runtime_error("options not parsed"));
|
||||
}
|
||||
if (i >= 0)
|
||||
{
|
||||
return result_[i].present;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw(out_of_range("no option with name '" + name + "'"));
|
||||
}
|
||||
}
|
||||
|
||||
const vector<string> & OptParser::getArgs(void) const
|
||||
{
|
||||
return arg_;
|
||||
}
|
||||
|
||||
// parse ///////////////////////////////////////////////////////////////////////
|
||||
bool OptParser::parse(int argc, char *argv[])
|
||||
{
|
||||
smatch sm;
|
||||
queue<string> arg;
|
||||
int expectVal = -1;
|
||||
bool isCorrect = true;
|
||||
|
||||
for (int i = 1; i < argc; ++i)
|
||||
{
|
||||
arg.push(argv[i]);
|
||||
}
|
||||
result_.clear();
|
||||
result_.resize(opt_.size());
|
||||
arg_.clear();
|
||||
for (unsigned int i = 0; i < opt_.size(); ++i)
|
||||
{
|
||||
result_[i].value = opt_[i].defaultVal;
|
||||
}
|
||||
while (!arg.empty())
|
||||
{
|
||||
// option
|
||||
if (regex_match(arg.front(), sm, optRegex_))
|
||||
{
|
||||
// should it be a value?
|
||||
if (expectVal >= 0)
|
||||
{
|
||||
cerr << "warning: expected value for option ";
|
||||
cerr << optName(opt_[expectVal]);
|
||||
cerr << ", got option '" << arg.front() << "' instead" << endl;
|
||||
expectVal = -1;
|
||||
isCorrect = false;
|
||||
}
|
||||
// short option
|
||||
if (sm[1].matched)
|
||||
{
|
||||
string optName = sm[2].str();
|
||||
|
||||
// find option
|
||||
auto it = find_if(opt_.begin(), opt_.end(),
|
||||
[&optName](const OptPar &p)
|
||||
{
|
||||
return (p.shortName == optName);
|
||||
});
|
||||
|
||||
// parse if found
|
||||
if (it != opt_.end())
|
||||
{
|
||||
unsigned int i = it - opt_.begin();
|
||||
|
||||
result_[i].present = true;
|
||||
if (opt_[i].type == OptType::value)
|
||||
{
|
||||
if (sm[3].matched)
|
||||
{
|
||||
result_[i].value = sm[3].str();
|
||||
}
|
||||
else
|
||||
{
|
||||
expectVal = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
// warning if not found
|
||||
else
|
||||
{
|
||||
cerr << "warning: unknown option '" << arg.front() << "'";
|
||||
cerr << endl;
|
||||
}
|
||||
}
|
||||
// long option
|
||||
else if (sm[4].matched)
|
||||
{
|
||||
string optName = sm[5].str();
|
||||
|
||||
// find option
|
||||
auto it = find_if(opt_.begin(), opt_.end(),
|
||||
[&optName](const OptPar &p)
|
||||
{
|
||||
return (p.longName == optName);
|
||||
});
|
||||
|
||||
// parse if found
|
||||
if (it != opt_.end())
|
||||
{
|
||||
unsigned int i = it - opt_.begin();
|
||||
|
||||
result_[i].present = true;
|
||||
if (opt_[i].type == OptType::value)
|
||||
{
|
||||
if (sm[6].matched)
|
||||
{
|
||||
result_[i].value = sm[6].str();
|
||||
}
|
||||
else
|
||||
{
|
||||
expectVal = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
// warning if not found
|
||||
else
|
||||
{
|
||||
cerr << "warning: unknown option '" << arg.front() << "'";
|
||||
cerr << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (expectVal >= 0)
|
||||
{
|
||||
result_[expectVal].value = arg.front();
|
||||
expectVal = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
arg_.push_back(arg.front());
|
||||
}
|
||||
arg.pop();
|
||||
}
|
||||
if (expectVal >= 0)
|
||||
{
|
||||
cerr << "warning: expected value for option ";
|
||||
cerr << optName(opt_[expectVal]) << endl;
|
||||
expectVal = -1;
|
||||
isCorrect = false;
|
||||
}
|
||||
for (unsigned int i = 0; i < opt_.size(); ++i)
|
||||
{
|
||||
if (!opt_[i].optional and !result_[i].present)
|
||||
{
|
||||
cerr << "warning: mandatory option " << optName(opt_[i]);
|
||||
cerr << " is missing" << endl;
|
||||
isCorrect = false;
|
||||
}
|
||||
}
|
||||
|
||||
return isCorrect;
|
||||
}
|
||||
|
||||
// find option index ///////////////////////////////////////////////////////////
|
||||
int OptParser::optIndex(const string name) const
|
||||
{
|
||||
auto it = find_if(opt_.begin(), opt_.end(), [&name](const OptPar &p)
|
||||
{
|
||||
return (p.shortName == name) or (p.longName == name);
|
||||
});
|
||||
|
||||
if (it != opt_.end())
|
||||
{
|
||||
return static_cast<int>(it - opt_.begin());
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// option name for messages ////////////////////////////////////////////////////
|
||||
std::string OptParser::optName(const OptPar &opt)
|
||||
{
|
||||
std::string res = "";
|
||||
|
||||
if (!opt.shortName.empty())
|
||||
{
|
||||
res += "-" + opt.shortName;
|
||||
if (!opt.longName.empty())
|
||||
{
|
||||
res += "/";
|
||||
}
|
||||
}
|
||||
if (!opt.longName.empty())
|
||||
{
|
||||
res += "--" + opt.longName;
|
||||
if (opt.type == OptParser::OptType::value)
|
||||
{
|
||||
res += "=";
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// print option list ///////////////////////////////////////////////////////////
|
||||
std::ostream & Latan::operator<<(std::ostream &out, const OptParser &parser)
|
||||
{
|
||||
for (auto &o: parser.opt_)
|
||||
{
|
||||
out << setw(20) << OptParser::optName(o);
|
||||
out << ": " << o.helpMessage;
|
||||
if (!o.defaultVal.empty())
|
||||
{
|
||||
out << " (default: " << o.defaultVal << ")";
|
||||
}
|
||||
out << endl;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
103
lib/Core/OptParser.hpp
Normal file
103
lib/Core/OptParser.hpp
Normal file
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* OptParser.hpp, part of LatAnalyze
|
||||
*
|
||||
* Copyright (C) 2016 Antonin Portelli
|
||||
*
|
||||
* LatAnalyze is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LatAnalyze 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LatAnalyze. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef LatAnalyze_OptParser_hpp_
|
||||
#define LatAnalyze_OptParser_hpp_
|
||||
|
||||
#include <LatAnalyze/Global.hpp>
|
||||
|
||||
BEGIN_LATAN_NAMESPACE
|
||||
|
||||
/******************************************************************************
|
||||
* command-line option parser *
|
||||
******************************************************************************/
|
||||
class OptParser
|
||||
{
|
||||
public:
|
||||
enum class OptType {value, trigger};
|
||||
private:
|
||||
struct OptPar
|
||||
{
|
||||
std::string shortName, longName, defaultVal, helpMessage;
|
||||
OptType type;
|
||||
bool optional;
|
||||
};
|
||||
struct OptRes
|
||||
{
|
||||
std::string value;
|
||||
bool present;
|
||||
};
|
||||
public:
|
||||
// constructor
|
||||
OptParser(void) = default;
|
||||
// destructor
|
||||
virtual ~OptParser(void) = default;
|
||||
// access
|
||||
void addOption(const std::string shortName, const std::string longName,
|
||||
const OptType type, const bool optional = false,
|
||||
const std::string helpMessage = "",
|
||||
const std::string defaultVal = "");
|
||||
bool gotOption(const std::string name) const;
|
||||
template <typename T = std::string>
|
||||
T optionValue(const std::string name) const;
|
||||
const std::vector<std::string> & getArgs(void) const;
|
||||
// parse
|
||||
bool parse(int argc, char *argv[]);
|
||||
// print option list
|
||||
friend std::ostream & operator<<(std::ostream &out,
|
||||
const OptParser &parser);
|
||||
private:
|
||||
// find option index
|
||||
int optIndex(const std::string name) const;
|
||||
// option name for messages
|
||||
static std::string optName(const OptPar &opt);
|
||||
private:
|
||||
std::vector<OptPar> opt_;
|
||||
std::vector<OptRes> result_;
|
||||
std::vector<std::string> arg_;
|
||||
static const std::regex optRegex_;
|
||||
};
|
||||
|
||||
std::ostream & operator<<(std::ostream &out, const OptParser &parser);
|
||||
|
||||
/******************************************************************************
|
||||
* OptParser template implementation *
|
||||
******************************************************************************/
|
||||
template <typename T>
|
||||
T OptParser::optionValue(const std::string name) const
|
||||
{
|
||||
int i = optIndex(name);
|
||||
|
||||
if (result_.size() != opt_.size())
|
||||
{
|
||||
throw(std::runtime_error("options not parsed"));
|
||||
}
|
||||
if (i >= 0)
|
||||
{
|
||||
return strTo<T>(result_[i].value);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw(std::out_of_range("no option with name '" + name + "'"));
|
||||
}
|
||||
}
|
||||
|
||||
END_LATAN_NAMESPACE
|
||||
|
||||
#endif // LatAnalyze_OptParser_hpp_
|
58
lib/Core/ParserState.hpp
Normal file
58
lib/Core/ParserState.hpp
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* ParserState.hpp, part of LatAnalyze 3
|
||||
*
|
||||
* Copyright (C) 2013 - 2016 Antonin Portelli
|
||||
*
|
||||
* LatAnalyze 3 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LatAnalyze 3 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LatAnalyze 3. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef Latan_ParserState_hpp_
|
||||
#define Latan_ParserState_hpp_
|
||||
|
||||
#include <LatAnalyze/Global.hpp>
|
||||
|
||||
BEGIN_LATAN_NAMESPACE
|
||||
|
||||
template <typename DataObj>
|
||||
class ParserState
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
ParserState(std::istream *streamPt, std::string *namePt, DataObj *dataPt);
|
||||
// destructor
|
||||
virtual ~ParserState(void) = default;
|
||||
private:
|
||||
// scanner allocation/deallocation
|
||||
virtual void initScanner(void) = 0;
|
||||
virtual void destroyScanner(void) = 0;
|
||||
public:
|
||||
DataObj *data;
|
||||
void *scanner;
|
||||
std::istream *stream;
|
||||
std::string *streamName;
|
||||
|
||||
};
|
||||
|
||||
template <typename DataObj>
|
||||
ParserState<DataObj>::ParserState(std::istream *streamPt, std::string *namePt,
|
||||
DataObj *dataPt)
|
||||
: data(dataPt)
|
||||
, scanner(nullptr)
|
||||
, stream(streamPt)
|
||||
, streamName(namePt)
|
||||
{}
|
||||
|
||||
END_LATAN_NAMESPACE
|
||||
|
||||
#endif // Latan_ParserState_hpp_
|
689
lib/Core/Plot.cpp
Normal file
689
lib/Core/Plot.cpp
Normal file
@ -0,0 +1,689 @@
|
||||
/*
|
||||
* Plot.cpp, part of LatAnalyze 3
|
||||
*
|
||||
* Copyright (C) 2013 - 2016 Antonin Portelli
|
||||
*
|
||||
* LatAnalyze 3 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LatAnalyze 3 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LatAnalyze 3. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <LatAnalyze/Core/Plot.hpp>
|
||||
#include <LatAnalyze/includes.hpp>
|
||||
#include <LatAnalyze/Core/Mat.hpp>
|
||||
|
||||
using namespace std;
|
||||
using namespace Latan;
|
||||
|
||||
/******************************************************************************
|
||||
* Plot objects *
|
||||
******************************************************************************/
|
||||
// PlotObject access ///////////////////////////////////////////////////////////
|
||||
const string & PlotObject::getCommand(void) const
|
||||
{
|
||||
return command_;
|
||||
}
|
||||
|
||||
const string & PlotObject::getHeadCommand(void) const
|
||||
{
|
||||
return headCommand_;
|
||||
}
|
||||
|
||||
void PlotObject::setCommand(const string &command)
|
||||
{
|
||||
command_ = command;
|
||||
}
|
||||
|
||||
void PlotObject::setHeadCommand(const string &command)
|
||||
{
|
||||
headCommand_ = command;
|
||||
}
|
||||
|
||||
string PlotObject::popTmpFile(void)
|
||||
{
|
||||
string res = tmpFileName_.top();
|
||||
|
||||
tmpFileName_.pop();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void PlotObject::pushTmpFile(const std::string &fileName)
|
||||
{
|
||||
tmpFileName_.push(fileName);
|
||||
}
|
||||
|
||||
// PlotObject dump a matrix to a temporary file ////////////////////////////////
|
||||
string PlotObject::dumpToTmpFile(const DMat &m)
|
||||
{
|
||||
char tmpFileName[MAX_PATH_LENGTH];
|
||||
int fd;
|
||||
FILE *tmpFile;
|
||||
|
||||
for (Index j = 0; j < m.cols(); ++j)
|
||||
{
|
||||
}
|
||||
sprintf(tmpFileName, "%s/latan_plot_tmp.XXXXXX.dat", P_tmpdir);
|
||||
fd = mkstemps(tmpFileName, 4);
|
||||
if (fd == -1)
|
||||
{
|
||||
LATAN_ERROR(System, "impossible to create a temporary file from template "
|
||||
+ strFrom(tmpFileName));
|
||||
}
|
||||
tmpFile = fdopen(fd, "w");
|
||||
for (Index i = 0; i < m.rows(); ++i)
|
||||
{
|
||||
for (Index j = 0; j < m.cols(); ++j)
|
||||
{
|
||||
fprintf(tmpFile, "%e ", m(i, j));
|
||||
}
|
||||
fprintf(tmpFile, "\n");
|
||||
}
|
||||
fclose(tmpFile);
|
||||
|
||||
return string(tmpFileName);
|
||||
}
|
||||
|
||||
// PlotObject test /////////////////////////////////////////////////////////////
|
||||
bool PlotObject::gotTmpFile(void) const
|
||||
{
|
||||
return !tmpFileName_.empty();
|
||||
}
|
||||
|
||||
// PlotCommand constructor /////////////////////////////////////////////////////
|
||||
PlotCommand::PlotCommand(const string &command)
|
||||
{
|
||||
setCommand(command);
|
||||
}
|
||||
|
||||
// PlotHeadCommand constructor /////////////////////////////////////////////////
|
||||
PlotHeadCommand::PlotHeadCommand(const string &command)
|
||||
{
|
||||
setHeadCommand(command);
|
||||
}
|
||||
|
||||
// PlotData constructor ////////////////////////////////////////////////////////
|
||||
PlotData::PlotData(const DMatSample &x, const DMatSample &y)
|
||||
{
|
||||
if (x[central].rows() != y[central].rows())
|
||||
{
|
||||
LATAN_ERROR(Size, "x and y vector does not have the same size");
|
||||
}
|
||||
|
||||
DMat d(x[central].rows(), 4);
|
||||
string usingCmd, tmpFileName;
|
||||
|
||||
d.col(0) = x[central];
|
||||
d.col(2) = y[central];
|
||||
d.col(1) = x.variance().cwiseSqrt();
|
||||
d.col(3) = y.variance().cwiseSqrt();
|
||||
tmpFileName = dumpToTmpFile(d);
|
||||
pushTmpFile(tmpFileName);
|
||||
setCommand("'" + tmpFileName + "' u 1:3:2:4 w xyerr");
|
||||
}
|
||||
|
||||
PlotData::PlotData(const DVec &x, const DMatSample &y)
|
||||
{
|
||||
if (x.rows() != y[central].rows())
|
||||
{
|
||||
LATAN_ERROR(Size, "x and y vector does not have the same size");
|
||||
}
|
||||
|
||||
DMat d(x.rows(), 3);
|
||||
string usingCmd, tmpFileName;
|
||||
|
||||
d.col(0) = x;
|
||||
d.col(1) = y[central];
|
||||
d.col(2) = y.variance().cwiseSqrt();
|
||||
tmpFileName = dumpToTmpFile(d);
|
||||
pushTmpFile(tmpFileName);
|
||||
setCommand("'" + tmpFileName + "' u 1:2:3 w yerr");
|
||||
}
|
||||
|
||||
PlotData::PlotData(const DMatSample &x, const DVec &y)
|
||||
{
|
||||
if (x[central].rows() != y.rows())
|
||||
{
|
||||
LATAN_ERROR(Size, "x and y vector does not have the same size");
|
||||
}
|
||||
|
||||
DMat d(x[central].rows(), 3), xerr, yerr;
|
||||
string usingCmd, tmpFileName;
|
||||
|
||||
d.col(0) = x[central];
|
||||
d.col(2) = y;
|
||||
d.col(1) = x.variance().cwiseSqrt();
|
||||
tmpFileName = dumpToTmpFile(d);
|
||||
pushTmpFile(tmpFileName);
|
||||
setCommand("'" + tmpFileName + "' u 1:3:2 w xerr");
|
||||
}
|
||||
|
||||
PlotData::PlotData(const XYStatData &data, const Index i, const Index j)
|
||||
{
|
||||
string usingCmd, tmpFileName;
|
||||
|
||||
usingCmd = (data.isXExact(i)) ? "u 1:3:4 w yerr" : "u 1:3:2:4 w xyerr";
|
||||
tmpFileName = dumpToTmpFile(data.getTable(i, j));
|
||||
pushTmpFile(tmpFileName);
|
||||
setCommand("'" + tmpFileName + "' " + usingCmd);
|
||||
}
|
||||
|
||||
// PlotHLine constructor ///////////////////////////////////////////////////////
|
||||
PlotHLine::PlotHLine(const double y)
|
||||
{
|
||||
setCommand(strFrom(y));
|
||||
}
|
||||
|
||||
// PlotHBand constructor ///////////////////////////////////////////////////////
|
||||
PlotBand::PlotBand(const double xMin, const double xMax, const double yMin,
|
||||
const double yMax, const double opacity)
|
||||
{
|
||||
setCommand("'< printf \"%e %e\\n%e %e\\n%e %e\\n%e %e\\n%e %e\\n\" "
|
||||
+ strFrom(xMin) + " " + strFrom(yMin) + " "
|
||||
+ strFrom(xMax) + " " + strFrom(yMin) + " "
|
||||
+ strFrom(xMax) + " " + strFrom(yMax) + " "
|
||||
+ strFrom(xMin) + " " + strFrom(yMax) + " "
|
||||
+ strFrom(xMin) + " " + strFrom(yMin)
|
||||
+ "' u 1:2 w filledcurves closed fs solid " + strFrom(opacity)
|
||||
+ " noborder");
|
||||
}
|
||||
|
||||
// PlotFunction constructor ////////////////////////////////////////////////////
|
||||
PlotFunction::PlotFunction(const DoubleFunction &function, const double xMin,
|
||||
const double xMax, const unsigned int nPoint)
|
||||
{
|
||||
DMat d(nPoint, 2);
|
||||
string tmpFileName;
|
||||
double dx = (xMax - xMin)/static_cast<double>(nPoint - 1);
|
||||
|
||||
for (Index i = 0; i < nPoint; ++i)
|
||||
{
|
||||
d(i, 0) = xMin + i*dx;
|
||||
d(i, 1) = function(d(i, 0));
|
||||
}
|
||||
tmpFileName = dumpToTmpFile(d);
|
||||
pushTmpFile(tmpFileName);
|
||||
setCommand("'" + tmpFileName + "' u 1:2 w lines");
|
||||
}
|
||||
|
||||
// PlotPredBand constructor ////////////////////////////////////////////////////
|
||||
PlotPredBand::PlotPredBand(const DoubleFunctionSample &function,
|
||||
const double xMin, const double xMax,
|
||||
const unsigned int nPoint, const double opacity)
|
||||
{
|
||||
DMat dLow(nPoint, 2), dHigh(nPoint, 2);
|
||||
DSample pred(function.size());
|
||||
double dx = (xMax - xMin)/static_cast<double>(nPoint - 1);
|
||||
string lowFileName, highFileName;
|
||||
|
||||
for (Index i = 0; i < nPoint; ++i)
|
||||
{
|
||||
double x = xMin + i*dx, err;
|
||||
|
||||
pred = function(x);
|
||||
err = sqrt(pred.variance());
|
||||
dLow(i, 0) = x;
|
||||
dLow(i, 1) = pred[central] - err;
|
||||
dHigh(i, 0) = x;
|
||||
dHigh(i, 1) = pred[central] + err;
|
||||
}
|
||||
lowFileName = dumpToTmpFile(dLow);
|
||||
highFileName = dumpToTmpFile(dHigh);
|
||||
pushTmpFile(lowFileName);
|
||||
pushTmpFile(highFileName);
|
||||
setCommand("'< (cat " + lowFileName + "; tac " + highFileName +
|
||||
"; head -n1 " + lowFileName + ")' u 1:2 w filledcurves closed" +
|
||||
" fs solid " + strFrom(opacity) + " noborder");
|
||||
}
|
||||
|
||||
// PlotHistogram constructor ///////////////////////////////////////////////////
|
||||
PlotHistogram::PlotHistogram(const Histogram &h)
|
||||
{
|
||||
DMat d(h.size(), 2);
|
||||
string tmpFileName;
|
||||
|
||||
for (Index i = 0; i < h.size(); ++i)
|
||||
{
|
||||
d(i, 0) = h.getX(i);
|
||||
d(i, 1) = h[i];
|
||||
}
|
||||
tmpFileName = dumpToTmpFile(d);
|
||||
pushTmpFile(tmpFileName);
|
||||
setCommand("'" + tmpFileName + "' u 1:2 w steps");
|
||||
}
|
||||
|
||||
// PlotMatrixNoRange constructor ///////////////////////////////////////////////
|
||||
PlotMatrixNoRange::PlotMatrixNoRange(const DMat &m)
|
||||
{
|
||||
string tmpFileName = dumpToTmpFile(m);
|
||||
|
||||
setCommand("'" + tmpFileName + "' matrix w image");
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Plot modifiers *
|
||||
******************************************************************************/
|
||||
// Caption constructor /////////////////////////////////////////////////////////
|
||||
Caption::Caption(const string &caption)
|
||||
: caption_(caption)
|
||||
{}
|
||||
|
||||
// Caption modifier ////////////////////////////////////////////////////////////
|
||||
void Caption::operator()(PlotOptions &option) const
|
||||
{
|
||||
option.caption = caption_;
|
||||
}
|
||||
|
||||
// Label constructor ///////////////////////////////////////////////////////////
|
||||
Label::Label(const string &label, const Axis axis)
|
||||
: label_(label)
|
||||
, axis_(axis)
|
||||
{}
|
||||
|
||||
// Label modifier //////////////////////////////////////////////////////////////
|
||||
void Label::operator()(PlotOptions &option) const
|
||||
{
|
||||
option.label[static_cast<int>(axis_)] = label_;
|
||||
}
|
||||
|
||||
// Color constructor ///////////////////////////////////////////////////////////
|
||||
Color::Color(const string &color)
|
||||
: color_(color)
|
||||
{}
|
||||
|
||||
// Color modifier //////////////////////////////////////////////////////////////
|
||||
void Color::operator()(PlotOptions &option) const
|
||||
{
|
||||
option.lineColor = color_;
|
||||
}
|
||||
|
||||
// LogScale constructor ////////////////////////////////////////////////////////
|
||||
LogScale::LogScale(const Axis axis)
|
||||
: axis_(axis)
|
||||
{}
|
||||
|
||||
// Logscale modifier ///////////////////////////////////////////////////////////
|
||||
void LogScale::operator()(PlotOptions &option) const
|
||||
{
|
||||
option.scaleMode[static_cast<int>(axis_)] |= Plot::Scale::log;
|
||||
}
|
||||
|
||||
// PlotRange constructors //////////////////////////////////////////////////////
|
||||
PlotRange::PlotRange(const Axis axis)
|
||||
: axis_(axis)
|
||||
, reset_(true)
|
||||
, min_(0.)
|
||||
, max_(0.)
|
||||
{}
|
||||
|
||||
PlotRange::PlotRange(const Axis axis, const double min, const double max)
|
||||
: axis_(axis)
|
||||
, reset_(false)
|
||||
, min_(min)
|
||||
, max_(max)
|
||||
{}
|
||||
|
||||
// PlotRange modifier ///////////////////////////////////////////////////////////
|
||||
void PlotRange::operator()(PlotOptions &option) const
|
||||
{
|
||||
int a = static_cast<int>(axis_);
|
||||
|
||||
if (!reset_)
|
||||
{
|
||||
option.scaleMode[a] |= Plot::Scale::manual;
|
||||
option.scale[a].min = min_;
|
||||
option.scale[a].max = max_;
|
||||
}
|
||||
else
|
||||
{
|
||||
option.scaleMode[a] = Plot::Scale::reset;
|
||||
}
|
||||
}
|
||||
|
||||
// Terminal constructor ////////////////////////////////////////////////////////
|
||||
Terminal::Terminal(const string &terminal, const std::string &options)
|
||||
: terminalCmd_(terminal + " " + options)
|
||||
{}
|
||||
|
||||
// Terminal modifier ///////////////////////////////////////////////////////////
|
||||
void Terminal::operator()(PlotOptions &option) const
|
||||
{
|
||||
option.terminal = terminalCmd_;
|
||||
}
|
||||
|
||||
// Title constructor ///////////////////////////////////////////////////////////
|
||||
Title::Title(const string &title)
|
||||
: title_(title)
|
||||
{}
|
||||
|
||||
// Title modifier //////////////////////////////////////////////////////////////
|
||||
void Title::operator()(PlotOptions &option) const
|
||||
{
|
||||
option.title = title_;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Plot implementation *
|
||||
******************************************************************************/
|
||||
// constructor /////////////////////////////////////////////////////////////////
|
||||
Plot::Plot(void)
|
||||
{
|
||||
initOptions();
|
||||
}
|
||||
|
||||
// default options /////////////////////////////////////////////////////////////
|
||||
void Plot::initOptions(void)
|
||||
{
|
||||
options_.terminal = "qt";
|
||||
options_.output = "";
|
||||
options_.caption = "";
|
||||
options_.title = "";
|
||||
options_.scaleMode[0] = Plot::Scale::reset;
|
||||
options_.scaleMode[1] = Plot::Scale::reset;
|
||||
options_.scale[0] = {0.0, 0.0};
|
||||
options_.scale[1] = {0.0, 0.0};
|
||||
options_.label[0] = "";
|
||||
options_.label[1] = "";
|
||||
options_.lineColor = "";
|
||||
}
|
||||
|
||||
// plot reset //////////////////////////////////////////////////////////////////
|
||||
void Plot::reset(void)
|
||||
{
|
||||
headCommand_.clear();
|
||||
plotCommand_.clear();
|
||||
tmpFileName_.clear();
|
||||
initOptions();
|
||||
}
|
||||
|
||||
// plot objects ////////////////////////////////////////////////////////////////
|
||||
Plot & Plot::operator<<(PlotObject &&command)
|
||||
{
|
||||
string commandStr;
|
||||
|
||||
while (command.gotTmpFile())
|
||||
{
|
||||
tmpFileName_.push_back(command.popTmpFile());
|
||||
commandStr += "'" + tmpFileName_.back() + "' ";
|
||||
}
|
||||
commandStr = command.getCommand();
|
||||
if (!commandStr.empty())
|
||||
{
|
||||
if (!options_.lineColor.empty())
|
||||
{
|
||||
commandStr += " lc " + options_.lineColor;
|
||||
options_.lineColor = "";
|
||||
}
|
||||
if (options_.title.empty())
|
||||
{
|
||||
commandStr += " notitle";
|
||||
}
|
||||
else
|
||||
{
|
||||
commandStr += " t '" + options_.title + "'";
|
||||
options_.title = "";
|
||||
}
|
||||
plotCommand_.push_back(commandStr);
|
||||
}
|
||||
if (!command.getHeadCommand().empty())
|
||||
{
|
||||
headCommand_.push_back(command.getHeadCommand());
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Plot & Plot::operator<<(PlotModifier &&modifier)
|
||||
{
|
||||
modifier(options_);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// find gnuplot ////////////////////////////////////////////////////////////////
|
||||
void Plot::getProgramPath(void)
|
||||
{
|
||||
int i, j, lg;
|
||||
char *path;
|
||||
static char buf[MAX_PATH_LENGTH];
|
||||
|
||||
// trivial case: try in CWD
|
||||
sprintf(buf,"./%s", gnuplotBin_.c_str()) ;
|
||||
if (access(buf, X_OK) == 0)
|
||||
{
|
||||
sprintf(buf,".");
|
||||
gnuplotPath_ = buf;
|
||||
}
|
||||
// try out in all paths given in the PATH variable
|
||||
else
|
||||
{
|
||||
buf[0] = 0;
|
||||
path = getenv("PATH") ;
|
||||
if (path)
|
||||
{
|
||||
for (i=0;path[i];)
|
||||
{
|
||||
for (j=i;(path[j]) and (path[j]!=':');j++);
|
||||
lg = j - i;
|
||||
strncpy(buf,path + i,(size_t)(lg));
|
||||
if (lg == 0)
|
||||
{
|
||||
buf[lg++] = '.';
|
||||
}
|
||||
buf[lg++] = '/';
|
||||
strcpy(buf + lg, gnuplotBin_.c_str());
|
||||
if (access(buf, X_OK) == 0)
|
||||
{
|
||||
// found it!
|
||||
break ;
|
||||
}
|
||||
buf[0] = 0;
|
||||
i = j;
|
||||
if (path[i] == ':') i++ ;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LATAN_ERROR(System, "PATH variable not set");
|
||||
}
|
||||
// if the buffer is still empty, the command was not found
|
||||
if (buf[0] == 0)
|
||||
{
|
||||
LATAN_ERROR(System, "cannot find gnuplot in $PATH");
|
||||
}
|
||||
// otherwise truncate the command name to yield path only
|
||||
lg = (int)(strlen(buf) - 1);
|
||||
while (buf[lg]!='/')
|
||||
{
|
||||
buf[lg] = 0;
|
||||
lg--;
|
||||
}
|
||||
buf[lg] = 0;
|
||||
gnuplotPath_ = buf;
|
||||
}
|
||||
}
|
||||
|
||||
// plot parsing and output /////////////////////////////////////////////////////
|
||||
void Plot::display(void)
|
||||
{
|
||||
int pid = fork();
|
||||
|
||||
if (pid == 0)
|
||||
{
|
||||
FILE *gnuplotPipe;
|
||||
string command;
|
||||
ostringstream scriptBuf;
|
||||
|
||||
if (!getenv("DISPLAY"))
|
||||
{
|
||||
LATAN_ERROR(System, "cannot find DISPLAY variable: is it set ?");
|
||||
}
|
||||
getProgramPath();
|
||||
command = gnuplotPath_ + "/" + gnuplotBin_;
|
||||
gnuplotPipe = popen(command.c_str(), "w");
|
||||
if (!gnuplotPipe)
|
||||
{
|
||||
LATAN_ERROR(System, "error starting gnuplot (command was '"
|
||||
+ command + "')");
|
||||
}
|
||||
commandBuffer_.str("");
|
||||
commandBuffer_ << *this << endl;
|
||||
commandBuffer_ << "pause mouse close" << endl;
|
||||
fprintf(gnuplotPipe, "%s", commandBuffer_.str().c_str());
|
||||
if (pclose(gnuplotPipe) == -1)
|
||||
{
|
||||
LATAN_ERROR(System, "problem closing communication to gnuplot");
|
||||
}
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
else if (pid == -1)
|
||||
{
|
||||
perror("fork error");
|
||||
LATAN_ERROR(System, "problem forking to the process handling gnuplot");
|
||||
}
|
||||
}
|
||||
|
||||
void Plot::save(string dirName)
|
||||
{
|
||||
vector<string> commandBack;
|
||||
string path, terminalBack, outputBack, gpCommand, scriptName;
|
||||
mode_t mode755;
|
||||
ofstream script;
|
||||
|
||||
mode755 = S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
|
||||
|
||||
// backup I/O parameters
|
||||
terminalBack = options_.terminal;
|
||||
outputBack = options_.output;
|
||||
commandBack = plotCommand_;
|
||||
|
||||
// generate directory
|
||||
if (mkdir(dirName))
|
||||
{
|
||||
LATAN_ERROR(Io, "impossible to create directory '" + dirName + "'");
|
||||
}
|
||||
|
||||
// save PDF
|
||||
options_.terminal = "pdf";
|
||||
options_.output = dirName + "/plot.pdf";
|
||||
display();
|
||||
options_.terminal = terminalBack;
|
||||
options_.output = outputBack;
|
||||
|
||||
// save script and datafiles
|
||||
for (unsigned int i = 0; i < tmpFileName_.size(); ++i)
|
||||
{
|
||||
ofstream dataFile;
|
||||
ifstream tmpFile;
|
||||
string dataFileName = "points_" + strFrom(i) + ".dat";
|
||||
|
||||
dataFile.open(dirName + "/" + dataFileName);
|
||||
tmpFile.open(tmpFileName_[i]);
|
||||
dataFile << tmpFile.rdbuf();
|
||||
dataFile.close();
|
||||
tmpFile.close();
|
||||
for (string &command: plotCommand_)
|
||||
{
|
||||
auto pos = command.find(tmpFileName_[i]);
|
||||
|
||||
while (pos != string::npos)
|
||||
{
|
||||
command.replace(pos, tmpFileName_[i].size(), dataFileName);
|
||||
pos = command.find(tmpFileName_[i], pos + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
scriptName = dirName + "/source.plt";
|
||||
script.open(scriptName);
|
||||
getProgramPath();
|
||||
gpCommand = gnuplotPath_ + "/" + gnuplotBin_ + " " + gnuplotArgs_;
|
||||
script << "#!/usr/bin/env " << gpCommand << "\n" << endl;
|
||||
script << "# script generated by " << Env::fullName << "\n" << endl;
|
||||
script << *this;
|
||||
script.close();
|
||||
if (chmod(scriptName.c_str(), mode755))
|
||||
{
|
||||
LATAN_ERROR(Io, "impossible to set file '" + scriptName +
|
||||
"' in mode 755");
|
||||
}
|
||||
plotCommand_ = commandBack;
|
||||
}
|
||||
|
||||
ostream & Latan::operator<<(ostream &out, const Plot &plot)
|
||||
{
|
||||
std::string begin, end;
|
||||
int x = static_cast<int>(Axis::x), y = static_cast<int>(Axis::y);
|
||||
|
||||
if (!plot.options_.terminal.empty())
|
||||
{
|
||||
out << "set term " << plot.options_.terminal << endl;
|
||||
}
|
||||
if (!plot.options_.output.empty())
|
||||
{
|
||||
out << "set output '" << plot.options_.output << "'" << endl;
|
||||
}
|
||||
if (!plot.options_.caption.empty())
|
||||
{
|
||||
out << "set title '" << plot.options_.caption << "'" << endl;
|
||||
}
|
||||
if (plot.options_.scaleMode[x] & Plot::Scale::manual)
|
||||
{
|
||||
out << "xMin = " << plot.options_.scale[x].min << endl;
|
||||
out << "xMax = " << plot.options_.scale[x].max << endl;
|
||||
}
|
||||
if (plot.options_.scaleMode[y] & Plot::Scale::manual)
|
||||
{
|
||||
out << "yMin = " << plot.options_.scale[y].min << endl;
|
||||
out << "yMax = " << plot.options_.scale[y].max << endl;
|
||||
}
|
||||
if (!plot.options_.title.empty())
|
||||
{
|
||||
out << "set title '" << plot.options_.title << "'" << endl;
|
||||
}
|
||||
if (plot.options_.scaleMode[x] & Plot::Scale::manual)
|
||||
{
|
||||
out << "set xrange [xMin:xMax]" << endl;
|
||||
}
|
||||
if (plot.options_.scaleMode[y] & Plot::Scale::manual)
|
||||
{
|
||||
out << "set yrange [yMin:yMax]" << endl;
|
||||
}
|
||||
if (plot.options_.scaleMode[x] & Plot::Scale::log)
|
||||
{
|
||||
out << "set log x" << endl;
|
||||
}
|
||||
if (plot.options_.scaleMode[y] & Plot::Scale::log)
|
||||
{
|
||||
out << "set log y" << endl;
|
||||
}
|
||||
if (!plot.options_.label[x].empty())
|
||||
{
|
||||
out << "set xlabel '" << plot.options_.label[x] << "'" << endl;
|
||||
}
|
||||
if (!plot.options_.label[y].empty())
|
||||
{
|
||||
out << "set ylabel '" << plot.options_.label[y] << "'" << endl;
|
||||
}
|
||||
for (unsigned int i = 0; i < plot.headCommand_.size(); ++i)
|
||||
{
|
||||
out << plot.headCommand_[i] << endl;
|
||||
}
|
||||
for (unsigned int i = 0; i < plot.plotCommand_.size(); ++i)
|
||||
{
|
||||
begin = (i == 0) ? "plot " : " ";
|
||||
end = (i == plot.plotCommand_.size() - 1) ? "" : ",\\";
|
||||
out << begin << plot.plotCommand_[i] << end << endl;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
342
lib/Core/Plot.hpp
Normal file
342
lib/Core/Plot.hpp
Normal file
@ -0,0 +1,342 @@
|
||||
/*
|
||||
* Plot.hpp, part of LatAnalyze 3
|
||||
*
|
||||
* Copyright (C) 2013 - 2016 Antonin Portelli
|
||||
*
|
||||
* LatAnalyze 3 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LatAnalyze 3 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LatAnalyze 3. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef Latan_Plot_hpp_
|
||||
#define Latan_Plot_hpp_
|
||||
|
||||
#include <LatAnalyze/Global.hpp>
|
||||
#include <LatAnalyze/Functional/Function.hpp>
|
||||
#include <LatAnalyze/Core/Mat.hpp>
|
||||
#include <LatAnalyze/Statistics/MatSample.hpp>
|
||||
#include <LatAnalyze/Statistics/Histogram.hpp>
|
||||
#include <LatAnalyze/Statistics/XYStatData.hpp>
|
||||
|
||||
// gnuplot default parameters
|
||||
#ifndef GNUPLOT_BIN
|
||||
#define GNUPLOT_BIN "gnuplot"
|
||||
#endif
|
||||
|
||||
#ifndef GNUPLOT_ARGS
|
||||
#define GNUPLOT_ARGS "-p"
|
||||
#endif
|
||||
|
||||
BEGIN_LATAN_NAMESPACE
|
||||
|
||||
/******************************************************************************
|
||||
* Plot objects *
|
||||
******************************************************************************/
|
||||
class PlotObject
|
||||
{
|
||||
public:
|
||||
// destructor
|
||||
virtual ~PlotObject(void) = default;
|
||||
// access
|
||||
std::string popTmpFile(void);
|
||||
const std::string & getCommand(void) const;
|
||||
const std::string & getHeadCommand(void) const;
|
||||
// test
|
||||
bool gotTmpFile(void) const;
|
||||
protected:
|
||||
// access
|
||||
void pushTmpFile(const std::string &fileName);
|
||||
void setCommand(const std::string &command);
|
||||
void setHeadCommand(const std::string &command);
|
||||
// dump a matrix to a temporary file
|
||||
std::string dumpToTmpFile(const DMat &m);
|
||||
private:
|
||||
// plot command
|
||||
std::string command_;
|
||||
std::string headCommand_;
|
||||
// stack of created temporary files
|
||||
std::stack<std::string> tmpFileName_;
|
||||
};
|
||||
|
||||
class PlotCommand: public PlotObject
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
explicit PlotCommand(const std::string &command);
|
||||
// destructor
|
||||
virtual ~PlotCommand(void) = default;
|
||||
};
|
||||
|
||||
class PlotHeadCommand: public PlotObject
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
explicit PlotHeadCommand(const std::string &command);
|
||||
// destructor
|
||||
virtual ~PlotHeadCommand(void) = default;
|
||||
};
|
||||
|
||||
class PlotData: public PlotObject
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
PlotData(const DMatSample &x, const DMatSample &y);
|
||||
PlotData(const DVec &x, const DMatSample &y);
|
||||
PlotData(const DMatSample &x, const DVec &y);
|
||||
PlotData(const XYStatData &data, const Index i = 0, const Index j = 0);
|
||||
// destructor
|
||||
virtual ~PlotData(void) = default;
|
||||
};
|
||||
|
||||
class PlotHLine: public PlotObject
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
PlotHLine(const double y);
|
||||
// destructor
|
||||
virtual ~PlotHLine(void) = default;
|
||||
};
|
||||
|
||||
class PlotBand: public PlotObject
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
PlotBand(const double xMin, const double xMax, const double yMin,
|
||||
const double yMax, const double opacity = 0.15);
|
||||
// destructor
|
||||
virtual ~PlotBand(void) = default;
|
||||
};
|
||||
|
||||
class PlotFunction: public PlotObject
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
PlotFunction(const DoubleFunction &function, const double xMin,
|
||||
const double xMax, const unsigned int nPoint = 1000);
|
||||
// destructor
|
||||
virtual ~PlotFunction(void) = default;
|
||||
};
|
||||
|
||||
class PlotPredBand: public PlotObject
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
PlotPredBand(const DoubleFunctionSample &function, const double xMin,
|
||||
const double xMax, const unsigned int nPoint = 1000,
|
||||
const double opacity = 0.15);
|
||||
// destructor
|
||||
virtual ~PlotPredBand(void) = default;
|
||||
};
|
||||
|
||||
class PlotHistogram: public PlotObject
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
PlotHistogram(const Histogram &h);
|
||||
// destructor
|
||||
virtual ~PlotHistogram(void) = default;
|
||||
};
|
||||
|
||||
class PlotMatrixNoRange: public PlotObject
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
PlotMatrixNoRange(const DMat &m);
|
||||
// destructor
|
||||
virtual ~PlotMatrixNoRange(void) = default;
|
||||
};
|
||||
|
||||
#define PlotMatrix(m)\
|
||||
PlotRange(Axis::x, -.5, (m).cols() - .5) <<\
|
||||
PlotRange(Axis::y, (m).rows() - .5, -.5) <<\
|
||||
PlotMatrixNoRange(m)
|
||||
|
||||
/******************************************************************************
|
||||
* Plot modifiers *
|
||||
******************************************************************************/
|
||||
enum class Axis {x = 0, y = 1};
|
||||
|
||||
struct Range
|
||||
{
|
||||
double min, max;
|
||||
};
|
||||
|
||||
struct PlotOptions
|
||||
{
|
||||
std::string terminal;
|
||||
std::string output;
|
||||
std::string caption;
|
||||
std::string title;
|
||||
unsigned int scaleMode[2];
|
||||
Range scale[2];
|
||||
std::string label[2];
|
||||
std::string lineColor;
|
||||
};
|
||||
|
||||
class PlotModifier
|
||||
{
|
||||
public:
|
||||
// destructor
|
||||
virtual ~PlotModifier(void) = default;
|
||||
// modifier
|
||||
virtual void operator()(PlotOptions &option) const = 0;
|
||||
};
|
||||
|
||||
class Caption: public PlotModifier
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
explicit Caption(const std::string &title);
|
||||
// destructor
|
||||
virtual ~Caption(void) = default;
|
||||
// modifier
|
||||
virtual void operator()(PlotOptions &option) const;
|
||||
private:
|
||||
const std::string caption_;
|
||||
};
|
||||
|
||||
class Label: public PlotModifier
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
explicit Label(const std::string &label, const Axis axis);
|
||||
// destructor
|
||||
virtual ~Label(void) = default;
|
||||
// modifier
|
||||
virtual void operator()(PlotOptions &option) const;
|
||||
private:
|
||||
const std::string label_;
|
||||
const Axis axis_;
|
||||
};
|
||||
|
||||
class Color: public PlotModifier
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
explicit Color(const std::string &color);
|
||||
// destructor
|
||||
virtual ~Color(void) = default;
|
||||
// modifier
|
||||
virtual void operator()(PlotOptions &option) const;
|
||||
private:
|
||||
const std::string color_;
|
||||
};
|
||||
|
||||
class LogScale: public PlotModifier
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
explicit LogScale(const Axis axis);
|
||||
// destructor
|
||||
virtual ~LogScale(void) = default;
|
||||
// modifier
|
||||
virtual void operator()(PlotOptions &option) const;
|
||||
private:
|
||||
const Axis axis_;
|
||||
};
|
||||
|
||||
class PlotRange: public PlotModifier
|
||||
{
|
||||
public:
|
||||
// constructors
|
||||
PlotRange(const Axis axis);
|
||||
PlotRange(const Axis axis, const double min, const double max);
|
||||
// destructor
|
||||
virtual ~PlotRange(void) = default;
|
||||
// modifier
|
||||
virtual void operator()(PlotOptions &option) const;
|
||||
private:
|
||||
const Axis axis_;
|
||||
const bool reset_;
|
||||
const double min_, max_;
|
||||
};
|
||||
|
||||
class Terminal: public PlotModifier
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
Terminal(const std::string &terminal, const std::string &options = "");
|
||||
// destructor
|
||||
virtual ~Terminal(void) = default;
|
||||
// modifier
|
||||
virtual void operator()(PlotOptions &option) const;
|
||||
private:
|
||||
const std::string terminalCmd_;
|
||||
};
|
||||
|
||||
class Title: public PlotModifier
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
explicit Title(const std::string &title);
|
||||
// destructor
|
||||
virtual ~Title(void) = default;
|
||||
// modifier
|
||||
virtual void operator()(PlotOptions &option) const;
|
||||
private:
|
||||
const std::string title_;
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
* Plot class *
|
||||
******************************************************************************/
|
||||
class Plot
|
||||
{
|
||||
public:
|
||||
class Scale
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
reset = 0,
|
||||
manual = 1 << 0,
|
||||
log = 1 << 1
|
||||
};
|
||||
};
|
||||
public:
|
||||
// constructor/destructor
|
||||
Plot(void);
|
||||
virtual ~Plot(void) = default;
|
||||
// plot operations
|
||||
Plot & operator<<(PlotObject &&command);
|
||||
Plot & operator<<(PlotModifier &&modifier);
|
||||
// plot parsing and output
|
||||
void display(void);
|
||||
void save(std::string dirName);
|
||||
friend std::ostream & operator<<(std::ostream &out, const Plot &plot);
|
||||
// plot reset
|
||||
void reset(void);
|
||||
private:
|
||||
// find gnuplot
|
||||
void getProgramPath(void);
|
||||
// default options
|
||||
void initOptions(void);
|
||||
private:
|
||||
// gnuplot execution parameters
|
||||
std::string gnuplotBin_ {GNUPLOT_BIN};
|
||||
std::string gnuplotArgs_ {GNUPLOT_ARGS};
|
||||
std::string gnuplotPath_ {""};
|
||||
// string buffer for commands
|
||||
std::ostringstream commandBuffer_;
|
||||
// stack of created temporary files
|
||||
std::vector<std::string> tmpFileName_;
|
||||
// plot content
|
||||
PlotOptions options_;
|
||||
std::vector<std::string> headCommand_;
|
||||
std::vector<std::string> plotCommand_;
|
||||
};
|
||||
|
||||
std::ostream & operator<<(std::ostream &out, const Plot &plot);
|
||||
|
||||
END_LATAN_NAMESPACE
|
||||
|
||||
#endif // Latan_Plot_hpp_
|
137
lib/Core/Utilities.cpp
Normal file
137
lib/Core/Utilities.cpp
Normal file
@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Utilities.cpp, part of LatAnalyze
|
||||
*
|
||||
* Copyright (C) 2013 - 2015 Antonin Portelli
|
||||
*
|
||||
* LatAnalyze is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LatAnalyze 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LatAnalyze. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <LatAnalyze/Core/Utilities.hpp>
|
||||
#include <LatAnalyze/includes.hpp>
|
||||
|
||||
using namespace std;
|
||||
using namespace Latan;
|
||||
|
||||
void Latan::testFunction(void)
|
||||
{}
|
||||
|
||||
ostream & Latan::operator<<(ostream &out, const ProgressBar &&bar)
|
||||
{
|
||||
const Index nTick = bar.nCol_*bar.current_/bar.total_;
|
||||
|
||||
out << "[";
|
||||
for (Index i = 0; i < nTick; ++i)
|
||||
{
|
||||
out << "=";
|
||||
}
|
||||
for (Index i = nTick; i < bar.nCol_; ++i)
|
||||
{
|
||||
out << " ";
|
||||
}
|
||||
out << "] " << bar.current_ << "/" << bar.total_;
|
||||
out.flush();
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
int Latan::mkdir(const std::string dirName)
|
||||
{
|
||||
if (access(dirName.c_str(), R_OK|W_OK|X_OK))
|
||||
{
|
||||
mode_t mode755;
|
||||
char tmp[MAX_PATH_LENGTH];
|
||||
char *p = NULL;
|
||||
size_t len;
|
||||
|
||||
mode755 = S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
|
||||
|
||||
snprintf(tmp, sizeof(tmp), "%s", dirName.c_str());
|
||||
len = strlen(tmp);
|
||||
if(tmp[len - 1] == '/')
|
||||
{
|
||||
tmp[len - 1] = 0;
|
||||
}
|
||||
for(p = tmp + 1; *p; p++)
|
||||
{
|
||||
if(*p == '/')
|
||||
{
|
||||
*p = 0;
|
||||
::mkdir(tmp, mode755);
|
||||
*p = '/';
|
||||
}
|
||||
}
|
||||
|
||||
return ::mkdir(tmp, mode755);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
string Latan::basename(const string &s)
|
||||
{
|
||||
constexpr char sep = '/';
|
||||
size_t i = s.rfind(sep, s.length());
|
||||
|
||||
if (i != string::npos)
|
||||
{
|
||||
return s.substr(i+1, s.length() - i);
|
||||
}
|
||||
else
|
||||
{
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
std::string Latan::dirname(const std::string &s)
|
||||
{
|
||||
constexpr char sep = '/';
|
||||
size_t i = s.rfind(sep, s.length());
|
||||
|
||||
if (i != std::string::npos)
|
||||
{
|
||||
return s.substr(0, i);
|
||||
}
|
||||
else
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
VarName::VarName(const string defName)
|
||||
: defName_(defName)
|
||||
{}
|
||||
|
||||
string VarName::getName(const Index i) const
|
||||
{
|
||||
if (hasName(i))
|
||||
{
|
||||
return name_.at(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
return defName_ + "_" + strFrom(i);
|
||||
}
|
||||
}
|
||||
|
||||
void VarName::setName(const Index i, const string name)
|
||||
{
|
||||
name_[i] = name;
|
||||
}
|
||||
|
||||
bool VarName::hasName(const Index i) const
|
||||
{
|
||||
return (name_.find(i) != name_.end());
|
||||
}
|
250
lib/Core/Utilities.hpp
Normal file
250
lib/Core/Utilities.hpp
Normal file
@ -0,0 +1,250 @@
|
||||
/*
|
||||
* Utilities.hpp, part of LatAnalyze
|
||||
*
|
||||
* Copyright (C) 2013 - 2015 Antonin Portelli
|
||||
*
|
||||
* LatAnalyze is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LatAnalyze 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LatAnalyze. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef LatAnalyze_Utilities_hpp_
|
||||
#define LatAnalyze_Utilities_hpp_
|
||||
|
||||
#ifndef LATAN_GLOBAL_HPP_
|
||||
#include <LatAnalyze/Global.hpp>
|
||||
#endif
|
||||
|
||||
BEGIN_LATAN_NAMESPACE
|
||||
|
||||
// Random seed type ////////////////////////////////////////////////////////////
|
||||
typedef std::random_device::result_type SeedType;
|
||||
|
||||
// Type utilities //////////////////////////////////////////////////////////////
|
||||
// pointer type test
|
||||
template <typename Derived, typename Base>
|
||||
inline bool isDerivedFrom(const Base *pt)
|
||||
{
|
||||
return (dynamic_cast<const Derived *>(pt) != nullptr);
|
||||
}
|
||||
|
||||
// static logical or
|
||||
template <bool... b>
|
||||
struct static_or;
|
||||
|
||||
template <bool... tail>
|
||||
struct static_or<true, tail...> : static_or<tail...> {};
|
||||
|
||||
template <bool... tail>
|
||||
struct static_or<false, tail...> : std::false_type {};
|
||||
|
||||
template <>
|
||||
struct static_or<> : std::true_type {};
|
||||
|
||||
// Environment /////////////////////////////////////////////////////////////////
|
||||
void testFunction(void);
|
||||
|
||||
// String utilities ////////////////////////////////////////////////////////////
|
||||
inline std::string extension(const std::string fileName)
|
||||
{
|
||||
return fileName.substr(fileName.find_last_of(".") + 1);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T strTo(const std::string &str)
|
||||
{
|
||||
T buf;
|
||||
std::istringstream stream(str);
|
||||
|
||||
stream >> buf;
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
// optimized specializations
|
||||
template <>
|
||||
inline float strTo<float>(const std::string &str)
|
||||
{
|
||||
return strtof(str.c_str(), (char **)NULL);
|
||||
}
|
||||
template <>
|
||||
inline double strTo<double>(const std::string &str)
|
||||
{
|
||||
return strtod(str.c_str(), (char **)NULL);
|
||||
}
|
||||
template <>
|
||||
inline int strTo<int>(const std::string &str)
|
||||
{
|
||||
return (int)(strtol(str.c_str(), (char **)NULL, 10));
|
||||
}
|
||||
template <>
|
||||
inline long strTo<long>(const std::string &str)
|
||||
{
|
||||
return strtol(str.c_str(), (char **)NULL, 10);
|
||||
}
|
||||
template <>
|
||||
inline std::string strTo<std::string>(const std::string &str)
|
||||
{
|
||||
return str;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline std::string strFrom(const T x)
|
||||
{
|
||||
std::ostringstream stream;
|
||||
|
||||
stream << x;
|
||||
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
// specialization for vectors
|
||||
template<>
|
||||
inline DVec strTo<DVec>(const std::string &str)
|
||||
{
|
||||
DVec res;
|
||||
std::vector<double> vbuf;
|
||||
double buf;
|
||||
std::istringstream stream(str);
|
||||
|
||||
while (!stream.eof())
|
||||
{
|
||||
stream >> buf;
|
||||
vbuf.push_back(buf);
|
||||
}
|
||||
res = Map<DVec>(vbuf.data(), static_cast<Index>(vbuf.size()));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline IVec strTo<IVec>(const std::string &str)
|
||||
{
|
||||
IVec res;
|
||||
std::vector<int> vbuf;
|
||||
int buf;
|
||||
std::istringstream stream(str);
|
||||
|
||||
while (!stream.eof())
|
||||
{
|
||||
stream >> buf;
|
||||
vbuf.push_back(buf);
|
||||
}
|
||||
res = Map<IVec>(vbuf.data(), static_cast<Index>(vbuf.size()));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline UVec strTo<UVec>(const std::string &str)
|
||||
{
|
||||
UVec res;
|
||||
std::vector<unsigned int> vbuf;
|
||||
unsigned int buf;
|
||||
std::istringstream stream(str);
|
||||
|
||||
while (!stream.eof())
|
||||
{
|
||||
stream >> buf;
|
||||
vbuf.push_back(buf);
|
||||
}
|
||||
res = Map<UVec>(vbuf.data(), static_cast<Index>(vbuf.size()));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void tokenReplace(std::string &str, const std::string token,
|
||||
const T &x, const std::string mark = "@")
|
||||
{
|
||||
std::string fullToken = mark + token + mark;
|
||||
|
||||
auto pos = str.find(fullToken);
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
str.replace(pos, fullToken.size(), strFrom(x));
|
||||
}
|
||||
}
|
||||
|
||||
// Manifest file reader ////////////////////////////////////////////////////////
|
||||
inline std::vector<std::string> readManifest(const std::string manFileName)
|
||||
{
|
||||
std::vector<std::string> list;
|
||||
std::ifstream manFile;
|
||||
char buf[MAX_PATH_LENGTH];
|
||||
|
||||
manFile.open(manFileName);
|
||||
while (!manFile.eof())
|
||||
{
|
||||
manFile.getline(buf, MAX_PATH_LENGTH);
|
||||
if (!std::string(buf).empty())
|
||||
{
|
||||
list.push_back(buf);
|
||||
}
|
||||
}
|
||||
manFile.close();
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
// Recursive directory creation ////////////////////////////////////////////////
|
||||
int mkdir(const std::string dirName);
|
||||
|
||||
// C++ version of basename/dirname /////////////////////////////////////////////
|
||||
std::string basename(const std::string& s);
|
||||
std::string dirname(const std::string& s);
|
||||
|
||||
// Progress bar class //////////////////////////////////////////////////////////
|
||||
class ProgressBar
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
template <typename A, typename B>
|
||||
ProgressBar(const A current, const B total, const Index nCol = 60);
|
||||
// IO
|
||||
friend std::ostream & operator<<(std::ostream &out,
|
||||
const ProgressBar &&bar);
|
||||
private:
|
||||
Index current_, total_, nCol_;
|
||||
};
|
||||
|
||||
template <typename A, typename B>
|
||||
ProgressBar::ProgressBar(const A current, const B total, const Index nCol)
|
||||
: current_(static_cast<Index>(current))
|
||||
, total_(static_cast<Index>(total))
|
||||
, nCol_(nCol)
|
||||
{}
|
||||
|
||||
std::ostream & operator<<(std::ostream &out, const ProgressBar &&bar);
|
||||
|
||||
// named variable interface ////////////////////////////////////////////////////
|
||||
// FIXME: check redundant names and variable number limit
|
||||
class VarName
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
VarName(const std::string defName);
|
||||
// destructor
|
||||
virtual ~VarName(void) = default;
|
||||
// access
|
||||
std::string getName(const Index i) const;
|
||||
void setName(const Index i, const std::string name);
|
||||
// test
|
||||
bool hasName(const Index i) const;
|
||||
private:
|
||||
std::string defName_;
|
||||
std::unordered_map<Index, std::string> name_;
|
||||
};
|
||||
|
||||
END_LATAN_NAMESPACE
|
||||
|
||||
#endif // LatAnalyze_Utilities_hpp_
|
56
lib/Core/stdincludes.hpp
Normal file
56
lib/Core/stdincludes.hpp
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* stdincludes.hpp, part of LatAnalyze 3
|
||||
*
|
||||
* Copyright (C) 2013 - 2016 Antonin Portelli
|
||||
*
|
||||
* LatAnalyze 3 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LatAnalyze 3 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LatAnalyze 3. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef Latan_stdincludes_hpp_
|
||||
#define Latan_stdincludes_hpp_
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
#include <complex>
|
||||
#include <fstream>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
#include <random>
|
||||
#include <regex>
|
||||
#include <set>
|
||||
#include <stack>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <cfloat>
|
||||
#include <climits>
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#endif // Latan_stdincludes_hpp_
|
Reference in New Issue
Block a user