求解非线性方程组R

时间:2017-04-02 19:06:08

标签: r

我尝试使用R中的nleqslv函数求解一组非线性方程组。不幸的是,我遇到了猜测正确的初始值以使函数成功运行的麻烦。我有一个值介于0和1之间的向量,称为c(t)。它们应满足以下等式

c(t)=A*(exp(-mt)+exp(-m(1024-t)))+B^2

使用t的三个后续值,我的目标是使用以下代码确定系数A,B,m

library(nleqslv)

C10 <- c(1.000000e+00,9.754920e-01,9.547681e-01,9.359057e-01,9.182586e-01,9.014674e-01)
system_size <- 1024

for(i in 2:5)
{
  C <- c(C10[i-1],C10[i],C10[i+1],i-2)
  #function
  target <- function(Coeffs){
  y <- numeric(3)
  y[1] <- Coeffs[1]*(exp(-Coeffs[2]*(C[4]-1))+exp(-Coeffs[2]*(system_size-(C[4]-1))))+Coeffs[3]^2-C[1]
  y[2] <- Coeffs[1]*(exp(-Coeffs[2]*(C[4]))+exp(-Coeffs[2]*(system_size-(C[4]))))+Coeffs[3]^2-C[2]
  y[3] <- Coeffs[1]*(exp(-Coeffs[2]*(C[4]+1))+exp(-Coeffs[2]*(system_size-(C[4]+1))))+Coeffs[3]^2-C[3]
  y
 }
 init <- c(0.001,0.01,0)
 sol <- nleqslv(init, target,control=list(btol=.01), method="Broyden")
 }

使用的初始值反映了在绘制关联值c(t)时得到的结果。尽管如此,生成的输出sol给出了

chr "Jacobian is ill-conditioned (1/condition=9.0e-18) (see allowSingular option)"

知道出了什么问题以及如何解决这个问题?

OP编辑:修改代码以获得最少的工作示例:为C10添加前几个值,为system_size添加调整后的循环和附加值

1 个答案:

答案 0 :(得分:0)

如果您为C10添加了一些数据,那么如果考虑到循环应该考虑length(C10),则该示例运行完全正常。 像这样(有一些变化;为什么看下面):

library(nleqslv)

C10 <- c(1.000000e+00,9.754920e-01,9.547681e-01,9.359057e-01,9.182586e-01,9.014674e-01)
system_size <- 1024

target <- function(Coeffs){
    y <- numeric(3)
    y[1] <- Coeffs[1]*(exp(-Coeffs[2]*(C[4]-1))+exp(-Coeffs[2]*(system_size-(C[4]-1))))+Coeffs[3]^2-C[1]
    y[2] <- Coeffs[1]*(exp(-Coeffs[2]*(C[4]))+exp(-Coeffs[2]*(system_size-(C[4]))))+Coeffs[3]^2-C[2]
    y[3] <- Coeffs[1]*(exp(-Coeffs[2]*(C[4]+1))+exp(-Coeffs[2]*(system_size-(C[4]+1))))+Coeffs[3]^2-C[3]
    y
}

init <- 50*c(0.001,0.01,0)

for(i in 2:min(length(C10)-1,(system_size/2)))
{

    C <- c(C10[i-1],C10[i],C10[i+1],i-2)
  #function
    target <- function(Coeffs){
        y <- numeric(3)
        y[1] <- Coeffs[1]*(exp(-Coeffs[2]*(C[4]-1))+exp(-Coeffs[2]*(system_size-(C[4]-1))))+Coeffs[3]^2-C[1]
        y[2] <- Coeffs[1]*(exp(-Coeffs[2]*(C[4]))+exp(-Coeffs[2]*(system_size-(C[4]))))+Coeffs[3]^2-C[2]
        y[3] <- Coeffs[1]*(exp(-Coeffs[2]*(C[4]+1))+exp(-Coeffs[2]*(system_size-(C[4]+1))))+Coeffs[3]^2-C[3]
        y
    }

    cat("i=",i,"init=",init, "target(init)=",target(init),"\n")
    sol <- nleqslv(init, target,control=list(btol=.01), method="Broyden")
    print(sol)
}

使用您的初始起始值,模型无法解决并提供您提及的错误消息。我通过增加值来更改init的值。然后找到一个解决方案 - i=5。给定C10的较大值将不会运行,因为在引用循环C10[i+1]内(并且它不存在)。

我在函数调用之后调用catnleqslv之前插入了一个print(sol)语句,这样一个人至少可以看到发生了什么,以及是否找到了解决方案

您不需要指定method="Broyden",因为它是默认值。

如果发生错误,您应该在sol$termcd循环结束出口处测试for

使用这样的脚本总是在循环内打印东西!

Mislav是正确的:起始值可能完全错误。

即使起始值正常,所使用的算法也会失败。这就是包提供函数testnslvsearchZeros

的原因

我使用testnslv做了一些实验(此处未显示),结论是method="Newton"失败了。狗腿洞的全球战略似乎总能奏效。 linesearch战略并不总是奏效。

相关问题