This repository is a fork and extension of the original ConStruct implementation by Madeira et al.
Original Work: ConStruct - Generative Modelling of Structurally Constrained Graphs
Original Authors: Manuel Madeira et al.
Original Paper: "Generative Modelling of Structurally Constrained Graphs"
License: MIT
- Ring-Based Constraints: Extended the model to include comprehensive ring count and ring length constraints
- Molecular Dataset Focus: Extensive testing and validation on molecular datasets, starting with QM9
- Edge-Deletion Constraints: Implemented "at most" constraints for ring count and ring length
- Organized Experiment Structure: Created systematic experiment configurations for debug and thesis-level testing
- SLURM Integration: Added comprehensive SLURM job scripts for cluster execution
- Constraint Validation: Implemented robust constraint satisfaction monitoring and validation
- Constraint Types: Added
ring_count_at_mostandring_length_at_mostprojectors - Molecular Focus: Optimized for molecular graph generation with QM9 dataset
- Experiment Organization: Structured configs and scripts for systematic constraint testing
- Cluster Support: Enhanced SLURM integration for high-performance computing environments
These steps are based on real-world cluster, GPU, RDKit, PyTorch, and graph-tool nightmares.
You MUST follow the order and warnings below, or your environment will break.
conda create -y -c conda-forge -n construct python=3.9 rdkit=2023.03.2
conda activate constructpython -c "from rdkit import Chem"
# No error means it's fine.conda install -c conda-forge graph-tool=2.45
python -c "import graph_tool as gt"- graph-tool is only required for non-molecular datasets (e.g., tree, planar, lobster).
- If you work only with molecular datasets (QM9, etc.), you can skip installing graph-tool to avoid compatibility headaches.
pip install torch==2.0.1 --index-url https://download.pytorch.org/whl/cu118
pip install torch-geometric==2.3.1
python -c "import torch; print(torch.cuda.is_available())"
# Should print True if GPU is visible.pip install --no-deps fcd
# Do NOT install dependencies here, or you WILL break torch/rdkit versions!
# This gives you fcd.load_ref_model, fcd.get_fcd, etc.pip install -r requirements.txt
# (If requirements.txt has torch or rdkit, double check they don't get downgraded!)pip install -e .cd ./ConStruct/analysis/orca
g++ -O2 -std=c++11 -o orca orca.cpp
cd -python -c "import fcd; print(hasattr(fcd, 'load_ref_model'))"
python -c "import torch; print(torch.cuda.is_available())"Both should print True or not error.
- Never use
pip install fcd(without--no-deps) after torch/rdkit, or you’ll nuke your versions. - Never install
cudalibraries via conda. Cluster GPUs already have drivers. - Never install both
fcdandfcd_torchin the same env unless you know why. - Always check for libstdc++ or libgomp errors (see troubleshooting below).
| Step | Command |
|---|---|
| Create env | conda create -y -c conda-forge -n construct python=3.9 rdkit=2023.03.2 |
| Activate env | conda activate construct |
| Install graph-tool | conda install -c conda-forge graph-tool=2.45 |
| Install PyTorch | pip install torch==2.0.1 --index-url https://download.pytorch.org/whl/cu118 |
| Install torch-geometric | pip install torch-geometric==2.3.1 |
| Install fcd | pip install --no-deps fcd |
| Other packages | pip install -r requirements.txt |
| Your package | pip install -e . |
| Compile ORCA | g++ -O2 -std=c++11 -o orca orca.cpp |
If you get something like
ImportError: ... libstdc++.so.6: version 'GLIBCXX_3.4.29' not found ...
run:
find $CONDA_PREFIX -name "libstdc++.so.6"
LD_PRELOAD=$CONDA_PREFIX/lib/libstdc++.so.6 python -c "from rdkit import Chem; import fcd; print(hasattr(fcd, 'load_ref_model'))"If it fixes things, make it permanent:
mkdir -p $CONDA_PREFIX/etc/conda/activate.d
echo 'export LD_PRELOAD="$CONDA_PREFIX/lib/libstdc++.so.6"' > $CONDA_PREFIX/etc/conda/activate.d/zz_preload_libstdcxx.sh
chmod +x $CONDA_PREFIX/etc/conda/activate.d/zz_preload_libstdcxx.shIf you see
libgomp-a34b3233.so.1: version 'GOMP_5.0' not found (required by ...)
run:
export LD_PRELOAD="$CONDA_PREFIX/lib/libgomp.so.1"
python test_env.pyIf it works, make it permanent:
mkdir -p $CONDA_PREFIX/etc/conda/activate.d
echo 'export LD_PRELOAD="$CONDA_PREFIX/lib/libgomp.so.1"' > $CONDA_PREFIX/etc/conda/activate.d/zz_preload_libgomp.sh
chmod +x $CONDA_PREFIX/etc/conda/activate.d/zz_preload_libgomp.shIf still not working, add to every SLURM script after conda activate:
export LD_PRELOAD="$CONDA_PREFIX/lib/libgomp.so.1"Paste and run these one by one in your (construct) environment:
-
RDKit Basic Import
python -c "from rdkit import Chem; print(Chem.MolFromSmiles('CCO') is not None)" -
PyTorch + CUDA Check
python -c "import torch; print(torch.__version__); print(torch.cuda.is_available())" -
torch-geometric Check
python -c "import torch_geometric; print(torch_geometric.__version__)" -
fcd Import and Model Load
python -c "import fcd; print(hasattr(fcd, 'load_ref_model')); m = fcd.load_ref_model(); print(m is not None)" -
Your Own Package Import
python -c "import ConStruct; print('ConStruct imported\!')" -
(Optional) Try a minimal fcd score calculation
python -c "import fcd; s = fcd.get_fcd(['CCO', 'CCC'], ['CCO', 'CCN']); print('FCD score:', s)"
If all these work: your env is cluster-proof.
The codebase includes a comprehensive, organized experiment structure for testing different constraint types.
Note: Edge-insertion constraints are documented but not yet implemented in the current codebase.
configs/experiment/
├── debug/ # Debug-level experiments (quick testing)
│ ├── no_constraint/ # No constraint experiments
│ └── edge_deletion/ # Edge-deletion constraints ("at most")
│ ├── planarity/ # Planarity constraints
│ ├── ring_count_at_most/ # Ring count "at most" constraints
│ └── ring_length_at_most/ # Ring length "at most" constraints
└── thesis/ # Thesis-level experiments (full-scale)
├── no_constraint/ # No constraint experiments
└── edge_deletion/ # Edge-deletion constraints ("at most")
├── planarity/ # Planarity constraints
├── ring_count_at_most/ # Ring count "at most" constraints
└── ring_length_at_most/ # Ring length "at most" constraints
ConStruct/slurm_jobs/
├── debug/ # Debug-level SLURM scripts
│ ├── no_constraint/ # No constraint scripts
│ └── edge_deletion/ # Edge-deletion scripts
└── thesis/ # Thesis-level SLURM scripts
├── no_constraint/ # No constraint scripts
└── edge_deletion/ # Edge-deletion scripts
Edge-Deletion Constraints ("At Most"):
- Purpose: Limit maximum ring count, ring length, or enforce planarity
- Transition:
absorbing_edges - Projectors:
ring_count_at_most,ring_length_at_most,planar - Use Case: Generate molecules with limited ring complexity or planar structures
No Constraint:
- Purpose: Baseline training without any constraints
- Transition:
absorbing_edges - Projector:
null - Use Case: Generate molecules without structural constraints
Edge-Insertion Constraints ("At Least") - Not Yet Implemented:
- Status: Documented but not implemented in current codebase
- Note: The
edge_insertiontransition andring_count_at_least/ring_length_at_leastprojectors are commented out in the model configuration
# Debug experiments
python ConStruct/main.py \
--config-name experiment/debug/no_constraint/qm9_debug_no_constraint.yaml \
--config-path configs/
# Ring count at most 2 (debug)
python ConStruct/main.py \
--config-name experiment/debug/edge_deletion/ring_count_at_most/qm9_debug_ring_count_at_most_2.yaml \
--config-path configs/
# Planarity constraint (debug)
python ConStruct/main.py \
--config-name experiment/debug/edge_deletion/planarity/qm9_debug_planar.yaml \
--config-path configs/
# Thesis experiments
python ConStruct/main.py \
--config-name experiment/thesis/edge_deletion/ring_count_at_most/qm9_thesis_ring_count_at_most_3.yaml \
--config-path configs/
# Ring length at most 5 (thesis)
python ConStruct/main.py \
--config-name experiment/thesis/edge_deletion/ring_length_at_most/qm9_thesis_ring_length_at_most_5.yaml \
--config-path configs/# Debug experiments
sbatch ConStruct/slurm_jobs/debug/no_constraint/qm9_no_constraint_debug.slurm
sbatch ConStruct/slurm_jobs/debug/edge_deletion/ring_count_at_most/qm9_ring_count_at_most_2_debug.slurm
sbatch ConStruct/slurm_jobs/debug/edge_deletion/planarity/qm9_debug_planar.slurm
# Thesis experiments
sbatch ConStruct/slurm_jobs/thesis/no_constraint/qm9_no_constraint_thesis.slurm
sbatch ConStruct/slurm_jobs/thesis/edge_deletion/ring_count_at_most/qm9_ring_count_at_most_3_thesis.slurm
sbatch ConStruct/slurm_jobs/thesis/edge_deletion/ring_length_at_most/qm9_ring_length_at_most_5_thesis.slurm