Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
66 changes: 57 additions & 9 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,52 @@ version: 2.1
# See https://circleci.com/docs/reusing-config/
commands:

# Build SDPB locally, using homebrew package manager (used for MacOS)
# NB: this step takes much longer than Docker since one has to
# build Elemental and other dependencies!
native-brew-build-test:
description: Build and test SDPB natively, installing dependencies via homebrew
steps:
- checkout
- run:
name: Install dependencies via Homebrew
command: |
export HOMEBREW_NO_INSTALL_CLEANUP=1
export HOMEBREW_NO_ANALYTICS=1
brew install gmp mpfr boost rapidjson libarchive openblas flint cmake open-mpi metis automake libtool pkgconf bison
- run:
name: Install Elemental
command: |
git clone https://gitlab.com/bootstrapcollaboration/elemental.git
cd elemental
mkdir build
cd build
cmake .. -DCMAKE_INSTALL_PREFIX=$HOME/install -DCMAKE_CXX_COMPILER=mpicxx -DCMAKE_C_COMPILER=mpicc
make && make install
cd ../..
- run:
name: Install MPSolve
command: |
git clone https://github.com/robol/MPSolve.git
cd MPSolve
./autogen.sh
CC=mpicc CXX=mpicxx LDFLAGS="-L$(brew --prefix gmp)/lib" CPPFLAGS="-I$(brew --prefix gmp)/include" YACC=$(brew --prefix bison)/bin/yacc ./configure --prefix=$HOME/install --disable-dependency-tracking --disable-examples --disable-ui --disable-graphical-debugger --disable-documentation
make && make install
cd ..
- run:
name: Build SDPB
command: |
CXXFLAGS="${CXXFLAGS} -D_GNU_SOURCE=1" ./waf configure --elemental-dir=$HOME/install --mpsolve-dir=$HOME/install --boost-dir=$(brew --prefix boost) --gmpxx-dir=$(brew --prefix gmp) --mpfr-dir=$(brew --prefix mpfr) --rapidjson-dir=$(brew --prefix rapidjson) --libarchive-dir=$(brew --prefix libarchive) --flint-dir=$(brew --prefix flint) --cblas-dir=$(brew --prefix openblas) --prefix=$HOME/install/sdpb/master
./waf
./build/sdpb --help
- run:
name: Run tests
command: ./test/run_all_tests.sh
- run:
name: Install
command: ./waf install


docker-build-test:
description: Build and test Docker image for platform
parameters:
Expand Down Expand Up @@ -144,15 +190,12 @@ jobs:
platform: linux/arm64
tag: arm64

# TODO MacOS M1 will be available on free plan after 24 Jun 2024
# build-macos-m1:
# macos:
# xcode: 15.3.0
# resource_class: macos.m1.medium.gen1
# steps:
# - docker-build-test:
# platform: linux/arm64
# tag: arm64
build-test-macos:
macos:
xcode: 26.1.1
resource_class: m4pro.medium
steps:
- native-brew-build-test

# Test deploy process for local registry
# TODO:docker manifest push works for DockerHub, but fails for local registry.
Expand Down Expand Up @@ -200,6 +243,11 @@ workflows:
tags:
only: /^\d+\.\d+\.\d+$/

- build-test-macos:
filters:
tags:
only: /^\d+\.\d+\.\d+$/

- deploy-master:
filters:
branches:
Expand Down
10 changes: 5 additions & 5 deletions docs/site_installs/Apple_MacBook.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ to path following instructions shown after installing.

Then you can install packages required for SDPB:

brew install gmp mpfr boost rapidjson libarchive openblas flint cmake open-mpi
brew install gmp mpfr boost rapidjson libarchive openblas flint cmake open-mpi metis automake libtool pkgconf bison

You can see installation directory and another information for a package (e.g. `boost`)
by calling `brew info <package>` (e.g. `brew info boost`).
Expand Down Expand Up @@ -42,7 +42,7 @@ On other laptops, Python 2 fails instead, so that one has to call `python3 ./waf
git clone https://github.com/robol/MPSolve.git
cd MPSolve
./autogen.sh
CC=mpicc CXX=mpicxx ./configure --prefix=$HOME/install --disable-dependency-tracking --disable-examples --disable-ui --disable-graphical-debugger --disable-documentation
CC=mpicc CXX=mpicxx LDFLAGS="-L$(brew --prefix gmp)/lib" CPPFLAGS="-I$(brew --prefix gmp)/include" YACC=$(brew --prefix bison)/bin/yacc ./configure --prefix=$HOME/install --disable-dependency-tracking --disable-examples --disable-ui --disable-graphical-debugger --disable-documentation
make && make install
cd ..

Expand All @@ -54,7 +54,7 @@ On other laptops, Python 2 fails instead, so that one has to call `python3 ./waf

