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

Added Sympiler Wrapper #34

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
10 changes: 9 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ endif()
# Polysolve options
option(POLYSOLVE_WITH_SANITIZERS "Enable sanitizers in compilation targets" OFF)
# Polysolve options for enabling/disabling optional libraries
option(POLYSOLVE_WITH_SYMPILER "Enable sympiler library" ON)
option(POLYSOLVE_WITH_ACCELERATE "Enable Apple Accelerate" ${POLYSOLVE_ON_APPLE_SILICON})
option(POLYSOLVE_WITH_CHOLMOD "Enable Cholmod library" ON)
option(POLYSOLVE_WITH_UMFPACK "Enable UmfPack library" ON)
Expand Down Expand Up @@ -160,7 +161,14 @@ endif()
include(json)
target_link_libraries(polysolve PUBLIC nlohmann_json::nlohmann_json)

# Accelerate solvers
# Polysolve solver
if (POLYSOLVE_WITH_SYMPILER)
include(sympiler)
target_link_libraries(polysolve PUBLIC sympiler::sym_sparse_blas)
target_compile_definitions(polysolve PUBLIC -DPOLYSOLVE_WITH_SYMPILER)
endif()

# Accelerate solver
if(POLYSOLVE_WITH_ACCELERATE)
target_compile_definitions(polysolve PUBLIC -DPOLYSOLVE_WITH_ACCELERATE)
endif()
Expand Down
36 changes: 36 additions & 0 deletions cmake/recipes/CPM.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Source: https://github.com/cpm-cmake/CPM.cmake/blob/master/cmake/get_cpm.cmake
# SPDX-License-Identifier: MIT

set(CPM_DOWNLOAD_VERSION 0.38.1)

