from __future__ import division
Yesterday and this morning we saw how we can solve linear equations in 3,4 variables, and some of you have even seen how to do it in general.
We will now go over this more carefully.
### Helper functions
def multiply_equation(eq,num):
"""Multiply all coefficients of equation eq by number num.
Return result"""
res = []
for x in eq:
res += [x*num]
return res
def add_equations(eq1,eq2):
"""Add eq1 and eq2. Return result"""
res = []
for i in range(len(eq1)):
res.append(eq1[i]+eq2[i])
return res
Input: List of $n$ equations $eqs= [ eqs[0], \ldots, eqs[n-1] ]$ in $n$ variables. For every $i=0..n-1$, $eqs[i]$ is a list of $n+1$ numbers.
Output: List of $n$ numbers $[x_0,\ldots,x_n-1]$ that are a solution to the equations. That is, for every $i=0..n-1$, $eqs[i][0]x_0+...+eqs[i][n-1]x_{n-1} + eqs[i][n] = 0$
Assumption: We already know how to solve $n-1$ equations in $n-1$ variables.
Operation:
def solve100(eqs):
n = len(eqs)
make_first_coeff_nonzero_general(eqs) # make 1st coef of 1st equation nonzero
eqs[0] = multiply_equation(eqs[0],1/eqs[0][0])
# make 1st coef of 1st equation equal 1
for i in range(1,n-1):
eqs[i] = add_equations(eqs[i],multiply_equation(eqs[0],-eqs[i][0])) # zero out first coefficient in eqs 1,2
# make 1st coef of 2nd .. n-th equation equal zero
rest_equations = []
for i in range(1,n):
rest_equations.append(eqs[i][1:n+1])
solutions = solve99(rest_equations)
# solve remainder of equations for remainder of variables
x = - eqs[0][n]
for i in range(1,n):
x -= eqs[0][i]*solutions[i-1]
# solve 1st variable using solution for 2nd and 3rd variable
return [x] + solutions
def solve99(eqs):
n = len(eqs)
make_first_coeff_nonzero_general(eqs) # make 1st coef of 1st equation nonzero
eqs[0] = multiply_equation(eqs[0],1/eqs[0][0])
# make 1st coef of 1st equation equal 1
for i in range(1,n-1):
eqs[i] = add_equations(eqs[i],multiply_equation(eqs[0],-eqs[i][0])) # zero out first coefficient in eqs 1,2
# make 1st coef of 2nd .. n-th equation equal zero
rest_equations = []
for i in range(1,n):
rest_equations.append(eqs[i][1:n+1])
solutions = solve98(rest_equations)
# solve remainder of equations for remainder of variables
x = - eqs[0][n]
for i in range(1,n):
x -= eqs[0][i]*solutions[i-1]
# solve 1st variable using solution for 2nd and 3rd variable
return [x] + solutions
So, we could write functions solve1
,solve2
,...,solve10000
But we can see that they are very similar. The solution for solve
$n$ uses solve
$n-1$
This suggests that we should use recursion
def solve(eqs):
n = len(eqs)
make_first_coeff_nonzero_general(eqs) # make 1st coef of 1st equation nonzero
eqs[0] = multiply_equation(eqs[0],1/eqs[0][0])
# make 1st coef of 1st equation equal 1
for i in range(1,n-1):
eqs[i] = add_equations(eqs[i],multiply_equation(eqs[0],-eqs[i][0])) # zero out first coefficient in eqs 1,2
# make 1st coef of 2nd .. n-th equation equal zero
rest_equations = []
for i in range(1,n):
rest_equations.append(eqs[i][1:n+1])
solutions = solve(rest_equations)
# solve remainder of equations for remainder of variables
x = - eqs[0][n]
for i in range(1,n):
x -= eqs[0][i]*solutions[i-1]
# solve 1st variable using solution for 2nd and 3rd variable
return [x] + solutions
Let's see if it works:
solve([[1,2,3],[4,5,6]])
------------------------------------------------------------------------ IndexError Traceback (most recent call last) <ipython-input-17-4bfdb83a874e> in <module>() ----> 1 solve([[1,2,3],[4,5,6]]) <ipython-input-7-f7aa95396613> in solve(eqs) 13 rest_equations.append(eqs[i][1:n+1]) 14 ---> 15 solutions = solve(rest_equations) 16 # solve remainder of equations for remainder of variables 17 <ipython-input-7-f7aa95396613> in solve(eqs) 2 n = len(eqs) 3 make_first_coeff_nonzero_general(eqs) # make 1st coef of 1st equation nonzero ----> 4 eqs[0] = multiply_equation(eqs[0],1/eqs[0][0]) 5 # make 1st coef of 1st equation equal 1 6 IndexError: list index out of range
Since it didn't work let's try to see where the problem was: let's print the length of equations so we understand where in the recursion it fails.
def solve(eqs):
n = len(eqs)
print "Solving ", n, " equations in ", n, "variables"
make_first_coeff_nonzero_general(eqs) # make 1st coef of 1st equation nonzero
eqs[0] = multiply_equation(eqs[0],1/eqs[0][0])
# make 1st coef of 1st equation equal 1
for i in range(1,n-1):
eqs[i] = add_equations(eqs[i],multiply_equation(eqs[0],-eqs[i][0])) # zero out first coefficient in eqs 1,2
# make 1st coef of 2nd .. n-th equation equal zero
rest_equations = []
for i in range(1,n):
rest_equations.append(eqs[i][1:n+1])
solutions = solve(rest_equations)
# solve remainder of equations for remainder of variables
x = - eqs[0][n]
for i in range(1,n):
x -= eqs[0][i]*solutions[i-1]
# solve 1st variable using solution for 2nd and 3rd variable
return [x] + solutions
solve([[1,2,3],[4,5,6]])
------------------------------------------------------------------------ IndexError Traceback (most recent call last) <ipython-input-25-4bfdb83a874e> in <module>() ----> 1 solve([[1,2,3],[4,5,6]]) <ipython-input-22-3e3cfcace514> in solve(eqs) 13 rest_equations.append(eqs[i][1:n+1]) 14 ---> 15 solutions = solve(rest_equations) 16 # solve remainder of equations for remainder of variables 17 <ipython-input-22-3e3cfcace514> in solve(eqs) 13 rest_equations.append(eqs[i][1:n+1]) 14 ---> 15 solutions = solve(rest_equations) 16 # solve remainder of equations for remainder of variables 17 <ipython-input-22-3e3cfcace514> in solve(eqs) 2 n = len(eqs) 3 make_first_coeff_nonzero_general(eqs) # make 1st coef of 1st equation nonzero ----> 4 eqs[0] = multiply_equation(eqs[0],1/eqs[0][0]) 5 # make 1st coef of 1st equation equal 1 6 IndexError: list index out of range
We tried to solve zero equations in zero variables! No wonder we ran into trouble.
The problem is that we need to always have a base for the recursion. Just like we need a base for proofs by inductions in mathematics.
Here is an updated version:
def solve(eqs):
n = len(eqs)
print "Solving ", n, " equations in ", n, "variables"
if n==1:
return [ -eqs[0][1]/eqs[0][0] ]
make_first_coeff_nonzero_general(eqs) # make 1st coef of 1st equation nonzero
eqs[0] = multiply_equation(eqs[0],1/eqs[0][0])
# make 1st coef of 1st equation equal 1
for i in range(1,n):
eqs[i] = add_equations(eqs[i],multiply_equation(eqs[0],-eqs[i][0])) # zero out first coefficient in eqs 1,2
# make 1st coef of 2nd .. n-th equation equal zero
rest_equations = []
for i in range(1,n):
rest_equations.append(eqs[i][1:n+1])
solutions = solve(rest_equations)
# solve remainder of equations for remainder of variables
x = - eqs[0][n]
for i in range(1,n):
x -= eqs[0][i]*solutions[i-1]
# solve 1st variable using solution for 2nd and 3rd variable
return [x] + solutions
solve([[1,2,3],[4,5,6]])
Solving 2 equations in 2 variables Solving 1 equations in 1 variables Solving 0 equations in 0 variables
[1.0, -2.0]
Let's check if it can solve 25 equations in 25 variables.
n= 25
solutions = []
for j in range(n):
solutions.append(j)
solutions
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]
import random
equations = []
for i in range(n):
constant_term = 0
eq = []
for j in range(n):
x = random.randint(-100,+100)
eq.append(x)
constant_term -= x*solutions[j]
eq.append(constant_term)
equations.append(eq)
my_solutions = solve(equations)
Solving 25 equations in 25 variables Solving 24 equations in 24 variables Solving 23 equations in 23 variables Solving 22 equations in 22 variables Solving 21 equations in 21 variables Solving 20 equations in 20 variables Solving 19 equations in 19 variables Solving 18 equations in 18 variables Solving 17 equations in 17 variables Solving 16 equations in 16 variables Solving 15 equations in 15 variables Solving 14 equations in 14 variables Solving 13 equations in 13 variables Solving 12 equations in 12 variables Solving 11 equations in 11 variables Solving 10 equations in 10 variables Solving 9 equations in 9 variables Solving 8 equations in 8 variables Solving 7 equations in 7 variables Solving 6 equations in 6 variables Solving 5 equations in 5 variables Solving 4 equations in 4 variables Solving 3 equations in 3 variables Solving 2 equations in 2 variables Solving 1 equations in 1 variables Solving 0 equations in 0 variables
my_solutions
[-4.0456527017340704e-13, 0.9999999999998579, 1.9999999999998543, 3.0000000000005302, 4.0000000000001315, 4.999999999999893, 6.000000000000206, 6.999999999999762, 8.000000000000284, 8.999999999999783, 9.999999999999716, 11.000000000000341, 12.000000000000338, 12.999999999999893, 14.000000000000146, 14.999999999999332, 15.999999999999972, 16.999999999999982, 17.99999999999974, 19.00000000000005, 19.999999999999986, 20.999999999999563, 22.00000000000005, 22.999999999999698, 23.99999999999945]
round_solutions = []
for x in my_solutions:
round_solutions.append(round(x,3))
round_solutions
[-0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0]
[ round(x,3) for x in my_solutions ]
[-0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0]
We have now obtained a function solve
that solves general linear equations.
This is still not enough however.
Eventually, we want to be able to achieve a function that reads the equations and outputs the solution, like the following:
solve_eqs()
Number of variables / equations?3 Enter equation number 1: 5x - y + z = 0 Enter equation number 2: 2y - 3y = 4 + z Enter equation number 3: 10z - 4x +3y = 20 Solving 3 equations in 3 variables Solving 2 equations in 2 variables Solving 1 equations in 1 variables Solving 0 equations in 0 variables x = -2.13953488372 y = -7.3488372093 z = 3.3488372093
Note that the equations now are given in arbitrary order, so we will need to sort them to make them into the standard format of $ax+by+cy+d=0$ so we can extract the coefficients $[a,b,c,d]$ for our solve
function.
So, we will now talk about sorting lists. That is, coming up with a function sort_list
sort_list([9,8,7,6,5])
[5, 6, 7, 8, 9]
sort_list([100,3,4,8,7])
[3, 4, 7, 8, 100]
sort_list([3,1,4,1,5,9,2])
[1, 1, 2, 3, 4, 5, 9]
As usual, we will start by writing sort2
:
def sort2(L):
if L[0]>L[1]:
L[0],L[1] = L[1],L[0]
return L
sort2([1,2])
[1, 2]
sort2([2,1])
[1, 2]
And then sort3
:
def sort3(L):
if L[0]>L[1]:
L[0],L[1] = L[1],L[0]
if L[0]>L[2]:
L[0],L[2] = L[2],L[0]
return [L[0]] + sort2(L[1:3])
sort3([9,5,8])
[5, 8, 9]
Theorem: For every three numbers $x_0,x_1,x_2$, sort3(
$[ x_0,x_1,x_2 ]$ )
returns a list $[ x_i,x_j,x_k ]$ such that $x_i \leq x_j \leq x_k$ and $i,j,k$ are distinct numbers in $\{0,1,2\}$.
Proof: Suppose we run sort3(
$[x_0,x_1,x_2]$)
. Let's split into cases:
Case 1: $x_0 \leq \min \{ x_1,x_2\}$.
Then both if
's don't execute, and we output $[ x_0 ] + $ sort2(
$[x_1,x_2]$ )
.
Since $x_0$ is the smallest element then this output will be sorted.
Case 2: $x_0 > x_1$ but $x_1 \leq x_2$.
Then the first if
executes and after it is done, $L[0]=x_1$.
Because $x_1 \leq x_2$, the second if
does not execute, and we output $[ x_1 ] + $ sort2(
$[x_0,x_2]$ )
.
Since $x_1$ is the smallest element then this output will be sorted.
Case 3: $x_0 > x_1$ and $x_1 > x_2$.
Then the first if
executes, and after it $L[0]=x_1$ and then the second if
executes and after it, $L[0]=x_2$. We output $[ x_2 ] + $ sort2(
$[x_1,x_0]$ )
which will be sorted since $x_2$ is the smallest element.
sort3(['cat','apple','dog'])
['apple', 'cat', 'dog']
'apple' < 'cat'
True
'car' > 'cat'
False
Write the function sort4(L)
that takes a list of 4 elements and sorts it.
The last line of the function must be return [L[0]]+sort3(L[1:4])
sort4 = sort_list
def sort4(L):
#
# your code goes below
#
return [L[0]]+ sort3(L[1:4])
Here are some output examples:
sort4([7,8,1,2])
[1, 2, 7, 8]
sort4([1,9,2,3])
[1, 2, 3, 9]
sort4(['Mickey','Donald','Goofy','Minney'])
['Donald', 'Goofy', 'Mickey', 'Minney']
Suppose that you are given the function sort9
that sorts a list of 9 elements. Write a function sort10(L)
that sorts a list L of 10 elements. The last line of the function must be return [L[0]]+sort9(L[1,4])
# you can use this function as a "black box" but there's no need to read it or understand its code
def sort9(L):
return sorted(L[0:9])
def sort10(L):
#
# your code goes below
#
return [L[0]] + sort9(L[1:10])
sort10([0, 1, 6, 10, 9, 3, 3, 9, 9, 5])
[0, 1, 3, 3, 5, 6, 9, 9, 9, 10]
sort10([15, 16, 19, 13, 5, 1, 7, 19, 12, 4])
[15, 1, 4, 5, 7, 12, 13, 16, 19, 19]
sort10([5, 9, 13, 8, 15, 17, 20, 9, 10, 8])
[5, 8, 8, 9, 9, 10, 13, 15, 17, 20]
Use recursion to write the general sort_list(L)
function that works for lists of any length.
Again, the last line of your code must be a recursive call to sort_list
of the form return [L[0]]+sort_list(L[1:len(L)])
def sort_list(L):
#
# your code goes below
#
return [L[0]] + sort_list(L[1:len(L)])
The array below contains the names of all the students that were registered to the course. Compute an array that contains these students in alphabetical order by first name. Use the function you wrote to sort it by first name.
L = ['abinet mulugeta', 'urgie huseien', 'yonatan wosenyeleh', 'amanuel asfaw', 'tibebu solomon', 'hailegbrel wudneh', 'gatluk chuol', 'elsabet buzuneh', 'eden ketema', 'maeden seid', 'mikyas legese', 'meskerem birhanu demeke', 'kumneger worku', 'shambel abate', 'hailmeskel shimeles', 'tsega hailu', 'dawit fikeru', 'asmare habitamo', 'zelalem ades', 'betelehem eshetu', 'yosef tadiwos', 'haymanot gidena', 'henock mersha', 'binyam kidane', 'mohammed nur', 'bethelehem walelegn', 'lewi mekonnen', 'wondimu yohanes', 'hodo mukitar', 'yonas adugna', 'tigabu gebrecherkos', 'nardos gesese', 'mohammed nur', 'abdurezak temam', 'shambel elena', 'adem mohamed', 'zakira tebarek', 'lidya gegnaw', 'knesa desta', 'ibrahim ahmed', 'betlehem desalegn', 'adonay geremew', 'kalkidan muluneh', 'haile gebreselasie', 'eden tekilu tilahun', 'ayantu aleneh', 'yosef nosha', 'mebrihity girmay', 'finet hailu', 'elisa feloh', 'bezawit gebremariam', 'nigusu terefe', 'amina bedrie', 'kiflom leuel', 'hana tariku', 'nejat beshir', 'mesfen tamiru', 'shafi abdi', 'kelbesa ambesa', 'abrham tuna', 'daniel hagos', 'yordanos jemberu', 'aman musa', 'habene abdi', 'kawuser jemal', 'tariku erina', 'mesigina gebretsadik', 'yetnayet birhanu', 'semer abrar', 'nur ahmed', 'eman hasen', 'natol gizaw', 'banchayehu asrat', 'hilina thewodros', 'hasen ali', 'mebrihatu lebelo', 'yosef enawgaw', 'nesera teyib', 'mekdes muluneh', 'surafel sewutu', 'mentesenot tefera']
Sort the array above in reverse alphabetical order by first name (so that L[0] will be the name that is last in alphabetical order and L[80] will be the name that is first)
Sort the array in alphabetical order by last name.