Skip to content

Commit

Permalink
Merge pull request #8 from terasakisatoshi/terasaki/affine
Browse files Browse the repository at this point in the history
Add affine project that utilizes Eigen
  • Loading branch information
terasakisatoshi authored May 16, 2024
2 parents 67644df + 98f7a39 commit d1f55b1
Show file tree
Hide file tree
Showing 16 changed files with 492 additions and 0 deletions.
56 changes: 56 additions & 0 deletions .github/workflows/affine.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
name: affine
on:
push:
branches:
- main
tags: ['*']
pull_request:
paths:
- "affine/*"
- ".github/workflows/affine.yml"
workflow_dispatch:

defaults:
run:
working-directory: ./affine

concurrency:
# Skip intermediate builds: always.
# Cancel intermediate builds: only if it is a pull request build.
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }}
jobs:
test:
name: Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }}
runs-on: ${{ matrix.os }}
timeout-minutes: 60
continue-on-error: ${{ matrix.experimental }}
permissions: # needed to allow julia-actions/cache to proactively delete old caches that it has created
actions: write
contents: read
strategy:
fail-fast: false
matrix:
version: ['1.6', '1.10', '1']
experimental: [false]
os:
- ubuntu-latest
# - macos-latest
arch: [x64]
steps:
- uses: actions/checkout@v4
- uses: julia-actions/setup-julia@v2
with:
version: ${{ matrix.version }}
arch: ${{ matrix.arch }}
- uses: julia-actions/cache@v1
- name: Install CxxWrap
run: julia -e 'using Pkg; Pkg.add("CxxWrap")'
- name: Install Eigen
run: sudo apt-get install libeigen3-dev
- name: Build shared libraries
run: bash build.sh
- name: Run Julia Tests
run: julia --project -e 'using Pkg; Pkg.test()'
- name: Run CXX Tests
run: make test
33 changes: 33 additions & 0 deletions affine/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
cmake_minimum_required(VERSION 3.24)
project(main)

set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin")

find_package(Eigen3 REQUIRED)
find_package(JlCxx)
get_target_property(JlCxx_location JlCxx::cxxwrap_julia LOCATION)
get_filename_component(JlCxx_location ${JlCxx_location} DIRECTORY)
message(STATUS "Found JlCxx at ${JlCxx_location}")
message(STATUS "Julia_LIBRARY at ${Julia_LIBRARY}")

add_library(jl_affine SHARED jl_affine.cpp)
target_link_libraries(jl_affine affine JlCxx::cxxwrap_julia ${Julia_LIBRARY})

include_directories(${EIGEN3_INCLUDE_DIR})

add_library(myproject_compiler_flags INTERFACE)

add_library(affine affine.cpp)
target_compile_features(myproject_compiler_flags INTERFACE cxx_std_17)

