Skip to content

Additional Enzyme examples and use cases (e.g DistributedGenerator) #54

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

Merged
merged 57 commits into from
Feb 27, 2025
Merged
Show file tree
Hide file tree
Changes from 52 commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
ba3ea2a
Fix spacing in Enzyme basic examples.
nkoukpaizan Feb 3, 2025
2904eff
SparseMatrix directory.
nkoukpaizan Feb 3, 2025
8254ce2
Add preliminary Enzyme support
ashermancinelli Mar 3, 2022
8b50a7e
Use better naming conventions
ashermancinelli Mar 3, 2022
be8f2e8
Apply suggestions from code review
ashermancinelli Mar 7, 2022
3d608a3
More verbose tests for enzyme support.
pelesh May 26, 2022
536865e
int --> double in Enzyme examples.
nkoukpaizan Oct 29, 2024
aa7b2c8
Minor name changes for Enzyme tests.
nkoukpaizan Oct 29, 2024
b508275
Separate scalar and vector examples using Enzyme.
nkoukpaizan Nov 12, 2024
119b572
Jacobian of vector input function is diagonal. Using Enzyme in forwar…
nkoukpaizan Nov 19, 2024
23dc868
Attempt to use classes in EnzymeLibCheck.
nkoukpaizan Nov 25, 2024
0d08de1
Minor improvements in scalar and vector Enzyme standalone tests.
nkoukpaizan Nov 25, 2024
cc83e0f
Minor name change for Enzyme test files.
nkoukpaizan Dec 9, 2024
fa3c09a
Move Enzyme examples.
nkoukpaizan Feb 3, 2025
caeef0c
Minor edits to match develop
nkoukpaizan Feb 3, 2025
e999877
LinearAlgebra directory in examples and DenseTest.
nkoukpaizan Feb 3, 2025
c0694dd
Fix path of example using Enzyme for vectors and Jacobians.
nkoukpaizan Feb 6, 2025
ee0c9a9
Enzyme vector/Jacobian example.
nkoukpaizan Feb 6, 2025
1a6260d
Cleanup Enzyme CMakeList.
nkoukpaizan Feb 6, 2025
e84ad62
Bug fix (type): columns in DenseMatrix.
nkoukpaizan Feb 7, 2025
9294ed3
A very manual way to link GridKit targets with Enzyme executables. Ne…
nkoukpaizan Feb 7, 2025
2d9200b
Fixed spacing in Enzyme examples
nkoukpaizan Feb 7, 2025
88845a6
Basic usage of DenseMatrix in EnzymeVector example.
nkoukpaizan Feb 7, 2025
2ff261e
Intdx-->IdxT
nkoukpaizan Feb 8, 2025
991dca1
Method to convert Dense matriz to COO.
nkoukpaizan Feb 8, 2025
7f5d49f
Use DenseMatrix to store the Jacobians in Enzyme vector example.
nkoukpaizan Feb 10, 2025
c918663
Typo fix in CMakeLists: mirco-->micro.
nkoukpaizan Feb 10, 2025
f11e460
Minor formatting.
nkoukpaizan Feb 10, 2025
4b39fe8
pragma once for COO_Matrix.
nkoukpaizan Feb 10, 2025
91e291c
Better way to ensure paths exist for INCLUDES in enzyme_add_executable.
nkoukpaizan Feb 10, 2025
016fb74
Merge branch 'develop' into nicholson/enzyme-usecase
nkoukpaizan Feb 10, 2025
de6cc71
Functional use of -Wl to link GridKit libraries with Enzyme examples.
nkoukpaizan Feb 10, 2025
a25ed69
Remove extra debug statements from FindEnzyme.
nkoukpaizan Feb 10, 2025
6b53a07
Progress on model autodiff (distributed generator case).
nkoukpaizan Feb 10, 2025
4e48386
Attempts with DisctributedGenerator autodiff.
nkoukpaizan Feb 11, 2025
7ba837e
Name input for COO_Matrix printMatrix method.
nkoukpaizan Feb 11, 2025
c7c9546
Bug fix: need to check abs(value) to sparsify DenseMatrix.
nkoukpaizan Feb 11, 2025
7a42e5f
Working Enzyme derivative of DistributedGenerator with evalResidual c…
nkoukpaizan Feb 11, 2025
0096cf2
Method to set DenseMatrix values from COO.
nkoukpaizan Feb 11, 2025
d7ba02d
Using DenseMatrix form of reference Jacobian to check the answer.
nkoukpaizan Feb 11, 2025
6dab218
EnzymeLibCheck->EnzymeLibScalarCheck in preparation for a vector vers…
nkoukpaizan Feb 11, 2025
ef110ac
Seemingly working EnzymeStandaloneVectorCheck using std::vector<doubl…
nkoukpaizan Feb 11, 2025
733b37d
EnzymePowerElectronicsCheck also works with std::vector<double> inste…
nkoukpaizan Feb 11, 2025
30e1065
Bug fix: Need to pass output vector as a reference.
nkoukpaizan Feb 11, 2025
2b3d79f
Remove unneeded enzyme_autodiff declaration.
nkoukpaizan Feb 11, 2025
37166f7
EnzymeLibVectorCheck.
nkoukpaizan Feb 11, 2025
de8e4fc
Minor fixes to EnzymeLibVectorCheck.
nkoukpaizan Feb 11, 2025
4711620
Correct way to specify library depencencies in enzyme_add_executable?
nkoukpaizan Feb 11, 2025
4ac1e49
Merge branch 'develop' into nicholson/enzyme-usecase
nkoukpaizan Feb 13, 2025
be03069
ModelLib -> GridKit on this branch.
nkoukpaizan Feb 13, 2025
a385880
Merge 'develop' into 'nicholson/enzyme-usecase'.
nkoukpaizan Feb 20, 2025
8329bf9
Better documentation of the DenseMatrix class.
nkoukpaizan Feb 20, 2025
140c2b7
Rename a few variables in Enzyme examples.
nkoukpaizan Feb 21, 2025
fc974dc
Merge 'develop' into 'nicholson/enzyme-usecase'.
nkoukpaizan Feb 24, 2025
356d8a5
powerelec --> power_elec in GRIDKIT::targets.
nkoukpaizan Feb 24, 2025
495ab8c
Added comments to describe the Enzyme examples along with TODO items …
nkoukpaizan Feb 26, 2025
4fc7f46
Fix braces in Enzyme examples.
nkoukpaizan Feb 27, 2025
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
28 changes: 23 additions & 5 deletions cmake/FindEnzyme.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ message(STATUS "opt: ${GRIDKIT_OPT}")
macro(enzyme_add_executable)
set(options)
set(oneValueArgs NAME)
set(multiValueArgs SOURCES LINK_LIBRARIES)
set(multiValueArgs SOURCES LINK_LIBRARIES INCLUDE_DIRECTORIES)
cmake_parse_arguments(enzyme_add_executable "${options}" "${oneValueArgs}"
"${multiValueArgs}" ${ARGN})

