Solving Linear Equations Step by Step

Two Equations in Two Unknowns

by George Beck

This notebook discusses the solutions of systems of equations  The built-in functions Solve and NSolve are the usual way to solve such systems.  The defined function WalkSolve solves a system step by step.

Proper formatting of output

From the menu, select Info, Preferences, Action... to produce a big box titled Action Preferences.

Look at the second box within Action Preferences titled Placing Print Output.

Click on the first little button so that there is no check mark for ``Place Print output as it is generated''.

Click on the second little button so that there is a check mark for ``Place each Print line in a separate cell''.

Click on the Apply button at the bottom.

Discussion

This defines four linear equations. that we will solve in pairs. The single equal sign is an assignment, the double equal signs represent equality. The variables l1, l2, l3, and l4 stand for the whole equation.

l1 = 2 x + 3 y == 4;

l2 = -4 x + 3 y == -1;

l3 = 2 x + 3 y == 8;

l4 = -8 x + 6 y == -2;

The fast way

Example 1

This is the format for solving the two equations simultaneously. Solve gives the answers immediately.

Solve[{l1, l2}, {x, y}]

If you want to see decimals, use N, which stands for numeric. In Mathematica % means the previous result.

N[%]

You can get decimals right away by using NSolve.

NSolve[{l1, l2}, {x, y}]

Example 2

There are no solutions to this next system, because the equations l1 and l3 are the same on the left hand side but different on the right.

Solve[{l1, l3}, {x, y}]

Example 3

In this case there are infinitely many solutions, because one of the equations is a multiple of the other.

Solve[{l2, l4}, {x, y}]

One step at a time

You can solve systems of equations one step at a time, instead of all at once like Solve or NSolve.  With WalkSolve, each step is explained and the usual Mathematica output for Solve is shown as a check.  With RunSolve no explanations are given.

Example 4

WalkSolve[{l1, l2}, {x, y}]

Example 5

WalkSolve[{l1, l3}, {x, y}]

Example 6

RunSolve[{l3, l4}, {x, y}]

Implementation

WalkSolve::usage = 
"WalkSolve[{a x + b y == u, c x + d y == v}, {x, y}] 
solves the pair of simultaneous system of equations  
for x and y one step at a time, explaining each step.";

RunSolve::usage = 
"RunSolve[{a x + b y == u, c x + d y == v}, {x, y}] 
solves the pair of simultaneous system of equations  
for x and y one step at a time with no explanations.";

Converting between equations and a matrix

MatrixFromEquations[eqns_, {x_, y_}] := 
{
	{
		eqns[[1, 1]] /. {x -> 1, y -> 0}, 
		eqns[[1, 1]] /. {x -> 0, y -> 1},
		eqns[[1, 2]]
	},
	{
		eqns[[2, 1]] /. {x -> 1, y -> 0}, 
		eqns[[2, 1]] /. {x -> 0, y -> 1},
		eqns[[2, 2]]
	}
}

EquationsFromMatrix[{{a_, b_, u_}, {c_, d_, v_}}, 
	{x_, y_}] := {a x + b y ==u, c x +d y == v}

WalkSolve

many or no solutions

WalkSolve[eqns:{True, _}, {x_, y_}] := (
	Print @ TableForm @ eqns; 
	Print["There are infinitely many solutions!"];
	Print["This is the result from Solve in one step: "];
	Solve[eqns, {x, y}] )

WalkSolve[eqns:{_, True}, {x_, y_}] := (
	Print @ TableForm @ eqns; 
	Print["There are infinitely many solutions!"];
	Print["Using Solve: "];
	Solve[eqns, {x, y}] )

WalkSolve[eqns:{False, _}, {x_, y_}] := (
	Print @ TableForm @ eqns; 
	Print["There are no solutions!"];
	Print["This is the result from Solve in one step: "];
	Solve[eqns, {x, y}] )

WalkSolve[eqns:{_, False}, {x_, y_}] := (
	Print @ TableForm @ eqns; 
	Print["There are no solutions!"];
	Print["This is the result from Solve in one step: "];
	Solve[eqns, {x, y}] )

both equations solved

WalkSolve[
	eqns:{x_ == u_, y_ == v_}, 
	{x_, y_}] := (
	Print @ TableForm @ eqns; 
	Print["This is the result from Solve in one step: "];
	Solve[eqns, {x, y}]
)

the loop

WalkSolve[eqns_, {x_, y_}] := Module[
	{rm, neweqns}, 
	Print @ TableForm @ eqns; 
	rm = ReduceMatrix[MatrixFromEquations[eqns, {x, y}]];
	Print[ rm[[1]] ];
	neweqns = EquationsFromMatrix[rm[[2]], {x, y}];
	WalkSolve[neweqns, {x, y}]
]

RunSolve

many or no solutions

WalkSolve[eqns:{True, _}, {x_, y_}] := 
	Print @ TableForm @ eqns;

