Skip to content

Commit be724a8

Browse files
authored
Merge pull request #819 from mlr-org/housekeeping
minor fixes for changes in mlr3
2 parents 945bc5d + bd94245 commit be724a8

36 files changed

+8253
-7
lines changed

DESCRIPTION

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,12 @@ Roxygen: list(markdown = TRUE, r6 = FALSE)
9999
RoxygenNote: 7.3.2
100100
VignetteBuilder: knitr
101101
Collate:
102+
'CnfAtom.R'
103+
'CnfClause.R'
104+
'CnfFormula.R'
105+
'CnfFormula_simplify.R'
106+
'CnfSymbol.R'
107+
'CnfUniverse.R'
102108
'Graph.R'
103109
'GraphLearner.R'
104110
'mlr_pipeops.R'

NAMESPACE

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,40 @@
11
# Generated by roxygen2: do not edit by hand
22

3+
S3method("!",CnfAtom)
4+
S3method("!",CnfClause)
5+
S3method("!",CnfFormula)
6+
S3method("$",CnfUniverse)
7+
S3method("%among%",CnfSymbol)
8+
S3method("%among%",default)
9+
S3method("&",CnfAtom)
10+
S3method("&",CnfClause)
11+
S3method("&",CnfFormula)
12+
S3method("[",CnfClause)
13+
S3method("|",CnfAtom)
14+
S3method("|",CnfClause)
15+
S3method("|",CnfFormula)
16+
S3method(all,equal.CnfAtom)
17+
S3method(all,equal.CnfClause)
18+
S3method(all,equal.CnfFormula)
19+
S3method(as.CnfAtom,CnfAtom)
20+
S3method(as.CnfAtom,default)
21+
S3method(as.CnfAtom,logical)
22+
S3method(as.CnfClause,CnfAtom)
23+
S3method(as.CnfClause,CnfClause)
24+
S3method(as.CnfClause,default)
25+
S3method(as.CnfClause,logical)
26+
S3method(as.CnfFormula,CnfAtom)
27+
S3method(as.CnfFormula,CnfClause)
28+
S3method(as.CnfFormula,CnfFormula)
29+
S3method(as.CnfFormula,default)
30+
S3method(as.CnfFormula,logical)
331
S3method(as.data.table,DictionaryGraph)
432
S3method(as.data.table,DictionaryPipeOp)
33+
S3method(as.list,CnfClause)
34+
S3method(as.list,CnfFormula)
35+
S3method(as.logical,CnfAtom)
36+
S3method(as.logical,CnfClause)
37+
S3method(as.logical,CnfFormula)
538
S3method(as_graph,Graph)
639
S3method(as_graph,default)
740
S3method(as_graph,list)
@@ -11,6 +44,11 @@ S3method(as_pipeop,Filter)
1144
S3method(as_pipeop,Learner)
1245
S3method(as_pipeop,PipeOp)
1346
S3method(as_pipeop,default)
47+
S3method(format,CnfAtom)
48+
S3method(format,CnfClause)
49+
S3method(format,CnfFormula)
50+
S3method(format,CnfSymbol)
51+
S3method(format,CnfUniverse)
1452
S3method(marshal_model,Multiplicity)
1553
S3method(marshal_model,graph_learner_model)
1654
S3method(marshal_model,pipeop_impute_learner_state)
@@ -25,6 +63,11 @@ S3method(pos,"NULL")
2563
S3method(pos,character)
2664
S3method(pos,list)
2765
S3method(predict,Graph)
66+
S3method(print,CnfAtom)
67+
S3method(print,CnfClause)
68+
S3method(print,CnfFormula)
69+
S3method(print,CnfSymbol)
70+
S3method(print,CnfUniverse)
2871
S3method(print,Multiplicity)
2972
S3method(print,Selector)
3073
S3method(set_validate,GraphLearner)
@@ -35,6 +78,12 @@ S3method(unmarshal_model,pipeop_impute_learner_state_marshaled)
3578
S3method(unmarshal_model,pipeop_learner_cv_state_marshaled)
3679
export("%>>!%")
3780
export("%>>%")
81+
export("%among%")
82+
export(CnfAtom)
83+
export(CnfClause)
84+
export(CnfFormula)
85+
export(CnfSymbol)
86+
export(CnfUniverse)
3887
export(Graph)
3988
export(GraphLearner)
4089
export(LearnerClassifAvg)
@@ -116,6 +165,9 @@ export(PipeOpUnbranch)
116165
export(PipeOpVtreat)
117166
export(PipeOpYeoJohnson)
118167
export(add_class_hierarchy_cache)
168+
export(as.CnfAtom)
169+
export(as.CnfClause)
170+
export(as.CnfFormula)
119171
export(as.Multiplicity)
120172
export(as.data.table)
121173
export(as_graph)
@@ -157,6 +209,9 @@ export(selector_none)
157209
export(selector_setdiff)
158210
export(selector_type)
159211
export(selector_union)
212+
if (getRversion() >= "4.3.0") S3method(chooseOpsMethod,CnfAtom)
213+
if (getRversion() >= "4.3.0") S3method(chooseOpsMethod,CnfClause)
214+
if (getRversion() >= "4.3.0") S3method(chooseOpsMethod,CnfFormula)
160215
import(checkmate)
161216
import(data.table)
162217
import(mlr3)