Expand All @@ -111,14 +111,32 @@ macro(enzyme_add_executable)
set(PHASE5 "${CMAKE_CURRENT_BINARY_DIR}/${enzyme_add_executable_NAME}")

set(OBJS "")
set(includes "${enzyme_add_executable_INCLUDE_DIRECTORIES}")

foreach(lib ${enzyme_add_executable_LINK_LIBRARIES})
get_target_property(include ${lib} INCLUDE_DIRECTORIES)
set(includes "${includes}" ${include})

get_target_property(libsource ${lib} SOURCES)
string(FIND "${libsource}" "TARGET" found)
if(NOT(${found} EQUAL -1))
list(APPEND LINKER_FLAGS "-Wl,${libsource}")
endif()
endforeach()

foreach(dir ${includes})
if(EXISTS ${dir})
list(APPEND INCLUDE_COMPILER_LIST "-I${dir}")
endif()
endforeach()

foreach(SRC ${enzyme_add_executable_SOURCES})
set(PHASE0 "${CMAKE_CURRENT_SOURCE_DIR}/${SRC}")
set(PHASE1 "${CMAKE_CURRENT_BINARY_DIR}/${enzyme_add_executable_NAME}_${SRC}_compile.o")
add_custom_command(
DEPENDS ${PHASE0}
DEPENDS ${PHASE0}
OUTPUT ${PHASE1}
COMMAND ${CMAKE_CXX_COMPILER} -flto -c ${PHASE0} -O2 -fno-vectorize -ffast-math -fno-unroll-loops -o ${PHASE1}
COMMAND ${CMAKE_CXX_COMPILER} -flto -c ${PHASE0} ${INCLUDE_COMPILER_LIST} -O2 -fno-vectorize -ffast-math -fno-unroll-loops -o ${PHASE1}
COMMENT "Compiling ${SRC} to object file for target ${enzyme_add_executable_NAME}"
)
set(OBJS "${OBJS} ${PHASE1}")
Expand Down Expand Up @@ -148,9 +166,9 @@ macro(enzyme_add_executable)
)

