views:

108

answers:

3

I am trying to write a Matlab program that accepts variables for a system from the user, but there are more variables than system parameters. To be specific, six variables in three equations:

w - d - M = 0
l - d - T = 0
N - T + M = 0

This could be represented in matrix form as A*x=0 where

A = [1  0  0 -1  0 -1;
     0  1  0 -1 -1  0;
     0  0  1  0 -1  1];

x = [w  l  N  d  T  M]';

I would like to be able to solve this system given a known subset of the variables. For example, if the user gives d, T, M, then the system is trivially solved for the other three variables. If the user supplies w, N, M, then it becomes a solvable 3-DOF system. And so on. (If the user over- or under-specifies the system then an error may of course result.)

Given any one of these combinations it's simple to (a priori) use matrix algebra to calculate the unknown quantities. But I don't know how to solve the general case, aside from using the symbolic toolbox (which I prefer not to do for compatibility reasons).

When I started with this approach I thought this step would be easy, but my linear algebra is rusty; am I missing something simple?

A: 

The system of equations is fixed? What if you store the variables present in your three equations in a list per equation:

(w, d, M)
(l, d, T)
(N, T, M)

Then you get the user input and you can calculate the number of variables given in each equation:

User input: w, N, M
Given variables:
(w, d, M) -> 2
(l, d, T) -> 0
(N, T, M) -> 1

This would trivially give you d from the first equation. Therefore you end up with two equations containing two variables and you know you the equation system you have to solve.

It's basically your own simple symbolic solver for a single system of equations.

Sebastian
Yes, this is what I'm trying to do... but it's the missing details in here that I'm having trouble with. I agree it's easy to do algebraically but the tricky part is doing it generally (but perhaps I'm being too optimistic/ambitious trying to do it generally).
Will Robertson
+4  A: 

First, let x be a vector with NaN for the unknown values. This allows you to use ISNAN to find the indeces of the unknowns. If you calculate A*x for only the user-specified terms, that gives you a column of constants b. Take those constants to the right-hand side of the equation, and you have an equation of the form A*x = -b.

A = [1  0  0 -1  0 -1;
     0  1  0 -1 -1  0;
     0  0  1  0 -1  1];

idx = ~isnan(x); 
b = A(:,idx)*x(idx); % user provided constants
z = A(:,~idx)\(-b); % solution of Ax = -b
x(~idx) = z;

With input x = [NaN NaN NaN 1 1 1]', for instance, you get the result [2 2 0 1 1 1]'. This uses MLDIVIDE, I'm not well versed enough in linear algebra to know whether PINV or something else would be better.

mtrw
This looks promising, thanks!
Will Robertson
Indeed, works like a charm :) After seeing the solution I should have been able to figure that for myself... too long an evening for me, I think!
Will Robertson
+3  A: 

Given the linear system

A = [1  0  0 -1  0 -1;
     0  1  0 -1 -1  0;
     0  0  1  0 -1  1];

A*x = 0

Where the elements of x are identified as:

x = [w  l  N  d  T  M]';

Now, suppose that {d,T,M} have known, fixed values. What we need are the indices of these elements in x. We've chosen the 4th, 5th and 6th elements of x to be knowns.

known_idx = [4 5 6];
unknown_idx = setdiff(1:6,known_idx);

Now, let me pick some arbitrary numbers for those known variables.

xknown = [1; -3; 7.5];

We will partition A into two submatrices, corresponding to the known and unknown variables.

Aknown = A(:,known_idx);
Aunknown = A(:,unknown_idx);

Now, move the known values to the right hand side of the equality, and solve. See that Aknown is a 3x3 matrix, so the problem is (hopefully) well posed.

xunknown = Aunknown\(-Aknown*xknown)
xunknown =
         -8.5
            2
         10.5

Combine it all into the final solution.

x = zeros(6,1);
x(known_idx) = xknown;
x(unknown_idx) = xunknown;
x =
         -8.5
            2
         10.5
            1
           -3
          7.5

Note that I've expanded this all out into a few lines to show what is happening more clearly. But I could have done it all in just a line or two of code had I wanted to be parsimonious.

Finally, see that had I chosen some other sets of numbers to be the knowns, such as {l,d,T}, then the resulting system would be singular. So you must watch for that event. A test on the rank of Aunknown might be useful to weed out the problems. Or you might choose to employ pinv to build the solution.

woodchips