From fee5b10b0e7320ce8baf995a9c5fd0d164a82799 Mon Sep 17 00:00:00 2001 From: "Mayeul@Zama" Date: Wed, 13 Apr 2022 09:26:30 +0200 Subject: [PATCH] feat(cpp): use cxx (was cbindgen) and mv interface in a workspace --- .github/workflows/rust.yml | 6 +- Cargo.toml | 1 + concrete-optimizer-cpp/.gitignore | 1 + concrete-optimizer-cpp/Cargo.toml | 17 ++++ concrete-optimizer-cpp/Makefile | 41 ++++++++++ concrete-optimizer-cpp/build.rs | 5 ++ .../cmake-utils/CMakeLists.txt | 16 ++++ .../src/concrete-optimizer.rs | 80 +++++++++++++++++++ .../src/cpp/concrete-optimizer.cpp | 33 ++++++++ .../src/cpp/concrete-optimizer.hpp | 28 +++++++ concrete-optimizer-cpp/tests/src/main.cpp | 11 +++ concrete-optimizer/Cargo.toml | 2 +- .../src/graph/unparametrized.rs | 5 ++ concrete-optimizer/src/weight.rs | 2 +- 14 files changed, 243 insertions(+), 5 deletions(-) create mode 100644 concrete-optimizer-cpp/.gitignore create mode 100644 concrete-optimizer-cpp/Cargo.toml create mode 100644 concrete-optimizer-cpp/Makefile create mode 100644 concrete-optimizer-cpp/build.rs create mode 100644 concrete-optimizer-cpp/cmake-utils/CMakeLists.txt create mode 100644 concrete-optimizer-cpp/src/concrete-optimizer.rs create mode 100644 concrete-optimizer-cpp/src/cpp/concrete-optimizer.cpp create mode 100644 concrete-optimizer-cpp/src/cpp/concrete-optimizer.hpp create mode 100644 concrete-optimizer-cpp/tests/src/main.cpp diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 942a02212..ff6ff7ece 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -32,8 +32,6 @@ jobs: - name: Formatting run: cargo fmt --check - # For some reason doing the build explicitely before make it available for both clippy and test - # But clippy and test alone do not share the build - name: Build run: cargo build --all-targets @@ -41,4 +39,6 @@ jobs: run: cargo clippy --all-targets - name: Tests - run: cargo test --no-fail-fast --all-targets + run: | + cargo test --no-fail-fast --all-targets + make -C concrete-optimizer-cpp test-ci diff --git a/Cargo.toml b/Cargo.toml index 92b1ccc7e..e15a6d47b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,5 +3,6 @@ members = [ "concrete-optimizer", "v0-parameters", + "concrete-optimizer-cpp" ] diff --git a/concrete-optimizer-cpp/.gitignore b/concrete-optimizer-cpp/.gitignore new file mode 100644 index 000000000..a1b91a125 --- /dev/null +++ b/concrete-optimizer-cpp/.gitignore @@ -0,0 +1 @@ +tests/tests_exe \ No newline at end of file diff --git a/concrete-optimizer-cpp/Cargo.toml b/concrete-optimizer-cpp/Cargo.toml new file mode 100644 index 000000000..4fc04c33c --- /dev/null +++ b/concrete-optimizer-cpp/Cargo.toml @@ -0,0 +1,17 @@ +[package] +# see https://doc.rust-lang.org/cargo/reference/manifest.html +name = "concrete-optimizer-cpp" +version = "0.1.0" +authors = [""] +edition = "2021" + +[dependencies] +cxx = "1.0" +concrete-optimizer = {path = "../concrete-optimizer" } + +[build-dependencies] +cxx-build = "1.0" + +[lib] +path = "src/concrete-optimizer.rs" +crate-type = ["staticlib"] diff --git a/concrete-optimizer-cpp/Makefile b/concrete-optimizer-cpp/Makefile new file mode 100644 index 000000000..b5c09c906 --- /dev/null +++ b/concrete-optimizer-cpp/Makefile @@ -0,0 +1,41 @@ +# dev or release +CARGO_PROFILE ?= release +# debug or release +PROFILE_SUBDIR ?= release + +ROOT = .. +TARGET_DIR = $(ROOT)/target +PROFILE_DIR = $(TARGET_DIR)/$(PROFILE_SUBDIR) +CXXBRIDGE_DIR = $(TARGET_DIR)/cxxbridge/concrete-optimizer-cpp/src + +INTERFACE_LIB = $(TARGET_DIR)/libconcrete_optimizer_cpp.a +INTERFACE_HEADER = src/cpp/concrete-optimizer.hpp +INTERFACE_CPP = src/cpp/concrete-optimizer.cpp +INTERFACE_SOURCES = $(INTERFACE_HEADER) $(INTERFACE_CPP) + +SOURCES = $(shell find $(ROOT)/concrete-optimizer/src) \ + $(shell find $(ROOT)/concrete-optimizer-cpp/src -name '*.rs') +TESTS_SOURCES = tests/src/main.cpp +TEST_DEP_LIBS = -l pthread -ldl + +$(INTERFACE_SOURCES) $(INTERFACE_LIB): $(SOURCES) + cd $(ROOT) && cargo build -p concrete-optimizer-cpp --profile $(CARGO_PROFILE) + cp $(CXXBRIDGE_DIR)/concrete-optimizer.rs.h $(INTERFACE_HEADER) + cp $(CXXBRIDGE_DIR)/concrete-optimizer.rs.cc $(INTERFACE_CPP) + cp $(PROFILE_DIR)/libconcrete_optimizer_cpp.a $(TARGET_DIR) + +tests/tests_exe: $(INTERFACE_SOURCES) $(INTERFACE_LIB) $(TESTS_SOURCES) + g++ -o $@ $(TESTS_SOURCES) $(INTERFACE_CPP) $(INTERFACE_LIB) -I $(shell dirname $(INTERFACE_HEADER)) $(TEST_DEP_LIBS) + chmod +x $@ + +build: $(INTERFACE_SOURCES) $(INTERFACE_LIB) + +test: tests/tests_exe + ./tests/tests_exe + +test-ci: + $(MAKE) CARGO_PROFILE=dev PROFILE_SUBDIR=debug test + git diff --check src/cpp || echo Please commit the new version of generated files + +clean: + rm -f $(INTERFACE_LIB) tests/tests_exe diff --git a/concrete-optimizer-cpp/build.rs b/concrete-optimizer-cpp/build.rs new file mode 100644 index 000000000..df7cae062 --- /dev/null +++ b/concrete-optimizer-cpp/build.rs @@ -0,0 +1,5 @@ +fn main() { + let _build = cxx_build::bridge("src/concrete-optimizer.rs"); + + println!("cargo:rerun-if-changed=src/lib.rs"); +} diff --git a/concrete-optimizer-cpp/cmake-utils/CMakeLists.txt b/concrete-optimizer-cpp/cmake-utils/CMakeLists.txt new file mode 100644 index 000000000..f62148553 --- /dev/null +++ b/concrete-optimizer-cpp/cmake-utils/CMakeLists.txt @@ -0,0 +1,16 @@ +# In your project CMakeLists.txt: +# 1. define the path containing concrete-optimizer repository, builded. +# CONCRETE_OPTIMIZER_DIR +# 2. add lines: +# add_subdirectory(${CONCRETE_OPTIMIZER_DIR}/concrete-optimizer-cpp/cmake-utils) +# include_directories(${CONCRETE_OPTIMIZER_DIR}/concrete-optimizer-cpp/src/cpp) + +add_library(concrete_optimizer STATIC ${CONCRETE_OPTIMIZER_DIR}/concrete-optimizer-cpp/src/cpp/concrete-optimizer.cpp) + +target_link_libraries(concrete_optimizer PRIVATE + pthread m dl + "${CONCRETE_OPTIMIZER_DIR}/target/libconcrete_optimizer_cpp.a" +) + +install(TARGETS concrete_optimizer EXPORT concrete_optimizer) +install(EXPORT concrete_optimizer DESTINATION "./") diff --git a/concrete-optimizer-cpp/src/concrete-optimizer.rs b/concrete-optimizer-cpp/src/concrete-optimizer.rs new file mode 100644 index 000000000..45c19226b --- /dev/null +++ b/concrete-optimizer-cpp/src/concrete-optimizer.rs @@ -0,0 +1,80 @@ +fn no_solution() -> ffi::Solution { + ffi::Solution { + p_error: 1.0, // error probability to signal an impossible solution + ..ffi::Solution::default() + } +} + +fn optimise_bootstrap( + precision: u64, + security_level: u64, + noise_factor: f64, + maximum_acceptable_error_probability: f64, +) -> ffi::Solution { + use concrete_optimizer::global_parameters::DEFAUT_DOMAINS; + let sum_size = 1; + let glwe_log_polynomial_sizes = DEFAUT_DOMAINS + .glwe_pbs_constrained + .log2_polynomial_size + .as_vec(); + let glwe_dimensions = DEFAUT_DOMAINS.glwe_pbs_constrained.glwe_dimension.as_vec(); + let internal_lwe_dimensions = DEFAUT_DOMAINS.free_glwe.glwe_dimension.as_vec(); + let result = concrete_optimizer::optimisation::atomic_pattern::optimise_one::( + sum_size, + precision, + security_level, + noise_factor, + maximum_acceptable_error_probability, + &glwe_log_polynomial_sizes, + &glwe_dimensions, + &internal_lwe_dimensions, + None, + ); + result.best_solution.map_or_else(no_solution, |a| a.into()) +} + +impl From for ffi::Solution { + fn from(a: concrete_optimizer::optimisation::atomic_pattern::Solution) -> Self { + Self { + input_lwe_dimension: a.input_lwe_dimension, + internal_ks_output_lwe_dimension: a.internal_ks_output_lwe_dimension, + ks_decomposition_level_count: a.ks_decomposition_level_count, + ks_decomposition_base_log: a.ks_decomposition_base_log, + glwe_polynomial_size: a.glwe_polynomial_size, + glwe_dimension: a.glwe_dimension, + br_decomposition_level_count: a.br_decomposition_level_count, + br_decomposition_base_log: a.br_decomposition_base_log, + complexity: a.complexity, + noise_max: a.noise_max, + p_error: a.p_error, + } + } +} + +#[cxx::bridge] +mod ffi { + #[namespace = "concrete_optimizer"] + extern "Rust" { + fn optimise_bootstrap( + precision: u64, + security_level: u64, + noise_factor: f64, + maximum_acceptable_error_probability: f64, + ) -> Solution; + } + + #[derive(Debug, Clone, Copy, Default)] + pub struct Solution { + pub input_lwe_dimension: u64, //n_big + pub internal_ks_output_lwe_dimension: u64, //n_small + pub ks_decomposition_level_count: u64, //l(KS) + pub ks_decomposition_base_log: u64, //b(KS) + pub glwe_polynomial_size: u64, //N + pub glwe_dimension: u64, //k + pub br_decomposition_level_count: u64, //l(BR) + pub br_decomposition_base_log: u64, //b(BR) + pub complexity: f64, + pub noise_max: f64, + pub p_error: f64, // error probability + } +} diff --git a/concrete-optimizer-cpp/src/cpp/concrete-optimizer.cpp b/concrete-optimizer-cpp/src/cpp/concrete-optimizer.cpp new file mode 100644 index 000000000..2babc5b13 --- /dev/null +++ b/concrete-optimizer-cpp/src/cpp/concrete-optimizer.cpp @@ -0,0 +1,33 @@ +#include +#include + +struct Solution; + +#ifndef CXXBRIDGE1_STRUCT_Solution +#define CXXBRIDGE1_STRUCT_Solution +struct Solution final { + ::std::uint64_t input_lwe_dimension; + ::std::uint64_t internal_ks_output_lwe_dimension; + ::std::uint64_t ks_decomposition_level_count; + ::std::uint64_t ks_decomposition_base_log; + ::std::uint64_t glwe_polynomial_size; + ::std::uint64_t glwe_dimension; + ::std::uint64_t br_decomposition_level_count; + ::std::uint64_t br_decomposition_base_log; + double complexity; + double noise_max; + double p_error; + + using IsRelocatable = ::std::true_type; +}; +#endif // CXXBRIDGE1_STRUCT_Solution + +namespace concrete_optimizer { +extern "C" { +::Solution concrete_optimizer$cxxbridge1$optimise_bootstrap(::std::uint64_t precision, ::std::uint64_t security_level, double noise_factor, double maximum_acceptable_error_probability) noexcept; +} // extern "C" + +::Solution optimise_bootstrap(::std::uint64_t precision, ::std::uint64_t security_level, double noise_factor, double maximum_acceptable_error_probability) noexcept { + return concrete_optimizer$cxxbridge1$optimise_bootstrap(precision, security_level, noise_factor, maximum_acceptable_error_probability); +} +} // namespace concrete_optimizer diff --git a/concrete-optimizer-cpp/src/cpp/concrete-optimizer.hpp b/concrete-optimizer-cpp/src/cpp/concrete-optimizer.hpp new file mode 100644 index 000000000..8157e8a35 --- /dev/null +++ b/concrete-optimizer-cpp/src/cpp/concrete-optimizer.hpp @@ -0,0 +1,28 @@ +#pragma once +#include +#include + +struct Solution; + +#ifndef CXXBRIDGE1_STRUCT_Solution +#define CXXBRIDGE1_STRUCT_Solution +struct Solution final { + ::std::uint64_t input_lwe_dimension; + ::std::uint64_t internal_ks_output_lwe_dimension; + ::std::uint64_t ks_decomposition_level_count; + ::std::uint64_t ks_decomposition_base_log; + ::std::uint64_t glwe_polynomial_size; + ::std::uint64_t glwe_dimension; + ::std::uint64_t br_decomposition_level_count; + ::std::uint64_t br_decomposition_base_log; + double complexity; + double noise_max; + double p_error; + + using IsRelocatable = ::std::true_type; +}; +#endif // CXXBRIDGE1_STRUCT_Solution + +namespace concrete_optimizer { +::Solution optimise_bootstrap(::std::uint64_t precision, ::std::uint64_t security_level, double noise_factor, double maximum_acceptable_error_probability) noexcept; +} // namespace concrete_optimizer diff --git a/concrete-optimizer-cpp/tests/src/main.cpp b/concrete-optimizer-cpp/tests/src/main.cpp new file mode 100644 index 000000000..cb9f32c76 --- /dev/null +++ b/concrete-optimizer-cpp/tests/src/main.cpp @@ -0,0 +1,11 @@ +#include "concrete-optimizer.hpp" + +int main(int argc, char *argv[]) { + auto solution = concrete_optimizer::optimise_bootstrap(1, 128, 1, .05); + + if (solution.glwe_polynomial_size != 1024) { + return 1; + } + + return 0; +} diff --git a/concrete-optimizer/Cargo.toml b/concrete-optimizer/Cargo.toml index 6fb7f1cf1..93480e7bc 100644 --- a/concrete-optimizer/Cargo.toml +++ b/concrete-optimizer/Cargo.toml @@ -14,7 +14,7 @@ statrs = "0.15.0" approx = "0.5" [build-dependencies] -cbindgen = "0.20.0" +cbindgen = "0.23.0" [lib] crate-type= [ diff --git a/concrete-optimizer/src/graph/unparametrized.rs b/concrete-optimizer/src/graph/unparametrized.rs index b9752ea27..4f70cfcc5 100644 --- a/concrete-optimizer/src/graph/unparametrized.rs +++ b/concrete-optimizer/src/graph/unparametrized.rs @@ -40,6 +40,11 @@ impl AtomicPatternDag { extra_data: (), }) } + + #[allow(clippy::len_without_is_empty)] + pub fn len(&self) -> usize { + self.operators.len() + } } #[cfg(test)] diff --git a/concrete-optimizer/src/weight.rs b/concrete-optimizer/src/weight.rs index 1ac9abdaf..ef6272115 100644 --- a/concrete-optimizer/src/weight.rs +++ b/concrete-optimizer/src/weight.rs @@ -1,2 +1,2 @@ #[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub struct Weight(pub(crate) u32); +pub struct Weight(pub u64);