### Configure

CXXFLAGS="${CXXFLAGS} -D_GNU_SOURCE=1" ./waf configure --elemental-dir=$HOME/install --mpsolve-dir=$HOME/install --boost-dir=/opt/homebrew/Cellar/boost/1.84.0_1 --gmpxx-dir=/opt/homebrew/Cellar/gmp/6.3.0 --mpfr-dir=/opt/homebrew/Cellar/mpfr/4.2.1 --rapidjson-dir=/opt/homebrew/Cellar/rapidjson/1.1.0 --libarchive-dir=/opt/homebrew/Cellar/libarchive/3.7.3 --flint-dir=/opt/homebrew/Cellar/flint/3.1.0 --cblas-dir=/opt/homebrew/Cellar/openblas/0.3.27 --prefix=$HOME/install/sdpb-master
CXXFLAGS="${CXXFLAGS} -D_GNU_SOURCE=1" ./waf configure --elemental-dir=$HOME/install --mpsolve-dir=$HOME/install --boost-dir=$(brew --prefix boost) --gmpxx-dir=$(brew --prefix gmp) --mpfr-dir=$(brew --prefix mpfr) --rapidjson-dir=$(brew --prefix rapidjson) --libarchive-dir=$(brew --prefix libarchive) --flint-dir=$(brew --prefix flint) --cblas-dir=$(brew --prefix openblas) --prefix=$HOME/install/sdpb/master

If waf fails to find some package, e.g. `boost`, check the installation directory by calling, e.g. `brew info boost` and
update `--boost-dir` argument above.
Expand All @@ -63,11 +63,11 @@ The above `./waf configure` command works or x86 processors (e.g. Intel i5), but
M2) with linker warnings `found architecture 'arm64', required architecture 'x86_64` in `build/config.log`.
In that case, you should set `-arch arm64` flag explicitly:

CXXFLAGS="${CXXFLAGS} -D_GNU_SOURCE=1 -arch arm64" LDFLAGS="${LDFLAGS} -arch arm64" ./waf configure --elemental-dir=$HOME/install --mpsolve-dir=$HOME/install --boost-dir=/opt/homebrew/Cellar/boost/1.84.0_1 --gmpxx-dir=/opt/homebrew/Cellar/gmp/6.3.0 --mpfr-dir=/opt/homebrew/Cellar/mpfr/4.2.1 --rapidjson-dir=/opt/homebrew/Cellar/rapidjson/1.1.0 --libarchive-dir=/opt/homebrew/Cellar/libarchive/3.7.3 --flint-dir=/opt/homebrew/Cellar/flint/3.1.0 --cblas-dir=/opt/homebrew/Cellar/openblas/0.3.27 --prefix=$HOME/install/sdpb-master
CXXFLAGS="${CXXFLAGS} -D_GNU_SOURCE=1 -arch arm64" LDFLAGS="${LDFLAGS} -arch arm64" ./waf configure --elemental-dir=$HOME/install --mpsolve-dir=$HOME/install --boost-dir=$(brew --prefix boost) --gmpxx-dir=$(brew --prefix gmp) --mpfr-dir=$(brew --prefix mpfr) --rapidjson-dir=$(brew --prefix rapidjson) --libarchive-dir=$(brew --prefix libarchive) --flint-dir=$(brew --prefix flint) --cblas-dir=$(brew --prefix openblas) --prefix=$HOME/install/sdpb/master

### Compile and install

./waf # build binaries
./build/sdpb --help # run SDPB binary
./test/run_all_tests.sh # run tests to check correctness
./waf install # install sdpb to --prefix=$HOME/install/sdpb-master
./waf install # install sdpb to --prefix=$HOME/install/sdpb/master
90 changes: 46 additions & 44 deletions test/src/integration_tests/cases/end-to-end.test.cxx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include "integration_tests/common.hxx"

#include <boost/program_options/parsers.hpp>

// Realistic end-to-end test for pmp2sdp + sdpb
// JSON input taken from "SingletScalar_cT_test_nmax6" and
// "SingletScalarAllowed_test_nmax6"
Expand All @@ -22,7 +24,7 @@ namespace
int num_procs = 6;
int precision = 768;
Named_Args_Map pmp2sdp_args;
std::string default_sdpb_args;
std::vector<std::string> default_sdpb_args;
std::vector<std::string> sdpb_out_filenames;
std::vector<std::string> sdpb_out_txt_keys;
bool check_sdp = true;
Expand Down Expand Up @@ -92,7 +94,7 @@ namespace
{"--output", sdp_path},
{"--precision", std::to_string(precision)}});

