Solving an algebraic equation

Viewed 141

I'm trying to solve this equation: ((2300+1900*1)+(x+2300+1900*1)*0.002)/(600-400) =1

Is there a way to do this with R?

ATTEMPT with incorrect solution:

library(Ryacas)
eq <- "((2300+1900*1)+(x+2300+1900*1)*0.002)/(600-400) ==1 "
# simplify the equation:
library(glue)
yac_str(glue("Simplify({eq})"))
library(evaluate)
evaluate(eq,list(x=c(0,1,10,100,-100)))

evaluate() just returns the equation:

"((2300+1900*1)+(x+2300+1900*1)*0.002)/(600-400) ==1 " 

The answer for the equation is −2004200

5 Answers

It sounds like you want to Solve() for x rather than merely simplifying ... ? The following code solves the equation, strips off the x== from the solution, and evaluates the expression:

eq2 <- gsub("x==","",yac_str(glue("Solve({eq},x)")))
[1] "{(-0.80168e6)/0.4}"
eval(parse(text=eq2))
[1] -2004200

1) Ryacas Use the Ryacas package solve as shown below. (Thanks to @mikldk for improvement to last line.)

library(Ryacas)
eq <- "((2300+1900*1)+(x+2300+1900*1)*0.002)/(600-400) ==1 "  # from question

res <- solve(ysym(eq), "x")
as_r(y_rmvars(res))  # extract and convert to R
## [1] -2004200

if eq has R variables in it, here h is referenced in eq2, then use eval to evaluate the result.

h <- 2300
eq2 <- "((h+1900*1)+(x+2300+1900*1)*0.002)/(600-400) ==1 "  # from question
res2 <- solve(ysym(eq2), "x")
eval(as_r(y_rmvars(res2)))
## [1] -2004200

2) Ryacas0 or using eq from above with the Ryacas0 package:

library(Ryacas0)

res <- Solve(eq, "x")
eval(Expr(res)[[1:3]]) # convert to R
## [1] -2004200

3a) Base R In light of the fact that this is a linear equation and the solution to the following where A is the slope and B is the intercept:

A * x + B = 0

is

x = - B / A

if we replace x with the imaginary 1i and then move the rhs to the lhs we have that B and A are the real and imaginary parts of that expression. No packages are used.

r <- eval(parse(text = sub("==", "-", eq)), list(x = 1i))
-Re(r) / Im(r)
## [1] -2004200

3b) If we move the rhs to lhs then B equals it at x=0 and A equals the derivative wrt x so another base R solution would be:

e <- parse(text = sub("==", "-", eq))
- eval(e, list(x = 0)) / eval(D(e, "x"))
## [1] -200420

Here is a base R solution.
Rewrite the equation in the form of a function, use curve to get two end points where the function has different signs and put uniroot to work.

f <- function(x) ((2300+1900*1)+(x+2300+1900*1)*0.002)/(600-400) - 1
curve(f, -1e7, 1)
uniroot(f, c(-1e7, 1))
#$root
#[1] -2004200
#
#$f.root
#[1] 0
#
#$iter
#[1] 1
#
#$init.it
#[1] NA
#
#$estim.prec
#[1] 7995800

Following the discussion in the comments to the question, here is a general solution. The function whose roots are to be found now accepts an argument params in order to pass the values of rent, salary, number of workers, price, unit cost and capital cost. This argument must be a named list.

f <- function(x, K = 1, params) {
  A <- with(params, rent + salary*workers)
  with(params, (A + (x + A)*capitalcost)/(price - unitcost) - K)
}

params <- list(
  rent = 2300, 
  salary = 1900, 
  workers = 1, 
  price = 600, 
  unitcost = 400, 
  capitalcost = 0.002
)
curve(f(x, params = params), -1e7, 1)
uniroot(f, c(-1e7, 1), params = params)

If you want something quick: rootSolve library is your go-to.

library(rootSolve)
func_ <- function(x) ((2300+1900*1)+(x+2300+1900*1)*0.002)/(600-400)-1
uniroot.all(func_, c(-1e9, 1e9))
[1] -2004200

Note that most of the time reducing the interval is better.

If you will maintain the same structure, then in Base R, you could do:

solveX <- function(eq){
  U <- function(x)abs(eval(parse(text = sub("=+","-", eq)), list(x=x)))
  optim(0, U, method = "L-BFGS-B")$par
}
eq <- "((2300+1900*1)+(x+2300+1900*1)*0.002)/(600-400) ==1 "
solveX(eq)
[1] -2004200
Related