if(CPM_SOURCE_CACHE)
set(CPM_DOWNLOAD_LOCATION "${CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
elseif(DEFINED ENV{CPM_SOURCE_CACHE})
set(CPM_DOWNLOAD_LOCATION "$ENV{CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
else()
set(CPM_DOWNLOAD_LOCATION "${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
endif()

# Expand relative path. This is important if the provided path contains a tilde (~)
get_filename_component(CPM_DOWNLOAD_LOCATION ${CPM_DOWNLOAD_LOCATION} ABSOLUTE)

function(download_cpm)
message(STATUS "Downloading CPM.cmake to ${CPM_DOWNLOAD_LOCATION}")
file(DOWNLOAD
https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake
${CPM_DOWNLOAD_LOCATION}
)
endfunction()

if(NOT (EXISTS ${CPM_DOWNLOAD_LOCATION}))
download_cpm()
else()
# resume download if it previously failed
file(READ ${CPM_DOWNLOAD_LOCATION} check)
if("${check}" STREQUAL "")
download_cpm()
endif()
unset(check)
endif()

include(${CPM_DOWNLOAD_LOCATION})
48 changes: 48 additions & 0 deletions cmake/recipes/sympiler.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#
# Copyright 2020 Adobe. All rights reserved.
# This file is licensed to you under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. You may obtain a copy
# of the License at http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software distributed under
# the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
# OF ANY KIND, either express or implied. See the License for the specific language
# governing permissions and limitations under the License.
#
if(TARGET sympiler::sym_sparse_blas)
return()
endif()

message(STATUS "Third-party (external): creating target 'sympiler::sym_sparse_blas'")

if("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "arm64" OR "${CMAKE_OSX_ARCHITECTURES}" MATCHES "arm64")
# apple M1
set(SYMPILER_BLAS_BACKEND "Apple" CACHE STRING "BLAS implementation for SYMPILER to use")
else()
# windows, linux, apple intel
set(SYMPILER_BLAS_BACKEND "MKL" CACHE STRING "BLAS implementation for SYMPILER to use")
endif()

if(SYMPILER_BLAS_BACKEND STREQUAL "MKL")
message("INCLUDING MKL")
include(mkl)
if(NOT TARGET MKL::MKL)
add_library(MKL::MKL ALIAS mkl::mkl)
endif()
endif()

include(CPM)
CPMAddPackage(
NAME sympiler
GITHUB_REPOSITORY ryansynk/sympiler
GIT_TAG 51bffd948f902b4606b8a8173a933ad9b54e29bf
ryansynk marked this conversation as resolved.
Show resolved Hide resolved
OPTIONS "SYMPILER_BLAS_BACKEND MKL"
)

add_library(sympiler::sym_sparse_blas ALIAS sym_sparse_blas)

include(GNUInstallDirs)
target_include_directories(sym_sparse_blas INTERFACE
"$<BUILD_INTERFACE:${sympiler_SOURCE_DIR}>/include"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
)
2 changes: 2 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ set(SOURCES
polysolve/LinearSolverEigen.tpp
polysolve/LinearSolverHypre.cpp
polysolve/LinearSolverHypre.hpp
polysolve/LinearSolverSympiler.hpp
polysolve/LinearSolverSympiler.cpp
polysolve/LinearSolverPardiso.cpp
polysolve/LinearSolverPardiso.hpp
polysolve/SaddlePointSolver.cpp
Expand Down
12 changes: 12 additions & 0 deletions src/polysolve/LinearSolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@

// -----------------------------------------------------------------------------
#include <Eigen/Sparse>
#ifdef POLYSOLVE_WITH_SYMPILER
#include <polysolve/LinearSolverSympiler.hpp>
#endif
#ifdef POLYSOLVE_WITH_ACCELERATE
#include <Eigen/AccelerateSupport>
#endif
Expand Down Expand Up @@ -191,6 +194,12 @@ namespace polysolve
else if (solver == "Eigen::SparseLU")
{
RETURN_DIRECT_SOLVER_PTR(SparseLU, "Eigen::SparseLU");
#ifdef POLYSOLVE_WITH_SYMPILER
}
else if (solver == "Sympiler")
{
return std::make_unique<LinearSolverSympiler>();
#endif
#ifdef POLYSOLVE_WITH_ACCELERATE
}
else if (solver == "Eigen::AccelerateLLT")
Expand Down Expand Up @@ -363,6 +372,9 @@ namespace polysolve
return {{
"Eigen::SimplicialLDLT",
"Eigen::SparseLU",
#ifdef POLYSOLVE_WITH_SYMPILER
"Sympiler",
#endif
#ifdef POLYSOLVE_WITH_ACCELERATE
"Eigen::AccelerateLLT",
"Eigen::AccelerateLDLT",
Expand Down
78 changes: 78 additions & 0 deletions src/polysolve/LinearSolverSympiler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#ifdef POLYSOLVE_WITH_SYMPILER

#include <polysolve/LinearSolverSympiler.hpp>
#include <Eigen/Core>

namespace polysolve
{
void LinearSolverSympiler::setSolverMode(int _solver_mode)
{
solver_mode = _solver_mode;
}

void LinearSolverSympiler::updateCSC()
{
m_A_csc->nzmax = m_A_copy.nonZeros();
m_A_csc->ncol = m_A_csc->nrow = m_A_copy.rows();
m_A_csc->p = m_A_copy.outerIndexPtr();
m_A_csc->i = m_A_copy.innerIndexPtr();

m_A_csc->x = m_A_copy.valuePtr();
m_A_csc->stype = -1;
m_A_csc->packed = 1;
m_A_csc->nz = nullptr;
}

void LinearSolverSympiler::setParameters(const json &params)
{
if (params.contains("Sympiler"))
{
if (params["Sympiler"].contains("solver_mode"))
{
setSolverMode(params["Sympiler"]["mtype"].get<int>());
}
}
}

void LinearSolverSympiler::getInfo(json &params) const
{
if (factorize_status == 1)
{
params["factorize_info"] = "Success";
}
else
{
params["factorize_info"] = "Failure";
}
}

void LinearSolverSympiler::analyzePattern(const StiffnessMatrix &A, const int precond_num)
{
m_A_copy = StiffnessMatrix(A);
updateCSC();
m_solver = std::make_unique<sym_lib::parsy::SolverSettings>(m_A_csc.get());
m_solver->symbolic_analysis();
}

// Factorize system matrix
void LinearSolverSympiler::factorize(const StiffnessMatrix &A)
ryansynk marked this conversation as resolved.
Show resolved Hide resolved
{
// Only copy when matrix changes
if (!m_A_copy.isApprox(A))
{
m_A_copy = StiffnessMatrix(A);
updateCSC();
}
factorize_status = m_solver->numerical_factorization(m_A_csc.get());
}

// Solve the linear system Ax = b
void LinearSolverSympiler::solve(const Ref<const Eigen::VectorXd> b, Ref<Eigen::VectorXd> x)
{
double *x_ptr = m_solver->solve_only(b.data());
x = Eigen::Map<Eigen::VectorXd>(x_ptr, x.rows(), x.cols());
}

} // namespace polysolve

#endif
59 changes: 59 additions & 0 deletions src/polysolve/LinearSolverSympiler.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#ifdef POLYSOLVE_WITH_SYMPILER

#include <polysolve/LinearSolver.hpp>
#include <sympiler/parsy/cholesky_solver.h>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's move this header to the .cpp. This will require moving the definition of the constructor/destructor to the .cpp of this file as well.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this possible given the member variables of type sym_lib::parsy::CSC and sym_lib::parsy::SolverSettings?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I took a crack at it -- let me know how it looks


namespace polysolve
{
class LinearSolverSympiler : public LinearSolver
{
public:
LinearSolverSympiler()
: m_solver(nullptr), m_A_csc(std::make_unique<sym_lib::parsy::CSC>()) {}
virtual ~LinearSolverSympiler() = default;

private:
POLYSOLVE_DELETE_MOVE_COPY(LinearSolverSympiler)

protected:
void setSolverMode(int _solver_mode);
void updateCSC();

public:
//////////////////////
// Public interface //
//////////////////////

// Set solver parameters
virtual void setParameters(const json &params) override;

// Retrieve status (success/failure) of factorization
virtual void getInfo(json &params) const override;

// Analyze sparsity pattern
virtual void analyzePattern(const StiffnessMatrix &A, const int precond_num) override;

// Factorize system matrix
virtual void factorize(const StiffnessMatrix &A) override;

// Solve the linear system Ax = b
virtual void solve(const Ref<const VectorXd> b, Ref<VectorXd> x) override;

// Name of the solver type (for debugging purposes)
virtual std::string name() const override { return "Sympiler"; }

private:
std::unique_ptr<sym_lib::parsy::SolverSettings> m_solver;
std::unique_ptr<sym_lib::parsy::CSC> m_A_csc;
polysolve::StiffnessMatrix m_A_copy;

protected:
////////////////////
// Sympiler stuff //
////////////////////
int solver_mode = 0; // 0 is normal solve, 1 is row/col addition
int factorize_status = -1;
Comment on lines +51 to +52
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jdumas @teseoch Is there a convention for naming member variables we should follow in polysolve? I see m_ prefix for some member variables and _ postfix for other member variables.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd vote for using m_ prefix for member variables consistently.

};
} // namespace polysolve

#endif