Skip to content

Commit 0b35be3

Browse files
authored
Merge pull request #2 from liamjdavis/mamba-conda-env
Micromamba/Conda environment for Dependencies
2 parents d43163f + d00ac92 commit 0b35be3

9 files changed

Lines changed: 100 additions & 122 deletions

File tree

.github/workflows/ci.yml

Lines changed: 17 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ on:
3131

3232
defaults:
3333
run:
34-
shell: sh
34+
shell: bash -el {0}
3535

3636
jobs:
3737
build:
@@ -51,38 +51,31 @@ jobs:
5151
steps:
5252
- uses: actions/checkout@v4
5353

54-
- uses: actions/setup-python@v5
54+
- uses: mamba-org/setup-micromamba@v2
5555
with:
56-
python-version: "3.9"
56+
environment-file: environment.yml
57+
environment-name: marabou
58+
cache-environment: true
59+
init-shell: bash
60+
post-cleanup: none
5761

58-
- name: Install system packages
62+
- name: Install system build tools
5963
if: runner.os == 'Linux'
6064
run: |
6165
sudo apt-get update -y
62-
sudo apt-get install -y \
63-
build-essential \
64-
ccache \
65-
cmake \
66-
cxxtest \
67-
protobuf-compiler \
68-
libprotoc-dev
69-
70-
- name: Install system packages
66+
sudo apt-get install -y build-essential ccache
67+
68+
- name: Install system build tools
7169
if: runner.os == 'macOS'
72-
run: |
73-
brew install \
74-
ccache \
75-
cmake \
76-
cxxtest \
77-
protobuf-c
70+
run: brew install ccache
7871

7972
- name: Install Python packages
8073
run: |
81-
python -m pip install --user --upgrade pip
82-
python -m pip install --user --upgrade setuptools
83-
python -m pip install --user wheel
84-
python -m pip install --user bumpver
85-
python -m pip install --user -r maraboupy/test_requirements.txt --cache-dir $HOME/.pip-cache
74+
python -m pip install --upgrade pip
75+
python -m pip install --upgrade setuptools
76+
python -m pip install wheel
77+
python -m pip install bumpver
78+
python -m pip install -r maraboupy/test_requirements.txt --cache-dir $HOME/.pip-cache
8679
echo "/usr/lib/ccache" >> $GITHUB_PATH
8780
8881
- name: Test BumpVer Configuration
@@ -120,13 +113,7 @@ jobs:
120113
ccache -z
121114
122115
- name: Configure CMake
123-
# Use a bash shell so we can use the same syntax for environment variable bb
124-
# access regardless of the host operating system
125-
shell: bash
126116
working-directory: build
127-
# Note the current convention is to use the -S and -B options here to specify source
128-
# and build directories, but this is only available with CMake 3.13 and higher.
129-
# The CMake binaries on the Github Actions machines are (as of this writing) 3.12
130117
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DBUILD_PYTHON=ON -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER=${{ matrix.compiler }}
131118

132119
- name: Build

CMakeLists.txt

Lines changed: 23 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,18 @@ execute_process(
4646
)
4747
add_definitions("-DGIT_COMMIT_HASH=\"${GIT_COMMIT_HASH}\"")
4848

49+
############################
50+
## Conda env detection ##
51+
############################
52+
53+
if(DEFINED ENV{CONDA_PREFIX} AND NOT DEFINED ENV{CONDA_BUILD})
54+
list(INSERT CMAKE_PREFIX_PATH 0 "$ENV{CONDA_PREFIX}")
55+
message(STATUS "Conda environment detected: $ENV{CONDA_PREFIX}")
56+
elseif(DEFINED ENV{CONDA_BUILD})
57+
list(INSERT CMAKE_PREFIX_PATH 0 "$ENV{PREFIX}" "$ENV{BUILD_PREFIX}")
58+
message(STATUS "Conda build environment detected")
59+
endif()
60+
4961
#########################
5062
## Basic configuration ##
5163
#########################
@@ -80,56 +92,17 @@ include_directories(SYSTEM ${CVC4_DIR} ${CVC4_DIR}/include)
8092
## Boost ##
8193
###########
8294

