Repository navigation
Releases
0.6.0
ConceptFlow 0.6.0 adds tools for comparing views of a data set and for judging how well a lattice is drawn. Existing code keeps working unchanged.
New
Scale-measures
conceptflow.core now builds and checks scale-measures (Hanika & Hirth, 2022): coarser views of a formal context on the same objects.
scale_measure(context, attributes)builds one from original attributes and their conjunctions (("a", "b")becomes"a ∧ b"), in a fixed, reproducible column order.is_scale_measureandscale_measure_problemscheck any view, attribute by attribute.refines(coarse, fine)tells whether every concept of one view is a concept of the other (a refinement pair).
Order indices
conceptflow.metrics adds lattice_width (largest antichain), lattice_height (longest chain), incomparable_pairs and concept_levels. They work on iceberg lattices too.
Drawing quality metrics
14 scores in [0, 1] for line diagrams, in four families: crossings, layering, slopes and clearance. drawing_quality_scores computes all of them at once, with optional worst cases. They take a laid-out GraphData or a networkx.DiGraph. Layouts such as DimFlux's are scored upright, as they are drawn.
Contributed by marcelnoehre (#2). On all 635 drawings of a study of eight layout algorithms, they reproduce the original implementation's scores to within 1e-9.
Layout positions
conceptflow.visualization.layout_positions(graph_data) returns where each concept is drawn, keyed by its extent. Drawings of two related lattices can then be compared concept by concept.
Documentation
Two new guide pages: Scale-measures and order indices and Drawing quality.
Reliability
- Built packages tested in CI: the wheel and the source archive are each installed into a clean environment and smoke-tested outside the repository.
- More CI coverage: CI also runs on Python 3.13. On the oldest supported scikit-learn, everything except the estimator checks now runs.
- New tests:
- independent reference implementations for the new functions;
- workflow tests that run whole chains on contexts too large for exhaustive checks.
- README: the first example now runs after a plain
pip install, without LaTeX.
Install
pip install --upgrade conceptflow
Full list of changes: changelog · compare with v0.5.0
ConceptFlow 0.5.0: now beta
ConceptFlow is now beta. For this release every part of the package was checked against brute force or the definitions in the literature, and the bugs found were fixed. Most of them were in the visualization, which is now also tested in a real browser in CI.
Changes that affect existing code
Ord2Factornow usesmethod="annealing"by default. The previous default,"exact", is exponential: about 20 seconds for a 15 × 15 context and hours a little beyond, without a warning. Annealing gave the same results on small contexts and takes seconds on larger ones."exact"is still available and now stops aftermax_timeseconds (default 60) with aTimeoutError.- Ord2Factor's greedy and annealing results change. They are now inclusion-minimal, as the paper states (no dropped cross could be kept). Greedy drops noticeably fewer crosses: 3 instead of 10 on
triangles_en. - Some layout coordinates change. Line diagrams no longer draw an edge straight through a concept it does not connect.
conceptflow.model_selectionwas removed. It was an empty, undocumented placeholder.- Deprecated:
debug_filled_pairsanddebug_bottom_outer(removal in 0.6.0); useconceptflow.exploration.realized_pairs.
Visualization
- Interactive line diagrams use reduced labelling (attributes above, objects below) instead of each concept's full intent.
- Nodes and nested bubbles no longer overlap on larger lattices, and every node can be clicked.
- Several interactive figures in one Jupyter notebook all draw; each is shown in its own frame.
- Nested diagrams show attribute names exactly as given (
color!=redwas shown asred), and clicking the preview dots inside a bubble opens it. - "Save PDF" in nested diagrams writes a vector PDF of a few KB instead of a 6.9 MB image.
- LaTeX in names is shown as symbols (
\sqrt{3}→ √3,\alpha→ α) and typeset properly in TikZ. - Narrow pages work, D3 is pinned to an exact version, and invalid plotting options raise clear errors.
- The visualization guide has a new Known limitations section.
Other fixes
make_random_contextaccepts NumPy Generators, as documented.write_cxt,write_jsonandwrite_csvcreate missing folders.- Clearer errors for misused index arguments and for wrong
scalesinExplorationBuilder. - A hand-built
GraphDataof an iceberg lattice no longer labels objects at the wrong concept.
Testing
- Oracle tests: about 480 tests compare the mathematical core with independent references written from the definitions. This covers concepts, the canonical, proper-premise and Luxenburger bases, stability, incomplete contexts, GreConD and ASSO as in their papers, optimal ordinal factorization, nested diagrams and ordinal scales.
- Browser tests: the interactive pages are tested in headless Firefox.
- More CI platforms: CI now also runs on macOS and Windows.
Install
pip install --upgrade conceptflow
Full list of changes: changelog · compare with v0.4.0
0.4.0
New algorithms, a datasets module, large speed-ups and benchmarks against fcapy and concepts. Documentation: https://conceptflow.readthedocs.io
New
- Boolean matrix factorization:
GreConDandASSOas scikit-learn transformers (likeNMF). Ord2Factor: large ordinal two-factorizations of any context (Dürrschnabel & Stumme 2023), with an exact SAT method and greedy/annealing heuristics.conceptflow.datasets: the 20 contexts of the FCA repository bundled,fetch_fca_repository, the UCI Mushroom data and random contexts.ConceptualScaler(handle_unknown="ignore")for values unseen during fit, e.g. in cross-validation.- Benchmarks against fcapy and concepts, an API stability and deprecation policy,
CITATION.cff,CONTRIBUTING.mdand continuous integration.
Faster (same results)
- Canonical basis with LinCbO: UCI Mushroom 134 s → 17 s; 40–85× faster with many attributes.
- Concept enumeration with FCbO pruning: Mushroom 26 s → 14 s.
- Exact stability, now per concept: all of Mushroom in about 40 s; also works on iceberg lattices.
- Conceptual scaling: Mushroom 49 s → 0.1 s.
Changed
- Concept ids and feature names are derived from the intent: stable across reordered or resampled data, but different from earlier versions.
NominalScale(0)means the first column (as inColumnTransformer).infin DataFrames is rejected.- Python 3.14 is supported.
Full list in the CHANGELOG.
pip install --upgrade conceptflow
0.3.1
Bug fixes found in an audit of 0.3.0: broken HTML pages with special characters in names, two-concept lattices drawn as one point, wrong labels on iceberg drawings, NominalScale failing when a column's type changes, a hang in ExactOrdinalTwoFactorizer, and contexts that could be modified after creation. Full list in the CHANGELOG
0.3.0
ew features: lattice navigation, concept measures, iceberg lattices, TikZ/Graphviz export, context operations, data-quality tools and an outlier detector. Documentation is now at https://conceptflow.readthedocs.io.
Added
- Documentation site with a user guide, API reference and changelog; every guide example is run by the test suite.
- Lattice navigation:
join,meet,upset,downset,atoms,coatoms,object_concept,attribute_concept,concept_from_objects,concept_from_attributes. - Iceberg lattices:
min_support=computes only frequent concepts. - Size guard: a
LargeLatticeWarningpast 50,000 concepts, and an opt-inmax_concepts=limit. - Concept measures: stability (exact and bounds), Δ-measure, entropy, information gain, linearity and distributivity indices;
ConceptLatticeEstimator(select=..., n_concepts=...). - Minimal generators and the proper-premise basis.
- Context handling: transpose, subcontext, rename, add/remove objects and attributes, full reduction, JSON (FCART/fcapy) and CSV files.
- Context operations: apposition, subposition, direct sum and product, complement, dual; nested diagrams of any two contexts.
- Layouts and export: layered layout, TikZ/LaTeX and Graphviz export.
- Data quality:
check_implications,redundancy_report,explain_object,explain_rule. ImplicationOutlierDetector: a scikit-learn outlier detector that explains each flag with the rules it breaks.
Changed
- Cell values follow one rule per cell: numbers > 0 are crosses; strings must be a known spelling (
"yes"/"no"now raise instead of being guessed). - Out-of-range object/attribute indices raise
IndexError. - Estimators fitted on named columns refuse different or reordered columns, as scikit-learn's do.
Full details: CHANGELOG
pip install --upgrade conceptflow
v0.2.0
Install with pip install conceptflow==0.2.0 (requires Python 3.12+).
Breaking changes
- Python 3.12 or newer is required. The layout engine is now the
dim-fluxpackage from PyPI, which
needs Python 3.12. The bundled copy of DimFlux, its Java jar and the Java
requirement are gone;sympyandz3-solverare no longer direct
dependencies. - Missing values are no longer silently converted.
FormalContext(constructor,from_dataframe,from_array) reads
empty cells (None, NaN,pd.NA) as "no cross", like a printed cross
table. Previously NaN became a cross (bool(NaN)is True) while None
became a non-cross. The marker"?"(unknown) raises; use
IncompleteContextfor unknown entries.- The scikit-learn estimators still reject NaN, as scikit-learn requires;
convert withFormalContext.from_dataframefor the cross-table reading. ConceptualScalerraises by default (missing="error"). Previously NaN
became its own category (color=nan) in nominal scales and "below every
threshold" in threshold scales. To keep going, passmissing="false"
(none of the scale's attributes) ormissing="unknown"(see below), or
fill missing values yourself before scaling.- The string
"?"counts as missing (unknown) inConceptualScalerand
IncompleteContext.
plot_lattice(..., title=...)defaults toNone; the d3 backend still
shows "Concept lattice" when no title is given.- Index handling is stricter:
Conceptaccepts only integer indices (NumPy
integers are converted; floats and NumPy booleans raise), andTrue/False
are no longer accepted as attribute or object indices in derivations. FormalContextcopies the incidence array it is given, so changing the
original array afterwards no longer changes the context.compute_luxenburger_basis(concepts=...)rejects concepts with indices
outside the context and ignores duplicates.
Added
compute_luxenburger_basis: near-implications (confidence < 1) with
support, confidence and exception objects, asAssociationRuleobjects.conceptflow.metrics.implication_exceptions: the objects violating a rule.IncompleteContext: yes / no / unknown contexts with certain/possible
derivations, completions, andimplication_status("valid", "possible",
"refuted" over all completions).ConceptualScaler(missing=...)with"error","false"and"unknown";
ExplorationBuilder(missing=...)with"error"and"false".- Static figures:
plot_lattice(..., backend="matplotlib")and
plot_nested(..., backend="matplotlib")return matplotlib figures for
SVG/PDF/PNG export. Withlayout="none"large lattices render in
well under a second. nested_combinations(view)andrealized_pairs(...): the realized and
unrealized (outer, inner) concept pairs of a nested diagram as data.timeout_msfor DimFlux layouts inplot_lattice,plot_nestedand
lattice_to_graph_data_dimflux; a warning for lattices above 150 concepts.compute_canonical_basis_bruteforce: the definition-based reference
implementation, kept for testing.
Fixed
compute_canonical_basisuses NextClosure instead of trying every
attribute subset: a 240 x 30 context went from not finishing to 0.04 s.ConceptLattice.edges,parents()andchildren()are computed once and
cached; previously everyparents()/children()call recomputed all
edges.compute_hasse_edgesitself is also much faster when given the
context.- Concepts holding NumPy integer indices no longer produce wrong Hasse edges.
- Nested diagrams compute filled nodes with a direct test per pair, which is
much faster on large diagrams (same result).
Performance
Measured on a laptop; "before" is 0.1.1 or the first fixed version where
0.1.1 did not finish.
| Operation | Context | Before | Now |
|---|---|---|---|
| Canonical basis | 357 x 42 (1,376 implications) | 3.9 s | 0.22 s |
| Canonical basis | random 100 x 24, dense (8,423) | ~150 s | 0.95 s |
| Canonical basis | random 60 x 80 (3,432) | 23 s | 2.1 s |
| Concept enumeration, Close-by-One | random 300 x 40 (55,392 concepts) | 3.3 s | 0.8 s |
| Concept enumeration, NextClosure | random 300 x 40 | 3.0 s | 1.3 s |
ConceptLatticeEstimator.fit_transform |
random 300 x 40 | 22 s | 2.3 s |
ImplicationBasisEstimator.transform |
random 300 x 40 | 17 s | 0.09 s |
| Luxenburger basis, confidence >= 0.8, support >= 5 | random 300 x 40 | 2.7 s | 0.43 s |
- The canonical basis closes candidate sets under the implications found so
far with vectorised NumPy passes (packed 64-bit words up to 64 attributes,
a matrix-vector product beyond), and stops a closure as soon as it fails
NextClosure's canonicity test. Pure-Python LinClosure was benchmarked as
well and was slower here. - NextClosure and Close-by-One run on integer bitsets.
- The transformers compute concept/premise membership for all objects with
one matrix product instead of per-pair set tests. - The Luxenburger basis only enumerates concepts that reach the support
threshold and reads their lower neighbours off the attribute extents.
Compatibility notes
ConceptualScalerobjects pickled with 0.1.x still load and behave like
missing="error".import conceptflowno longer imports the layout engine; it is loaded on
first use.