runner.create_nested("pmp2sdp").mpi_run({"build/pmp2sdp"}, args,
runner.create_nested("pmp2sdp").mpi_run({"build/pmp2sdp", args},
num_procs);

if(check_sdp)
Expand All @@ -115,17 +117,17 @@ namespace
{"--outDir", (output_dir / "out").string()},
{"--checkpointDir", (output_dir / "ck").string()}};
runner.create_nested("sdpb").mpi_run(
{"build/sdpb", default_sdpb_args}, args, num_procs);
{"build/sdpb", default_sdpb_args, args}, num_procs);
if(run_sdpb_twice)
{
runner.create_nested("sdpb-2").mpi_run(
{"build/sdpb", default_sdpb_args}, args, num_procs);
{"build/sdpb", default_sdpb_args, args}, num_procs);
}

// Read c,B,y and check that (c - B.y) equals to the vector written to c_minus_By/c_minus_By.json
check_c_minus_By(sdp_path, output_dir / "out", precision,
diff_precision,
runner.create_nested("check_c_minus_By"));
// Read c,B,y and check that (c - B.y) equals to the vector written to c_minus_By/c_minus_By.json
check_c_minus_By(sdp_path, output_dir / "out", precision,
diff_precision,
runner.create_nested("check_c_minus_By"));

// SDPB runs with --precision=<precision>
// We check test output up to lower precision=<sdpb_output_diff_precision>
Expand All @@ -146,7 +148,7 @@ namespace
{"--verbosity", "debug"},
};
runner.create_nested("spectrum")
.mpi_run({"build/spectrum"}, args, num_procs);
.mpi_run({"build/spectrum", args}, num_procs);

