rnumerical-methodsnonlinear-optimizationnewtons-methodnonlinear-equation

solving a simple (?) system of nonlinear equations


I'm trying to solve a simple system of non-linear equations described in this post.

The system is two equations with two unknowns p and q and a free parameter lambda:

enter image description here

When lambda = 1 the system looks like this:

enter image description here

There is a unique solution and it's in the vicinity of p = 0.3, q = 0.1.

I'm trying to solve it with nleqslv. My objective function is:

library(nleqslv)

fn = function(x, lambda = 1){ 
  # p = x[1]
  # q = x[2]
  pstar = exp(lambda * (1*x[2])) / (exp(lambda * (1*x[2])) + exp(lambda * (1 - x[2])))
  qstar = exp(lambda * (1 - x[1])) / (exp(lambda * ((1 - x[1]))) + exp(lambda * (9*x[1])))
  return(c(pstar,qstar))
}

but the results don't match what the plot:

> xstart = c(0.1, 0.3)
> nleqslv(xstart, fn)$x
[1]  1.994155 -8.921285

My first question is: am I using nleqslv correctly? I thought so after looking at other examples. But now I'm not sure.

My second question: is this a good problem nleqslv? Or am I barking up the wrong tree?


Solution

  • Your function does not reflect properly what you want.

    You can see this by evaluating fn(c(0.3,0.1)) as follows.

    fn(c(0.3,0.1))
    [1] 0.3100255 0.1192029
    

    So the output is very close to the input. You wanted (almost) zero as output.

    So you want to solve the system for p and q. What you need to do is to make your function return the difference between the input p and the expression for pstar and the difference between the input q and the expression for qstar.

    So rewrite your function as follows

    fn <- function(x, lambda = 1){ 
      p <- x[1]
      q <- x[2]
      pstar <- exp(lambda * (1*x[2])) / (exp(lambda * (1*x[2])) + exp(lambda * (1 -    x[2])))
      qstar <- exp(lambda * (1 - x[1])) / (exp(lambda * ((1 - x[1]))) + exp(lambda * (9*x[1])))
      return(c(pstar-p,qstar-q))
    }  
    

    and then call nleqslv as follows (PLEASE always show all the code you are using. You left out the library(nleqslv)).

    library(nleqslv)
    xstart <- c(0.1, 0.3)
    nleqslv(xstart, fn)
    

    This will display the full output of the function. Always a good idea to check for succes. Always check $termcd for succes.

    $x
    [1] 0.3127804 0.1064237
    
    $fvec
    [1] 5.070055e-11 6.547240e-09
    
    $termcd
    [1] 1
    
    $message
    [1] "Function criterion near zero"
    
    $scalex
    [1] 1 1
    
    $nfcnt
    [1] 7
    
    $njcnt
    [1] 1
    
    $iter
    [1] 7
    

    The result for $x is more what you expect.

    Finally please use <- for assignment. If you don't there will come the day that you will be bitten by R and its magic.

    This is nothing wrong in using nleqslv for this problem. You only made a small mistake.