CORAtool

Combinational Regularity Analysis (CORA) in an R environment.

The package is named CORAtool because CRAN already carries a package called cora; the method it implements is CORA.

License: GPL v3

Combinational Regularity Analysis is a configurational comparative method. It searches data for INUS structures - cause-effect relations marked by conjunctivity (a and not b and c) and disjunctivity (d or e or f) - using Boolean minimisation algorithms borrowed from switching circuit analysis. Unlike related methods, CORA analyses structures with simple as well as complex effects, and it handles multi-value conditions.

This package is an R port of the Python packages CORA and LOGIGRAM by Zuzana Sebechlebská, Lusine Mkrtchyan and Alrik Thiem. It computes in plain R and requires no Python installation.

It is an independent implementation and is not endorsed by the authors of the original packages. Anything it gets wrong by departing from the Python implementation is this package’s responsibility, not theirs.

Installation

# install.packages("remotes")
remotes::install_github("youngchanresearcher/CORAtool")
library(CORAtool)

Usage

library(CORAtool)

df <- data.frame(A   = c(1, 0, 1, 0),
                 B   = c(1, 0, 0, 1),
                 C   = c(0, 1, 1, 0),
                 OUT = c(1, 1, 0, 1))

ctx <- cora_context(df, output_labels = "OUT")

cora_truth_table(ctx)        # the configurations the analysis works on
cora_prime_implicants(ctx)   # #A{0}, C{0}, B{1}
cora_irredundant_sums(ctx)   # M1: #A{0} + C{0} ; M2: #A{0} + B{1}

Every literal is printed as CONDITION{value}, so a term says outright which value of a condition it stands for: B{2}*D{0} is B at 2 and D at 0. An essential prime implicant is prefixed with #. The package does not use the upper/lower case convention of the Python implementation, which marks a negated literal by the presence of 0 in its value set and therefore says nothing when a condition happens to be coded without a zero.

Truth table construction

cora_context() aggregates the cases into configurations and decides which of them count as positive:

argument meaning
n_cut minimum number of cases below which a configuration is a don’t care
inc_score1 minimum inclusion score for an output function value of 1
inc_score2, U the second inclusion cut-off and which value it applies to
case_col column holding case identifiers
algorithm "ON-DC" (Quine-McCluskey over positive and don’t care terms) or "ON-OFF" (McCluskey’s modified algorithm over positive and negative terms)

Conditions must be coded from zero upwards, with no gaps: 0, 1, 2, ... The package refuses data that is coded otherwise and names the columns to fix, as the other configurational packages in R do. as.integer() on a factor numbers the levels from one, so this is easy to run into:

df <- cora_recode(df, c("A", "B"))   # or cora_recode(df) to find them itself

Multi-value conditions and complex effects

Outcome values that count as positive are declared in curly brackets. With more than one outcome column the analysis returns irredundant systems rather than sums:

ctx <- cora_context(bergschlosser, c("AUTH{1}", "DEM{1}"),
                    input_labels = c("PS", "RQ", "LRC"),
                    case_col = "Case", inc_score1 = 0.6,
                    algorithm = "ON-OFF")
cora_irredundant_systems(ctx)

Configurational data mining

cora_data_mining() scores every n-tuple of conditions, a configurational version of Occam’s razor:

cora_data_mining(mccluskey, c("F1", "F2"), len_of_tuple = 2)

Logic diagrams

cora_logigram() draws a solution, or any expression in disjunctive normal form, as a two-level logic diagram:

cora_logigram("A{1}*B{1}+C{0}<=>F")
cora_logigram(cora_irredundant_sums(ctx)[[1]])

A solution writes itself above its own diagram: the implicants, with the # that marks an essential one, and the coverage and inclusion scores. Pass show_terms = TRUE to label each gate with the conjunction it forms, title and subtitle to write your own header, or NA to either for no header at all.

The diagram reader still accepts the upper/lower case notation on input ("A*B+c*A+b<=>F"), so expressions written by hand or taken from the Python implementation can be drawn as they are.

Function reference

function purpose
cora_context() data and analytical choices
cora_truth_table() configurations after aggregation and cut-offs
cora_prime_implicants() Boolean minimisation
cora_pi_chart() prime implicant chart
cora_irredundant_sums() solutions, one outcome
cora_irredundant_systems() solutions, several outcomes
cora_petrick() Petrick’s method on a coverage list
cora_recode() map conditions onto 0, 1, 2, ...
cora_pi_details(), cora_system_details(), cora_solutions() summary tables
cora_coverage_score(), cora_inclusion_score() sufficiency statistics
cora_describe(), cora_dnf() textual renderings of a solution
cora_logigram() two-level logic diagram
cora_data_mining() configurational data mining
cora_compare_python() optional cross-check against the Python package

Documentation

vignette("cora", package = "CORAtool")

walks through an analysis end to end in English: what the method looks for, the five stages, how to read coverage and inclusion, multi-value conditions and complex effects, the diagrams, choosing between the algorithms, and what to do when there are more solutions than anyone can report.

A fuller manual goes further: the theory, every stage of the pipeline, how to read a diagram, the six defects found in the Python implementation with their source locations, and how QCA, QCApro and cna handle the same problems. It ships in both English and Traditional Chinese:

file.show(system.file("docs", "manual_en.md", package = "CORAtool"))
file.show(system.file("docs", "manual_zh-TW.md", package = "CORAtool"))

inst/examples/getting-started.R is a runnable script over the same material.

Checking a build

tools/acceptance.R exercises every exported function against an installed copy, confirms the behaviours this version introduces, and checks that the inputs which should be refused are refused:

Rscript tools/acceptance.R

tools/check.R builds the tarball and runs R CMD check --as-cran over it, then prints only the checks that did not return OK and says which of those come from the machine rather than from the package:

Rscript tools/check.R

Bundled data

swiss_minaret, gross_carvin, mccluskey and bergschlosser, all taken from the examples of the Python CORA package.

Relation to the Python implementation

The R results were checked configuration by configuration against the Python package on its own test and example data: truth tables, prime implicants, coverage sets and solution sets agree. Five differences are worth knowing, and each of them is this package’s own judgement rather than the original authors’:

cora_compare_python() runs a context through both implementations and reports whether they agree; it needs reticulate and the Python package, and nothing else in the package does.

Citation

Cite this package, the method it implements, and the packages it was adapted from. citation("CORAtool") prints all three entries:

Chan, Y. (2026). CORAtool: Combinational Regularity Analysis. R package version 0.1.2.

Thiem, A., Mkrtchyan, L., & Sebechlebská, Z. (2022). Combinational Regularity Analysis (CORA) - a new method for uncovering complex causation in medical and health research. BMC Medical Research Methodology, 22(1), 333.

Sebechlebská, Z., Mkrtchyan, L., & Thiem, A. (2023). CORA and LOGIGRAM: A duo of Python packages for Combinational Regularity Analysis (CORA). Journal of Open Source Software, 8(85), 5019.

License

GPL (>= 3), as required by the original implementation from which this package is derived. See inst/NOTICE for attribution details.