83-
# Avoid using deprecated operations
8495
add_definitions(-DBOOST_NO_CXX98_FUNCTION_BASE)
85-
set(BOOST_VERSION 1.84.0)
86-
set(BOOST_DIR "${TOOLS_DIR}/boost-${BOOST_VERSION}")
87-
if (MSVC)
88-
set(BOOST_ROOT "${BOOST_DIR}/win_installed")
89-
set(Boost_NAMESPACE libboost)
90-
elseif (${CMAKE_SIZEOF_VOID_P} EQUAL 4 AND NOT MSVC)
91-
set(BOOST_ROOT "${BOOST_DIR}/installed32")
92-
else()
93-
set(BOOST_ROOT "${BOOST_DIR}/installed")
94-
endif()
95-
96-
set(Boost_USE_DEBUG_RUNTIME FALSE)
97-
find_package(Boost ${BOOST_VERSION} COMPONENTS program_options timer chrono thread)
98-
# Find boost
99-
if (NOT ${Boost_FOUND})
100-
execute_process(COMMAND ${TOOLS_DIR}/download_boost.${SCRIPT_EXTENSION} ${BOOST_VERSION})
101-
find_package(Boost ${BOOST_VERSION} REQUIRED COMPONENTS program_options timer chrono thread regex)
102-
endif()
96+
find_package(Boost 1.84.0 REQUIRED COMPONENTS program_options timer chrono thread)
10397
set(LIBS_INCLUDES ${Boost_INCLUDE_DIRS})
10498
list(APPEND LIBS ${Boost_LIBRARIES})
10599

106100
##############
107101
## Protobuf ##
108102
##############
109-
# Protobuf is needed to compile ONNX
110103

111-
set(PROTOBUF_VERSION 3.19.2)
112-
set(PROTOBUF_DEFAULT_DIR "${TOOLS_DIR}/protobuf-${PROTOBUF_VERSION}")
113-
if (NOT PROTOBUF_DIR)
114-
set(PROTOBUF_DIR ${PROTOBUF_DEFAULT_DIR})
115-
endif()
116-
117-
if(NOT EXISTS "${PROTOBUF_DIR}/installed/lib/libprotobuf.a")
118-
message("Can't find protobuf, installing. If protobuf is installed please use the PROTOBUF_DIR parameter to pass the path")
119-
if (${PROTOBUF_DIR} STREQUAL ${PROTOBUF_DEFAULT_DIR})
120-
message("installing protobuf")
121-
execute_process(COMMAND ${TOOLS_DIR}/download_protobuf.sh ${PROTOBUF_VERSION})
122-
else()
123-
message(FATAL_ERROR "Can't find protobuf in the supplied directory")
124-
endif()
125-
endif()
126-
127-
set(PROTOBUF_LIB protobuf)
128-
add_library(${PROTOBUF_LIB} SHARED IMPORTED)
129-
set_property(TARGET ${PROTOBUF_LIB} PROPERTY POSITION_INDEPENDENT_CODE ON)
130-
set_target_properties(${PROTOBUF_LIB} PROPERTIES IMPORTED_LOCATION ${PROTOBUF_DIR}/installed/lib/libprotobuf.a)
131-
target_include_directories(${PROTOBUF_LIB} INTERFACE ${PROTOBUF_DIR}/installed/include)
132-
list(APPEND LIBS ${PROTOBUF_LIB})
104+
find_package(Protobuf 3.19.2 REQUIRED)
105+
list(APPEND LIBS protobuf::libprotobuf)
133106

134107
##########
135108
## ONNX ##
@@ -141,7 +114,7 @@ set(ONNX_DIR "${TOOLS_DIR}/onnx-${ONNX_VERSION}")
141114

