#!/usr/bin/env python # coding: utf-8 # # Solving linear equations # # When we want to solve a hard problem, it is good to start with the simplest possible problem. # So we will start with solving one equation with one variable of the form $ax = b$ # # In fact, we'll make our life even easier, and so we don't worry about reading the input for now # So, our goal is to find a function solve1(a,b) that will solve equations of the form $ax + b =0$. # For example $solve1(2,-4)=2$ # # In[10]: from __future__ import division # In[20]: def solve1(a,b): #solve xa + b =0 return -b/a # In[145]: solve1(2,-3) # Let's now try to solve _two_ equations, of the form $ax + by + c = 0 , dx + ey + f = 0$ # So, $solve2(a,b,c,d,e,f)$ should return a list $[x,y]$ of the solution for $x$ and the solution for $y$. # # The idea is the following: # if $a \neq 0$, then we can divide the first equation by $a$ to get an equation of the form # $1x + b'y + c' = 0$ # Then we can subtract the first equation times $d$ from the second equation, to make the second equation have the form $e'y + f' = 0$. # But then the second equation is only over _one_ variable, which we already know how to solve. # So, we can get a solution for $y$, and then plug it into the first equation to get a solution for $x$. # In[18]: def solve2(a,b,c,d,e,f): # solve xa+by+c = 0 , xd+ey+f = 0 if a: # True if a is not zero # x = (-by-c)/a # d(-by-c)/a+ey+f=0 y = solve1(-d*b/a+e,-d*c/a+f) x = (-b*y-c)/a return x,y # x = (-ey-f)/d # a(-ey-f)/d+by+c=0 y = solve1(-a*e/d+b,-f*a/d+c) x = (-e*y-f)/d return x,y # In[59]: solve2(1,1,-10,1,-1,-4) # Now we want to solve three equations of the form: # # $ax + by + cz + dw + e = 0$ # # $fx + gy + hz + iw + j = 0$ # # $kx + ly + mz + nw + o = 0$ # We are starting to run out of letters, so we will write this as: # # $a_{0,0}x_0 + a_{0,1}x_1 + a_{0,2}x_2 + a_{0,3} = 0$ # # $a_{1,0}x_0 + a_{1,1}x_1 + a_{1,2}x_2 + a_{1,3} = 0$ # # $a_{2,0}x_0 + a_{2,1}x_1 + a_{2,2}x_2 + a_{2,3} = 0$ # We will represent the input as a _list of lists_: # # # $[$ # # $[ a_{0,0} , a_{0,1} , a_{0,2} ,a_{0,3} ],$ # # $[ a_{1,0} , a_{1,1} , a_{1,2} ,a_{1,3} ],$ # # $[ a_{2,0} , a_{2,1} , a_{2,2} ,a_{2,3} ],$ # # $]$ # # # Our solution will have the following form: # # We will write a function $solve3(eqs)$ that given a list $eqs$ that contains three lists $eqs[0],eqs[1],eqs[2]$ where each of those corresponds to an equation, returns a list of three numbers that is the solution to the equations. # The approach would be as follows: # # 1. Make sure that the first equation has the first coefficient equal to one. That is, it should be of the form $1x_0 + a'_{0,1}x_1 + a'_{0,2}x_2 + a'_{0,3} = 0$ for some numbers $a'_{0,1},a'_{0,2},a'_{0,3}$. # # 2. Subtract a multiple of this first equation from all the rest of the equations, so that all the rest of the equations have the first coefficient equalling zero # # 3. Run $solve2$ on the second and third equations with 2 variables to get solution $(y,z)$ # # 4. Compute $x = -a'_{0,3} - a'_{0,2}z - a'_{0,2}y$ # # 5. Return $[x,y,z]$ # In[80]: # first solve using "wishful thinking" def solve3(eqs): make_first_coeff_nonzero(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 to 1 for i in [1,2]: eqs[i] = add_equations(eqs[i],multiply_equation(eqs[0],-eqs[i][0])) # zero out first coefficient in 2nd and 3rd equations (y,z) = solve2(eqs[1][1],eqs[1][2],eqs[1][3], eqs[2][1],eqs[2][2],eqs[2][3]) # solve 2nd and 3rd equations on 2nd and 3rd variables x = -eqs[0][1]*y - eqs[0][2]*z - eqs[0][3] # solve 1st variable given solutions for 2nd and 3rd variables return (x,y,z) # In[110]: def make_first_coeff_nonzero(eqs): """Switch order of equations so 1st coef of 1st equation is nonzero""" if eqs[0][0]: return if eqs[1][0]: eqs[0], eqs[1] = eqs[1] , eqs[0] return if eqs[2][0]: eqs[0] , eqs[2] = eqs[2], eqs[0] return sys.exit("Oh oh! All first coefficients are zero - can't solve!") # In[100]: def multiply_equation(eq,num): """Multiply all coefficients of equation eq by number num. Return result""" res = [] for x in eq: res.append(x*num) return res # In[101]: 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 # In[102]: # recalling the definition of solve3: def solve3(eqs): make_first_coeff_nonzero(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 [1,2]: 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 and 3rd equation equal zero (y,z) = solve2(eqs[1][1],eqs[1][2],eqs[1][3],eqs[2][1],eqs[2][2],eqs[2][3]) # solve 2nd and 3rd equations for 2nd and 3rd variables x = -eqs[0][1]*y - eqs[0][2]*z - eqs[0][3] # solve 1st variable using solution for 2nd and 3rd variable return (x,y,z) # In[112]: solve3([ [1,1,1,-6] , [1,1,-1,0], [1,-1,1,-2]]) # # Labwork # ### Exercise 1 # We wrote a function $solve1(a,b)$ that gets input coefficients for an equation $ax + b =0$ and outputs a solution for $x$. # # But we can also write an equation in the form $cx=d$. # Write a function $other_solve1(c,d)$ that outputs the solution $x$ such that $cx =d$. # # Below are some examples for the output of other_solve1 # In[2]: def other_solve1(c,d): return float(d)/float(c) # In[12]: other_solve1(1.0,1.0) # In[13]: other_solve1(1.0,2.0) # In[14]: other_solve1(2.0,1.0) # In[15]: other_solve1(3.0,-2.0) # ### Exercise 2 # # Write a similar function for solving 2 equations in 2 variables. # $other_solve2(a,b,c,d,e,f)$ should output two numbers $x,y$ such that $ax+by =c$ and $dx + ey = f$. # # Below are some examples for the output of $other_solve2$ # In[16]: def other_solve2(a,b,c,d,e,f): return solve2(a,b,-c,d,e,-f) # In[21]: other_solve2(1.0,1.0,3.0,1.0,-1.0,1.0) # In[22]: other_solve2(0.0,1.0,2.0,2.0,3.0,10.0) # ### Exercise 3 # # There are some inputs that "breal" the $solve2$ function we saw in class. # That is, there are some examples of equations it will not be able to solve and will output an error instead. # Can you find such an example? # # That is, find 6 numbers $a,b,c,d,e,f$ such that $solve2(a,b,c,d,e,f)$ will result in an error # ### Exercise 4 # # Write a function $solve4(eqs)$ that solves _four_ equations in _four_ variables. # The function will get a list of $4$ equations, each of them a list of $5$ numbers which correspond to the coefficients of an equation in variables $x_0,x_1,x_2,x_3$ of the form $a_0x_0 + a_1x_2 + a_2x_2+ a_3x_3 + a_4 = 0$. # # That is, $solve4$ gets as input a list $\mathtt{eqs}$ such that $\mathtt{eqs} = [ \mathtt{eq}0, \mathtt{eq}1, \mathtt{eq}2 ,\mathtt{eq}3 ]$. # Each one of the $\mathtt{eq}i$'s is itself a list of 5 numbers corresponding the coefficients $a_{i,0},a_{1,1},\ldots,a_{i,4}$ in the equation $a_{i,0}x_0 + a_{i,1}x_1 + a_{i,2}x_2 = a_{i,3}x_3 + a_{i,4} = 0$. # # The function should return $(x_0,x_1,x_2,x_3)$: the solution for the four variables. # # For example: # # In[114]: solve4([ [1,1,1,1,-10] , [1,1,1,-1,-2], [1,1,-1,1,-4], [1,-1,1,1,-6] ])