flamapy-configurator is a plugin to flamapy module
Project description
configurator_metamodel
A Flamapy plugin that transforms a Feature Model into an interactive configurator. It guides users through a sequence of questions—one per feature group—and uses a solver to reject inconsistent selections in real time.
Features
- Loads Feature Models in UVL format via
flamapy-fm - Converts the FM into an ordered list of questions and options
- Two interchangeable solver backends — choose based on your model:
- PySAT / Glucose3 (default) — fast SAT-based unit propagation for boolean models
- Z3 SMT solver — full support for typed features (
INTEGER,REAL,STRING) and arithmetic cross-tree constraints
- Full undo support: revert the last answer at any point
- Exposes a clean dictionary-based API suitable for embedding in web or CLI apps
Installation
pip install flamapy-configurator
For typed-feature models (INTEGER, REAL, STRING), also install the Z3 extra:
pip install "flamapy-configurator[z3]"
Or install from source:
git clone https://github.com/flamapy/configurator_metamodel
cd configurator_metamodel
pip install -e . # PySAT backend only
pip install -e ".[z3]" # PySAT + Z3 backends
Requirements
| Package | Version | Required |
|---|---|---|
flamapy-fw |
~2.5.0 | always |
flamapy-fm |
~2.5.0 | always |
flamapy-sat |
~2.5.0 | always |
flamapy-z3 |
~2.5.0 | only for Z3 backend |
| Python | ≥ 3.9 | always |
Choosing a solver backend
Pass solver='pysat' (default) or solver='z3' to FmToConfigurator:
| Scenario | Recommended backend |
|---|---|
| Pure boolean feature model | pysat (faster) |
Model with Integer / Real / String features |
z3 |
Arithmetic cross-tree constraints (price > 10, qty >= 2) |
z3 |
from flamapy.metamodels.configurator_metamodel.transformation.fm_to_configurator import FmToConfigurator
# Boolean model — PySAT (default)
configurator_model = FmToConfigurator(fm).transform()
# Typed-feature model — Z3
configurator_model = FmToConfigurator(fm, solver='z3').transform()
How each backend propagates constraints
After each answer the backend checks whether the current partial configuration is still satisfiable and derives any additionally forced feature values:
-
PySAT runs unit propagation on the CNF encoding of the feature model. This is very fast (linear in the number of clauses) but operates only on boolean selection — typed values are not propagated.
-
Z3 calls
solver.check()with the current decisions as assumptions, then performs backbone detection: for every undecided feature it checks whether fixing it in either direction would be UNSAT. This is slower (one SMT call per undecided feature) but handles arbitrary arithmetic constraints natively.
Quick start
from flamapy.metamodels.fm_metamodel.transformations import UVLReader
from flamapy.metamodels.configurator_metamodel.transformation.fm_to_configurator import FmToConfigurator
from flamapy.metamodels.configurator_metamodel.operations.configure import Configure
# 1. Load a feature model
fm = UVLReader('model.uvl').transform()
# 2. Build the configurator model — use solver='z3' for typed features
configurator_model = FmToConfigurator(fm).transform()
# 3. Create and start the configure operation
op = Configure()
op.execute(configurator_model)
op.start()
# 4. Iterate through questions
while not op.is_finished():
status = op.get_current_status()
print(f"\nQuestion: {status['currentQuestion']} ({status['currentQuestionType']})")
for opt in status['possibleOptions']:
print(f" [{opt['id']}] {opt['name']} (type: {opt['featureType']})")
# Answer with a dict {option_name: value}
# Value type must match the feature type: bool, int, float, or str
choice_name = status['possibleOptions'][0]['name']
success = op.answer_question({choice_name: True})
if not success:
print("Contradiction! Try a different option.")
continue
if not op.next_question():
break # No more questions
print("Configuration complete!")
Typed-feature example (Z3 backend)
# model.uvl contains: Integer SpicyLevel, with constraint SpicyLevel >= 1 & SpicyLevel <= 5
fm = UVLReader('model.uvl').transform()
configurator_model = FmToConfigurator(fm, solver='z3').transform()
op = Configure()
op.execute(configurator_model)
op.start()
while not op.is_finished():
status = op.get_current_status()
for opt in status['possibleOptions']:
feature_type = opt['featureType'].name # 'BOOLEAN', 'INTEGER', 'REAL', 'STRING'
if feature_type == 'INTEGER':
op.answer_question({opt['name']: 3})
elif feature_type == 'REAL':
op.answer_question({opt['name']: 9.99})
elif feature_type == 'STRING':
op.answer_question({opt['name']: 'Margherita'})
else:
op.answer_question({opt['name']: True})
op.next_question()
API reference
FmToConfigurator(source_model, solver='pysat')
Transforms a FeatureModel into a ConfiguratorModel.
| Parameter | Type | Description |
|---|---|---|
source_model |
FeatureModel |
The feature model to configure. |
solver |
str |
Backend to use: 'pysat' (default) or 'z3'. |
| Method | Description |
|---|---|
transform() |
Run the transformation and return the ConfiguratorModel. |
Configure
The main operation class. Call execute(model) to initialise.
| Method | Returns | Description |
|---|---|---|
start() |
None |
Advance to the first question. |
get_current_status() |
dict |
Status snapshot (question name, type, options, …). |
answer_question(answer) |
bool |
Apply {name: value} dict; returns False on conflict. |
next_question() |
bool |
Move to the next question; False when finished. |
previous_question() |
bool |
Move to the previous question; False when at the start. |
undo_answer() |
bool |
Revert to the state before the last answer. |
is_finished() |
bool |
True when all questions have been answered. |
get_result() |
dict |
Current configuration as {feature_name: value}. |
Running the tests
make test # pytest tests/ -sv
make cov # coverage report + html
License
GPLv3+. See LICENSE for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file flamapy_configurator-2.5.1.tar.gz.
File metadata
- Download URL: flamapy_configurator-2.5.1.tar.gz
- Upload date:
- Size: 20.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ca11d88dcfa1178439ced593a387c39b458955ce32d2ff34bb2dec7a432e8fa0
|
|
| MD5 |
bdcc5d88e1003cebe59a982d0716adae
|
|
| BLAKE2b-256 |
aaf839e64f098a94cc122404ed1fbd2a3a20d89251b213d5e186b0c81ff17185
|
File details
Details for the file flamapy_configurator-2.5.1-py3-none-any.whl.
File metadata
- Download URL: flamapy_configurator-2.5.1-py3-none-any.whl
- Upload date:
- Size: 15.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
72f593a9ebfdf348d0ca19cd21eb0ae726572364575001ec9a45ced7c03f217c
|
|
| MD5 |
972e693a1c1898f239299ac522f3bb37
|
|
| BLAKE2b-256 |
747d5a4dff613ed6c3caaed75899b66f2724632f2b57b39e3017648ad7dbc00c
|