RunSolve[eqns:{_, True}, {x_, y_}] := 
	Print @ TableForm @ eqns;

RunSolve[eqns:{False, _}, {x_, y_}] := 
	Print @ TableForm @ eqns;

RunSolve[eqns:{_, False}, {x_, y_}] := 
	Print @ TableForm @ eqns;

both equations solved

RunSolve[
	eqns:{x_ == u_, y_ == v_}, 
	{x_, y_}] := Print @ TableForm @ eqns;

the loop

RunSolve[eqns_, {x_, y_}] := Module[
	{rm, neweqns}, 
	Print @ TableForm @ eqns; 
	rm = ReduceMatrix[MatrixFromEquations[eqns, {x, y}]];
	Print[ "........................................." ];
	neweqns = EquationsFromMatrix[rm[[2]], {x, y}];
	RunSolve[neweqns, {x, y}]
]

String statements

ToNiceString[z_] :=
If[
	Head[z] === Rational, 
	StringJoin[
		ToString[Numerator[z]], 
		"/", 
		ToString[Denominator[z]]
	],
	ToString[z]
]

SwitchFirstSecond[] := 
	"Switch the equations."

SubtractFirstSecond[] := 
	"Subtract the first equation from the second."

SubtractSecondFirst[] :=
	"Subtract the second equation from the first."

DivideFirst[z_] := 
StringJoin[
	"Divide by ", 
	ToNiceString[z], 
	" in the first equation."
	]

DivideSecond[z_] := 
StringJoin[
	"Divide by ", 
	ToNiceString[z], 
	" in the second equation."
]

SubtractMultipleFirstSecond[z_] := 
StringJoin[
	"Subtract ", 
	ToNiceString[z], 
	" times the first equation from the second."
]

SubtractMultipleSecondFirst[z_] := 
StringJoin[
	"Subtract ", 
	ToNiceString[z], 
	" times the second equation from the first."
]

ReduceMatrix

one equation is solved

ReduceMatrix[{{1, 0, u_}, {c_, d_, v_}}] := 
	{
		SubtractMultipleFirstSecond[c], 
		{{1, 0, u}, {0, d, v - c u}}
	} /; c!= 0

ReduceMatrix[{{a_, b_, u_}, {0, 1, v_}}] := 
	{
		SubtractMultipleSecondFirst[a], 
		{{a, 0, u - b v}, {0, 1, v}}
	} /; b != 0

missing terms

ReduceMatrix[{{0, b_, u_}, {c_, d_, v_}}] := 
	{
		SwitchFirstSecond[],
		{{c, d, v}, {0, b, u}}
	}

ReduceMatrix[{{a_, b_, u_}, {0, d_, v_}}] := 
	{
		DivideSecond[d],  
		{{a, b, u}, {0, 1, v/d}}
	} /; d != 1

ReduceMatrix[{{a_, b_, u_}, {c_, 0, v_}}] := 
	{
		SwitchFirstSecond[],
		{{c, 0, v}, {a, b, u}}
	}

ReduceMatrix[{{a_, 0, u_}, {c_, d_, v_}}] := 
	{
		DivideFirst[a],  
		{{1, 0, u/a}, {c, d, v}} 
	} /; a != 1

matching terms

ReduceMatrix[{{a_, b_, u_}, {a_, d_, v_}}] := 
	{	
		SubtractFirstSecond[],
		{{a, b, u}, {0, d - b, v - u}}
	}

ReduceMatrix[{{a_, b_, u_}, {c_, b_, v_}}] := 
	{
		SubtractSecondFirst[],
		{{a - c, 0, u - v}, {c, b, v}}
	}

a coefficient is 1

ReduceMatrix[{{1, b_, u_}, {c_, d_, v_}}] := 
	{
		SubtractMultipleFirstSecond[c], 
		{{1, b, u}, {0, d - b c, v - c u}}
	}/; c != 1

ReduceMatrix[{{a_, b_, u_}, {1, d_, v_}}] := 
	{
		SubtractMultipleSecondFirst[a], 
		{{0, b - a d, u - a v}, {1, d, v}}
	} /; a != 1

ReduceMatrix[{{a_, 1, u_}, {c_, d_, v_}}] := 
	{
		SubtractMultipleFirstSecond[d], 
		{{a, 1, u}, {c - a d, 0, v - d u}}
	}/; d != 1

ReduceMatrix[{{a_, b_, u_}, {c_, 1, v_}}] := 
	{
		SubtractMultipleSecondFirst[b], 
		{{a - b c, 0, u - b v}, {c, 1, v}}
	} /; b != 1

the general case

ReduceMatrix[{{a_, b_, u_}, {c_, d_, v_}}] :=
	{
		DivideFirst[a], 
		{{1, b/a, u/a}, {c, d, v}}
	} /; a != 1