diff --git a/CMakeLists.txt b/CMakeLists.txt
index de73d496..7d45ff77 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -153,7 +153,7 @@ ENDIF()
# ----------------------------------------------------------------------------
# Check if it is possible to use LLVM/Clang for JIT
# ----------------------------------------------------------------------------
-SET(CPPADCG_LLVM_LINK_LIB "3.2|3.6|3.8|4.0|5.0|6.0|7.0|8.0")
+SET(CPPADCG_LLVM_LINK_LIB "3.2|3.6|3.8|4.0|5.0|6.0|7.0|8.0|9.0")
IF((("${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}" MATCHES "^(${CPPADCG_LLVM_LINK_LIB})$") AND CLANG_FOUND)
OR
diff --git a/cmake/FindLLVM.cmake b/cmake/FindLLVM.cmake
index 785e6bcf..87b85305 100644
--- a/cmake/FindLLVM.cmake
+++ b/cmake/FindLLVM.cmake
@@ -41,7 +41,7 @@ UNSET(LLVM_MODULE_LIBS CACHE)
MACRO(find_llvm_iteratively)
IF(NOT LLVM_CONFIG AND NOT LLVM_FIND_VERSION_EXACT)
- SET(_LLVM_KNOWN_VERSIONS ${LLVM_ADDITIONAL_VERSIONS} "8" "7" "6.0" "5.0" "4.0" "3.8" "3.7" "3.6" "3.5" "3.4" "3.3" "3.2")
+ SET(_LLVM_KNOWN_VERSIONS ${LLVM_ADDITIONAL_VERSIONS} "9" "8" "7" "6.0" "5.0" "4.0" "3.8" "3.7" "3.6" "3.5" "3.4" "3.3" "3.2")
# Select acceptable versions.
FOREACH(version ${_LLVM_KNOWN_VERSIONS})
diff --git a/include/cppad/cg/lang/mathml/language_mathml.hpp b/include/cppad/cg/lang/mathml/language_mathml.hpp
index 0a629d30..023fa81e 100644
--- a/include/cppad/cg/lang/mathml/language_mathml.hpp
+++ b/include/cppad/cg/lang/mathml/language_mathml.hpp
@@ -601,7 +601,7 @@ class LanguageMathML : public Language {
const std::vector& indArg = _nameGen->getIndependent();
const std::vector& depArg = _nameGen->getDependent();
const std::vector& tmpArg = _nameGen->getTemporary();
- CPPADCG_ASSERT_KNOWN(!indArg.empty() && depArg.size() > 0,
+ CPPADCG_ASSERT_KNOWN(!indArg.empty() && !depArg.empty(),
"There must be at least one dependent and one independent argument")
CPPADCG_ASSERT_KNOWN(tmpArg.size() == 3,
"There must be three temporary variables")
@@ -1906,7 +1906,7 @@ class LanguageMathML : public Language {
CPPADCG_ASSERT_KNOWN(node.getOperationType() == CGOpCode::IndexAssign, "Invalid node type")
CPPADCG_ASSERT_KNOWN(node.getArguments().size() > 0, "Invalid number of arguments for an index assignment operation")
- IndexAssignOperationNode& inode = static_cast&> (node);
+ auto& inode = static_cast&> (node);
const IndexPattern& ip = inode.getIndexPattern();
_code << _startEq
diff --git a/include/cppad/cg/model/llvm/llvm.hpp b/include/cppad/cg/model/llvm/llvm.hpp
index 23d6914a..360b9be1 100644
--- a/include/cppad/cg/model/llvm/llvm.hpp
+++ b/include/cppad/cg/model/llvm/llvm.hpp
@@ -36,6 +36,8 @@
#include
#elif LLVM_VERSION_MAJOR==8 && LLVM_VERSION_MINOR==0
#include
+#elif LLVM_VERSION_MAJOR==9 && LLVM_VERSION_MINOR==0
+#include
#endif
#endif
diff --git a/include/cppad/cg/model/llvm/v9_0/llvm9_0.hpp b/include/cppad/cg/model/llvm/v9_0/llvm9_0.hpp
new file mode 100644
index 00000000..c5719a2c
--- /dev/null
+++ b/include/cppad/cg/model/llvm/v9_0/llvm9_0.hpp
@@ -0,0 +1,92 @@
+#ifndef CPPAD_CG_LLVM9_0_INCLUDED
+#define CPPAD_CG_LLVM9_0_INCLUDED
+/* --------------------------------------------------------------------------
+ * CppADCodeGen: C++ Algorithmic Differentiation with Source Code Generation:
+ * Copyright (C) 2019 Joao Leal
+ *
+ * CppADCodeGen is distributed under multiple licenses:
+ *
+ * - Eclipse Public License Version 1.0 (EPL1), and
+ * - GNU General Public License Version 3 (GPL3).
+ *
+ * EPL1 terms and conditions can be found in the file "epl-v10.txt", while
+ * terms and conditions for the GPL3 can be found in the file "gpl3.txt".
+ * ----------------------------------------------------------------------------
+ * Author: Joao Leal
+ */
+
+/**
+ * LLVM requires the use of it own flags which can make it difficult to compile
+ * libraries not using NDEBUG often required by LLVM.
+ * The define LLVM_CPPFLAG_NDEBUG can be used to apply NDEBUG only to LLVM
+ * headers.
+ */
+#ifdef LLVM_WITH_NDEBUG
+
+// save the original NDEBUG definition
+#ifdef NDEBUG
+#define _OUTER_NDEBUG_DEFINED
+#endif
+
+#if LLVM_WITH_NDEBUG == 1
+#define NDEBUG
+#else
+#undef NDEBUG
+#endif
+
+#endif
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+//#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+//#include
+#include
+#include
+
+#ifdef LLVM_WITH_NDEBUG
+
+// recover the original NDEBUG
+#ifdef _OUTER_NDEBUG_DEFINED
+#define NDEBUG
+#else
+#undef NDEBUG
+#endif
+
+// no need for this anymore
+#undef _OUTER_NDEBUG_DEFINED
+
+#endif
+
+#include
+#include
+#include
+#include // yes, this is from version 5.0
+#include
+
+#endif
diff --git a/include/cppad/cg/model/llvm/v9_0/llvm_model_library_processor.hpp b/include/cppad/cg/model/llvm/v9_0/llvm_model_library_processor.hpp
new file mode 100644
index 00000000..d5176654
--- /dev/null
+++ b/include/cppad/cg/model/llvm/v9_0/llvm_model_library_processor.hpp
@@ -0,0 +1,54 @@
+#ifndef CPPAD_CG_LLVM_MODEL_LIBRARY_PROCESSOR_INCLUDED
+#define CPPAD_CG_LLVM_MODEL_LIBRARY_PROCESSOR_INCLUDED
+/* --------------------------------------------------------------------------
+ * CppADCodeGen: C++ Algorithmic Differentiation with Source Code Generation:
+ * Copyright (C) 2020 Joao Leal
+ *
+ * CppADCodeGen is distributed under multiple licenses:
+ *
+ * - Eclipse Public License Version 1.0 (EPL1), and
+ * - GNU General Public License Version 3 (GPL3).
+ *
+ * EPL1 terms and conditions can be found in the file "epl-v10.txt", while
+ * terms and conditions for the GPL3 can be found in the file "gpl3.txt".
+ * ----------------------------------------------------------------------------
+ * Author: Joao Leal
+ */
+
+#include
+
+namespace CppAD {
+namespace cg {
+
+/**
+ * Useful class for generating a JIT evaluated model library (LLVM 9.0).
+ *
+ * @author Joao Leal
+ */
+template
+class LlvmModelLibraryProcessor : public LlvmBaseModelLibraryProcessorImpl {
+public:
+
+ /**
+ * Creates a LLVM model library processor.
+ *
+ * @param librarySourceGen
+ */
+ LlvmModelLibraryProcessor(ModelLibraryCSourceGen& librarySourceGen) :
+ LlvmBaseModelLibraryProcessorImpl(librarySourceGen, "9") {
+ }
+
+ virtual ~LlvmModelLibraryProcessor() = default;
+
+ using LlvmBaseModelLibraryProcessorImpl::create;
+
+ static inline std::unique_ptr> create(ModelLibraryCSourceGen& modelLibraryHelper) {
+ LlvmModelLibraryProcessor p(modelLibraryHelper);
+ return p.create();
+ }
+};
+
+} // END cg namespace
+} // END CppAD namespace
+
+#endif
diff --git a/include/cppad/cg/util.hpp b/include/cppad/cg/util.hpp
index ec630632..ac6a00c1 100644
--- a/include/cppad/cg/util.hpp
+++ b/include/cppad/cg/util.hpp
@@ -139,7 +139,7 @@ inline void addMatrixSparsity(const VectorSet& a,
template
inline void addMatrixSparsity(const VectorSet& a,
VectorSet2& result) {
- CPPADCG_ASSERT_UNKNOWN(result.size() == a.size());
+ CPPADCG_ASSERT_UNKNOWN(result.size() == a.size())
addMatrixSparsity(a, a.size(), result);
}
@@ -197,7 +197,7 @@ inline void multMatrixMatrixSparsity(const VectorSet& a,
for (size_t jj = 0; jj < q; jj++) { //loop columns of b
const std::set& colB = bt[jj];
- if (colB.size() > 0) {
+ if (!colB.empty()) {
for (size_t i = 0; i < m; i++) {
const std::set& rowA = a[i];
for (size_t rowb : colB) {
@@ -264,7 +264,7 @@ inline void multMatrixTransMatrixSparsity(const VectorSet& a,
for (size_t jj = 0; jj < q; jj++) { //loop columns of b
const std::set& colB = bt[jj];
- if (colB.size() > 0) {
+ if (!colB.empty()) {
for (size_t i = 0; i < n; i++) {
const std::set& rowAt = at[i];
if (!rowAt.empty()) {
@@ -805,6 +805,16 @@ inline std::string implode(const std::vector& text,
}
}
+std::string readStringFromFile(const std::string& path) {
+ std::ifstream iStream;
+ iStream.open(path);
+
+ std::stringstream strStream;
+ strStream << iStream.rdbuf();
+
+ return strStream.str();
+}
+
} // END cg namespace
} // END CppAD namespace
diff --git a/test/CppADCGTest.hpp b/test/CppADCGTest.hpp
index 671e421e..ce2b68b3 100644
--- a/test/CppADCGTest.hpp
+++ b/test/CppADCGTest.hpp
@@ -53,6 +53,19 @@ class CppADCGTest : public ::testing::Test {
protected:
+ static inline ::testing::AssertionResult compareValues(const std::vector& depCGen,
+ const std::vector >& dep,
+ double epsilonR = 1e-14, double epsilonA = 1e-14) {
+
+ std::vector depd(dep.size());
+
+ for (size_t i = 0; i < depd.size(); i++) {
+ depd[i] = dep[i].getValue();
+ }
+
+ return compareValues(depCGen, depd, epsilonR, epsilonA);
+ }
+
template
static inline ::testing::AssertionResult compareValues(const std::vector >& depCGen,
const std::vector >& dep,
diff --git a/test/cppad/cg/CppADCGDynamicAtomicTest.hpp b/test/cppad/cg/CppADCGDynamicAtomicTest.hpp
index 9d259e55..067d3115 100644
--- a/test/cppad/cg/CppADCGDynamicAtomicTest.hpp
+++ b/test/cppad/cg/CppADCGDynamicAtomicTest.hpp
@@ -16,13 +16,13 @@
* Author: Joao Leal
*/
-#include "CppADCGTest.hpp"
+#include "CppADCGModelTest.hpp"
#include "gccCompilerFlags.hpp"
namespace CppAD {
namespace cg {
-class CppADCGDynamicAtomicTest : public CppADCGTest {
+class CppADCGDynamicAtomicTest : public CppADCGModelTest {
public:
using Super = CppADCGTest;
using Base = Super::Base;
@@ -43,7 +43,7 @@ class CppADCGDynamicAtomicTest : public CppADCGTest {
explicit CppADCGDynamicAtomicTest(std::string modelName,
bool verbose = false,
bool printValues = false) :
- CppADCGTest(verbose, printValues),
+ CppADCGModelTest(verbose, printValues),
_modelName(std::move(modelName)) {
//this->verbose_ = true;
}
@@ -51,14 +51,14 @@ class CppADCGDynamicAtomicTest : public CppADCGTest {
virtual std::vector model(const std::vector& x) = 0;
virtual std::vector modelOuter(const std::vector& y) {
- std::vector Z(y.size() - 1);
+ std::vector z(y.size() - 1);
for (size_t i = 0; i < y.size() - 1; i++) {
- Z[i] = 2 * y[i];
+ z[i] = 2 * y[i];
}
- Z[Z.size() - 1] += y[y.size() - 1];
+ z[z.size() - 1] += y[y.size() - 1];
- return Z;
+ return z;
}
void TearDown() override {
@@ -120,196 +120,56 @@ class CppADCGDynamicAtomicTest : public CppADCGTest {
atomicfun(ax, ay);
- // create f2: x -> y and stop tape recording
- ADFun f2(ax, ay);
+ // create fWrapAtom: x -> y and stop tape recording
+ ADFun fWrapAtom(ax, ay);
/**
* Test zero order
*/
- vector xOrig(n);
- for (size_t j = 0; j < n; j++)
- xOrig[j] = x[j];
-
- vector yOrig = _funInner->Forward(0, xOrig);
- vector yInner = modelLib->ForwardZero(x);
- vector yOuter = f2.Forward(0, x);
+ std::vector xOrig(x.data(), x.data() + x.size());
- ASSERT_TRUE(compareValues(yInner, yOrig, epsilonR, epsilonA));
- ASSERT_TRUE(compareValues(yOuter, yOrig, epsilonR, epsilonA));
+ testForwardZeroResults(*modelLib, *_funInner, &fWrapAtom, xOrig, epsilonR, epsilonA);
/**
* Test first order forward mode
*/
- size_t k = 1;
- size_t k1 = k + 1;
-
- vector x_p(n);
- for (size_t j = 0; j < n; j++)
- x_p[j] = 0;
-
- vector x_pOrig(n);
- vector tx(k1 * n);
- for (size_t j = 0; j < n; j++)
- tx[j * k1] = x[j]; // zero order
- for (size_t j = 0; j < n; j++)
- tx[j * k1 + 1] = 0; // first order
-
- for (size_t j = 0; j < n; j++) {
- x_p[j] = 1;
- x_pOrig[j] = 1;
- tx[j * k1 + 1] = 1;
-
- vector y_pOrig = _funInner->Forward(1, x_pOrig);
- vector y_pInner = modelLib->ForwardOne(tx);
- vector y_pOuter = f2.Forward(1, x_p);
-
- x_p[j] = 0;
- x_pOrig[j] = 0;
- tx[j * k1 + 1] = 0;
-
- ASSERT_TRUE(compareValues(y_pInner, y_pOrig, epsilonR, epsilonA));
- ASSERT_TRUE(compareValues(y_pOuter, y_pOrig, epsilonR, epsilonA));
- }
+ testForwardOneResults(*modelLib, *_funInner, &fWrapAtom, xOrig, epsilonR, epsilonA);
/**
* Test first order reverse mode
*/
- k = 0;
- k1 = k + 1;
-
- vector w(m);
- for (size_t i = 0; i < m; i++)
- w[i] = 0;
- vector wOrig(m);
- tx.resize(k1 * n);
- for (size_t j = 0; j < n; j++)
- tx[j * k1] = x[j]; // zero order
- vector ty(k1 * m);
- for (size_t i = 0; i < m; i++)
- ty[i * k1] = yInner[i]; // zero order
-
- for (size_t i = 0; i < m; i++) {
- w[i] = 1;
- wOrig[i] = 1;
-
- vector dwOrig = _funInner->Reverse(1, wOrig);
- vector dwInner = modelLib->ReverseOne(tx, ty, w);
- vector dwOuter = f2.Reverse(1, w);
-
- w[i] = 0;
- wOrig[i] = 0;
-
- ASSERT_TRUE(compareValues(dwInner, dwOrig, epsilonR, epsilonA));
- ASSERT_TRUE(compareValues(dwOuter, dwOrig, epsilonR, epsilonA));
- }
+ testReverseOneResults(*modelLib, *_funInner, &fWrapAtom, xOrig, epsilonR, epsilonA);
/**
* Test second order reverse mode
*/
- k = 1;
- k1 = k + 1;
- tx.resize(k1 * n);
- ty.resize(k1 * m);
- vector py(k1 * m);
- vector pyOrig(k1 * m);
- //wOrig.resize(k1 * m);
- for (size_t j = 0; j < n; j++) {
- tx[j * k1] = x[j]; // zero order
- tx[j * k1 + 1] = 0; // first order
- }
- for (size_t i = 0; i < m; i++) {
- ty[i * k1] = yInner[i]; // zero order
- py[i * k1] = 0.0;
- py[i * k1 + 1] = 1.0; // first order
- pyOrig[i * k1] = 0.0;
- pyOrig[i * k1 + 1] = 1.0; // first order
- }
-
- for (size_t j = 0; j < n; j++) {
- x_p[j] = 1;
- x_pOrig[j] = 1;
- tx[j * k1 + 1] = 1;
-
- _funInner->Forward(1, x_pOrig);
- vector dwOrig = _funInner->Reverse(2, pyOrig);
- vector dwInner = modelLib->ReverseTwo(tx, ty, py);
- f2.Forward(1, x_p);
- vector dwOuter = f2.Reverse(2, py);
-
- x_p[j] = 0;
- x_pOrig[j] = 0;
- tx[j * k1 + 1] = 0;
-
- // only compare second order information
- // (location of the elements is different then if py.size() == m)
- ASSERT_EQ(dwOrig.size(), n * k1);
- ASSERT_EQ(dwOrig.size(), dwInner.size());
- ASSERT_EQ(dwOrig.size(), dwOuter.size());
- for (size_t j2 = 0; j2 < n; j2++) {
- ASSERT_TRUE(nearEqual(dwInner[j2 * k1], dwOrig[j2 * k1].getValue()));
- ASSERT_TRUE(nearEqual(dwOuter[j2 * k1], dwOrig[j2 * k1].getValue()));
- }
- }
+ testReverseTwoResults(*modelLib, *_funInner, &fWrapAtom, xOrig, epsilonR, epsilonA);
/**
- * Jacobian
+ * Dense Jacobian
*/
- vector jacOrig = _funInner->Jacobian(xOrig);
- vector jacOuter = f2.Jacobian(x);
- ASSERT_TRUE(compareValues(jacOuter, jacOrig, epsilonR, epsilonA));
+ testDenseJacResults(*modelLib, *_funInner, xOrig, epsilonR, epsilonA);
/**
* Jacobian sparsity
*/
- const std::vector jacSparsityOrig = jacobianForwardSparsity, CGD>(*_funInner);
- const std::vector jacSparsityOuter = jacobianForwardSparsity, double>(f2);
-
- compareBoolValues(jacSparsityOrig, jacSparsityOuter);
-
- const std::vector jacSparsityOrigRev = jacobianReverseSparsity, CGD>(*_funInner);
- const std::vector jacSparsityOuterRev = jacobianReverseSparsity, double>(f2);
-
- compareBoolValues(jacSparsityOrigRev, jacSparsityOrig);
- compareBoolValues(jacSparsityOrigRev, jacSparsityOuterRev);
+ testJacobianSparsity(*_funInner, fWrapAtom);
/**
- * Sparse jacobian
+ * Sparse Jacobian
*/
- jacOrig = _funInner->SparseJacobian(xOrig);
- jacOuter = f2.SparseJacobian(x);
- ASSERT_TRUE(compareValues(jacOuter, jacOrig, epsilonR, epsilonA));
-
- // sparse reverse
- std::vector row, col;
- generateSparsityIndexes(jacSparsityOuter, m, n, row, col);
-
- sparse_jacobian_work workOrig;
- jacOrig.resize(row.size());
- _funInner->SparseJacobianReverse(xOrig, jacSparsityOrig, row, col, jacOrig, workOrig);
-
- sparse_jacobian_work work2;
- jacOuter.resize(row.size());
- f2.SparseJacobianReverse(x, jacSparsityOuter, row, col, jacOuter, work2);
-
- ASSERT_TRUE(compareValues(jacOuter, jacOrig, epsilonR, epsilonA));
+ size_t n_tests = _dynamicLib->getThreadNumber() > 1 ? 2 : 1;
+ testSparseJacobianResults(n_tests, *modelLib, *_funInner, &fWrapAtom, xOrig, false, epsilonR, epsilonA);
/**
- * Hessian
+ * Dense Hessian
*/
- for (size_t i = 0; i < m; i++) {
- w[i] = 1;
- wOrig[i] = 1;
- }
- vector hessOrig = _funInner->Hessian(xOrig, wOrig);
- vector hessOuter = f2.Hessian(x, w);
- ASSERT_TRUE(compareValues(hessOuter, hessOrig, epsilonR, epsilonA));
+ testDenseHessianResults(*modelLib, *_funInner, xOrig, epsilonR, epsilonA);
/**
* Sparse Hessian
*/
- hessOrig = _funInner->SparseHessian(xOrig, wOrig);
- hessOuter = f2.SparseHessian(x, w);
- ASSERT_TRUE(compareValues(hessOuter, hessOrig, epsilonR, epsilonA));
+ testSparseHessianResults(n_tests, *modelLib, *_funInner, &fWrapAtom, xOrig, false, epsilonR, epsilonA);
}
/**
@@ -345,8 +205,8 @@ class CppADCGDynamicAtomicTest : public CppADCGTest {
Base epsilonR = 1e-14,
Base epsilonA = 1e-14) {
CppAD::vector xNorm(x.size());
- for (size_t i = 0; i < xNorm.size(); i++)
- xNorm[i] = 1.0;
+ for (double & i : xNorm)
+ i = 1.0;
CppAD::vector eqNorm;
testADFunAtomicLib(x, xNorm, eqNorm, epsilonR, epsilonA);
@@ -359,8 +219,8 @@ class CppADCGDynamicAtomicTest : public CppADCGTest {
Base epsilonR = 1e-14,
Base epsilonA = 1e-14) {
CppAD::vector xNorm(x.size());
- for (size_t i = 0; i < xNorm.size(); i++)
- xNorm[i] = 1.0;
+ for (double & i : xNorm)
+ i = 1.0;
CppAD::vector eqNorm;
testAtomicLibAtomicLib(x, xNorm, eqNorm, epsilonR, epsilonA);
@@ -651,10 +511,10 @@ class CppADCGDynamicAtomicTest : public CppADCGTest {
ASSERT_TRUE(compareValues(hessOuter, hessOrig, epsilonR, epsilonA));
}
- void testAtomicLibModelInCppAD(ADFun& funOuter,
- ADFun& funOuterAtom, // with an atomic function
- const CppAD::vector& xx,
- Base epsilonR = 1e-14, Base epsilonA = 1e-14) {
+ static void testAtomicLibModelInCppAD(ADFun& funOuter,
+ ADFun& funOuterAtom, // with an atomic function
+ const CppAD::vector& xx,
+ Base epsilonR = 1e-14, Base epsilonA = 1e-14) {
using namespace CppAD;
using namespace std;
using CppAD::vector;
@@ -679,8 +539,6 @@ class CppADCGDynamicAtomicTest : public CppADCGTest {
/**
* Test first order forward mode
*/
- size_t k = 1;
- size_t k1 = k + 1;
vector x_p(n);
@@ -713,8 +571,8 @@ class CppADCGDynamicAtomicTest : public CppADCGTest {
/**
* Test second order reverse mode
*/
- k = 1;
- k1 = k + 1;
+ size_t k = 1;
+ size_t k1 = k + 1;
vector py(m); // not (k1 * m)
for (size_t i = 0; i < m; i++) {
//py[i * k1] = 0.0;
@@ -843,7 +701,7 @@ class CppADCGDynamicAtomicTest : public CppADCGTest {
generateSparsityIndexes(jacOuterSpar, jacOuterRows, jacOuterCols);
vector jacOrig(jacOuterCols.size());
_funOuter->SparseJacobianReverse(xOrig, jacSparsityOrig,
- jacOuterRows, jacOuterCols, jacOrig, work);
+ jacOuterRows, jacOuterCols, jacOrig, work);
std::vector jacOuter(jacOuterRows.size());
size_t const* rows, *cols;
@@ -1180,6 +1038,8 @@ class CppADCGDynamicAtomicTest : public CppADCGTest {
cSourceInner->setCreateForwardOne(true);
cSourceInner->setCreateReverseOne(true);
cSourceInner->setCreateReverseTwo(true);
+ cSourceInner->setCreateJacobian(true);
+ cSourceInner->setCreateHessian(true);
cSourceInner->setCreateSparseJacobian(true);
cSourceInner->setCreateSparseHessian(true);
diff --git a/test/cppad/cg/CppADCGDynamicTest.hpp b/test/cppad/cg/CppADCGDynamicTest.hpp
index d0d25f5c..21b5f64c 100644
--- a/test/cppad/cg/CppADCGDynamicTest.hpp
+++ b/test/cppad/cg/CppADCGDynamicTest.hpp
@@ -82,7 +82,10 @@ class CppADCGDynamicTest : public CppADCGModelTest {
std::vector xTape(_xTape.size());
for (size_t i = 0; i < xTape.size(); ++i) xTape[i] = _xTape[i];
- CppAD::Independent(xTape);
+ size_t abort_op_index = 0;
+ bool record_compare = false;
+ CppAD::Independent(xTape, abort_op_index, record_compare);
+
if (!_xNorm.empty()) {
for (size_t i = 0; i < xTape.size(); i++)
@@ -169,7 +172,7 @@ class CppADCGDynamicTest : public CppADCGModelTest {
}
void testForwardZero() {
- this->testForwardZeroResults(*_model, *_fun, _xRun, epsilonR, epsilonA);
+ this->testForwardZeroResults(*_model, *_fun, nullptr, _xRun, epsilonR, epsilonA);
}
// Jacobian
@@ -183,12 +186,20 @@ class CppADCGDynamicTest : public CppADCGModelTest {
// sparse Jacobian
void testJacobian() {
- this->testJacobianResults(*_dynamicLib, *_model, *_fun, _xRun, !_jacRow.empty(),epsilonR, epsilonA);
+ // sparse Jacobian again (make sure the second run is also OK)
+ size_t n_tests = _dynamicLib->getThreadNumber() > 1 ? 2 : 1;
+
+ this->testSparseJacobianResults(n_tests, *_model, *_fun, nullptr, _xRun, !_jacRow.empty(), epsilonR,
+ epsilonA);
}
// sparse Hessian
void testHessian() {
- this->testHessianResults(*_dynamicLib, *_model, *_fun, _xRun, !_hessRow.empty(), epsilonR, epsilonA);
+ // sparse Hessian again (make sure the second run is also OK)
+ size_t n_tests = _dynamicLib->getThreadNumber() > 1 ? 2 : 1;
+
+ this->testSparseHessianResults(n_tests, *_model, *_fun, nullptr, _xRun, !_hessRow.empty(), epsilonR,
+ epsilonA);
}
};
diff --git a/test/cppad/cg/CppADCGModelTest.hpp b/test/cppad/cg/CppADCGModelTest.hpp
index c1c6920c..4a7ef65f 100644
--- a/test/cppad/cg/CppADCGModelTest.hpp
+++ b/test/cppad/cg/CppADCGModelTest.hpp
@@ -48,11 +48,12 @@ class CppADCGModelTest : public CppADCGTest {
* @param epsilonR relative error
* @param epsilonA absolute error
*/
- void testForwardZeroResults(GenericModel& model,
- ADFun& fun,
- const std::vector& x,
- double epsilonR = 1e-14,
- double epsilonA = 1e-14) {
+ static void testForwardZeroResults(GenericModel& model,
+ ADFun& fun,
+ ADFun* fun2,
+ const std::vector& x,
+ double epsilonR = 1e-14,
+ double epsilonA = 1e-14) {
ASSERT_EQ(model.Domain(), fun.Domain());
ASSERT_EQ(model.Range(), fun.Range());
@@ -62,6 +63,171 @@ class CppADCGModelTest : public CppADCGTest {
std::vector depCGen = model.ForwardZero(x);
ASSERT_TRUE(compareValues(depCGen, dep, epsilonR, epsilonA));
+
+ if (fun2 != nullptr) {
+ std::vector yOuter = fun2->Forward(0, x);
+ ASSERT_TRUE(compareValues(yOuter, depCGen, epsilonR, epsilonA));
+ }
+ }
+
+ static void testForwardOneResults(GenericModel& model,
+ ADFun& fun,
+ ADFun* funWrapModel,
+ const std::vector& x,
+ double epsilonR = 1e-14,
+ double epsilonA = 1e-14) {
+ ASSERT_EQ(model.Domain(), fun.Domain());
+ ASSERT_EQ(model.Range(), fun.Range());
+
+ size_t n = model.Domain();
+
+ /**
+ * Test first order forward mode
+ */
+ size_t k = 1;
+ size_t k1 = k + 1;
+
+ std::vector x_p(n, 0.0);
+ std::vector x_pOrig(n);
+ std::vector tx(k1 * n);
+ for (size_t j = 0; j < n; j++)
+ tx[j * k1] = x[j]; // zero order
+ for (size_t j = 0; j < n; j++)
+ tx[j * k1 + 1] = 0; // first order
+
+ for (size_t j = 0; j < n; j++) {
+ x_p[j] = 1;
+ x_pOrig[j] = 1;
+ tx[j * k1 + 1] = 1;
+
+ std::vector y_pOrig = fun.Forward(1, x_pOrig);
+ std::vector y_pInner = model.ForwardOne(tx);
+
+ ASSERT_TRUE(compareValues(y_pInner, y_pOrig, epsilonR, epsilonA));
+
+ if (funWrapModel != nullptr) {
+ std::vector y_pOuter = funWrapModel->Forward(1, x_p);
+ ASSERT_TRUE(compareValues(y_pOuter, y_pOrig, epsilonR, epsilonA));
+ }
+
+ x_p[j] = 0;
+ x_pOrig[j] = 0;
+ tx[j * k1 + 1] = 0;
+ }
+ }
+
+ static void testReverseOneResults(GenericModel& model,
+ ADFun& fun,
+ ADFun* funWrapModel,
+ const std::vector& x,
+ double epsilonR = 1e-14,
+ double epsilonA = 1e-14) {
+ ASSERT_EQ(model.Domain(), fun.Domain());
+ ASSERT_EQ(model.Range(), fun.Range());
+
+ size_t m = model.Range();
+ size_t n = model.Domain();
+
+ size_t k = 0;
+ size_t k1 = k + 1;
+
+ std::vector yInner = model.ForwardZero(x);
+
+ std::vector w(m, 0.0);
+ std::vector wOrig(m);
+ std::vector tx(k1 * n);
+ for (size_t j = 0; j < n; j++)
+ tx[j * k1] = x[j]; // zero order
+ std::vector ty(k1 * m);
+ for (size_t i = 0; i < m; i++)
+ ty[i * k1] = yInner[i]; // zero order
+
+ for (size_t i = 0; i < m; i++) {
+ w[i] = 1;
+ wOrig[i] = 1;
+
+ std::vector dwOrig = fun.Reverse(1, wOrig);
+ std::vector dwInner = model.ReverseOne(tx, ty, w);
+
+ ASSERT_TRUE(compareValues(dwInner, dwOrig, epsilonR, epsilonA));
+
+ if (funWrapModel != nullptr) {
+ std::vector dwOuter = funWrapModel->Reverse(1, w);
+ ASSERT_TRUE(compareValues(dwOuter, dwOrig, epsilonR, epsilonA));
+ }
+
+ w[i] = 0;
+ wOrig[i] = 0;
+ }
+ }
+
+ static void testReverseTwoResults(GenericModel& model,
+ ADFun& fun,
+ ADFun* funWrapModel,
+ const std::vector& x,
+ double epsilonR = 1e-14,
+ double epsilonA = 1e-14) {
+ ASSERT_EQ(model.Domain(), fun.Domain());
+ ASSERT_EQ(model.Range(), fun.Range());
+
+ size_t m = model.Range();
+ size_t n = model.Domain();
+
+ std::vector yInner = model.ForwardZero(x);
+
+ size_t k = 1;
+ size_t k1 = k + 1;
+ std::vector tx(k1 * n);
+ std::vector ty(k1 * m);
+ std::vector py(k1 * m);
+ std::vector pyOrig(k1 * m);
+ //wOrig.resize(k1 * m);
+ for (size_t j = 0; j < n; j++) {
+ tx[j * k1] = x[j]; // zero order
+ tx[j * k1 + 1] = 0; // first order
+ }
+ for (size_t i = 0; i < m; i++) {
+ ty[i * k1] = yInner[i]; // zero order
+ py[i * k1] = 0.0;
+ py[i * k1 + 1] = 1.0; // first order
+ pyOrig[i * k1] = 0.0;
+ pyOrig[i * k1 + 1] = 1.0; // first order
+ }
+
+ std::vector x_p(n, 0.0);
+ std::vector x_pOrig(n);
+
+ for (size_t j = 0; j < n; j++) {
+ x_p[j] = 1;
+ x_pOrig[j] = 1;
+ tx[j * k1 + 1] = 1;
+
+ fun.Forward(1, x_pOrig);
+ std::vector dwOrig = fun.Reverse(2, pyOrig);
+ std::vector dwInner = model.ReverseTwo(tx, ty, py);
+
+ // only compare second order information
+ // (location of the elements is different then if py.size() == m)
+ ASSERT_EQ(dwOrig.size(), n * k1);
+ ASSERT_EQ(dwOrig.size(), dwInner.size());
+
+ for (size_t j2 = 0; j2 < n; j2++) {
+ ASSERT_TRUE(nearEqual(dwInner[j2 * k1], dwOrig[j2 * k1].getValue()));
+ }
+
+ if(funWrapModel != nullptr) {
+ funWrapModel->Forward(1, x_p);
+ std::vector dwOuter = funWrapModel->Reverse(2, py);
+ ASSERT_EQ(dwOrig.size(), dwOuter.size());
+ for (size_t j2 = 0; j2 < n; j2++) {
+ ASSERT_TRUE(nearEqual(dwOuter[j2 * k1], dwOrig[j2 * k1].getValue()));
+ }
+ }
+
+ x_p[j] = 0;
+ x_pOrig[j] = 0;
+ tx[j * k1 + 1] = 0;
+ }
}
/**
@@ -130,6 +296,7 @@ class CppADCGModelTest : public CppADCGTest {
private:
void testJacobianResults(GenericModel& model,
+ ADFun* funWrapModel,
const std::vector& jac,
const std::vector& x,
bool customSparsity,
@@ -141,7 +308,7 @@ class CppADCGModelTest : public CppADCGTest {
model.SparseJacobian(x, jacCGen, row, col);
std::vector jacCGenDense(jac.size());
-
+
for (size_t i = 0; i < jacCGen.size(); i++) {
size_t p = row[i] * x.size() + col[i];
jacCGenDense[p] = jacCGen[i];
@@ -163,9 +330,30 @@ class CppADCGModelTest : public CppADCGTest {
}
ASSERT_TRUE(this->compareValues(jacCGenDense, jacAdFunPartial, epsilonR, epsilonA));
+
+ if (funWrapModel != nullptr) {
+ auto jacOuter = funWrapModel->SparseJacobian(x);
+
+ if (verbose_) {
+ std::cout << "ADFun2 Jacobian" << std::endl;
+ print(jacOuter);
+ }
+
+ ASSERT_TRUE(compareValues(jacOuter, jac, epsilonR, epsilonA));
+
+ // sparse reverse
+ const auto jacSparsityWrap = jacobianReverseSparsitySet>, Base>(*funWrapModel);
+
+ sparse_jacobian_work workWrapFun;
+ std::vector jacWrapFunSparse(row.size());
+ funWrapModel->SparseJacobianReverse(x, jacSparsityWrap, row, col, jacWrapFunSparse, workWrapFun);
+
+ ASSERT_TRUE(compareValues(jacCGen, jacWrapFunSparse, epsilonR, epsilonA));
+ }
}
void testHessianResults(GenericModel& model,
+ ADFun* funWrapModel,
const std::vector& hess,
const std::vector& x,
bool customSparsity,
@@ -200,26 +388,62 @@ class CppADCGModelTest : public CppADCGTest {
}
ASSERT_TRUE(this->compareValues(hessCGenDense, hessAdFunPartial, epsilonR, epsilonA));
+
+ if(funWrapModel != nullptr) {
+ auto hessFunWrap = funWrapModel->SparseHessian(x, w);
+
+ if (verbose_) {
+ std::cout << "ADFun2 Hessian" << std::endl;
+ print(hessFunWrap);
+ }
+
+ ASSERT_TRUE(compareValues(hessFunWrap, hessAdFunPartial, epsilonR, epsilonA));
+
+ const auto hessSparsityWrap = hessianSparsitySet>, Base>(*funWrapModel);
+
+ sparse_hessian_work workWrapFun;
+ std::vector hessWrapFunSparse(row.size());
+ funWrapModel->SparseHessian(x, w, hessSparsityWrap, row, col, hessWrapFunSparse, workWrapFun);
+
+ ASSERT_TRUE(compareValues(hessCGen, hessWrapFunSparse, epsilonR, epsilonA));
+ }
}
public:
+ static void testJacobianSparsity(ADFun& fun1,
+ ADFun& fun2) {
+ const std::vector jacSparsityOrig = jacobianForwardSparsity, CGD>(fun1);
+ const std::vector jacSparsityOuter = jacobianForwardSparsity, double>(fun2);
+
+ compareBoolValues(jacSparsityOrig, jacSparsityOuter);
+
+ const std::vector jacSparsityOrigRev = jacobianReverseSparsity, CGD>(fun1);
+ const std::vector jacSparsityOuterRev = jacobianReverseSparsity, double>(fun2);
+
+ compareBoolValues(jacSparsityOrigRev, jacSparsityOrig);
+ compareBoolValues(jacSparsityOrigRev, jacSparsityOuterRev);
+ }
+
/**
* Compares the results from a sparse Jacobian.
*
+ * @param n_tests number of times to run this test
* @param model
* @param fun
* @param x independent vector values
+ * @param customSparsity
* @param epsilonR relative error
* @param epsilonA absolute error
*/
- void testJacobianResults(ModelLibrary& lib,
- GenericModel& model,
- ADFun& fun,
- const std::vector& x,
- bool customSparsity,
- double epsilonR = 1e-14,
- double epsilonA = 1e-14) {
+ void testSparseJacobianResults(size_t n_tests,
+ GenericModel& model,
+ ADFun& fun,
+ ADFun* funWrapModel,
+ const std::vector& x,
+ bool customSparsity,
+ double epsilonR = 1e-14,
+ double epsilonA = 1e-14) {
ASSERT_EQ(model.Domain(), fun.Domain());
ASSERT_EQ(model.Range(), fun.Range());
@@ -231,13 +455,9 @@ class CppADCGModelTest : public CppADCGTest {
print(jac);
}
- testJacobianResults(model, jac, x, customSparsity, epsilonR, epsilonA);
-
- if (lib.getThreadNumber() > 1) {
- // sparse Jacobian again (make sure the second run is also OK)
- testJacobianResults(model, jac, x, customSparsity, epsilonR, epsilonA);
+ for (size_t i = 0; i< n_tests; ++i) {
+ testJacobianResults(model, funWrapModel, jac, x, customSparsity, epsilonR, epsilonA);
}
-
}
/**
@@ -249,13 +469,14 @@ class CppADCGModelTest : public CppADCGTest {
* @param epsilonR relative error
* @param epsilonA absolute error
*/
- void testHessianResults(ModelLibrary& lib,
- GenericModel& model,
- ADFun& fun,
- const std::vector& x,
- bool customSparsity,
- double epsilonR = 1e-14,
- double epsilonA = 1e-14) {
+ void testSparseHessianResults(size_t n_tests,
+ GenericModel& model,
+ ADFun& fun,
+ ADFun* funWrapModel,
+ const std::vector& x,
+ bool customSparsity,
+ double epsilonR = 1e-14,
+ double epsilonA = 1e-14) {
ASSERT_EQ(model.Domain(), fun.Domain());
ASSERT_EQ(model.Range(), fun.Range());
@@ -270,66 +491,9 @@ class CppADCGModelTest : public CppADCGTest {
print(hess);
}
- testHessianResults(model, hess, x, customSparsity, epsilonR, epsilonA);
-
- if (lib.getThreadNumber() > 1) {
- // sparse Hessian again (make sure the second run is also OK)
- testHessianResults(model, hess, x, customSparsity, epsilonR, epsilonA);
- }
- }
-
- /**
- * Compares the results from Hessian, Jacobian, sparse Hessian and
- * sparse Jacobian.
- *
- * @param model
- * @param fun
- * @param x independent vector values
- * @param epsilonR relative error
- * @param epsilonA absolute error
- */
- void testModelResults(ModelLibrary& lib,
- GenericModel& model,
- ADFun& fun,
- const std::vector& x,
- bool customSparsity,
- double epsilonR = 1e-14,
- double epsilonA = 1e-14,
- bool denseJacobian = true,
- bool denseHessian = true) {
- // dimensions
- ASSERT_EQ(model.Domain(), fun.Domain());
- ASSERT_EQ(model.Range(), fun.Range());
-
- testForwardZeroResults(model, fun, x, epsilonR, epsilonA);
-
- // Jacobian
- if (denseJacobian) {
- testDenseJacResults(model, fun, x, epsilonR, epsilonA);
+ for (size_t i = 0; i < n_tests; ++i) {
+ testHessianResults(model, funWrapModel, hess, x, customSparsity, epsilonR, epsilonA);
}
-
- if (denseHessian) {
- testDenseHessianResults(model, fun, x, epsilonR, epsilonA);
- }
-
- // sparse Jacobian
- testJacobianResults(lib, model, fun, x, customSparsity, epsilonR, epsilonA);
-
- // sparse Hessian
- testHessianResults(lib, model, fun, x, customSparsity, epsilonR, epsilonA);
- }
-
- inline ::testing::AssertionResult compareValues(const std::vector& depCGen,
- const std::vector >& dep,
- double epsilonR = 1e-14, double epsilonA = 1e-14) {
-
- std::vector depd(dep.size());
-
- for (size_t i = 0; i < depd.size(); i++) {
- depd[i] = dep[i].getValue();
- }
-
- return CppADCGTest::compareValues(depCGen, depd, epsilonR, epsilonA);
}
};
diff --git a/test/cppad/cg/model/dynamiclib/cg_atomic_generic_model.cpp b/test/cppad/cg/model/dynamiclib/cg_atomic_generic_model.cpp
index 61f031f6..a8ef6fd4 100644
--- a/test/cppad/cg/model/dynamiclib/cg_atomic_generic_model.cpp
+++ b/test/cppad/cg/model/dynamiclib/cg_atomic_generic_model.cpp
@@ -50,23 +50,23 @@ class SingleVarAtomicGenericModelTest : public CGAtomicGenericModelTest {
/**
* @test
*/
-TEST_F(SingleVarAtomicGenericModelTest, TestForwardZero) {
+TEST_F(SingleVarAtomicGenericModelTest, TestForwardZero) { // NOLINT(cert-err58-cpp)
this->testCGAtomicGenericModelForwardZero();
}
-TEST_F(SingleVarAtomicGenericModelTest, TestReverseOne) {
+TEST_F(SingleVarAtomicGenericModelTest, TestReverseOne) { // NOLINT(cert-err58-cpp)
this->testCGAtomicGenericModelReverseOne();
}
-TEST_F(SingleVarAtomicGenericModelTest, TestReverseTwo) {
+TEST_F(SingleVarAtomicGenericModelTest, TestReverseTwo) { // NOLINT(cert-err58-cpp)
this->testCGAtomicGenericModelReverseTwo();
}
-TEST_F(SingleVarAtomicGenericModelTest, TestJacobian) {
+TEST_F(SingleVarAtomicGenericModelTest, TestJacobian) { // NOLINT(cert-err58-cpp)
this->testCGAtomicGenericModelJacobian();
}
-TEST_F(SingleVarAtomicGenericModelTest, TestHessian) {
+TEST_F(SingleVarAtomicGenericModelTest, TestHessian) { // NOLINT(cert-err58-cpp)
this->testCGAtomicGenericModelHessian();
}
@@ -96,23 +96,23 @@ class SingleVarAtomicGenericModelTest2 : public CGAtomicGenericModelTest {
} // END cg namespace
} // END CppAD namespace
-TEST_F(SingleVarAtomicGenericModelTest2, TestForwardZero) {
+TEST_F(SingleVarAtomicGenericModelTest2, TestForwardZero) { // NOLINT(cert-err58-cpp)
this->testCGAtomicGenericModelForwardZero();
}
-TEST_F(SingleVarAtomicGenericModelTest2, TestReverseOne) {
+TEST_F(SingleVarAtomicGenericModelTest2, TestReverseOne) { // NOLINT(cert-err58-cpp)
this->testCGAtomicGenericModelReverseOne();
}
-TEST_F(SingleVarAtomicGenericModelTest2, TestReverseTwo) {
+TEST_F(SingleVarAtomicGenericModelTest2, TestReverseTwo) { // NOLINT(cert-err58-cpp)
this->testCGAtomicGenericModelReverseTwo();
}
-TEST_F(SingleVarAtomicGenericModelTest2, TestJacobian) {
+TEST_F(SingleVarAtomicGenericModelTest2, TestJacobian) { // NOLINT(cert-err58-cpp)
this->testCGAtomicGenericModelJacobian();
}
-TEST_F(SingleVarAtomicGenericModelTest2, TestHessian) {
+TEST_F(SingleVarAtomicGenericModelTest2, TestHessian) { // NOLINT(cert-err58-cpp)
this->testCGAtomicGenericModelHessian();
}
@@ -142,23 +142,23 @@ class MultiVarAtomicGenericModelTest : public CGAtomicGenericModelTest {
} // END CppAD namespace
-TEST_F(MultiVarAtomicGenericModelTest, TestForwardZero) {
+TEST_F(MultiVarAtomicGenericModelTest, TestForwardZero) { // NOLINT(cert-err58-cpp)
this->testCGAtomicGenericModelForwardZero();
}
-TEST_F(MultiVarAtomicGenericModelTest, TestReverseOne) {
+TEST_F(MultiVarAtomicGenericModelTest, TestReverseOne) { // NOLINT(cert-err58-cpp)
this->testCGAtomicGenericModelReverseOne();
}
-TEST_F(MultiVarAtomicGenericModelTest, TestReverseTwo) {
+TEST_F(MultiVarAtomicGenericModelTest, TestReverseTwo) { // NOLINT(cert-err58-cpp)
this->testCGAtomicGenericModelReverseTwo();
}
-TEST_F(MultiVarAtomicGenericModelTest, TestJacobian) {
+TEST_F(MultiVarAtomicGenericModelTest, TestJacobian) { // NOLINT(cert-err58-cpp)
this->testCGAtomicGenericModelJacobian();
}
-TEST_F(MultiVarAtomicGenericModelTest, TestHessian) {
+TEST_F(MultiVarAtomicGenericModelTest, TestHessian) { // NOLINT(cert-err58-cpp)
this->testCGAtomicGenericModelHessian();
}
@@ -176,7 +176,7 @@ class MultiVarAtomicGenericModelLowerTest : public MultiVarAtomicGenericModelTes
} // END cg namespace
} // END CppAD namespace
-TEST_F(MultiVarAtomicGenericModelLowerTest, TestHessian) {
+TEST_F(MultiVarAtomicGenericModelLowerTest, TestHessian) { // NOLINT(cert-err58-cpp)
this->testCGAtomicGenericModelHessian();
}
@@ -192,7 +192,7 @@ class MultiVarAtomicGenericModelUpperTest : public MultiVarAtomicGenericModelTes
} // END cg namespace
} // END CppAD namespace
-TEST_F(MultiVarAtomicGenericModelUpperTest, TestHessian) {
+TEST_F(MultiVarAtomicGenericModelUpperTest, TestHessian) { // NOLINT(cert-err58-cpp)
this->testCGAtomicGenericModelHessian();
}
@@ -233,22 +233,22 @@ class MultiVarAtomicGenericModelTest2 : public CGAtomicGenericModelTest {
} // END CppAD namespace
-TEST_F(MultiVarAtomicGenericModelTest2, TestForwardZero) {
+TEST_F(MultiVarAtomicGenericModelTest2, TestForwardZero) { // NOLINT(cert-err58-cpp)
this->testCGAtomicGenericModelForwardZero();
}
-TEST_F(MultiVarAtomicGenericModelTest2, TestReverseOne) {
+TEST_F(MultiVarAtomicGenericModelTest2, TestReverseOne) { // NOLINT(cert-err58-cpp)
this->testCGAtomicGenericModelReverseOne();
}
-TEST_F(MultiVarAtomicGenericModelTest2, TestReverseTwo) {
+TEST_F(MultiVarAtomicGenericModelTest2, TestReverseTwo) { // NOLINT(cert-err58-cpp)
this->testCGAtomicGenericModelReverseTwo();
}
-TEST_F(MultiVarAtomicGenericModelTest2, TestJacobian) {
+TEST_F(MultiVarAtomicGenericModelTest2, TestJacobian) { // NOLINT(cert-err58-cpp)
this->testCGAtomicGenericModelJacobian();
}
-TEST_F(MultiVarAtomicGenericModelTest2, TestHessian) {
+TEST_F(MultiVarAtomicGenericModelTest2, TestHessian) { // NOLINT(cert-err58-cpp)
this->testCGAtomicGenericModelHessian();
}
diff --git a/test/cppad/cg/model/lang/latex/latex.cpp b/test/cppad/cg/model/lang/latex/latex.cpp
index 86c422ef..ead13a7e 100644
--- a/test/cppad/cg/model/lang/latex/latex.cpp
+++ b/test/cppad/cg/model/lang/latex/latex.cpp
@@ -1,6 +1,7 @@
/* --------------------------------------------------------------------------
* CppADCodeGen: C++ Algorithmic Differentiation with Source Code Generation:
* Copyright (C) 2014 Ciengis
+ * Copyright (C) 2020 Joao Leal
*
* CppADCodeGen is distributed under multiple licenses:
*
@@ -14,7 +15,6 @@
*/
#include
-#include
#include
#include
@@ -23,7 +23,7 @@
using namespace CppAD;
using namespace CppAD::cg;
-TEST(CppADCGLatexTest, latex) {
+TEST(CppADCGLatexTest, latex) { // NOLINT(cert-err58-cpp)
// use a special object for source code generation
using CGD = CG;
using ADCG = AD;
@@ -76,7 +76,7 @@ TEST(CppADCGLatexTest, latex) {
}
-TEST(CppADCGLatexTest, latexJac) {
+TEST(CppADCGLatexTest, latexJac) { // NOLINT(cert-err58-cpp)
// use a special object for source code generation
using CGD = CG;
using ADCG = AD;
diff --git a/test/cppad/cg/model/lang/mathml/CMakeLists.txt b/test/cppad/cg/model/lang/mathml/CMakeLists.txt
index 49157b86..9eb32549 100644
--- a/test/cppad/cg/model/lang/mathml/CMakeLists.txt
+++ b/test/cppad/cg/model/lang/mathml/CMakeLists.txt
@@ -23,6 +23,15 @@ add_cppadcg_test(mathml.cpp)
link_file("${CMAKE_CURRENT_SOURCE_DIR}/variableSelection.js"
"${CMAKE_CURRENT_BINARY_DIR}/variableSelection.js")
+link_file("${CMAKE_CURRENT_SOURCE_DIR}/mathml.css"
+ "${CMAKE_CURRENT_BINARY_DIR}/mathml.css")
+link_file("${CMAKE_CURRENT_SOURCE_DIR}/head_extra.html"
+ "${CMAKE_CURRENT_BINARY_DIR}/head_extra.html")
+
+
ADD_CUSTOM_TARGET(link_or_copy_variableSelectionJS
- DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/variableSelection.js")
+ DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/variableSelection.js"
+ "${CMAKE_CURRENT_BINARY_DIR}/mathml.css"
+ "${CMAKE_CURRENT_BINARY_DIR}/head_extra.html")
+
ADD_DEPENDENCIES("mathml" link_or_copy_variableSelectionJS)
\ No newline at end of file
diff --git a/test/cppad/cg/model/lang/mathml/head_extra.html b/test/cppad/cg/model/lang/mathml/head_extra.html
new file mode 100644
index 00000000..9943ce0c
--- /dev/null
+++ b/test/cppad/cg/model/lang/mathml/head_extra.html
@@ -0,0 +1,9 @@
+
+
\ No newline at end of file
diff --git a/test/cppad/cg/model/lang/mathml/mathml.cpp b/test/cppad/cg/model/lang/mathml/mathml.cpp
index 56c38ed2..e0dfb07b 100644
--- a/test/cppad/cg/model/lang/mathml/mathml.cpp
+++ b/test/cppad/cg/model/lang/mathml/mathml.cpp
@@ -1,6 +1,7 @@
/* --------------------------------------------------------------------------
* CppADCodeGen: C++ Algorithmic Differentiation with Source Code Generation:
* Copyright (C) 2015 Ciengis
+ * Copyright (C) 2020 Joao Leal
*
* CppADCodeGen is distributed under multiple licenses:
*
@@ -14,7 +15,6 @@
*/
#include
-#include
#include
#include
@@ -40,7 +40,7 @@ TEST(CppADCGLatexTest, latex) {
// the model
ADCG a = x[0] / 1. + x[1] * x[1];
ADCG b = a / 2e-6;
- y[0] = b + 1 / (sign(b)*5 * a);
+ y[0] = b + 1 / (sign(b) * 5 * a);
y[1] = x[1];
y[2] = CondExpLt(ADCG(1.0), x[0], x[1], b);
y[3] = CondExpLe(x[0], ADCG(2.0), x[1], b);
@@ -68,39 +68,18 @@ TEST(CppADCGLatexTest, latex) {
langMathML.setSaveVariableRelations(true);
// add some additional code to select variables
- langMathML.setStyle(langMathML.getStyle() + "\n.selectedProp{background-color: #ccc;}"
- "\n.faded{\n"
- " opacity: 0.2;\n"
- " filter: alpha(opacity=20); /* For IE8 and earlier */\n"
- "}\n"
- "\n.faded2{\n"
- " opacity: 0.5;\n"
- " filter: alpha(opacity=50); /* For IE8 and earlier */\n"
- "}");
+ langMathML.setStyle(langMathML.getStyle() + readStringFromFile("mathml.css"));
// use block display
- langMathML.setEquationMarkup("");
+ langMathML.setEquationMarkup(R"(");
// use inline display
//langMathML.setEquationMarkup("
");
// use MathJax (and align to the left)
- langMathML.setHeadExtraMarkup("\n"
- "");
-
- std::ifstream jsFile;
- jsFile.open("variableSelection.js");
-
- std::stringstream strStream;
- strStream << jsFile.rdbuf();
-
- langMathML.setJavascript(strStream.str());
+ langMathML.setHeadExtraMarkup(readStringFromFile("head_extra.html"));
+
+ langMathML.setJavascript(readStringFromFile("variableSelection.js"));
// create the HMTL file
std::ofstream htmlFile;
diff --git a/test/cppad/cg/model/lang/mathml/mathml.css b/test/cppad/cg/model/lang/mathml/mathml.css
new file mode 100644
index 00000000..3ea386d8
--- /dev/null
+++ b/test/cppad/cg/model/lang/mathml/mathml.css
@@ -0,0 +1,13 @@
+.selectedProp {
+ background-color: #ccc;
+}
+
+.faded {
+ opacity: 0.2;
+ filter: alpha(opacity=20); /* For IE8 and earlier */
+}
+
+.faded2 {
+ opacity: 0.5;
+ filter: alpha(opacity=50); /* For IE8 and earlier */
+}
\ No newline at end of file
diff --git a/test/cppad/cg/model/lang/mathml/variableSelection.js b/test/cppad/cg/model/lang/mathml/variableSelection.js
index 30951916..6ce9c3fc 100644
--- a/test/cppad/cg/model/lang/mathml/variableSelection.js
+++ b/test/cppad/cg/model/lang/mathml/variableSelection.js
@@ -2,8 +2,8 @@ function contains(arr, o) {
if (usages === null || usages === undefined) {
return false;
}
- var l = arr.length;
- for (var i = 0; i < l; i++) {
+ const l = arr.length;
+ for (let i = 0; i < l; i++) {
if (arr[i] === o) {
return true;
}
@@ -14,7 +14,7 @@ function contains(arr, o) {
function findEquation(el) {
if (el.classList.contains('indep'))
return null;
- while (el != document) {
+ while (el !== document) {
if (el.classList.contains('equation')) {
return el;
}
@@ -24,8 +24,8 @@ function findEquation(el) {
}
function isBranch(eq) {
- var el = eq.parentNode;
- while (el != document && el.id != 'algorithm') {
+ let el = eq.parentNode;
+ while (el !== document && el.id !== 'algorithm') {
if (el.classList.contains('condBody')) {
return true;
}
@@ -35,9 +35,9 @@ function isBranch(eq) {
}
function showEquations(eqId, level) {
- var el = document.getElementById('v' + eqId);
+ const el = document.getElementById('v' + eqId);
if (el !== null) {
- var eq = findEquation(el);
+ const eq = findEquation(el);
if (eq !== null && eq !== undefined) {
eq.classList.remove('faded');
if (!eq.classList.contains('depEq')) {
@@ -50,30 +50,30 @@ function showEquations(eqId, level) {
}
}
- var deps = var2dep[eqId];
+ const deps = var2dep[eqId];
if (deps === undefined || deps === null) {
return;
}
- for (var i = 0; i < deps.length; i++) {
- var id = deps[i];
+ for (let i = 0; i < deps.length; i++) {
+ const id = deps[i];
showEquations(id, level + 1);
}
}
function hideEquationForIds(ids, visibleId) {
- for (var co in ids) {
+ for (const co in ids) {
if (visibleId === ids[co])
continue;
- var el = document.getElementById(ids[co]);
+ const el = document.getElementById(ids[co]);
if (el !== null && el !== undefined) {
- var eq = findEquation(el);
+ const eq = findEquation(el);
if (eq !== null && eq !== undefined)
eq.classList.add('faded');
}
}
}
function clearAllClass(className) {
- var list = document.getElementsByClassName(className);
+ const list = document.getElementsByClassName(className);
if (list !== undefined) {
while (list.length > 0) {
list[0].classList.remove(className);
@@ -82,19 +82,19 @@ function clearAllClass(className) {
}
function clickHandler(e) {
- var t = e.target;
+ let t = e.target;
clearAllClass('selectedProp');
clearAllClass('faded');
clearAllClass('faded2');
clearAllClass('depEq');
- while (t != document) {
- if (t.id !== null && t.id !== '' && t.id.charAt(0) == 'v') {
- var baseId = t.id.split('_')[0];
- var idval = baseId.substring(1);
- var el = document.getElementById(baseId);
- var n = 0;
+ while (t !== document) {
+ if (t.id !== null && t.id !== '' && t.id.charAt(0) === 'v') {
+ const baseId = t.id.split('_')[0];
+ const idval = baseId.substring(1);
+ let el = document.getElementById(baseId);
+ let n = 0;
while (el !== null) {
el.classList.add('selectedProp');
n++;
@@ -103,15 +103,15 @@ function clickHandler(e) {
// fade other equations which do not use this variable
usages = dep2var[idval];
- for (var i in var2dep) {
+ for (const i in var2dep) {
if (i === idval)
continue;
- var vi = parseInt(i);
+ const vi = parseInt(i);
if (!contains(usages, vi)) {
- var el2 = document.getElementById('v' + i);
+ let el2 = document.getElementById('v' + i);
n = 0;
while (el2 !== null) {
- var eq = findEquation(el2);
+ const eq = findEquation(el2);
if (eq === null)
break;
eq.classList.add('faded');
diff --git a/test/cppad/cg/model/llvm/llvm_external_compiler.cpp b/test/cppad/cg/model/llvm/llvm_external_compiler.cpp
index 65f08135..bd9479a0 100644
--- a/test/cppad/cg/model/llvm/llvm_external_compiler.cpp
+++ b/test/cppad/cg/model/llvm/llvm_external_compiler.cpp
@@ -28,7 +28,7 @@ class LlvmModelExternalCompilerTest : public LlvmModelTest {
TEST_F(LlvmModelExternalCompilerTest, ForwardZero) {
- testForwardZeroResults(*model, *fun, x);
+ testForwardZeroResults(*model, *fun, nullptr, x);
}
TEST_F(LlvmModelExternalCompilerTest, DenseJacobian) {
@@ -40,9 +40,15 @@ TEST_F(LlvmModelExternalCompilerTest, DenseHessian) {
}
TEST_F(LlvmModelExternalCompilerTest, Jacobian) {
- testJacobianResults(*llvmModelLib, *model, *fun, x, false);
+ // sparse Jacobian again (make sure the second run is also OK)
+ size_t n_tests = llvmModelLib->getThreadNumber() > 1 ? 2 : 1;
+
+ testSparseJacobianResults(n_tests, *model, *fun, nullptr, x, false);
}
TEST_F(LlvmModelExternalCompilerTest, Hessian) {
- testHessianResults(*llvmModelLib, *model, *fun, x, false);
+ // sparse Hessian again (make sure the second run is also OK)
+ size_t n_tests = llvmModelLib->getThreadNumber() > 1 ? 2 : 1;
+
+ testSparseHessianResults(n_tests, *model, *fun, nullptr, x, false);
}
diff --git a/test/cppad/cg/model/llvm/llvm_link_clang.cpp b/test/cppad/cg/model/llvm/llvm_link_clang.cpp
index 88f67b3a..240381da 100644
--- a/test/cppad/cg/model/llvm/llvm_link_clang.cpp
+++ b/test/cppad/cg/model/llvm/llvm_link_clang.cpp
@@ -27,7 +27,7 @@ class LlvmModelLinkLlvmTest : public LlvmModelTest {
TEST_F(LlvmModelLinkLlvmTest, ForwardZero) {
- testForwardZeroResults(*model, *fun, x);
+ testForwardZeroResults(*model, *fun, nullptr, x);
}
TEST_F(LlvmModelLinkLlvmTest, DenseJacobian) {
@@ -39,9 +39,15 @@ TEST_F(LlvmModelLinkLlvmTest, DenseHessian) {
}
TEST_F(LlvmModelLinkLlvmTest, Jacobian) {
- testJacobianResults(*llvmModelLib, *model, *fun, x, false);
+ // sparse Jacobian again (make sure the second run is also OK)
+ size_t n_tests = llvmModelLib->getThreadNumber() > 1 ? 2 : 1;
+
+ testSparseJacobianResults(n_tests, *model, *fun, nullptr, x, false);
}
TEST_F(LlvmModelLinkLlvmTest, Hessian) {
- testHessianResults(*llvmModelLib, *model, *fun, x, false);
+ // sparse Hessian again (make sure the second run is also OK)
+ size_t n_tests = llvmModelLib->getThreadNumber() > 1 ? 2 : 1;
+
+ testSparseHessianResults(n_tests, *model, *fun, nullptr, x, false);
}