142115
if(NOT EXISTS "${ONNX_DIR}/onnx.proto3.pb.h")
143116
message("generating ONNX protobuf file")
144-
execute_process(COMMAND ${TOOLS_DIR}/download_onnx.sh ${ONNX_VERSION} ${PROTOBUF_VERSION})
117+
execute_process(COMMAND ${TOOLS_DIR}/download_onnx.sh ${ONNX_VERSION} ${Protobuf_PROTOC_EXECUTABLE})
145118
endif()
146119
file(GLOB DEPS_ONNX "${ONNX_DIR}/*.cc")
147120
include_directories(SYSTEM ${ONNX_DIR})
@@ -183,30 +156,15 @@ endif()
183156
##############
184157

185158
if (NOT MSVC AND ${ENABLE_OPENBLAS})
186-
set(OPENBLAS_VERSION 0.3.19)
187-
188-
set(OPENBLAS_LIB openblas)
189-
set(OPENBLAS_DEFAULT_DIR "${TOOLS_DIR}/OpenBLAS-${OPENBLAS_VERSION}")
190-
if (NOT OPENBLAS_DIR)
191-
set(OPENBLAS_DIR ${OPENBLAS_DEFAULT_DIR})
192-
endif()
193-
194159
message(STATUS "Using OpenBLAS for matrix multiplication")
195160
add_compile_definitions(ENABLE_OPENBLAS)
196-
if(NOT EXISTS "${OPENBLAS_DIR}/installed/lib/libopenblas.a")
197-
message("Can't find OpenBLAS, installing. If OpenBLAS is installed please use the OPENBLAS_DIR parameter to pass the path")
198-
if (${OPENBLAS_DIR} STREQUAL ${OPENBLAS_DEFAULT_DIR})
199-
message("Installing OpenBLAS")
200-
execute_process(COMMAND ${TOOLS_DIR}/download_openBLAS.sh ${OPENBLAS_VERSION})
201-
else()
202-
message(FATAL_ERROR "Can't find OpenBLAS in the supplied directory")
203-
endif()
161+
find_library(OPENBLAS_LIB openblas REQUIRED)
162+
find_path(OPENBLAS_INCLUDE_DIR openblas_config.h PATH_SUFFIXES openblas)
163+
if (NOT OPENBLAS_INCLUDE_DIR)
164+
message(FATAL_ERROR "Could not find OpenBLAS headers (openblas_config.h)")
204165
endif()
205-
206-
add_library(${OPENBLAS_LIB} SHARED IMPORTED)
207-
set_target_properties(${OPENBLAS_LIB} PROPERTIES IMPORTED_LOCATION ${OPENBLAS_DIR}/installed/lib/libopenblas.a)
208166
list(APPEND LIBS ${OPENBLAS_LIB})
209-
target_include_directories(${OPENBLAS_LIB} INTERFACE ${OPENBLAS_DIR}/installed/include)
167+
list(APPEND LIBS_INCLUDES ${OPENBLAS_INCLUDE_DIR})
210168
endif()
211169

212170
###########
@@ -370,9 +328,6 @@ endif()
370328

371329
# Actually build Python
372330
if (${BUILD_PYTHON})
373-
set(PYBIND11_VERSION 2.13.6)
374-
set(PYBIND11_DIR "${TOOLS_DIR}/pybind11-${PYBIND11_VERSION}")
375-
376331
# This is suppose to set the PYTHON_EXECUTABLE variable
377332
# First try to find the default python version
378333
find_package(PythonInterp ${DEFAULT_PYTHON_VERSION})
@@ -381,11 +336,7 @@ if (${BUILD_PYTHON})
381336
find_package(PythonInterp REQUIRED)
382337
endif()
383338

384-
if (NOT EXISTS ${PYBIND11_DIR})
385-
message("didnt find pybind, getting it")
386-
execute_process(COMMAND ${TOOLS_DIR}/download_pybind11.${SCRIPT_EXTENSION} ${PYBIND11_VERSION})
387-
endif()
388-
add_subdirectory(${PYBIND11_DIR})
339+
find_package(pybind11 REQUIRED)
389340

390341
set(MARABOU_PY MarabouCore)
391342
pybind11_add_module(${MARABOU_PY} ${PYTHON_API_DIR}/MarabouCore.cpp)
@@ -479,6 +430,6 @@ add_custom_target(build_input_parsers)
479430
add_dependencies(build_input_parsers ${MPS_PARSER} ${ACAS_PARSER}
480431
${BERKELEY_PARSER})
481432

