func_minim: Check functional minimality of solution formulas

functional minimalityR Documentation

Check functional minimality of solution formulas

Description

The functions fm_structural and fm_empirical check whether CNA solution formulas are functionally minimal, that is, whether they account for their outcomes on the basis of factor sets that do not contain redundant factors (cf. Zhang and Zhang 2023).

Usage

fm_structural(cond, x = full.ct(cond), verbose = FALSE)
fm_empirical(cond, verbose = FALSE)

Arguments

cond

Character vector specifying a set of solution formulas in the standard format.

x

Data frame or configTable specifying the factors' value ranges. For multi-value data, x must be specified explicitly, for example as full.ct(list(A = 1:6, B = 0:4, C = 0:5)).

verbose

Logical; if TRUE, information about the functionally redundant factors is printed to the console. Alternatively, verbose can be an integer specifying the maximal number of non-minimal formulas for which information is printed.

Details

Functional minimality is an additional non-redundancy constraint on solution formulas that Zhang and Zhang (2023) introduce into the INUS-theory of causation. In a nutshell, a solution formula (csf) is functionally minimal if, and only if, its outcomes cannot be accounted for on the basis of a proper subset of its factors. While minimal sufficiency eliminates redundant conjuncts from sufficient conditions and minimal necessity eliminates redundant disjuncts from necessary conditions, functional minimality eliminates redundant factors from the factor sets on the basis of which outcomes are modeled.

Zhang and Zhang (2023) formulate functional minimality for the purely conceptual context of defining causal relevance. fm_structural and fm_empirical are two different operationalizations of that constraint for the context of causal discovery, approximating it for ideal and non-ideal empirical data, respectively, and for the solution sets with which CNA works.

fm_structural checks each solution formula cond[i] in cond individually. To this end, cond[i] is evaluated against ideal data, that is, the configTable generated by selectCases(cond[i]), and it is tested, for every atomic solution formula (asf) contained in the complex solution formula (csf) cond[i] and every factor of that asf, whether the outcome is constant across the configurations that agree on the remaining factors of that asf. If this holds for at least one factor, the outcome can be expressed as a Boolean function without that factor, which thus turns out functionally redundant, meaning that cond[i] is labelled FALSE by fm_structural. The result of that redundancy check for cond[i] depends only on cond[i]; the other csf in cond are irrelevant for fm_structural(cond[i]). fm_structural is used by default in randomCsf.

fm_empirical compares the solution formulas in cond to each other. Only formulas that account for the same set of outcomes enter into this comparison. A formula cond[i] is functionally minimal if, and only if, no other cond[k] accounts for these outcomes on the basis of factor sets that are at least as small for each of them, and strictly smaller for at least one. The result for cond[i] therefore depends on the complete vector of csf cond. The func.minimal.only argument of cna, csf, and cnaControl applies fm_empirical. Setting func.minimal.only = TRUE removes all csf with fm_empirical = FALSE, and the attribute is then no longer attached to the output.

The two functions can yield different results. As fm_structural evaluates elements against their own ideal data, it can identify a redundant factor in a csf cond[i] even when no other cond[k] accounts for the outcome without that factor; conversely, fm_empirical can identify a cond[i] as non-minimal even when cond[i] is minimal relative to its own ideal data. Both measures are also available as solution attributes computed by detailMeasures (cf. showMeasures).

If cond is multi-value, the default value x = full.ct(cond) of fm_structural does not return the configurations of the full value range but only the configurations of the factor values appearing in cond. For multi-value data, x must therefore be specified explicitly, for example as full.ct(list(A = 1:6, B = 0:4, C = 0:5)) or as a data frame spanning the factors' value ranges; otherwise the configurations satisfying a csf cond[i] all carry the outcome value given in cond[i] and fm_structural flags cond[i] as not functionally minimal.

Value

A named logical vector of the same length as cond: TRUE for an element that is functionally minimal, FALSE for an element that is not. The names of the vector are the elements of cond in standard form.

References

Zhang, Jiji and Kun Zhang. 2023. “A New Minimality Condition for Boolean Accounts of Causal Regularities.” Erkenntnis 90(1):67-86. \Sexpr[results=rd]{tools:::Rd_expr_doi("10.1007/s10670-023-00685-4")}

See Also

cna, csf, cnaControl, detailMeasures, cyclic, showMeasures, full.ct, randomCsf

Examples

# fm_structural() and fm_empirical() applied to the same vector of csf.
cond <- c("(A*B + a*C <-> D)*(D*E + e*F <-> G)",
          "(A*B + a*C <-> D)*(D*F + e*F*A <-> G)",
          "(A*B + a*C <-> D)*(D*F + e*F + A*B*E + B*C*E <-> G)")
fm_structural(cond)
fm_empirical(cond)

# fm_structural() and fm_empirical() applied to a csf solution object of cna().
gt <- "(A*B + a*C <-> D)*(D*E + e*F <-> G)"
d.ideal <- selectCases(gt)
cond <- csf(cna(d.ideal, con = .9, cov = .9))$condition
cond
fm_structural(cond)
fm_empirical(cond)

# These examples illustrate that the two measures can come apart. The following
# 4 csf contain no redundant factor relative to their own ideal data, but other
# elements of cond account for D and G on the basis of fewer factors, which is
# what fm_empirical() detects.
cond[fm_structural(cond) & !fm_empirical(cond)]

# verbose = TRUE reports which other csf make an element non-minimal.
fm_empirical(cond, verbose = TRUE)

# The causal structure behind Zhang and Zhang's (2023) air-conditioning scenario.
# cna() builds 4 csf for these data, of which 3 are fm_structural and 2 are
# fm_empirical. The second csf is not fm_structural, because E1 is redundant in
# its asf for E2.
aircon <- selectCases("(A + B <-> E1)*(A*b + A*C <-> E2)")
cond <- csf(cna(aircon))$condition
fm_structural(cond, verbose = 10)
fm_empirical(cond, verbose = 10)

# fm_empirical() is the function behind the fm_empirical solution attribute and
# behind the func.minimal.only argument of cna() and csf(). d.pban is a
# multi-value data set: 14 csf are built at cov = .95, of which 2 are
# functionally minimal. For multi-value data, fm_structural() requires x to be
# specified explicitly, as the default x = full.ct(cond) does not span the
# factors' value ranges.
ana.pban <- cna(d.pban, cov = .95, maxstep = c(6, 6, 10))
cond.pban <- csf(ana.pban)$condition
length(cond.pban)
sum(fm_empirical(cond.pban))
sum(fm_structural(cond.pban, x = full.ct(d.pban)))
length(csf(ana.pban, func.minimal.only = TRUE)$condition)

# fm_structural() and fm_empirical() also apply to csf built from fuzzy-set
# data. At con = cov = .85, csf() builds 10 two-outcome csf for d.jobsecurity,
# of which 5 are fm_structural and 4 are fm_empirical; the two measures come
# apart in both directions here. Unlike for multi-value data, full.ct(cond)
# spans the factors' value ranges for fuzzy-set data, so that fm_structural()
# does not require an explicit x.
ana.fs <- cna(d.jobsecurity, con = .85, cov = .85)
cond.fs <- csf(ana.fs)$condition
length(cond.fs)
fm_structural(cond.fs)
fm_empirical(cond.fs)

cna documentation built on Oct. 28, 2026, 9:07 a.m.