add_custom_command(
DEPENDS ${PHASE4}
DEPENDS ${PHASE4} ${enzyme_add_executable_LINK_LIBRARIES}
OUTPUT ${PHASE5}
COMMAND ${CMAKE_CXX_COMPILER} ${PHASE4} -o ${PHASE5}
COMMAND ${CMAKE_CXX_COMPILER} ${LINKER_FLAGS} ${PHASE4} -o ${PHASE5}
)

add_custom_target(
Expand Down
2 changes: 1 addition & 1 deletion examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
#

add_subdirectory(MatPowerTesting)
add_subdirectory(SparseTest)
add_subdirectory(LinearAlgebra)
add_subdirectory(DistributedGeneratorTest)

if(TARGET SUNDIALS::kinsol)
Expand Down
2 changes: 1 addition & 1 deletion examples/DistributedGeneratorTest/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

add_executable(dgtest DGTest.cpp)
target_link_libraries(dgtest GRIDKIT::powerelec_disgen
GRIDKIT::powerelec_mircoline
GRIDKIT::powerelec_microline
GRIDKIT::powerelec_microload
GRIDKIT::solvers_dyn)

Expand Down
1 change: 1 addition & 0 deletions examples/Enzyme/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
add_subdirectory(Standalone)
add_subdirectory(Library)
add_subdirectory(PowerElectronics)
6 changes: 2 additions & 4 deletions examples/Enzyme/Library/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,2 @@
enzyme_add_executable(NAME EnzymeLibCheck SOURCES main.cpp library.cpp)
#install(TARGETS ${CMAKE_CURRENT_BINARY_DIR}/EnzymeLibCheck DESTINATION bin)

add_test(NAME "EnzymeLibCheck" COMMAND ${CMAKE_CURRENT_BINARY_DIR}/EnzymeLibCheck)
add_subdirectory(Scalar)
add_subdirectory(Vector)
6 changes: 6 additions & 0 deletions examples/Enzyme/Library/Scalar/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
enzyme_add_executable(
NAME EnzymeLibScalarCheck
SOURCES EnzymeScalar.cpp ScalarModel.cpp
)

add_test(NAME "EnzymeLibScalarCheck" COMMAND ${CMAKE_CURRENT_BINARY_DIR}/EnzymeLibScalarCheck)
23 changes: 23 additions & 0 deletions examples/Enzyme/Library/Scalar/EnzymeScalar.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#include <iostream>
#include <limits>
#include "ScalarModel.hpp"

int main() {
int fail = 0;
ScalarModel scalar_model;
double var = 5.0;
scalar_model.setVariable(var);
scalar_model.evalFunction();
scalar_model.evalDerivative();
double sq = scalar_model.getFunctionValue();
double dsq = scalar_model.getDerivativeValue();

std::cout << "x = " << var << ", x^2 = " << sq << ", d(x^2)/dx = " << dsq << "\n";
if (std::abs(dsq - 2.0*var) > std::numeric_limits<double>::epsilon())
{
fail++;
std::cout << "Result incorrect\n";
}
std::cout << "Status: " << fail << "\n";
return fail;
}
15 changes: 15 additions & 0 deletions examples/Enzyme/Library/Scalar/EnzymeWrapper.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#pragma once

int enzyme_dup;
int enzyme_dupnoneed;
int enzyme_out;
int enzyme_const;

template <typename return_type, typename ... T>
return_type __enzyme_fwddiff(return_type*, int, T* ... );

template <typename return_type, typename T>
return_type wrapper(T* obj) {
obj->evalFunction();
return obj->getFunctionValue();
}
34 changes: 34 additions & 0 deletions examples/Enzyme/Library/Scalar/ScalarModel.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#include "EnzymeWrapper.hpp"
#include "ScalarModel.hpp"
#include <iostream>

inline
double ScalarModel::square(double x) {
return x * x;
}

void ScalarModel::setVariable(double x) {
x_ = x;
}

void ScalarModel::evalFunction() {
f_ = square(x_);
}

void ScalarModel::evalDerivative() {
ScalarModel d_scalar_model;
d_scalar_model.setVariable(1.0);
dfdx_ = __enzyme_fwddiff<double, ScalarModel>((double*)wrapper<double, ScalarModel>, enzyme_dup, this, &d_scalar_model);
}

double ScalarModel::getVariable() const {
return x_;
}

double ScalarModel::getFunctionValue() const {
return f_;
}

double ScalarModel::getDerivativeValue() const {
return dfdx_;
}
17 changes: 17 additions & 0 deletions examples/Enzyme/Library/Scalar/ScalarModel.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#pragma once

class ScalarModel {
private:
double x_, f_, dfdx_;
inline double square(double);

public:
ScalarModel() {};
void setVariable(double);
void evalFunction();
void evalDerivative();
double getVariable() const;
double getFunctionValue() const;
double getDerivativeValue() const;
~ScalarModel() {};
};
7 changes: 7 additions & 0 deletions examples/Enzyme/Library/Vector/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
enzyme_add_executable(
NAME EnzymeLibVectorCheck
SOURCES EnzymeVector.cpp VectorModel.cpp
LINK_LIBRARIES GRIDKIT::DenseMatrix
)

add_test(NAME "EnzymeLibVectorCheck" COMMAND ${CMAKE_CURRENT_BINARY_DIR}/EnzymeLibVectorCheck)
76 changes: 76 additions & 0 deletions examples/Enzyme/Library/Vector/EnzymeVector.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#include <iostream>
#include <limits>
#include "VectorModel.hpp"

inline
double dsquare_ref_scalar(double x) {
return 2.0 * x;
}

DenseMatrix dsquare_ref(std::vector<double> x, std::vector<double> y) {
DenseMatrix jac(x.size(), y.size());
for (int idy = 0; idy < y.size(); ++idy)
{
for (int idx = 0; idx < x.size(); ++idx)
{
if (idx == idy)
jac.setValue(idx, idy, dsquare_ref_scalar(x[idx]));
}
}
return jac;
}

int main() {
// Size and variable declarations
constexpr int N = 10;
std::vector<double> var(N);

// Random input values
srand(time(NULL));
for (int idx = 0; idx < var.size(); ++idx)
{
var[idx] = rand();
}

// Model
VectorModel* vector_model = new VectorModel(N);
vector_model->setVariable(var);
vector_model->evalResidual();
vector_model->evalJacobian();
std::vector<double> var_temp = vector_model->getVariable();
std::vector<double> res = vector_model->getResidual();
DenseMatrix jac = vector_model->getJacobian();

// Reference Jacobian
DenseMatrix jac_ref = dsquare_ref(var, res);

// Check
int fail = 0;
bool verbose = true;
for (int idy = 0; idy < res.size(); ++idy)
{
for (int idx = 0; idx < var.size(); ++idx)
{
if (std::abs(jac.getValue(idx, idy) - jac_ref.getValue(idx, idy)) > std::numeric_limits<double>::epsilon())
{
fail++;
if (verbose)
{
std::cout << "Result incorrect at line = " << idy << ", column = " << idx << "\n";
std::cout << "x = " << var_temp[idx] << ", x^2 = " << res[idx] << ", d(x^2)/dx = " << jac.getValue(idx, idy) << "\n";
}
}
}
}
if (verbose)
{
jac.printMatrix("Autodiff Jacobian");
jac_ref.printMatrix("Reference Jacobian");
}
std::cout << "Status: " << fail << "\n";

// Cleanup
delete vector_model;

return fail;
}
17 changes: 17 additions & 0 deletions examples/Enzyme/Library/Vector/EnzymeWrapper.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#pragma once

#include <vector>

int enzyme_dup;
int enzyme_dupnoneed;
int enzyme_out;
int enzyme_const;

template <typename T>
std::vector<double> __enzyme_fwddiff(std::vector<double>*, int, T*, T*);

template <typename T>
std::vector<double> wrapper(T* obj) {
obj->evalResidual();
return obj->getResidual();
}
72 changes: 72 additions & 0 deletions examples/Enzyme/Library/Vector/VectorModel.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#include "EnzymeWrapper.hpp"
#include "VectorModel.hpp"
#include <iostream>

VectorModel::VectorModel(int N) :
x_(N),
f_(N),
dfdx_(N, N)
{
};

inline
double VectorModel::square_scalar(double x) {
return x * x;
}

void VectorModel::square(std::vector<double>& x, std::vector<double>& y) {
for (int idx = 0; idx < x.size(); ++idx)
{
y[idx] = this->square_scalar(x[idx]);
}
}

void VectorModel::setVariable(std::vector<double> x) {
for (int idx = 0; idx < x.size(); ++idx)
{
x_[idx] = x[idx];
}
}

void VectorModel::evalResidual() {
square(x_, f_);
}

void VectorModel::evalJacobian() {
const int N = x_.size();
std::vector<double> v(N);
VectorModel d_vector_model(N);
for (int idy = 0; idy < N; ++idy)
{
// Elementary vector for Jacobian-vector product
for (int idx = 0; idx < N; ++idx)
{
v[idx] = 0.0;
}
v[idy] = 1.0;
d_vector_model.setVariable(v);

// Autodiff
std::vector<double> d_res = __enzyme_fwddiff<VectorModel>(
(std::vector<double>*)wrapper<VectorModel>,
enzyme_dup, this, &d_vector_model);

// Store result
for (int idx = 0; idx < N; ++idx)
{
dfdx_.setValue(idx, idy, d_res[idx]);
}
}
}

std::vector<double>& VectorModel::getVariable() {
return x_;
}

std::vector<double>& VectorModel::getResidual() {
return f_;
}

DenseMatrix& VectorModel::getJacobian() {
return dfdx_;
}
23 changes: 23 additions & 0 deletions examples/Enzyme/Library/Vector/VectorModel.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#pragma once

#include <LinearAlgebra/DenseMatrix/DenseMatrix.hpp>

using DenseMatrix = GridKit::LinearAlgebra::DenseMatrix<double, size_t>;

class VectorModel {
private:
std::vector<double> x_, f_;
DenseMatrix dfdx_;
inline double square_scalar(double);
void square(std::vector<double>&, std::vector<double>&);

public:
VectorModel(int);
void setVariable(std::vector<double>);
void evalResidual();
void evalJacobian();
std::vector<double>& getVariable();
std::vector<double>& getResidual();
DenseMatrix& getJacobian();
~VectorModel() {};
};
3 changes: 0 additions & 3 deletions examples/Enzyme/Library/library.cpp

This file was deleted.

2 changes: 0 additions & 2 deletions examples/Enzyme/Library/library.hpp

This file was deleted.

Loading