Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hessian and Jacobian #117

Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
64470d4
Groundwork for Hessian class
raneamri Jun 5, 2024
b0f8a77
Flexible function handling for hessian class
raneamri Jun 5, 2024
22f3cc3
Cleaned tests
raneamri Jun 6, 2024
5807a15
Added Hessian.hpp to CMakeList
raneamri Jun 6, 2024
33fef4f
Jacobian base implementation
raneamri Jun 6, 2024
9fcf15c
Merge branch 'main' into feature/hessian-jacobian
raneamri Jun 6, 2024
8dee7e8
Added fwd_fwd mode for Hessian, changed Jacobian args + some new tests
raneamri Jun 6, 2024
e48fcf7
Hessian & Jacobian now take matrix iterator (& corresponding tests)
raneamri Jun 7, 2024
a47b248
Jacobian fwd mode & corresponding tests
raneamri Jun 7, 2024
d619a9b
Jacobian adj mode implemented
raneamri Jun 7, 2024
303ed3f
Exception handling for RowIterator overloads & doc files added
raneamri Jun 7, 2024
d2acd8a
Changed iterator tests to use std::list & changed CI to use msvc 14.4…
raneamri Jun 7, 2024
d7722ca
Hessian & Jacobian impl. from OO to functional
raneamri Jun 9, 2024
1d260d2
Fixed naming convention
raneamri Jun 9, 2024
08668da
Removed redundant variable
raneamri Jun 9, 2024
dc344ee
QOL changes and new tests
raneamri Jun 10, 2024
0a44e62
Test fixes, finished Jacobian impl., guard headers and has_begin reve…
raneamri Jun 10, 2024
5c66207
Added M_PI def for windows
raneamri Jun 10, 2024
a945864
Added MATH_DEFINES in tests for Windows & added basic documentation
raneamri Jun 10, 2024
d28cdfe
Pre-merge code cleanup
raneamri Jun 10, 2024
93f5d90
Tests, doc & semantics:
raneamri Jun 11, 2024
3d8be2b
Added TypeTraits.hpp to CMakeLists
raneamri Jun 11, 2024
60f4245
New Jacobian test, fixed Jacobian being made transposed and format ch…
raneamri Jun 11, 2024
e5875bd
Fixed display of Jacobian in doc
raneamri Jun 11, 2024
fdf7447
Added tests for OutOfBounds exceptions
raneamri Jun 11, 2024
7fa8fa1
More exhaustive tests
raneamri Jun 11, 2024
7c0382c
Minimised total function calls in Jacobian at expense of late iterato…
raneamri Jun 11, 2024
06ee32f
Re-format as per Codacy
raneamri Jun 11, 2024
0cdeda2
More Markdown linting
raneamri Jun 11, 2024
3fa8a7a
Increased test rigor, Hessian & Jacobian final tweaks and doc fixes
raneamri Jun 12, 2024
a6263b6
Final changes for Codacy (the rest require config)
raneamri Jun 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ set(public_headers
XAD/Complex.hpp
XAD/Exceptions.hpp
XAD/Expression.hpp
XAD/Hessian.hpp
XAD/Interface.hpp
XAD/Jacobian.hpp
XAD/Literals.hpp
XAD/Macros.hpp
XAD/MathFunctions.hpp
Expand Down
74 changes: 74 additions & 0 deletions src/XAD/Hessian.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*******************************************************************************

Implementation of Hessian computing methods.

This file is part of XAD, a comprehensive C++ library for
automatic differentiation.

Copyright (C) 2010-2024 Xcelerit Computing Ltd.

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program 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 Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.

******************************************************************************/

#include <functional>
#include <vector>
raneamri marked this conversation as resolved.
Show resolved Hide resolved

namespace xad
{

template <class T>
class Hessian
{
public:
Hessian(std::function<T(std::vector<T> &)> func, std::vector<T> &v) : foo(func), v(v) {}

Check warning on line 35 in src/XAD/Hessian.hpp

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/XAD/Hessian.hpp#L35

Member variable 'Hessian::domain' is not initialized in the constructor.
raneamri marked this conversation as resolved.
Show resolved Hide resolved

std::vector<std::vector<T>> compute()
raneamri marked this conversation as resolved.
Show resolved Hide resolved
{
xad::Tape<xad::FReal<double>> tape;
domain = static_cast<unsigned int>(v.size());
std::vector<std::vector<T>> matrix(domain, std::vector<T>(domain, 0.0));

tape.registerInputs(v);

for (unsigned int i = 0; i < domain; i++)
{
derivative(value(v[i])) = 1.0;
tape.newRecording();

T y = foo(v);
tape.registerOutput(y);
value(derivative(y)) = 1.0;

tape.computeAdjoints();

for (unsigned int j = 0; j < domain; j++)
{
// std::cout << "d2y/dx" << i << "dx" << j << " = " << derivative(derivative(v[j]))
// << "\n";
matrix[i][j] = derivative(derivative(v[j]));
}

derivative(value(v[i])) = 0.0;
}

return matrix;
}

private:
std::function<T(std::vector<T> &)> foo;
std::vector<T> v;
unsigned int domain;
raneamri marked this conversation as resolved.
Show resolved Hide resolved
};
} // namespace xad
79 changes: 79 additions & 0 deletions src/XAD/Jacobian.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*******************************************************************************

Implementation of Jacobian computing methods.

This file is part of XAD, a comprehensive C++ library for
automatic differentiation.

Copyright (C) 2010-2024 Xcelerit Computing Ltd.

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program 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 Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.

******************************************************************************/

#include <functional>
#include <vector>

namespace xad
{

template <class T>
class Jacobian
{
public:
Jacobian(std::vector<std::function<T(std::vector<T> &)>> foos, std::vector<T> &v,
raneamri marked this conversation as resolved.
Show resolved Hide resolved
xad::Tape<double> *tape)
: foos(foos),
v(v),
tape(tape),
domain(static_cast<unsigned int>(v.size())),
codomain(static_cast<unsigned int>(foos.size()))
{
}

std::vector<std::vector<T>> compute()
{
std::vector<std::vector<T>> matrix(codomain, std::vector<T>(domain, 0.0));

tape->registerInputs(v);

for (unsigned int i = 0; i < domain; i++)
{
for (unsigned int j = 0; j < codomain; j++)
{
derivative(v[i]) = 1.0;
tape->newRecording();

T y = foos[j](v);
tape->registerOutput(y);
derivative(y) = 1.0;

tape->computeAdjoints();

// std::cout << "df" << j << "/dx" << i << " = " << derivative(v[i]) << std::endl;
matrix[i][j] = derivative(v[i]);
derivative(v[i]) = 0.0;
}
}

return matrix;
}

private:
std::vector<std::function<T(std::vector<T> &)>> foos;
std::vector<T> v;
Tape<double> *tape;
unsigned int domain, codomain;
};
} // namespace xad
2 changes: 2 additions & 0 deletions src/XAD/XAD.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@
#include <XAD/Config.hpp>
#include <XAD/Exceptions.hpp>
#include <XAD/Expression.hpp>
#include <XAD/Hessian.hpp>
#include <XAD/Interface.hpp>
#include <XAD/Jacobian.hpp>
raneamri marked this conversation as resolved.
Show resolved Hide resolved
#include <XAD/Literals.hpp>
#include <XAD/MathFunctions.hpp>
#include <XAD/Tape.hpp>
Expand Down
2 changes: 2 additions & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ set(testfiles
StdCompatibility_test.cpp
ReusableRange_test.cpp
PartialRollback_test.cpp
Hessian_test.cpp
Jacobian_test.cpp
)

if (CMAKE_COMPILER_IS_GNUCC)
Expand Down
92 changes: 92 additions & 0 deletions test/Hessian_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*******************************************************************************

Tests for xad::Hessian class.

This file is part of XAD, a comprehensive C++ library for
automatic differentiation.

Copyright (C) 2010-2024 Xcelerit Computing Ltd.

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program 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 Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.

******************************************************************************/

#include <XAD/XAD.hpp>

#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <complex>
#include <type_traits>
#include <typeinfo>
#include <vector>

using namespace ::testing;

template <class T>
T quad(std::vector<T> &x)
{
T c = x[0] * x[0];
T d = x[1] * x[1];
return c + d;
}

template <class T>
T tquad(std::vector<T> &x)
{
T c = x[0] * x[0];
T d = x[1] * x[1];
T e = x[2] * x[2];
return c + d + e;
}

template <class T>
T foo(std::vector<T> &x)
{
T c = exp(x[0]);
T d = sin(x[1]);
T e = cos(x[2]);
return c + d + e;
}

TEST(HessianTest, QuadraticForwardAdjoint)
{
typedef xad::AReal<xad::FReal<double>> AD;

std::vector<AD> x = {3, 2};
xad::Hessian<AD> h(quad<AD>, x);

std::vector<std::vector<AD>> cross_hessian = {{2.0, 0.0}, {0.0, 2.0}};
std::vector<std::vector<AD>> computed_hessian = h.compute();

for (unsigned int i = 0; i < cross_hessian.size(); i++)
for (unsigned int j = 0; j < cross_hessian.size(); j++)
ASSERT_EQ(cross_hessian[i][j], computed_hessian[i][j]);
}

TEST(HessianTest, ThreeVarQuadratic)
{
typedef xad::fwd_adj<double> mode;
typedef mode::active_type AD;

std::vector<AD> x = {3, 2, 4};
xad::Hessian<AD> hes(tquad<AD>, x);

std::vector<std::vector<AD>> cross_hessian = {
{2.0, 0.0, 0.0}, {0.0, 2.0, 0.0}, {0.0, 0.0, 2.0}};
std::vector<std::vector<AD>> computed_hessian = hes.compute();

for (unsigned int i = 0; i < cross_hessian.size(); i++)
for (unsigned int j = 0; j < cross_hessian.size(); j++)
ASSERT_EQ(cross_hessian[i][j], computed_hessian[i][j]);
}
auto-differentiation-dev marked this conversation as resolved.
Show resolved Hide resolved
65 changes: 65 additions & 0 deletions test/Jacobian_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*******************************************************************************

Tests for xad::Jacobian class.

This file is part of XAD, a comprehensive C++ library for
automatic differentiation.

Copyright (C) 2010-2024 Xcelerit Computing Ltd.

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program 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 Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.

******************************************************************************/

#include <XAD/XAD.hpp>

#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <functional>
#include <vector>

template <typename T>
T foo1(std::vector<T> &x)
{
return x[0] + sin(x[1]);
}

template <typename T>
T foo2(std::vector<T> &x)
{
return x[1] + sin(x[0]);
}

TEST(JacobianTest, SimpleJacobianAdjoint)
{
typedef xad::adj<double> mode;
typedef mode::tape_type tape_type;
typedef mode::active_type AD;

tape_type tape;

std::vector<std::function<AD(std::vector<AD> &)>> funcs(2);
funcs[0] = foo1<AD>;
funcs[1] = foo2<AD>;

std::vector<AD> x = {-2, 1};
xad::Jacobian<AD> jac(funcs, x, &tape);

std::vector<std::vector<AD>> cross_jacobian = {{1.0, cos(-2)}, {cos(1), 1.0}};
std::vector<std::vector<AD>> computed_jacobian = jac.compute();

for (unsigned int i = 0; i < cross_jacobian.size(); i++)
for (unsigned int j = 0; j < cross_jacobian.size(); j++)
ASSERT_EQ(cross_jacobian[i][j], computed_jacobian[i][j]);
}
Loading