target_include_directories(affine INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(affine PUBLIC myproject_compiler_flags)

add_executable(main main.cpp)
target_link_libraries(main PRIVATE affine myproject_compiler_flags)

enable_testing()

add_subdirectory(test)
10 changes: 10 additions & 0 deletions affine/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.PHONY: all run build test
all: build

build: *.cpp
# cmake -S . -B ./build
# cmake --build ./build
bash build.sh

test: build
ctest --test-dir ./build
77 changes: 77 additions & 0 deletions affine/Manifest.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# This file is machine-generated - editing it directly is not advised

julia_version = "1.10.3"
manifest_format = "2.0"
project_hash = "1bf575ae6f6226ebe875439048e07b3eae0f0506"

[[deps.Artifacts]]
uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33"

[[deps.Base64]]
uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"

[[deps.CxxWrap]]
deps = ["Libdl", "MacroTools", "libcxxwrap_julia_jll"]
git-tree-sha1 = "ba1a559afd562447710513525030d6ad83e5868a"
uuid = "1f15a43c-97ca-5a2a-ae31-89f07a497df4"
version = "0.15.1"

[[deps.Dates]]
deps = ["Printf"]
uuid = "ade2ca70-3891-5945-98fb-dc099432e06a"

[[deps.JLLWrappers]]
deps = ["Artifacts", "Preferences"]
git-tree-sha1 = "7e5d6779a1e09a36db2a7b6cff50942a0a7d0fca"
uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210"
version = "1.5.0"

[[deps.Libdl]]
uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb"

[[deps.MacroTools]]
deps = ["Markdown", "Random"]
git-tree-sha1 = "2fa9ee3e63fd3a4f7a9a4f4744a52f4856de82df"
uuid = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09"
version = "0.5.13"

[[deps.Markdown]]
deps = ["Base64"]
uuid = "d6f4376e-aef5-505a-96c1-9c027394607a"

[[deps.Preferences]]
deps = ["TOML"]
git-tree-sha1 = "9306f6085165d270f7e3db02af26a400d580f5c6"
uuid = "21216c6a-2e73-6563-6e65-726566657250"
version = "1.4.3"

[[deps.Printf]]
deps = ["Unicode"]
uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7"

[[deps.Random]]
deps = ["SHA"]
uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"

[[deps.Reexport]]
git-tree-sha1 = "45e428421666073eab6f2da5c9d310d99bb12f9b"
uuid = "189a3867-3050-52da-a836-e630ba90ab69"
version = "1.2.2"

[[deps.SHA]]
uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce"
version = "0.7.0"

[[deps.TOML]]
deps = ["Dates"]
uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76"
version = "1.0.3"

[[deps.Unicode]]
uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5"

[[deps.libcxxwrap_julia_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl"]
git-tree-sha1 = "0f10092db771939e29fd13a67967f5c63212fdfe"
uuid = "3eaa8342-bff7-56a5-9981-c04077f7cee7"
version = "0.12.3+0"
15 changes: 15 additions & 0 deletions affine/Project.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
name = "MyCxxWrap5"
uuid = "46426fcd-e896-4661-bc45-9218ef2390da"
authors = ["SatoshiTerasaki <[email protected]>"]
version = "0.1.0"

[deps]
CxxWrap = "1f15a43c-97ca-5a2a-ae31-89f07a497df4"
Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb"
Reexport = "189a3867-3050-52da-a836-e630ba90ab69"

[extras]
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[targets]
test = ["Test"]
3 changes: 3 additions & 0 deletions affine/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```
cmake -S . -B ./build && cmake --build ./build && ./build/bin/main
```
8 changes: 8 additions & 0 deletions affine/affine.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#include "affine.hpp"
#include <Eigen/Dense>

//constructor function
Affine::Affine(const Eigen::Matrix2d W, const Eigen::Vector2d b) : W(W), b(b) {};
Eigen::Vector2d Affine::transform(const Eigen::Vector2d x){
return W * x + b;
}
9 changes: 9 additions & 0 deletions affine/affine.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#include <Eigen/Dense>

class Affine{
public:
Affine(const Eigen::Matrix2d W, const Eigen::Vector2d b);
Eigen::Vector2d transform(const Eigen::Vector2d x);
Eigen::Matrix2d W;
Eigen::Vector2d b;
};
3 changes: 3 additions & 0 deletions affine/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
CXXWRAP_PREFIX=`julia --project -e 'using CxxWrap; CxxWrap.prefix_path() |> print'`
cmake -S . -B ./build -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH=$CXXWRAP_PREFIX
cmake --build ./build --config Release -j `nproc`
23 changes: 23 additions & 0 deletions affine/debug.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using Test

using MyCxxWrap5

W = MyCxxWrap5.EigenMatrix{Float64,2,2}()
b = MyCxxWrap5.EigenMatrix{Float64,2,1}()

W_ = rand(2, 2)
for ci in CartesianIndices(W_)
W[ci.I...] = W_[ci]
end

b_ = rand(2)
for i in eachindex(b_)
b[i, 1] = b_[i]
end

aff = MyCxxWrap5.Affine(W, b)
println(W)
println(MyCxxWrap5.getW(aff))

println(b)
println(MyCxxWrap5.getb(aff))
124 changes: 124 additions & 0 deletions affine/jl_affine.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/*
This jl_affine.cpp is based on https://github.com/barche/EigenCpp.jl/blob/master/deps/src/eigen_wrapper/wrap_eigen.cpp
The EigenCpp.jl package is licensed under the MIT "Expat" License:
> Copyright (c) 2015: Bart Janssens.
>
> Permission is hereby granted, free of charge, to any person obtaining
> a copy of this software and associated documentation files (the
> "Software"), to deal in the Software without restriction, including
> without limitation the rights to use, copy, modify, merge, publish,
> distribute, sublicense, and/or sell copies of the Software, and to
> permit persons to whom the Software is furnished to do so, subject to
> the following conditions:
>
> The above copyright notice and this permission notice shall be
> included in all copies or substantial portions of the Software.
>
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
> IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
> CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
> TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
> SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#include <Eigen/Dense>
#include <type_traits>
#include <string>

#include "jlcxx/jlcxx.hpp"
#include "affine.hpp"

namespace jlcxx
{
// Match the Eigen Matrix type, skipping the default parameters
template<typename ScalarT, int Rows, int Cols>
struct BuildParameterList<Eigen::Matrix<ScalarT, Rows, Cols>>
{
// We set the parameterlist to int64_t, to avoid having to wrap all parameters in Int32() in Julia
typedef ParameterList<ScalarT, std::integral_constant<int64_t, Rows>, std::integral_constant<int64_t, Cols>> type;
};
}

JLCXX_MODULE define_julia_module(jlcxx::Module &mod){
// Add some fixed-size matrices
mod.add_type<jlcxx::Parametric<jlcxx::TypeVar<1>, jlcxx::TypeVar<2>, jlcxx::TypeVar<3>>>("EigenMatrix")
.apply<Eigen::Matrix<double, 2, 2>, Eigen::Matrix<double, 2, 1>>([&mod](auto wrapped)
{
typedef typename decltype(wrapped)::type WrappedT;
typedef typename WrappedT::Scalar ScalarT;
typedef jlcxx::remove_const_ref<decltype(std::declval<WrappedT>()+std::declval<WrappedT>())> SumT;

mod.add_type<SumT>("Sum_" + std::string(typeid(SumT).name()));

mod.method("setConstant", [](WrappedT& eigen_mat, const ScalarT val)
{
eigen_mat.setConstant(val);
});

mod.set_override_module(jl_base_module);
mod.method("print", [](const WrappedT& eigen_mat)
{
std::cout << eigen_mat << std::endl;
});

mod.method("println", [](const WrappedT& eigen_mat)
{
std::cout << eigen_mat << std::endl;
});

mod.method("convert", [](jlcxx::SingletonType<jlcxx::ArrayRef<ScalarT, 2>>, WrappedT& eigen_mat)
{
return jlcxx::ArrayRef<ScalarT, 2>(eigen_mat.data(), eigen_mat.rows(), eigen_mat.cols());
});

mod.method("getindex", [](const WrappedT& eigen_mat, const int64_t row, const int64_t col)
{
return eigen_mat(row-1,col-1);
});

mod.method("setindex!", [](WrappedT& eigen_mat, const ScalarT val, const int64_t row, const int64_t col)
{
eigen_mat(row-1,col-1) = val;
});

mod.method("+", [](const WrappedT& mat1, const WrappedT& mat2)
{
return jlcxx::create<SumT>(mat1 + mat2);
});

mod.method("convert", [](jlcxx::SingletonType<WrappedT>, const SumT& sum)
{
return jlcxx::create<WrappedT>(sum);
});

mod.method("==", [](const WrappedT& eigen_mat, const jlcxx::ArrayRef<ScalarT, WrappedT::ColsAtCompileTime==1?1:2>& julia_mat)
{
return eigen_mat == Eigen::Map<const WrappedT>(julia_mat.data());
});
mod.unset_override_module();
});

// Mat-vec product for (2x2)*(2x1)
typedef jlcxx::remove_const_ref<decltype(std::declval<Eigen::Matrix<double, 2, 2>>()*std::declval<Eigen::Matrix<double, 2, 1>>())> ProductT;
mod.add_type<ProductT>("Product_" + std::string(typeid(ProductT).name()));

mod.set_override_module(jl_base_module);
mod.method("*", [](const Eigen::Matrix<double, 2, 2>& mat, const Eigen::Matrix<double, 2, 1>& vec)
{
return jlcxx::create<Eigen::Matrix<double, 2, 1>>(mat * vec);
});

mod.method("+", [](const Eigen::Matrix<double, 2, 1>& a, Eigen::Matrix<double, 2, 1>& b)
{
return jlcxx::create<Eigen::Matrix<double, 2, 1>>(a+b);
});
mod.unset_override_module();

mod.add_type<Affine>("Affine").constructor<Eigen::Matrix<double, 2, 2>, Eigen::Matrix<double,2,1>>();
mod.method("getW", [](const Affine& aff){return aff.W;});
mod.method("getb", [](const Affine& aff){return aff.b;});
}
13 changes: 13 additions & 0 deletions affine/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#include <Eigen/Dense>
#include <iostream>

using Eigen::MatrixXd;

int main() {
MatrixXd m(2, 2);
m(0, 0) = 3;
m(1, 0) = 2.5;
m(0, 1) = -1;
m(1, 1) = m(1, 0) + m(0, 1);
std::cout << m << std::endl;
}
Loading

0 comments on commit d1f55b1

Please sign in to comment.