R/CnfAtom.R

Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
# An expression of the form "X %in% {x1, x2, x3}"
2+
#' @title Atoms for CNF Formulas
3+
#'
4+
#' @description
5+
#' `CnfAtom` objects represent a single statement that is used to build up CNF formulae.
6+
#' They are mostly intermediate, created using the [`%among%`] operator or [`CnfAtom()`]
7+
#' directly, and combined into [`CnfClause`] and [`CnfFormula`] objects.
8+
#' [`CnfClause`] and [`CnfFormula`] do not, however, contain [`CnfAtom`] objects directly,
9+
#'
10+
#' `CnfAtom`s contain an indirect reference to a [`CnfSymbol`] by referencing its name
11+
#' and its [`CnfUniverse`]. They furthermore contain a set of values. An `CnfAtom`
12+
#' represents a statement asserting that the given symbol takes up one of the
13+
#' given values.
14+
#'
15+
#' If the set of values is empty, the `CnfAtom` represents a contradiction (FALSE).
16+
#' If it is the full domain of the symbol, the `CnfAtom` represents a tautology (TRUE).
17+
#' These values can be converted to, and from, `logical(1)` values using `as.logical()`
18+
#' and `as.CnfAtom()`.
19+
#'
20+
#' `CnfAtom` objects can be negated using the `!` operator, which will return the `CnfAtom`
21+
#' representing set membership in the complement of the symbol with respect to its domain.
22+
#' `CnfAtom`s can furthermore be combined using the `|` operator to form a [`CnfClause`],
23+
#' and using the `&` operator to form a [`CnfFormula`]. This happens even if the
24+
#' resulting statement could be represented as a single `CnfAtom`.
25+
#'
26+
#' This is part of the CNF representation tooling, which is currently considered
27+
#' experimental; it is for internal use.
28+
#'
29+
#' @details
30+
#' We would have preferred to overload the `%in%` operator, but this is currently
31+
#' not easily possible in R. We therefore created the `%among%` operator.
32+
#'
33+
#' The internal representation of a `CnfAtom` may change in the future.
34+
#'
35+
#' @param symbol ([`CnfSymbol`]) \cr
36+
#' The symbol to which the atom refers.
37+
#' @param values (`character`) \cr
38+
#' The values that the symbol can take.
39+
#' @param e1 (`CnfSymbol`) \cr
40+
#' Left-hand side of the `%among%` operator.
41+
#' Passed as `symbol` to `CnfAtom()`.
42+
#' @param e2 (`character`) \cr
43+
#' Right-hand side of the `%among%` operator.
44+
#' Passed as `values` to `CnfAtom()`.
45+
#' @param x (any) \cr
46+
#' The object to be coerced to a `CnfAtom` by `as.CnfAtom`.
47+
#' Only `logical(1)` and `CnfAtom` itself are currently supported.
48+
#' @return A new `CnfAtom` object.
49+
#' @examples
50+
#' u = CnfUniverse()
51+
#' X = CnfSymbol(u, "X", c("a", "b", "c"))
52+
#'
53+
#' CnfAtom(X, c("a", "b"))
54+
#' X %among% "a"
55+
#' X %among% character(0)
56+
#' X %among% c("a", "b", "c")
57+
#'
58+
#' as.logical(X %among% character(0))
59+
#' as.CnfAtom(TRUE)
60+
#'
61+
#' !(X %among% "a")
62+
#'
63+
#' X %among% "a" | X %among% "b" # creates a CnfClause
64+
#'
65+
#' X %among% "a" & X %among% c("a", "b") # creates a CnfFormula
66+
#' @family CNF representation objects
67+
#' @keywords internal
68+
#' @export
69+
CnfAtom = function(symbol, values) {
70+
assert_class(symbol, "CnfSymbol")
71+
domain = attr(symbol, "universe")[[symbol]]
72+
assert_subset(values, domain)
73+
if (all(domain %in% values)) {
74+
entry = TRUE
75+
} else if (length(values) == 0) {
76+
entry = FALSE
77+
} else {
78+
entry = list(symbol = c(symbol), values = unique(values))
79+
}
80+
structure(
81+
entry,
82+
universe = attr(symbol, "universe"),
83+
class = "CnfAtom"
84+
)
85+
}
86+
87+
#' @export
88+
print.CnfAtom = function(x, ...) {
89+
if (isTRUE(x)) {
90+
cat("CnfAtom: <TRUE>\n")
91+
} else if (isFALSE(x)) {
92+
cat("CnfAtom: <FALSE>\n")
93+
} else {
94+
cat(sprintf("CnfAtom: %s \U2208 {%s}.\n", x$symbol, paste(x$values, collapse = ", ")))
95+
}
96+
invisible(x)
97+
}
98+
99+
#' @export
100+
format.CnfAtom = function(x, ...) {
101+
if (isTRUE(x)) {
102+
return("CnfAtom: T")
103+
} else if (isFALSE(x)) {
104+
return("CnfAtom: F")
105+
} else {
106+
return(sprintf("CnfAtom(%s)", x$symbol))
107+
}
108+
}
109+
110+
# construct CnfAtom with `X %among% c("a", "b", "c")`
111+
# we cannot overload `%in%`, unfortunately
112+
#' @export
113+
#' @rdname CnfAtom
114+
`%among%` = function(e1, e2) {
115+
UseMethod("%among%")
116+
}
117+
118+
#' @export
119+
`%among%.CnfSymbol` = function(e1, e2) {
120+
CnfAtom(e1, e2)
121+
}
122+
123+
#' @export
124+
`%among%.default` = function(e1, e2) {
125+
stop("%among% operation not defined for LHS. %among% should typically be used with a CnfSymbol.")
126+
}
127+
128+
129+
#' @rdname CnfAtom
130+
#' @export
131+
as.CnfAtom = function(x) {
132+
UseMethod("as.CnfAtom")
133+
}
134+
135+
#' @export
136+
as.CnfAtom.default = function(x) {
137+
stop("Cannot convert object to CnfAtom.")
138+
}
139+
140+
#' @export
141+
as.CnfAtom.logical = function(x) {
142+
assert_flag(x)
143+
structure(
144+
x,
145+
universe = attr(x, "universe"),
146+
class = "CnfAtom"
147+
)
148+
}
149+
150+
#' @export
151+
as.CnfAtom.CnfAtom = function(x) {
152+
x
153+
}
154+
155+
#' @export
156+
as.logical.CnfAtom = function(x, ...) {
157+
if (is.logical(x)) {
158+
return(unclass(x))
159+
}
160+
return(NA)
161+
}
162+
163+
#' @export
164+
all.equal.CnfAtom = function(target, current, ...) {
165+
if (is.logical(target) && is.logical(current)) {
166+
# compare truth-values directly, even if they disagree on universe
167+
# (since logical atoms sometimes have universe set to NULL)
168+
if (identical(c(target), c(current))) {
169+
return(TRUE)
170+
}
171+
return("target and current are both logicals but not equal")
172+
}
173+
if (is.logical(target) || is.logical(current)) {
174+
return("target and current are not both logicals")
175+
}
176+
if (!inherits(current, "CnfAtom")) {
177+
return("current is not a CnfAtom")
178+
}
179+
target$values = sort(target$values)
180+
current$values = sort(current$values)
181+
all.equal.list(target, current, ...)
182+
}
183+
184+
#' @rawNamespace if (getRversion() >= "4.3.0") S3method(chooseOpsMethod,CnfAtom)
185+
chooseOpsMethod.CnfAtom <- function(x, y, mx, my, cl, reverse) TRUE
186+
187+
#' @export
188+
`&.CnfAtom` = function(e1, e2) {
189+
# Will return a CnfFormula, so we can just delegate to there.
190+
# `&.CnfFormula` handles conversion.
191+
`&.CnfFormula`(e1, e2)
192+
}
193+
194+
#' @export
195+
`|.CnfAtom` = function(e1, e2) {
196+
if (inherits(e2, "CnfFormula")) {
197+
# `|.CnfFormula` handles conversion
198+
return(`|.CnfFormula`(e1, e2))
199+
}
200+
if (isFALSE(e1) || isTRUE(e2)) return(as.CnfClause(e2))
201+
if (isFALSE(e2) || isTRUE(e1)) return(as.CnfClause(e1))
202+
203+
# either two proper CnfAtoms, or e2 is a CnfClause.
204+
CnfClause(list(e1, e2))
205+
}
206+
207+
#' @export
208+
`!.CnfAtom` = function(x) {
209+
if (is.logical(x)) {
210+
return(as.CnfAtom(!unclass(x)))
211+
}
212+
structure(
213+
list(symbol = x$symbol, values = setdiff(attr(x, "universe")[[x$symbol]], x$values)),
214+
universe = attr(x, "universe"),
215+
class = "CnfAtom"
216+
)
217+
}

0 commit comments

Comments
 (0)