/
classes.R
181 lines (139 loc) · 5.38 KB
/
classes.R
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
## SymEnginePTR is the parent class holding Basic, VecBasic, etc.
setClass("SymEnginePTR", slots = c(ptr = "externalptr"))
setClass("Basic", contains = "SymEnginePTR")
setClass("VecBasic", contains = "SymEnginePTR")
setClass("DenseMatrix", contains = "SymEnginePTR")
## Class for dispatch purpose (TODO: maybe use class inheritance instead of union)
setClassUnion("SymEngineDataType", c("Basic", "VecBasic", "DenseMatrix"))
setClassUnion("BasicOrVecBasic", c("Basic", "VecBasic"))
## A context is an environment where symbols in the expression may be substituted from
setClass("SymEnginePTRWithContext", contains = "SymEnginePTR", slots = c(context = "environment"))
setClass("BasicWithContext", contains = c("Basic", "SymEnginePTRWithContext"))
setClass("VecBasicWithContext", contains = c("VecBasic", "SymEnginePTRWithContext"))
setClass("DenseMatrixWithContext", contains = c("DenseMatrix", "SymEnginePTRWithContext"))
#### Function Symbol Generator ========================
setClass("FunctionSymbolGenerator",
contains = c("function"), slots = c(name = "character"),
prototype = function(...) FunctionSymbol(sys.function()@name, list(...))
)
#### Some conversion methods ==========================
setAs(from = "SymEnginePTR", to = "externalptr",
function(from) from@ptr
)
#### setAs for Basic ==================================
setAs(from = "ANY", to = "Basic",
function(from) s4basic_parse(from, check_whole_number = FALSE)
)
#' Some Conversion Methods
#'
#' Miscellaneous S4 methods defined for converting a \code{Basic} or
#' \code{VecBasic} object to R number/string/language object.
#'
#' @param x The object to be converted.
#'
#' @return Same as default methods of these generics. \code{as.language()}
#' may return \code{symbol}, \code{integer}, \code{double} or \code{call}.
#' @rdname conversion
setMethod("as.character", c(x = "Basic"),
## TODO: also define method for VecBasic
function(x) s4basic_str(x)
)
#' @rdname conversion
setMethod("as.numeric", c(x = "Basic"),
function(x) as.double(s4basic_as_sexp(x))
)
#' @rdname conversion
setMethod("as.integer", c(x = "Basic"),
function(x) {
if (s4basic_get_type(x) == "Integer")
return(s4basic_as_sexp(x))
stop(sprintf("Not implemented for type %s", get_type(x)))
}
)
setMethod("as.vector", c(x = "Basic"),
function(x, mode) {
## TODO
if (mode == "expression") ## Supports as.expression.default
return(as.expression(as.language(x)))
if (mode == "symbol") { ## Supports as.symbol and as.name
if (s4basic_get_type(x) != "Symbol")
stop("Type of the Basic object is not 'Symbol'")
return(as.symbol(as.character(x)))
}
stop(sprintf("mode [%s] not implemented", mode))
}
)
#### setAs for VecBasic ==============================
setAs("Basic", "VecBasic", function(from) Vector(from))
setAs("VecBasic", "Basic", function(from) {
stopifnot(length(from) == 1L)
from[[1]]
})
setAs("vector", "VecBasic", function(from) Vector(from))
## By defining as.vector, it automatically supports as.list, matrix, as.matrix, array, etc.
setMethod("as.vector", c(x = "VecBasic"),
function(x, mode) {
## TODO: add as.vector method to Basic as well?
if (mode == "any" || mode == "list") {
ans <- vector("list", length(x))
## TODO: Improve the performance of this
for (i in seq_along(ans))
ans[[i]] <- s4vecbasic_get(x, i)
return(ans)
}
## TODO: it might be useful to convert to other modes (e.g. numeric),
## if it is not possible, we can return NA and give a warning
## (NA introduced by coercion)
## Other modes: logical, integer, numeric (double), complex, character, raw,
## list, expression
stop(sprintf("Can not convert VecBasic to %s", mode))
}
)
#' @rdname conversion
setMethod("as.character", c(x = "VecBasic"),
function(x) {
vapply(as.list(x), as.character, character(1L))
}
)
#' @rdname conversion
setMethod("as.numeric", c(x = "VecBasic"),
function(x) {
vapply(as.list(x), as.double, double(1L))
}
)
#' @rdname conversion
setMethod("as.integer", c(x = "VecBasic"),
function(x) {
vapply(as.list(x), as.integer, integer(1L))
}
)
#### setAs for DenseMatrix ===========================
setAs("DenseMatrix", "VecBasic", function(from) {
## Extract by column
## TODO: this function is relative slow and used by other functions
nrow <- nrow(from)
ncol <- ncol(from)
row_idx <- rep(seq.int(nrow), ncol)
col_idx <- rep(seq.int(ncol), each = nrow)
s4DenseMat_get(from, row_idx, col_idx, get_basic = FALSE)
})
setAs("VecBasic", "DenseMatrix", function(from) Matrix(from))
setAs("matrix", "DenseMatrix", function(from) Matrix(from))
setMethod("as.vector", c(x = "DenseMatrix"),
function(x, mode) {
## TODO: maybe avoid converting to VecBasic with
## s4binding_subset(x, idx, get_basic = TRUE)
as.vector(as(x, "VecBasic"), mode)
}
)
#### Convert SymEngine objects to R expression ========
#' @rdname conversion
#' @export
setGeneric("as.language", function(x) standardGeneric("as.language"))
#' @rdname conversion
setMethod("as.language", c(x = "Basic"),
function(x) asLanguage(x)
)
setAs("Basic", "language",
function(from) asLanguage(from)
)