482-
add_subdirectory(${SRC_DIR})
483433
add_subdirectory(${TOOLS_DIR})
434+
add_subdirectory(${SRC_DIR})
484435
add_subdirectory(${REGRESS_DIR})

README.md

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,24 @@ The Python interface currently supports Python 3.8, 3.9, 3.10 and 3.11.
4242

4343
#### Build dependencies
4444

45-
The build process uses CMake version 3.16 (or later).
46-
You can get CMake [here](https://cmake.org/download/).
45+
Marabou uses a conda environment to manage its build dependencies
46+
(Boost, Protobuf, OpenBLAS, pybind11, CMake, Python, etc.).
47+
CxxTest is bundled in `tools/` and built automatically.
4748

48-
Marabou depends on the Boost and the OpenBLAS libraries, which are automatically
49-
downloaded and built when you run make. Library CXXTEST comes included in the
50-
repository.
49+
Using [conda/anaconda](https://docs.conda.io/en/latest/):
50+
```bash
51+
conda env create -f environment.yml
52+
conda activate marabou
53+
```
54+
55+
Using [micromamba](https://mamba.readthedocs.io/en/latest/installation/micromamba-installation.html):
56+
```bash
57+
micromamba create -f environment.yml
58+
micromamba activate marabou
59+
```
60+
61+
CMake automatically detects the active conda environment and finds all
62+
dependencies from it.
5163

5264
The current version of Marabou can be built for Linux or MacOS machines using CMake:
5365
```bash
@@ -62,9 +74,8 @@ To enable multiprocess build change the last command to:
6274
```bash
6375
cmake --build . -j PROC_NUM
6476
```
65-
After building Marabou, the compiled binary is located at `build/Marabou`, and the
66-
shared library for the Python API is located in `maraboupy/`. Building the Python
67-
interface requires *pybind11* (which is automatically downloaded).
77+
After building Marabou, the compiled binary is located at `build/Marabou`, and the
78+
shared library for the Python API is located in `maraboupy/`.
6879

6980
Export `Marabou` folder to Python and Jupyter paths:
7081
```

environment.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
name: marabou
2+
channels:
3+
- conda-forge
4+
dependencies:
5+
- boost-cpp=1.84.0
6+
- libprotobuf=3.19.2
7+
- protobuf=3.19.2
8+
- openblas>=0.3.19
9+
- pybind11>=2.13.6
10+
- cmake>=3.16
11+
- ninja
12+
- python>=3.9
13+
- numpy>=1.21.0,<2

maraboupy/test/test_network.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ def test_disjunction_constraint():
7474
network.setLowerBound(var, 0)
7575
network.setUpperBound(var, 1)
7676

77-
exitCode1, vals1, stats1 = network.solve()
77+
exitCode1, vals1, stats1 = network.solve(options=OPT)
7878

7979
for var in network.inputVars[0][0]:
8080
assert(abs(vals1[var] - 1) < 0.0000001 or abs(vals1[var]) < 0.0000001)

maraboupy/test/test_nnet_extensions.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from maraboupy import Marabou
55

66
# Global settings
7+
OPT = Marabou.createOptions(verbosity = 0) # Turn off printing
78
TOL = 1e-8
89

910
NETWORK_FOLDER = "../../resources/nnet/"
@@ -33,7 +34,7 @@ def test_evaluate_network():
3334
without_marabou_output = nnet_object.evaluate(np.array([inputs]),useMarabou=False)[0].flatten()
3435
without_marabou_output_rounded = np.array([float(round(y,8)) for y in without_marabou_output])
3536

36-
with_marabou_output = nnet_object.evaluate(np.array([inputs]),useMarabou=True)[0].flatten()
37+
with_marabou_output = nnet_object.evaluate(np.array([inputs]),useMarabou=True, options=OPT)[0].flatten()
3738
with_marabou_output_rounded = np.array([float(round(y,8)) for y in with_marabou_output])
3839

3940
# Assert that all of the above agree, at least up to 10^-8
@@ -88,7 +89,7 @@ def test_write_read_evaluate(tmpdir):
8889

8990
# Compare evaluation with and without Marabou
9091
without_marabou_output = nnet_object_a.evaluate(np.array([inputs]), useMarabou=False)[0].flatten()
91-
with_marabou_output = nnet_object_a.evaluate(np.array([inputs]), useMarabou=True)[0].flatten()
92+
with_marabou_output = nnet_object_a.evaluate(np.array([inputs]), useMarabou=True, options=OPT)[0].flatten()
9293

9394
# Assert that all of the above agree up to TOL
9495
assert (output2 == without_marabou_output).all()
@@ -123,7 +124,7 @@ def test_normalize_read_flag(tmpdir):
123124
without_marabou_output = nnet_object_a.evaluate(np.array([inputs]), useMarabou=False)[0].flatten()
124125
assert (output2 == without_marabou_output).all()
125126

126-
with_marabou_output = nnet_object_a.evaluate(np.array([inputs]), useMarabou=True)[0].flatten()
127+
with_marabou_output = nnet_object_a.evaluate(np.array([inputs]), useMarabou=True, options=OPT)[0].flatten()
127128
assert (abs(without_marabou_output - with_marabou_output) < TOL).all()
128129

129130
def test_reset_network():
@@ -173,9 +174,9 @@ def test_reset_network():
173174
assert (abs(output1_norm - output2_norm) < TOL).all()
174175

175176
without_marabou_output1 = nnet_object1.evaluate(np.array([inputs]), useMarabou=False)[0].flatten()
176-
with_marabou_output1 = nnet_object1.evaluate(np.array([inputs]), useMarabou=True)[0].flatten()
177+
with_marabou_output1 = nnet_object1.evaluate(np.array([inputs]), useMarabou=True, options=OPT)[0].flatten()
177178
without_marabou_output2 = nnet_object2.evaluate(np.array([inputs]), useMarabou=False)[0].flatten()
178-
with_marabou_output2 = nnet_object2.evaluate(np.array([inputs]), useMarabou=True)[0].flatten()
179+
with_marabou_output2 = nnet_object2.evaluate(np.array([inputs]), useMarabou=True, options=OPT)[0].flatten()
179180

180181
assert (abs(with_marabou_output1 - with_marabou_output2) < TOL).all()
181182
assert (abs(without_marabou_output1 - without_marabou_output2) < TOL).all()

pyproject.toml

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,20 @@ test-extras = ["test"]
6161
test-skip = []
6262

6363
[tool.cibuildwheel.linux]
64-
before-all = "yum install -y wget"
64+
manylinux-x86_64-image = "quay.io/pypa/manylinux_2_34_x86_64"
65+
before-all = [
66+
"curl -Ls https://micro.mamba.pm/api/micromamba/linux-64/latest | tar -xvj -C /usr/local bin/micromamba",
67+
"micromamba create -f {package}/environment.yml -p /tmp/mamba-env -y",
68+
]
69+
environment = { CONDA_PREFIX = "/tmp/mamba-env" }
6570

6671
[tool.cibuildwheel.macos]
72+
before-all = [
73+
"curl -Ls https://micro.mamba.pm/api/micromamba/osx-arm64/latest | tar -xvj -C /usr/local bin/micromamba",
74+
"micromamba create -f {package}/environment.yml -p /tmp/mamba-env -y",
75+
]
76+
environment = { CONDA_PREFIX = "/tmp/mamba-env" }
77+
6778
test-skip = [
6879
# 2023-04-15: Skip trying to test arm64 builds on Intel Macs
6980
"*-macosx_arm64",

src/common/tests/Test_ConstSimpleData.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ class ConstSimpleDataTestSuite : public CxxTest::TestSuite
6262

6363
void test_as_char()
6464
{
65-
char data[] = { 'a', 'b', 'c' };
65+
char data[] = { 'a', 'b', 'c', '\0' };
6666

6767
ConstSimpleData constSimpleData( data, sizeof( data ) );
6868

0 commit comments

Comments
 (0)