// Cannot check block paths if the same spectrum.json
// is generated several times by different PMP inputs,
Expand Down Expand Up @@ -240,14 +242,14 @@ TEST_CASE("end-to-end_tests")
INFO("Spectrum should find isolated zero for the last block "
"(corresponding to x=4/3).");
End_To_End_Test test("1d-isolated-zeros");
test.default_sdpb_args
= "--checkpointInterval 3600 --maxRuntime 1340 "
"--dualityGapThreshold 1.0e-30 --primalErrorThreshold 1.0e-30 "
"--dualErrorThreshold 1.0e-30 --initialMatrixScalePrimal 1.0e20 "
"--initialMatrixScaleDual 1.0e20 --feasibleCenteringParameter 0.1 "
"--infeasibleCenteringParameter 0.3 --stepLengthReduction 0.7 "
"--maxComplementarity 1.0e100 --maxIterations 1000 --verbosity 1 "
"--procGranularity 1 --writeSolution x,y";
test.default_sdpb_args = boost::program_options::split_unix(
"--checkpointInterval 3600 --maxRuntime 1340 "
"--dualityGapThreshold 1.0e-30 --primalErrorThreshold 1.0e-30 "
"--dualErrorThreshold 1.0e-30 --initialMatrixScalePrimal 1.0e20 "
"--initialMatrixScaleDual 1.0e20 --feasibleCenteringParameter 0.1 "
"--infeasibleCenteringParameter 0.3 --stepLengthReduction 0.7 "
"--maxComplementarity 1.0e100 --maxIterations 1000 --verbosity 1 "
"--procGranularity 1 --writeSolution x,y");
test.num_procs = 1;
test.check_sdp = false;
// Write SDP to zip archive to test that spectrum can read sdp.zip/pmp_info.json
Expand All @@ -262,15 +264,15 @@ TEST_CASE("end-to-end_tests")
"which caused a bug.");
INFO("Test data from Harvard cluster, gmp/6.2.1 mpfr/4.2.0");
End_To_End_Test test("dfibo-0-0-j=3-c=3.0000-d=3-s=6");
test.default_sdpb_args
= "--findDualFeasible --findPrimalFeasible "
"--initialMatrixScalePrimal 1e10 --initialMatrixScaleDual 1e10 "
"--maxComplementarity 1e30 --dualErrorThreshold 1e-10 "
"--primalErrorThreshold 1e-153 --maxRuntime 259200 "
"--checkpointInterval 3600 --maxIterations 1000 "
"--feasibleCenteringParameter=0.1 --infeasibleCenteringParameter=0.3 "
"--stepLengthReduction=0.7 "
"--maxSharedMemory=100K"; // forces split_factor=3 for Q window
test.default_sdpb_args = boost::program_options::split_unix(
"--findDualFeasible --findPrimalFeasible "
"--initialMatrixScalePrimal 1e10 --initialMatrixScaleDual 1e10 "
"--maxComplementarity 1e30 --dualErrorThreshold 1e-10 "
"--primalErrorThreshold 1e-153 --maxRuntime 259200 "
"--checkpointInterval 3600 --maxIterations 1000 "
"--feasibleCenteringParameter=0.1 --infeasibleCenteringParameter=0.3 "
"--stepLengthReduction=0.7 "
"--maxSharedMemory=100K"); // forces split_factor=3 for Q window
for(std::string sdp_format : {"", "bin", "json"})
{
DYNAMIC_SECTION(
Expand All @@ -291,14 +293,14 @@ TEST_CASE("end-to-end_tests")
"Scalars3d/SingletScalar2020.hs");
INFO("Test data is generated with SDPB 2.5.1 on Caltech cluster.");
INFO("SDPB should find primal-dual optimal solution.");
std::string default_sdpb_args
= "--checkpointInterval 3600 --maxRuntime 1340 "
"--dualityGapThreshold 1.0e-30 --primalErrorThreshold 1.0e-30 "
"--dualErrorThreshold 1.0e-30 --initialMatrixScalePrimal 1.0e20 "
"--initialMatrixScaleDual 1.0e20 --feasibleCenteringParameter 0.1 "
"--infeasibleCenteringParameter 0.3 --stepLengthReduction 0.7 "
"--maxComplementarity 1.0e100 --maxIterations 1000 --verbosity 2 "
"--procGranularity 1 --writeSolution x,y,z";
auto default_sdpb_args = boost::program_options::split_unix(
"--checkpointInterval 3600 --maxRuntime 1340 "
"--dualityGapThreshold 1.0e-30 --primalErrorThreshold 1.0e-30 "
"--dualErrorThreshold 1.0e-30 --initialMatrixScalePrimal 1.0e20 "
"--initialMatrixScaleDual 1.0e20 --feasibleCenteringParameter 0.1 "
"--infeasibleCenteringParameter 0.3 --stepLengthReduction 0.7 "
"--maxComplementarity 1.0e100 --maxIterations 1000 --verbosity 2 "
"--procGranularity 1 --writeSolution x,y,z");
SECTION("primal_dual_optimal")
{
End_To_End_Test test("SingletScalar_cT_test_nmax6/primal_dual_optimal");
Expand Down Expand Up @@ -330,16 +332,16 @@ TEST_CASE("end-to-end_tests")
"Scalars3d/SingletScalar2020.hs");
INFO("Test data is generated with SDPB 2.5.1 on Caltech cluster.");
std::string name = "SingletScalarAllowed_test_nmax6";
std::string default_sdpb_args
= "--checkpointInterval 3600 --maxRuntime 1341 "
"--dualityGapThreshold 1.0e-30 --primalErrorThreshold 1.0e-200 "
"--dualErrorThreshold 1.0e-200 --initialMatrixScalePrimal 1.0e20 "
"--initialMatrixScaleDual 1.0e20 --feasibleCenteringParameter 0.1 "
"--infeasibleCenteringParameter 0.3 --stepLengthReduction 0.7 "
"--maxComplementarity 1.0e100 --maxIterations 1000 --verbosity 2 "
"--procGranularity 1 --writeSolution y,z "
"--detectPrimalFeasibleJump --detectDualFeasibleJump "
"--maxSharedMemory=100.1K"; // forces split_factor=3 for Q window; also test floating-point --maxSharedMemory value
auto default_sdpb_args = boost::program_options::split_unix(
"--checkpointInterval 3600 --maxRuntime 1341 "
"--dualityGapThreshold 1.0e-30 --primalErrorThreshold 1.0e-200 "
"--dualErrorThreshold 1.0e-200 --initialMatrixScalePrimal 1.0e20 "
"--initialMatrixScaleDual 1.0e20 --feasibleCenteringParameter 0.1 "
"--infeasibleCenteringParameter 0.3 --stepLengthReduction 0.7 "
"--maxComplementarity 1.0e100 --maxIterations 1000 --verbosity 2 "
"--procGranularity 1 --writeSolution y,z "
"--detectPrimalFeasibleJump --detectDualFeasibleJump "
"--maxSharedMemory=100.1K"); // forces split_factor=3 for Q window; also test floating-point --maxSharedMemory value

SECTION("primal_feasible_jump")
{
Expand Down
6 changes: 3 additions & 3 deletions test/src/integration_tests/cases/outer_limits.test.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ TEST_CASE("outer_limits")

// TODO allow running pmp2functions in parallel
runner.create_nested("pmp2functions")
.run({"build/pmp2functions", std::to_string(precision), pmp_json,
functions_json});
.run({"build/pmp2functions",
{std::to_string(precision), pmp_json, functions_json}});
Test_Util::REQUIRE_Equal::diff_functions_json(
functions_json, functions_orig_json, precision, precision / 2);
}
Expand All @@ -54,7 +54,7 @@ TEST_CASE("outer_limits")
{
INFO("run outer_limits");
runner.create_nested("outer_limits")
.mpi_run({"build/outer_limits"}, args, num_procs);
.mpi_run({"build/outer_limits", args}, num_procs);

auto out_orig_json = data_dir / "out_orig.json";
Test_Util::REQUIRE_Equal::diff_outer_limits(out_json, out_orig_json,
Expand Down
16 changes: 8 additions & 8 deletions test/src/integration_tests/cases/pmp2sdp.test.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ TEST_CASE("pmp2sdp")
auto sdp_path = (runner.output_dir / "sdp").string();
args["--output"] = sdp_path;

runner.create_nested("run").mpi_run({"build/pmp2sdp"}, args);
runner.create_nested("run").mpi_run({"build/pmp2sdp", args});

Test_Util::REQUIRE_Equal::diff_sdp(sdp_path, sdp_orig, precision,
diff_precision,
Expand Down Expand Up @@ -69,7 +69,7 @@ TEST_CASE("pmp2sdp")
args["--output"] = sdp_path.string();
if(!output_format.empty())
args["--outputFormat"] = output_format;
runner.create_nested("run").mpi_run({"build/pmp2sdp"}, args);
runner.create_nested("run").mpi_run({"build/pmp2sdp", args});

{
INFO("Check that pmp2sdp actually uses --outputFormat="
Expand Down Expand Up @@ -117,7 +117,7 @@ TEST_CASE("pmp2sdp")
args["--input"] = input;
args["--output"] = sdp_dir.string();
// We allow pmp2sdp to overwrite exsiting sdp_temp
runner.mpi_run({"build/pmp2sdp"}, args, num_procs, 0,
runner.mpi_run({"build/pmp2sdp", args}, num_procs, 0,
"exists and will be overwritten");
}
SECTION("sdp_dir_exists")
Expand All @@ -137,7 +137,7 @@ TEST_CASE("pmp2sdp")
args["--input"] = input;
args["--output"] = sdp_dir.string();
// We allow pmp2sdp to overwrite exsiting sdp
runner.mpi_run({"build/pmp2sdp"}, args, num_procs, 0,
runner.mpi_run({"build/pmp2sdp", args}, num_procs, 0,
"exists and will be overwritten");
}

Expand All @@ -158,7 +158,7 @@ TEST_CASE("pmp2sdp")
args["--output"] = sdp_readonly_zip.string();
args["--zip"] = "";
// We allow pmp2sdp to overwrite exsiting sdp
runner.mpi_run({"build/pmp2sdp"}, args, num_procs, 0,
runner.mpi_run({"build/pmp2sdp", args}, num_procs, 0,
"exists and will be overwritten");
}

Expand All @@ -180,7 +180,7 @@ TEST_CASE("pmp2sdp")
args["--output"] = sdp_path;

auto sdp_invalid_zip = (runner.output_dir / "sdp.invalid.zip").string();
runner.mpi_run({"build/pmp2sdp"}, args, num_procs, 1, "No such file");
runner.mpi_run({"build/pmp2sdp", args}, num_procs, 1, "No such file");
}
}

Expand All @@ -207,7 +207,7 @@ TEST_CASE("pmp2sdp")
auto sdp_path = (runner.output_dir / "sdp").string();
args["--output"] = sdp_path;

runner.create_nested("run").mpi_run({"build/pmp2sdp"}, args, num_procs);
runner.create_nested("run").mpi_run({"build/pmp2sdp", args}, num_procs);

auto sdp_orig = Test_Config::test_data_dir / "end-to-end_tests"
/ "1d-constraints" / "output" / "sdp";
Expand Down Expand Up @@ -235,7 +235,7 @@ TEST_CASE("pmp2sdp")
args["--input"] = input_nsv;
auto sdp_path = (runner.output_dir / "sdp").string();
args["--output"] = sdp_path;
runner.mpi_run({"build/pmp2sdp"}, args, num_procs, 1,
runner.mpi_run({"build/pmp2sdp", args}, num_procs, 1,
"Found different objective vectors in input files:");
}
}
Expand Down
Loading