我试图解析XML中的表达式,然后在deSolve的ode函数中使用它们。
定义费率的XML位如下所示:
<model name="Lorenz">
<state_variables>
<variable id="X" name="x" value="1"/>
<variable id="Y" name="y" value="1"/>
<variable id="Z" name="z" value="1"/>
</state_variables>
<parameters>
<variable id="a" name="a" value="-2.66"/>
<variable id="b" name="b" value="-10"/>
<variable id="c" name="c" value="28"/>
</parameters>
<rates>
<variable id="dX" name="xchange" value="a*X+Y*Z"/>
<variable id="dY" name="ychange" value="b*(Y-Z)"/>
<variable id="dZ" name="zchange" value="-X*Y+c*Y-Z"/>
</rates>
</model>
在解析变量leafs后,我的R对象看起来像这样:
rates
expression(dX = a * X + Y * Z, dY = b * (Y - Z), dZ = -X * Y + c * Y - Z)
我的目标是在这样的函数中获取这些表达式,但不是硬编码:
differentialRates= function(t, states, parameters){
with(as.list(c(states, parameters)),{
# This works but is still hardcoded:
dX <- eval(rates[1])
dY <- eval(rates[2])
dZ <- eval(rates[3])
# return the rate of change
list(c(dX, dY, dZ))
})
}
out <- ode(y = states, times = times, func = differentialRates, parms = parameters)
因此,如果rates
向量因为加载了其他XML而发生更改,则不必更改函数differentialRates
。
非常感谢任何见解。
编辑正如Justin所要求的那样,我的代码解析了XML,我还将上面的XML扩展为更具包容性。
extractVars = function(doc, model, node, key = "id", value = "value", numeric = FALSE, expression = FALSE){
path = paste("/models/model[@name='",model, "']/", node, "/variable", sep="") # Construct xpath
xvars = xpathSApply(doc, path) # Retrieve variable leafs
xvars = sapply(xvars, xmlAttrs) # Retrieve attributes
vars = as.vector(t(xvars[value,])) # Turn matrix (svars) into vector (vars)
if(numeric){
vars = as.numeric(vars)
}
if(expression){
vars = mapply(parse, vars, text=vars)
}
names(vars) = xvars[key,] # Apply names from matrix to vector
return(vars)
}
检索这样的变量:
parameters = extractVars(doc, model="Lorenz", node="parameters", numeric=TRUE)
states = extractVars(doc, model="Lorenz", node="state_variables", numeric=TRUE)
rates = extractVars(doc, model="Lorenz", node="rates", expression=TRUE)
我的猜测是这样的函数:
differentialRates <- function(t, y, parameters){
return(lapply(rates, eval))
}
但是这会返回错误:
Error in split.default(rep_len(as.vector(e2), prod(dim(e1))), rep.int(seq_len(ncol(e1)), : unimplemented type 'expression' in 'split'