Search code examples
c#algorithmsymbolic-math

Is there general method to solve for a single unknown if the unknown variable changes?


I have a simple algebraic relationship that uses three variables. I can guarantee that I know two of the three and need to solve for the third, but I don't necessarily know which two of the variables I will know. I'm looking for a single method or algorithm that can handle any of the cases without a huge batch of conditionals. This may not be possible, but I would like to implement it in a more general sense rather than code in every relationship in terms of the other variables. For example, if this were the relationship:

3x - 5y + z = 5

I don't want to code this:

function(int x, int y)
{
  return 5 - 3x + 5y;
}

function(int x, int z)
{
  return (5 - z - 3x)/(-5);
}

And so on. Is there a standard sort of way to handle programming problems like this? Maybe using matrices, parameterization, etc?


Solution

  • If you restrict yourself to the kind of linear functions shown above, you could generalize the function like this

    3x - 5y + z = 5
    

    would become

    a[0]*x[0] + a[1]*x[1] + a[2]*x[2] = c
    

    with a = { 3, -5, 1 } and c = 5.

    I.e., you need a list (or array) of constant factors List<double> a; and a list of variables List<double?> x; plus the constant on the right side double c;

    public double Solve(IList<double> a, IList<double?> x, double c)
    {
        int unknowns = 0;
        int unkonwnIndex = 0; // Initialization required because the compiler is not smart
                              // enough to infer that unknownIndex will be initialized when
                              // our code reaches the return statement.
        double sum = 0.0;
    
        if (a.Count != x.Count) {
           throw new ArgumentException("a[] and x[] must have same length");
        }
        for (int i = 0; i < a.Count; i++) {
            if (x[i].HasValue) {
               sum += a[i] * x[i].Value;
            } else {
               unknowns++;
               unknownIndex = i;
            }
        }
        if (unknowns != 1) {
           throw new ArgumentException("Exactly one unknown expected");
        }
        return (c - sum) / a[unknownIndex];
    }
    

    Example:

    3x - 5y + z = 5
    
        5 - (- 5y + z)
    x = --------------
              3
    

    As seen in the example the solution consists of subtracting the sum of all terms except the unknown term from the constant and then to divide by the factor of the unknown. Therefore my solution memorizes the index of the unknown.


    You can generalize with powers like this, assuming that you have the equation

    a[0]*x[0]^p[0] + a[1]*x[1]^p[1] + a[2]*x[2]^p[2] = c
    

    you need an additional parameter IList<int> p and the result becomes

    return Math.Pow((c - sum) / a[unknownIndex], 1.0 / p[unknownIndex]);
    

    as x ^ (1/n) is equal to nth-root(x).


    If you use doubles for the powers, you will even be able to represent functions like

             5
    7*x^3 + --- + 4*sqrt(z) = 11
            y^2
    
    a = { 7, 5, 4 },  p = { 3, -2, 0.5 },  c = 11
    

    because

              1
    x^(-n) = ---
             x^n
    

    and

    nth-root(x) = x^(1/n)
    

    However, you will not be able to find the roots of true non-linear polynomials like x^2 - 5x = 7. The algorithm shown above, works only, if the unknown appears exactly once in the equation.