Skip to content

Instantly share code, notes, and snippets.

@MrLoh
Last active December 22, 2015 00:29
Show Gist options
  • Save MrLoh/6389638 to your computer and use it in GitHub Desktop.
Save MrLoh/6389638 to your computer and use it in GitHub Desktop.
MIT-IntroCS-Part1.ipynb
Display the source blob
Display the rendered blob
Raw
{
"metadata": {
"name": "MIT-IntroCS-Part1"
},
"nbformat": 3,
"nbformat_minor": 0,
"worksheets": [
{
"cells": [
{
"cell_type": "heading",
"level": 1,
"metadata": {},
"source": "MIT Introduction to Computer Science and Programming Lecture Notes 1"
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": "Lecture 1"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "###Goals"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "strategic goals: \n\n* understand the role computation can and can not play in solving problems \n* Appropiate level in programming experience\n* think like a computer scientist\n\nskills: \n\n* computational thinking\n* understanding code \n* understand capabilities and limits\n* map computations into models "
},
{
"cell_type": "markdown",
"metadata": {},
"source": "###Computerscientist thinking"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "* what is computation? \n* what is knowledge? \n * Declarative knowledge: statement of fact, tells you how you might test something, but not how to do something \n 0. $\\sqrt{x}$ is $y$ so $y^2=x$\n * Imperative knowledge: tells you how to do something \n1. start guess $G$\n2. if $G^2=x$, stop $\\rightarrow G$\n3. else $\\frac{G+x/\\epsilon}{2}\\to G$ start over with II.\n* How to solve a problem? \n * earliest Computers: calculator, Atari, Turing bombe\n * maschiene which can take recipes: interpreter \n* stored Programm computer\n * Memory connected to\n * Control unit \n * arithmetic logic unit (ALU) which can handle input and output\n * the memory can take take a recipy and execute it via its \n * programm counter which makes the computer follow the steps "
},
{
"cell_type": "markdown",
"metadata": {},
"source": "###Programms"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "* given a fixed set of primitives everything can be programmed\n* 6 primitives are enough to program anything (1936 Alan Turing)\n * everything which you can do with one language you can do with another (turing-compatibility)\n * we want to use more fundamental abstract \n* describe flow of controll \n* in order to describe the recipes we will need a language "
},
{
"cell_type": "markdown",
"metadata": {},
"source": "### Languages"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "* there is no best language\n* course will use python, because it is a good example, but the ideas can be \n* Differences between languages \n * Highlevel languages vs. lowlevel languages\n * General languages vs. targeted languages\n * Interpreted languages vs. compiled language \n* python is a highlevel, general and interpreted languages"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "###Python"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "* Unterscheidung von syntax und semantics\n * syntax: what are legal expressions \n * semantics: \n * static: which programs are meaningful\n * full: what is going to happen when I run it\n* Python will give lots of help with syntax, but just a few with semantics\n* To fix this problem, you need to get some programming style\n\n#### Values\n* numbers \n * integer eg: 3\n * floating point eg: 3.14\n* strings \n * type eg: 'abc'"
},
{
"cell_type": "code",
"collapsed": false,
"input": "3",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 1,
"text": "3"
}
],
"prompt_number": 1
},
{
"cell_type": "code",
"collapsed": false,
"input": "3.14",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 2,
"text": "3.14"
}
],
"prompt_number": 2
},
{
"cell_type": "code",
"collapsed": false,
"input": "'abc'",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 3,
"text": "'abc'"
}
],
"prompt_number": 3
},
{
"cell_type": "code",
"collapsed": false,
"input": "52 is not '52'",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 4,
"text": "True"
}
],
"prompt_number": 4
},
{
"cell_type": "code",
"collapsed": false,
"input": "3.0 is not 3",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 5,
"text": "True"
}
],
"prompt_number": 5
},
{
"cell_type": "markdown",
"metadata": {},
"source": "* Difference between expressions and commands"
},
{
"cell_type": "code",
"collapsed": false,
"input": "52*7",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 6,
"text": "364"
}
],
"prompt_number": 6
},
{
"cell_type": "code",
"collapsed": false,
"input": "print 52*7",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": "364\n"
}
],
"prompt_number": 7
},
{
"cell_type": "code",
"collapsed": false,
"input": "print '52*7'",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": "52*7\n"
}
],
"prompt_number": 8
},
{
"cell_type": "code",
"collapsed": false,
"input": "print '3' * 3",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": "333\n"
}
],
"prompt_number": 9
},
{
"cell_type": "code",
"collapsed": false,
"input": "52a",
"language": "python",
"metadata": {},
"outputs": [
{
"ename": "SyntaxError",
"evalue": "invalid syntax (<ipython-input-10-4d337bea22dd>, line 1)",
"output_type": "pyerr",
"traceback": [
"\u001b[0;36m File \u001b[0;32m\"<ipython-input-10-4d337bea22dd>\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m 52a\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n"
]
}
],
"prompt_number": 10
},
{
"cell_type": "code",
"collapsed": false,
"input": "3+5",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 11,
"text": "8"
}
],
"prompt_number": 11
},
{
"cell_type": "code",
"collapsed": false,
"input": "3**5",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 12,
"text": "243"
}
],
"prompt_number": 12
},
{
"cell_type": "code",
"collapsed": false,
"input": "3/4",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 13,
"text": "0"
}
],
"prompt_number": 13
},
{
"cell_type": "code",
"collapsed": false,
"input": "3./4",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 14,
"text": "0.75"
}
],
"prompt_number": 14
},
{
"cell_type": "code",
"collapsed": false,
"input": "'abc'+'cde'",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 15,
"text": "'abccde'"
}
],
"prompt_number": 15
},
{
"cell_type": "code",
"collapsed": false,
"input": "'abc'*'cde'",
"language": "python",
"metadata": {},
"outputs": [
{
"ename": "TypeError",
"evalue": "can't multiply sequence by non-int of type 'str'",
"output_type": "pyerr",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-16-4cb51b020a85>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;34m'abc'\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0;34m'cde'\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;31mTypeError\u001b[0m: can't multiply sequence by non-int of type 'str'"
]
}
],
"prompt_number": 16
},
{
"cell_type": "code",
"collapsed": true,
"input": "myString = 'tobi'",
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 17
},
{
"cell_type": "code",
"collapsed": false,
"input": "myString",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 18,
"text": "'tobi'"
}
],
"prompt_number": 18
},
{
"cell_type": "code",
"collapsed": false,
"input": "myString + ' lohse'",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 19,
"text": "'tobi lohse'"
}
],
"prompt_number": 19
},
{
"cell_type": "markdown",
"metadata": {},
"source": "##Lecture 2"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "###Expressions"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- Numbers and Strings are the atomic units of our language\n - They inherit numbers and types\n- Combination of of expressiones in order: operand - operative - operand\n- Two ways of doing it \n - Interpreter: evaluate and print \n - Script: no print unless explicit"
},
{
"cell_type": "code",
"collapsed": false,
"input": "3+'ab'",
"language": "python",
"metadata": {},
"outputs": [
{
"ename": "TypeError",
"evalue": "unsupported operand type(s) for +: 'int' and 'str'",
"output_type": "pyerr",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-20-5ffba38f15c2>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;36m3\u001b[0m\u001b[0;34m+\u001b[0m\u001b[0;34m'ab'\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;31mTypeError\u001b[0m: unsupported operand type(s) for +: 'int' and 'str'"
]
}
],
"prompt_number": 20
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- This is a static semantics error, because the syntactic structure is ok, but the operator suspected another kind of operand"
},
{
"cell_type": "code",
"collapsed": false,
"input": "str(3)+'ab'",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 21,
"text": "'3ab'"
}
],
"prompt_number": 21
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- this operation str() is called type-conversion"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "###Type checking"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- it is very important to check the spelling \n- Python has some Spellchecking embeded, but there's some things it won't get:\n- there's some problems with > for example: "
},
{
"cell_type": "code",
"collapsed": false,
"input": "'a'<3",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 22,
"text": "False"
}
],
"prompt_number": 22
},
{
"cell_type": "code",
"collapsed": false,
"input": "4<3",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 23,
"text": "False"
}
],
"prompt_number": 23
},
{
"cell_type": "code",
"collapsed": false,
"input": "'4'<3",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 24,
"text": "False"
}
],
"prompt_number": 24
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- Also it is important to realize the difference between integers and floats. (also: the rest of a division can be given by the %-command) "
},
{
"cell_type": "code",
"collapsed": false,
"input": "9/5",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 25,
"text": "1"
}
],
"prompt_number": 25
},
{
"cell_type": "code",
"collapsed": false,
"input": "9%5",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 26,
"text": "4"
}
],
"prompt_number": 26
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- also important to notice, there is operator precedece implemented in Python"
},
{
"cell_type": "code",
"collapsed": false,
"input": "3*4+1 is not 3*(4+1)",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 27,
"text": "True"
}
],
"prompt_number": 27
},
{
"cell_type": "markdown",
"metadata": {},
"source": "###Variable creation"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- It is possible to assign a value to a variable \n- For this an assignment statement needs to be made, which points the variable to the value \n- The value can be thought of a point in a set of things in a database \n- There's various ways of assignment statements: \n- We can for example assign the value of an expression: "
},
{
"cell_type": "code",
"collapsed": false,
"input": "x=3*5",
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 28
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- Or just a simple value: "
},
{
"cell_type": "code",
"collapsed": true,
"input": "y=15",
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 29
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- or we can assign the value of a variable to another variable "
},
{
"cell_type": "code",
"collapsed": true,
"input": "z=x",
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 30
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- all these assignments will define these variables x,y and z to the same value \n- the type of the variable will be defined by it's value\n- don't change types arbitrarily, this can mess up code quite easily\n- a variable can be used at any place, where it is alloud to use the value "
},
{
"cell_type": "markdown",
"metadata": {},
"source": "###Statements"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- statements are legal commands, that Python can interpret \n- we already saw a due of them, eg: \n - print, assignment"
},
{
"cell_type": "code",
"collapsed": false,
"input": "x = 3 #assign the value 3 to x\nx = x*x #assign the value 9 to x\nprint x ",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": "9\n"
}
],
"prompt_number": 31
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- use meaningfull names for variables \n- there are some things which are n"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "###Simple Branching programs"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- Programms which can change the order of instructions based on some test\n- the test will usually be a the value of a number\n- the simplest Branching programm is the simple conditional: "
},
{
"cell_type": "code",
"collapsed": false,
"input": "x=15\nif (x/2)*2 == x:\n print 'x is even' \nelse: \n print 'x is odd'",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": "x is odd\n"
}
],
"prompt_number": 32
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- it is important here to note the structure: "
},
{
"cell_type": "raw",
"metadata": {},
"source": "if <some test> : \n <block of instructions>\nelse:\n <block of instructions>"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- the : and the [tab] are important for the interpretation\n- the == sign for comparison is different to the = sign for assignment"
},
{
"cell_type": "code",
"collapsed": false,
"input": "z = 'b'\nif 'x'<z:\n print 'Hello'\n print 'Mom'",
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 33
},
{
"cell_type": "code",
"collapsed": false,
"input": "if 'x'<z:\n print 'Hello'\nprint 'Mom'",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": "Mom\n"
}
],
"prompt_number": 34
},
{
"cell_type": "code",
"collapsed": false,
"input": "x=15\ny=13\nz=11\nprint x,y,z\nif x<y: \n if x<z: \n print 'first number is least'\n else: \n print 'third number is least'\nelse: \n print 'second number is least'",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": "15 13 11\nsecond number is least\n"
}
],
"prompt_number": 35
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- a straight line programm will take as long as I have instructions \n- a simple branching program will take at most as long as every line runs \n- the running time of a simple branching program for this reason has a constant running time"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "###Boulean"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- A boulean is a logical \n- Boulean combinations: \n - and \n - or \n - not\n- Bouleans are also a third type of Values. \n- The Boulean can have exactly two logical values: \n - True\n - False"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "###Iteration"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- Iterations or Loops provide a powerful possibility to do more complex computations. \n- this littel Programm for example can square whole numbers"
},
{
"cell_type": "code",
"collapsed": false,
"input": "y = 0\nx = 3\nitersLeft = x\nwhile(itersLeft>0):\n y = y+x\n itersLeft = itersLeft -1\nprint y ",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": "9\n"
}
],
"prompt_number": 36
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- the structure of assignments of values to the 3 variables created by this program will be the following: "
},
{
"cell_type": "raw",
"metadata": {},
"source": "x y itersLeft\n3 0 3\n 3 2\n 6 1\n 9 0"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- when doing iterations it is very important to check, that the endpoint is not ill defined, if it is, the program will just run forever "
},
{
"cell_type": "code",
"collapsed": false,
"input": "y = 0\nx = 3\nitersLeft = x\nwhile(itersLeft>0):\n y = y+x",
"language": "python",
"metadata": {},
"outputs": [
{
"ename": "KeyboardInterrupt",
"evalue": "",
"output_type": "pyerr",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-37-3be20b6a405b>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0mitersLeft\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mx\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;32mwhile\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mitersLeft\u001b[0m\u001b[0;34m>\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 5\u001b[0;31m \u001b[0my\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m+\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;31mKeyboardInterrupt\u001b[0m: "
]
}
],
"prompt_number": 37
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- also it is important to think about the limitations of our program\n- our program for exampe won't compute negative integers correctly, but this could be easily fixed: "
},
{
"cell_type": "code",
"collapsed": false,
"input": "y = 0\nx = -4\nitersLeft = x\nwhile(itersLeft>0):\n y = y+x\n itersLeft = itersLeft -1\nprint y",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": "0\n"
}
],
"prompt_number": 38
},
{
"cell_type": "code",
"collapsed": false,
"input": "y = 0\nx = -4\nitersLeft = abs(x)\nwhile(itersLeft>0):\n y = y+abs(x)\n itersLeft = itersLeft -1\nprint y",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": "16\n"
}
],
"prompt_number": 39
},
{
"cell_type": "markdown",
"metadata": {},
"source": "\n\n## Lecture 3"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "##Review"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- We got to know different basicall peaces:\n - Data \n - Numbers \n - Strings\n - Booleans\n - Operators \n - for Numbers: +, *, **\n - for Booleans: and, or, ==\n - Commands\n - assignments\n - input/output\n - conditionals \n - loop mechanisms\n- this set of instruction is quite powerful, we won't need to get much more tools and peaces\n- good programming style \n - using commends \n - type discipline (make sure variables have the right \n - descriptive use of variable names \n - testing all possible branches\n- we want to now learn more about writing some basic code for general or typical problems"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "###Iterations"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- Steps to produce an iteration: \n- 1 choose variable that counts \n- 2 initialize outside of the loop \n- 3 setup an end test (will inclure the variable)\n- 4 construct the block of code (the variable will have to change in this code block)\n- 5 what to do when done "
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- Floatcharts for visualization of code: \n - include all steps \n - square boxes for simple actions\n - diamond boxes for tests\n - arrows for indication of path of actions"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "example: finding the squareroot of x \n\n- float chart:"
},
{
"cell_type": "code",
"collapsed": false,
"input": "from IPython.core.display import Image ",
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 40
},
{
"cell_type": "code",
"collapsed": false,
"input": "Image(filename='float1.png')",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"png": "iVBORw0KGgoAAAANSUhEUgAAAcIAAAIXCAYAAAAPA15EAAAACXBIWXMAAA0SAAANEgG1gDd0AAAB\n1WlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczpt\nZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNS4xLjIiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0\ndHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRl\nc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMu\nYWRvYmUuY29tL3RpZmYvMS4wLyI+CiAgICAgICAgIDx0aWZmOkNvbXByZXNzaW9uPjU8L3RpZmY6\nQ29tcHJlc3Npb24+CiAgICAgICAgIDx0aWZmOk9yaWVudGF0aW9uPjE8L3RpZmY6T3JpZW50YXRp\nb24+CiAgICAgICAgIDx0aWZmOlBob3RvbWV0cmljSW50ZXJwcmV0YXRpb24+MjwvdGlmZjpQaG90\nb21ldHJpY0ludGVycHJldGF0aW9uPgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6\nUkRGPgo8L3g6eG1wbWV0YT4KVqk98QAAQABJREFUeAHsnQecLEW59utkDjnJIUqS4CFnxMu9gmJC\nDIRLUvkQ/ZDwEa4iKGIA5GJG5JJFFBEEQUQQBEUvIFEEyShBkQznIPHE3fmef++8Q+/szO7s2Z2Z\nnp2nfr93qrq6urvmX9X1VFWncaVSKdmZgAmYgAmYQLcSGN+tf9z/2wRMwARMwAQgYCF0PTABEzAB\nE+hqAhbCri5+/3kTMAETMAELoeuACZiACZhAVxOY2Oi/HydXThs+i9Xh/HKju3Y6ExgJgbjbK3z2\nNSCsm8LycSM5nrc1ARMYYwSGFMIqAUTo8gaOEL9qf4yh8t8pKIEQOPywyGosl6IfZ0EMNPZNwASC\nwJBCWE6YF7/xkydP/sGkSZNW1roQv9hf9XLE2zeBZhIIMeQYWXjOnDkvzZ8//xNafjl34Hy6XLSD\nJmAC3UxgXL0Zo/JIMIRtgiBxPZHlSbKXDzvssDRt2jQF7UygWAR6e3vT0UcfTaY2k90vQwB7ZT2E\nPSoUBTsTMIEKgcGEMIQPH0MMMYRwxn333ZemT5+uoJ0JFItAT09Pmjgxm+zYWjlDCBHAMEQRLUQY\n7UzABEwgDTU1yggQQwBJiz9ZZmcCnUCAThv1ljoco0JPj3ZCyTmPJtBCAoMJYYhgtRDSuNiZQCcQ\niM4beY2p0RDFTsi/82gCJtACAjWFsHx9MD8dSpiRICI4tQX58iFMYDQITNFOsPkyhJD6Tjipjvta\nISDsTMAE6k6NVo8GEcEwC6ErTqcQWEgZxebK4hohnTpPjwqCnQmYQB8BGoV6DjFkfRi9acxTo4Jg\n1xEEos5ybZt6HB28jsi8M2kCJtAaAjQUgzkaDhzp4o5RjwgzJP7pAAIxnc9oMOpw3DRD3fbIsAMK\n0Vk0gWYTaEQI6UmTjkaF6y34dibQCQSYvcBCCDshz86jCZhAiwkgcrVcTCHhx5QSPuap0VrEHFdE\nAsxihFGX81OkRcyv82QCJtAGAvWEkKxUiyFpo1FpQ1Z9SBMYNgFmMqi3+bo87J14AxMwgbFNYCgh\nZH0YjUrY2KbifzdWCETHLeqwBXGslKz/hwmMIoHBhDAOk288SE/jYmcCnUCAuhqdN+ouddnOBEzA\nBPoRqCeEtRqMEMR62/TbsRdMoIAEog4XMGvOkgmYQLsIWNTaRd7HbReBEMNanb125cnHNQETaCMB\npo0acW48cpT0nbv04IMPpueffz6tt956abnllqusfeaZZ9Krr75aWa4O8OmqxRZbLIt+8cUX04wZ\nM9Jb3vKW6mTpH//4R5o3b14lfsKECWnFFVdMU6bwBEufG86xYpsu9i18XVz4/usmMCgBvXCRb9L0\nM22AQC4sW0q2vGxt2Zay7WS7ykr6DFP2rsZu+/ntb39bWnbZZfnieWmJJZbggezSDjvsUJKgZSh2\n2223LI74WvajH/2ogmzHHXfM0vzhD3+oxEVglVVWKY0fP76kDyBnJiHMjrn22muX/vSnPw37WLHf\nbvDVUQn2B6kMtpXxXcK1ZHxAkzpN3Z4gFv3qvZfNw3WgO+uAp0bVIjbqXnvttfSBD3wgfeITn0jP\nPfdcYkR3xx13pMcffzztt99+2W4kdOmll17K7Mc//nEWN3PmzErcnnvumcU99dRT6Zprrkksn3ba\naTWz8PWvfz3NnTu3YrfccktaeeWV00477ZQ14I0eq+bOHWkCJmACJpARsBAOoyLceeedafbs2emQ\nQw5JGhXyBYO06aabpuOOOy7NmjUr8WX0qVOnpsUXXzyzhRdm4JEqy8RrhJfFIWKbbLJJOvjgg9Ol\nl16ann322Sy+3o9Gh2nLLbdMRx11VHr66afTo48+2vCx6u3T8SZgAiZgAn3PCJpDgwQ23njj7Pre\npz/96XTjjTcmrhXiNB2arr766oRYNep++MMfpt133z297W1vS5oGTeecc05Dm1533XVp1VVXTauv\nvnpD6Z3IBEzABExgcAKN3iwz+F66ZO2iiy6arr/++vTRj340bbvttpko4jO9SVyj7oYbbkiPPfZY\n2nvvvbNR5T777JPOOOOMdOSRR/YT0/POOy/ddttt2W7nzJmTHn744cT07Le+9a1+6Ro9rtOZgAmY\ngAkMJND4EGbgtl0Zw6jw3nvvTQ888EA64YQTEndzImR77LFHwzx+8IMfZNOc3DF6//33py222CK7\nS/Sqq67qt4/ll18+uyuV0R/TsgixblJKu+7K/Up2JmACJmACo0HAI8JhULzrrrsSI7Otttoqrbvu\nuplxjU93kibdOZpdv0MoB3OvvPJK+vnPf54mTpyYjSoj7UILLZTdNKM7SSMq2+dnP/vZbPnwww/P\nxPP//J//ky666KJsJFlJ6IAJmIAJmMACE/CIcBjofvOb32RToNwUk3fbbLNNdhMMd4cO5X72s59l\no0ieAWREGMYokREhzw/WcowOucHmkksuSd/97ndrJXGcCZiACZjAAhCwEA4DGjfF8BA9ozZulkHE\nGCVyfZAH5bleOJTjphimNhkB5t3OO++c3V165pln5qP7hbfbbru0//77p2OOOSa7xthvpRdMwARM\nwAQWiICFcBjY1lhjjXTrrbeml19+OZu25BGKrbfeOlvmGb94NKLeLrmuePPNN6ePfexjA5IgjHvt\ntVdiZJh/o0x1whNPPDEtueSSmSBWr/OyCZiACZjA8AmM400K1U7Px3HtML5Izzu9FpctKVtEtozs\nYm7amD59uoLd6Zge/ec//5m99mwoAexOQu371z09Pdk1WOXgYNndstdlL5dtrvw5mOo+X663MwET\n6HICvllmASsAzwzyPJ+dCZiACZhAZxPw1Ghnl59zbwImYAImMEICFsIRAvTmJmACJmACnU3AQtjZ\n5efcm4AJmIAJjJCAhXCEAL25CZiACZhAZxOwEHZ2+Tn3JmACJmACIyRgIRwhQG9uAiZgAibQ2QQs\n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\n62o+XIS8OQ8mYAIFIVBPCAfLnhuUweh4XZEJUHep8/iux0UuKefNBFpIoFEhjIbDjUdV4fDJn4cf\nfjjNnTu3as3wFq+//vo0a9as4W00zNQ333xzeuUVPs/Xlc51tyuL3X/aBIYm0KgQDr2nLk2BsKy1\n1lrpgQceaIjABRdckH7xi1/0S/vQQw+l448/Pk2d2tx3Ffz9739PX/va1/od2wsmYAIm0O0ELIQj\nrAGLLLJIuvLKK9Maa6zR0J6OO+649Pzzz/dLe9RRR6WvfvWr/eKasbDHHnuk6667Lj3++OPN2L33\naQImYAIdSYDby+1yBP7whz+kVVZZJT355JPpT3/6U9p6660zGz++r8+AkKy++uqJaUbidtxxx/Ty\nyy8nPgY7b968dMkll6QPf/jD6Te/+U3661//mjbffPO03XbbZUdgW9LefvvtaYMNNkhve9vb0g03\n3JCNJgmHY4r0qquuSn/729/S0ksvnbbffvu05pprZqvJ35vf/Ob0r3/9KxFebrnl0i677FIZTTJV\ne/XVV6e77747Lb/88mmHHXZIK620UratvriQdt999/TFL34x/fjHP47D2TcBEzCB7iagT9GkahMR\nBHJh2VKy5WVry/jaNy36rrKSvlDPV2zGnHvXu95V2nTTTUsSkdL+++9fWnzxxUv77bdf5X++4x3v\nKEm0svUrrrhiSaOr7IOvd911V+nFF1/Mwuxjs802K+26664lfSm99K1vfSvb/sQTTywtscQSpW22\n2aZ0+umnZ3ESptIXvvCFyv6fffbZkqZaS1tuuWXpwAMPLG288calhRZaqCRRztKwbwlriWPvvffe\nmb/VVltVtifPq622WumAAw4ovfvd7y4tueSSpXvvvbey/rHHHitJELO8ViLHWGD+/PnxEd6DVFe3\nlW0mW0s2TUadpm5P0N8eUPcdZyauA91XB2o2BGokuloI3/SmN5Vee+21TB4eeeSRrFHVCC9bRgjX\nXXfd0pw5c7JljcwGCOHRRx+dreNH056l6dOnV5bf+ta3ls4444zKMut03bCy/JOf/KT07//+7yUa\n83AagZa+9KUvZYsI4XrrrVfSzTnZ8h133JEdPzommqotXXHFFbFp6fDDD++3zIpFF120dOONN1bS\njLWAhbD7GjLV4ZptmePNpZE60DffJ+Wze4PAe97znrTwwgwaUnbtT+KVTYVGColhmjx5ciwO8N/7\n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\n",
"prompt_number": 41,
"text": "<IPython.core.display.Image at 0x78152b0>"
}
],
"prompt_number": 41
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- code:"
},
{
"cell_type": "code",
"collapsed": false,
"input": "x=16\nans=0\nwhile ans*ans<x:\n ans=ans+1\nprint(ans)",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": "4\n"
}
],
"prompt_number": 42
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- simulation of the code for debugging: "
},
{
"cell_type": "raw",
"metadata": {},
"source": "ans x ana*ans \n 0 16 0\n 1 1\n 2 4\n 3 9\n 4 16"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "for which values of x does the code terminate: \n\n- perfect squares (gives right answer)\n- other positive integers (gives the first answer \n- negative integers (stops at first step, prints 0)"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "###defensive programming"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- write code that makes sure, that: \n - mistakes of the programmer will become apparent\n - mistakes of the user will become apparent \n- Some properties this kind of writing codes will \n - make sure, that I'm going through all parts of the code \n - make sure, that I'm returning meaningful information for each path through the code \n - make sure, that for all possible inputs, there is a path through the code \n"
},
{
"cell_type": "code",
"collapsed": false,
"input": "x=4\nans=0\nif x >= 0:\n while ans*ans < x:\n ans = ans+1\n print('ans =',ans)\n if ans*ans != x:\n print(x, 'is not perfect square')\n else: \n print(ans)\nelse:\n print(x, 'is negative number')",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": "('ans =', 1)\n('ans =', 2)\n2\n"
}
],
"prompt_number": 43
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- this kind of computation is called exhaustive enumeration: \n - try all \"reasonable\" values, until you find a solution"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "###For loop"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- if we want to do something like this"
},
{
"cell_type": "code",
"collapsed": false,
"input": "x=10\ni=1\nwhile i<x:\n if x%i == 0:\n print('divisor:',i)\n i=i+1",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": "('divisor:', 1)\n('divisor:', 2)\n('divisor:', 5)\n"
}
],
"prompt_number": 44
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- we have to update our variable here manually \n- instead of that it would be nice, to just define a range for our variable i\n- a so called for loop does exactly this:"
},
{
"cell_type": "raw",
"metadata": {},
"source": "for <variable> in <some collection>:\n <block of code>"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- for example we could rewrite the program from before as:"
},
{
"cell_type": "code",
"collapsed": false,
"input": "x=10\nfor i in range(1,x):\n if x%i == 0:\n print('divisor',i)",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": "('divisor', 1)\n('divisor', 2)\n('divisor', 5)\n"
}
],
"prompt_number": 45
},
{
"cell_type": "code",
"collapsed": false,
"input": "x=16\nfor ans in range(1,x):\n if ans*ans == x:\n print ans\n break",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": "4\n"
}
],
"prompt_number": 46
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- this has some advantages: \n - it has a cleaner view \n - we don't need any incremented \n - the collections can be arbitrary"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "###Tuples"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- a tuple is a ordered sequence of elements\n- tuple are immutable\n- in python tuples are created by brackets: () with come: , separated values"
},
{
"cell_type": "code",
"collapsed": false,
"input": "test=(0,1,2,3,4)",
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 47
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- to select the nth elemend out of the tuple we can use the following function\n- be aware, that counting starts at 0, not at one"
},
{
"cell_type": "code",
"collapsed": false,
"input": "print test[0]\nprint test[1]",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": "0\n1\n"
}
],
"prompt_number": 48
},
{
"cell_type": "code",
"collapsed": false,
"input": "test[10]",
"language": "python",
"metadata": {},
"outputs": [
{
"ename": "IndexError",
"evalue": "tuple index out of range",
"output_type": "pyerr",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mIndexError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-49-9f658fea5635>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mtest\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m10\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;31mIndexError\u001b[0m: tuple index out of range"
]
}
],
"prompt_number": 49
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- we can also select elements counting from the last one on: "
},
{
"cell_type": "code",
"collapsed": false,
"input": "print test[-1]\nprint test[-2]",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": "4\n3\n"
}
],
"prompt_number": 50
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- and we can select parts of the tuple from beginning or end on: "
},
{
"cell_type": "code",
"collapsed": false,
"input": "print test\nprint test[:2]\nprint test[2:]",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": "(0, 1, 2, 3, 4)\n(0, 1)\n(2, 3, 4)\n"
}
],
"prompt_number": 51
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- we can also create tuples from any list:"
},
{
"cell_type": "code",
"collapsed": false,
"input": "tuple(range(1,10))",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 52,
"text": "(1, 2, 3, 4, 5, 6, 7, 8, 9)"
}
],
"prompt_number": 52
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- and add tuples together, which means they will be concatenated"
},
{
"cell_type": "code",
"collapsed": false,
"input": "(1,2,3)+(4,5,6)",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 53,
"text": "(1, 2, 3, 4, 5, 6)"
}
],
"prompt_number": 53
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- tuples with only one number are created by using a , inside the parenthesis"
},
{
"cell_type": "code",
"collapsed": false,
"input": "print (1)+(2)\nprint (1,)+(2,)",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": "3\n(1, 2)\n"
}
],
"prompt_number": 54
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- tuples can be useful to create "
},
{
"cell_type": "code",
"collapsed": false,
"input": "x=10\ndivisors=()\nfor i in range(1,x):\n if x%i == 0:\n divisors = divisors + (i,)\nprint 'the divisors of',x,'are',divisors",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": "the divisors of 10 are (1, 2, 5)\n"
}
],
"prompt_number": 55
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- strings are very similar to tuples: "
},
{
"cell_type": "code",
"collapsed": false,
"input": "string='abcde'\nprint string[0]",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": "a\n"
}
],
"prompt_number": 56
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- this gives us some interesting possibilities:"
},
{
"cell_type": "code",
"collapsed": false,
"input": "sumDigits=0\nfor c in str(1952):\n sumDigits += int(c)\nprint sumDigits",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": "17\n"
}
],
"prompt_number": 57
},
{
"cell_type": "markdown",
"metadata": {},
"source": "##Lecture 4"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "###Functions"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- all the things we have learned so far, are enough to do anything\n- it is Turing complete \n- But it won't be enough to do anything easily\n- because it lacks to main things: \n - decomposition \n - abstraction \n- We want a possibility to not just write one big block of code, but break it down into smaller things\n- One possibility to do this is defining functions\n- functions can: \n - break up big blocks of code into small modules \n - suppress detail \n - create new 'primitives'\n- here is an example for a "
},
{
"cell_type": "code",
"collapsed": false,
"input": "def sqrt(x): \n #***Return the square root of x, if x is na perfect square. Prints an error message and returns None otherwise***\n ans=0\n if x>=0:\n while ans*ans<x: ans=ans+1\n if ans*ans!=x:\n print x,'is not a perfect square'\n return None \n else: \n return ans \n else: \n print x,'is negative'\n return None",
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 58
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- a function works as following: \n - we first put a keyword (def) \n - we then put a name(x) and parentesis containing the formal parameters \n - theres an end keyword, which is return, that will end the function and give out the following output\n - There's a special value called None, which is used to indicate, that the function doesn't return anything\n- a function is invoked by passing some value into the parameters "
},
{
"cell_type": "code",
"collapsed": false,
"input": "print sqrt(16)\nprint sqrt(5)\nprint sqrt(-1)",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": "4\n5 is not a perfect square\nNone\n-1 is negative\nNone\n"
}
],
"prompt_number": 59
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- what our defined functon does is actually binding x to 16, but only locally inside the function \n- it then return a value which is locally calculated\n- it is important to note, that the local bindings don't affect any global bindings"
},
{
"cell_type": "code",
"collapsed": false,
"input": "def f(x):\n x=x+1\n return x",
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 60
},
{
"cell_type": "code",
"collapsed": true,
"input": "x=3",
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 61
},
{
"cell_type": "code",
"collapsed": false,
"input": "x",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 62,
"text": "3"
}
],
"prompt_number": 62
},
{
"cell_type": "code",
"collapsed": true,
"input": "z=f(3)",
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 63
},
{
"cell_type": "code",
"collapsed": false,
"input": "z",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 64,
"text": "4"
}
],
"prompt_number": 64
},
{
"cell_type": "code",
"collapsed": false,
"input": "x",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 65,
"text": "3"
}
],
"prompt_number": 65
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- this means, we have to distinguish between to types of bindings: \n - global bindings, which are done in the interpreter\n - and local bindings, which are done in the def environment\n- The value none will just be asigned, but not printed out: "
},
{
"cell_type": "code",
"collapsed": true,
"input": "test=sqrt(16)",
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 66
},
{
"cell_type": "code",
"collapsed": false,
"input": "test",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 67,
"text": "4"
}
],
"prompt_number": 67
},
{
"cell_type": "code",
"collapsed": false,
"input": "test=sqrt(34)",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": "34 is not a perfect square\n"
}
],
"prompt_number": 68
},
{
"cell_type": "code",
"collapsed": true,
"input": "test",
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 69
},
{
"cell_type": "code",
"collapsed": false,
"input": "test==None",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 70,
"text": "True"
}
],
"prompt_number": 70
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- you should also wright down some specification for functions to let other users understand, what your function does "
},
{
"cell_type": "raw",
"metadata": {},
"source": "Farmyard problem: \nA pig and chicker farmer finds 20 heads and 56 legs in his farmyard. How many pigs and how many chickens does he have? "
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- If p is the number of pigs and c the number of chickens, we can write to simple linear equations, to describe the problem: \n - p+c=20\n - 4*p+2*c=56\n- How could we solve this with a little program? \n- one way would be to find the matrix for the system of linear equations and transform it in a specail way. \n- another way to do this would be by just checking all possibilities \n- the last aproach is called 'brute force algorithm' \n- this could look like this: "
},
{
"cell_type": "code",
"collapsed": true,
"input": "#l: number of legs\n#h: number of heads \n#p: number of pigs \n#c: number of chickens \ndef solve(l,h):\n for c in range(0,h+1):\n p=h-c\n lnew=4*p+2*c\n if lnew==l:\n return (p,c)\n return (None,None)",
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 71
},
{
"cell_type": "code",
"collapsed": false,
"input": "solve(56,20)",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 72,
"text": "(8, 12)"
}
],
"prompt_number": 72
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- we could also define a little program now, which will ask the user for some input and then return an answer "
},
{
"cell_type": "code",
"collapsed": true,
"input": "def barnYard():\n h=int(raw_input('enter number of heads: '))\n l=int(raw_input('enter number of legs: '))\n p,c=solve(l,h)\n if p==None:\n print 'there is no solution'\n else: \n print 'number of pigs:',p\n print 'number of chickens:',c",
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 73
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- we can also easily expand the problem now \n- lets say the farmer also has spiders for some strange reason: "
},
{
"cell_type": "code",
"collapsed": false,
"input": "def solve2(l,h):\n solutionFoud = False\n for s in range(0,h+1):\n for c in range(0,h-s+1):\n p=h-c-s\n lnew=4*p+2*c+8*s\n if lnew==l:\n print 'number of pigs:',p\n print 'number of chickens:',c\n print 'number of spiders:',s\n print \n solutionFoud=True \n if not solutionFoud: \n print 'ther is no solution' ",
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 74
},
{
"cell_type": "code",
"collapsed": false,
"input": "solve2(56,20)",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": "number of pigs: 8\nnumber of chickens: 12\nnumber of spiders: 0\n\nnumber of pigs: 5\nnumber of chickens: 14\nnumber of spiders: 1\n\nnumber of pigs: 2\nnumber of chickens: 16\nnumber of spiders: 2\n\n"
}
],
"prompt_number": 75
},
{
"cell_type": "code",
"collapsed": false,
"input": "solve2(0,1)",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": "ther is no solution\n"
}
],
"prompt_number": 76
},
{
"cell_type": "markdown",
"metadata": {},
"source": "###Recursion"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- a recursion consist of the following parts: \n - base case: simplest possible solution \n - recursive step: break the problem into a simpler version of the same problem and some other steps \n- for example the following code for testing the word, whether it is a palindrome is recursive: "
},
{
"cell_type": "code",
"collapsed": true,
"input": "def isPalindrone(s):\n if len(s)<=1: return True \n else: return s[0]==s[-1] and isPalindrone(s[1:-1])",
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 77
},
{
"cell_type": "code",
"collapsed": false,
"input": "isPalindrone('algreergla')",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 78,
"text": "True"
}
],
"prompt_number": 78
},
{
"cell_type": "code",
"collapsed": false,
"input": "isPalindrone('grace')",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 79,
"text": "False"
}
],
"prompt_number": 79
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- to make clearer what is happening, we can use the following code"
},
{
"cell_type": "code",
"collapsed": true,
"input": "def isPalindrone2(s, indent):\n print indent,'| isPalindrone called with',s\n if len(s)<=1: \n print indent,'| about to return True from base case'\n return True \n else: \n ans=s[0]==s[-1] and isPalindrone2(s[1:-1],indent+indent)\n print indent,'| About to return', ans\n return ans",
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 80
},
{
"cell_type": "code",
"collapsed": false,
"input": "isPalindrone2('abcba', ' ')",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": " | isPalindrone called with abcba\n | isPalindrone called with bcb\n | isPalindrone called with c\n | about to return True from base case\n | About to return True\n | About to return True\n"
},
{
"output_type": "pyout",
"prompt_number": 81,
"text": "True"
}
],
"prompt_number": 81
},
{
"cell_type": "code",
"collapsed": false,
"input": "isPalindrone2('abcdba', ' ')",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": " | isPalindrone called with abcdba\n | isPalindrone called with bcdb\n | isPalindrone called with cd\n | About to return False\n | About to return False\n | About to return False\n"
},
{
"output_type": "pyout",
"prompt_number": 82,
"text": "False"
}
],
"prompt_number": 82
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- Fibonacci wanted to calculate rabbit-calculation growth\n- For this he invented the famous fibonacci numbers\n- The sequence of fibonacci numbers is defined as followed: \n - Pairs(0)=1\n - Pairs(1)=1\n - Pairs(n)=Pairs(n-1)+Pairs(n-2)"
},
{
"cell_type": "code",
"collapsed": true,
"input": "def fib(x):\n if x==0 or x==1: return 1\n else: return fib(x-1)+fib(x-2)",
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 83
},
{
"cell_type": "code",
"collapsed": false,
"input": "fib(30)",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 84,
"text": "1346269"
}
],
"prompt_number": 84
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- note that most problems are either recursively or iteratively best solved"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "##Lecture 5"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "###Numbers"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- there are two different kinds of numbers in python: \n- The first numbers we have looked at so far are integers \n- integers can be arbitrarily long: "
},
{
"cell_type": "code",
"collapsed": true,
"input": "a=2**1000",
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 85
},
{
"cell_type": "code",
"collapsed": false,
"input": "a_len = len(str(a))\na_len",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 86,
"text": "302"
}
],
"prompt_number": 86
},
{
"cell_type": "code",
"collapsed": false,
"input": "\"...\"+str(a)[a_len-50:a_len]+'L'",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 87,
"text": "'...71196477686542167660429831652624386837205668069376L'"
}
],
"prompt_number": 87
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- really long numbers (bigger than 2 billion) are indexed with L"
},
{
"cell_type": "code",
"collapsed": true,
"input": "b=2**999",
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 88
},
{
"cell_type": "code",
"collapsed": false,
"input": "b_len = len(str(b))\nb_len",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 89,
"text": "301"
}
],
"prompt_number": 89
},
{
"cell_type": "code",
"collapsed": false,
"input": "\"...\"+str(b)[b_len-50:b_len]+\"L\"",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 90,
"text": "'...85598238843271083830214915826312193418602834034688L'"
}
],
"prompt_number": 90
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- L-numbers will allways stay long numbers: "
},
{
"cell_type": "code",
"collapsed": false,
"input": "a/b",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 91,
"text": "2L"
}
],
"prompt_number": 91
},
{
"cell_type": "markdown",
"metadata": {},
"source": "###Floating points"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- the other class of numbers are floating points, so called floats \n- python displays numbers according to IEEE754 floating point\n- this is a variation of the scientific represenation of numbers as a pair of a mantissa (or sagnificant) and an exponent \n- the exponent in computer science is not to the base of ten, but to the base of 2\n- the exponent and the mantissa can take the following values \n - 1<= mantissa < 2 \n - exponent: 1022:1023\n- these numbers come from the fact, that computers work with 64 bits, to represent a number, the bits are used as following: \n - 1 bit for the sign \n - 11 bits for the exponent \n - 52 bits for the mantissa \n- note, that not all numbers can be displayed perfectly in the basis of 2\n- what python gives us out will always just be an up to 17 digits long rounded number \n- it is very important to note, that this can sometimes have important implications"
},
{
"cell_type": "code",
"collapsed": true,
"input": "import math as m",
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 92
},
{
"cell_type": "code",
"collapsed": true,
"input": "a=m.sqrt(2)",
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 93
},
{
"cell_type": "code",
"collapsed": false,
"input": "a",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 94,
"text": "1.4142135623730951"
}
],
"prompt_number": 94
},
{
"cell_type": "code",
"collapsed": false,
"input": "a*a==2",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 95,
"text": "False"
}
],
"prompt_number": 95
},
{
"cell_type": "code",
"collapsed": false,
"input": "a*a",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 96,
"text": "2.0000000000000004"
}
],
"prompt_number": 96
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- so we should note, that the == operator should not be used with floats\n- instead you should design some other comparing operator which tests something "
},
{
"cell_type": "code",
"collapsed": false,
"input": "def near(a,b):\n epsilon=0.00000000001\n if a-b<=epsilon: return True \n else: return False ",
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 97
},
{
"cell_type": "code",
"collapsed": false,
"input": "print m.sqrt(2)*m.sqrt(2)==2\nprint near(m.sqrt(2)*m.sqrt(2),2)",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": "False\nTrue\n"
}
],
"prompt_number": 98
},
{
"cell_type": "markdown",
"metadata": {},
"source": "###Successive approximation"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- let us try to introduce some float function, for example sqrt\n- there are some problems to this: \n - the answer might not be the exact answer \n - we can't enumerate all guesses, because reals are uncountable and even though we could count all the floating points this is not a technically handy solution\n- so we will want to produce the algorithm, which does the following steps: \n - guess \n - check \n - improve \n- this process is called successive approximation\n- a Programm like this would look alike to the following: "
},
{
"cell_type": "raw",
"metadata": {},
"source": "guess = initial guess \nfor tier in range(N): \n if f(guess) close enough: return guess\n else: guess = better guess\nerror"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- for the example of the square root, we could write the following code\n- using the bisection method"
},
{
"cell_type": "code",
"collapsed": false,
"input": "def sqrtBi(x,epsilon):\n assert x>=0, 'x must be non negative, not'+str(x)\n assert epsilon>0, 'epsilon must be positive, not'+str(epsilon)\n low=0\n high=x\n guess=(low+high)/2.0\n ctr=1\n while abs(guess**2-x)>epsilon and ctr<=100:\n #print 'low:',low,'high:',high,'guess:',guess\n if guess**2<x:\n low=guess\n else: \n high=guess\n guess=(low+high)/2.0\n ctr+=1\n assert ctr<=100, 'iteration count exceeded'\n print 'bisection method, numerical iterations:',ctr,'estimate:',guess\n return guess",
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 99
},
{
"cell_type": "code",
"collapsed": false,
"input": "sqrtBi(4,0.001)",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": "bisection method, numerical iterations: 1 estimate: 2.0\n"
},
{
"output_type": "pyout",
"prompt_number": 100,
"text": "2.0"
}
],
"prompt_number": 100
},
{
"cell_type": "code",
"collapsed": false,
"input": "sqrtBi(9,0.001)",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": "bisection method, numerical iterations: 15 estimate: 3.00009155273\n"
},
{
"output_type": "pyout",
"prompt_number": 101,
"text": "3.000091552734375"
}
],
"prompt_number": 101
},
{
"cell_type": "code",
"collapsed": false,
"input": "sqrtBi(2,0.001)",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": "bisection method, numerical iterations: 8 estimate: 1.4140625\n"
},
{
"output_type": "pyout",
"prompt_number": 102,
"text": "1.4140625"
}
],
"prompt_number": 102
},
{
"cell_type": "code",
"collapsed": false,
"input": "sqrtBi(1000,0.00000000001)",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": "bisection method, numerical iterations: 50 estimate: 31.6227766017\n"
},
{
"output_type": "pyout",
"prompt_number": 103,
"text": "31.62277660168389"
}
],
"prompt_number": 103
},
{
"cell_type": "markdown",
"metadata": {},
"source": "##Lecture 6"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "### Regression testing"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- it is sometimes very useful to write a test function\n- this function can then be easily run determine, whether any changes to the code affect the results of some special part of it \n- This method is called regression testing "
},
{
"cell_type": "code",
"collapsed": true,
"input": "def testsqrtBi():\n print 'sqrtBi(4,0.0001)'\n sqrtBi(4,0.0001)\n print 'sqrtBi(9,0.0001)'\n sqrtBi(9,0.0001)\n print 'sqrtBi(2,0.0001)'\n sqrtBi(2,0.0001)\n print 'sqrtBi(0.25,0.0001)'\n sqrtBi(0.25,0.0001)",
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 104
},
{
"cell_type": "code",
"collapsed": false,
"input": "testsqrtBi()",
"language": "python",
"metadata": {},
"outputs": [
{
"ename": "AssertionError",
"evalue": "iteration count exceeded",
"output_type": "pyerr",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mAssertionError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-105-104c8d153e9a>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mtestsqrtBi\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;32m<ipython-input-104-567ba34527be>\u001b[0m in \u001b[0;36mtestsqrtBi\u001b[0;34m()\u001b[0m\n\u001b[1;32m 7\u001b[0m \u001b[0msqrtBi\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m0.0001\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 8\u001b[0m \u001b[0;32mprint\u001b[0m \u001b[0;34m'sqrtBi(0.25,0.0001)'\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 9\u001b[0;31m \u001b[0msqrtBi\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m0.25\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m0.0001\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;32m<ipython-input-99-4e84f28c19fe>\u001b[0m in \u001b[0;36msqrtBi\u001b[0;34m(x, epsilon)\u001b[0m\n\u001b[1;32m 14\u001b[0m \u001b[0mguess\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlow\u001b[0m\u001b[0;34m+\u001b[0m\u001b[0mhigh\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m/\u001b[0m\u001b[0;36m2.0\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 15\u001b[0m \u001b[0mctr\u001b[0m\u001b[0;34m+=\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 16\u001b[0;31m \u001b[0;32massert\u001b[0m \u001b[0mctr\u001b[0m\u001b[0;34m<=\u001b[0m\u001b[0;36m100\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'iteration count exceeded'\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 17\u001b[0m \u001b[0;32mprint\u001b[0m \u001b[0;34m'bisection method, numerical iterations:'\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mctr\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m'estimate:'\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mguess\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 18\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mguess\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;31mAssertionError\u001b[0m: iteration count exceeded"
]
},
{
"output_type": "stream",
"stream": "stdout",
"text": "sqrtBi(4,0.0001)\nbisection method, numerical iterations: 1 estimate: 2.0\nsqrtBi(9,0.0001)\nbisection method, numerical iterations: 18 estimate: 2.99998855591\nsqrtBi(2,0.0001)\nbisection method, numerical iterations: 14 estimate: 1.41418457031\nsqrtBi(0.25,0.0001)\n"
}
],
"prompt_number": 105
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- the problem is, that $\\sqrt{1/4}=1/2$, but the algorithm is just looking in the reason between 0 and $x=1/4$\n- so we can fix this easily: "
},
{
"cell_type": "code",
"collapsed": true,
"input": "def sqrtBi(x,epsilon):\n assert x>=0, 'x must be non negative, not'+str(x)\n assert epsilon>0, 'epsilon must be positive, not'+str(epsilon)\n low=0\n high=max(x,1)\n guess=(low+high)/2.0\n ctr=1\n while abs(guess**2-x)>epsilon and ctr<=100:\n #print 'low:',low,'high:',high,'guess:',guess\n if guess**2<x:\n low=guess\n else: \n high=guess\n guess=(low+high)/2.0\n ctr+=1\n assert ctr<=100, 'iteration count exceeded'\n print 'bisection method, numerical iterations:',ctr,'estimate:',guess\n return guess",
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 106
},
{
"cell_type": "code",
"collapsed": false,
"input": "testsqrtBi()",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": "sqrtBi(4,0.0001)\nbisection method, numerical iterations: 1 estimate: 2.0\nsqrtBi(9,0.0001)\nbisection method, numerical iterations: 18 estimate: 2.99998855591\nsqrtBi(2,0.0001)\nbisection method, numerical iterations: 14 estimate: 1.41418457031\nsqrtBi(0.25,0.0001)\nbisection method, numerical iterations: 1 estimate: 0.5\n"
}
],
"prompt_number": 107
},
{
"cell_type": "markdown",
"metadata": {},
"source": "###Newtons method"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- the speed of convergence of the algorithm can be improved \n- What are we really doing, if we are looking for $\\sqrt{x}$?\n- We are looking for the solution of the equation $f(guess)=guess^2-x$\n- Where $f(guess) = 0$\n- If we plot the function we are looking for the intersection of $f(guess)$ with the $x$-axis\n- So there is abother method for finding this intersection, called Newtons method. \n- In Newtones method we will use the intersection of the tangent line with the $x$-axis for the new guess: \n\n- $guess_{n+1}=guess_n-\\frac{f(guess_n)}{f'(guess_n)}=guess_n-\\frac{guess^2-x}{2\\cdot guess_n}$\n- for example this would do: "
},
{
"cell_type": "markdown",
"metadata": {},
"source": "$ \\sqrt{16}: $\n\n$guess_0=3 \\qquad f(3)=9-16=-7 $\n\n$guess_{1}=3-(-7/6)=4.167 \\qquad f(4.116)=1.361$\n\n$guess_2=4.167-(1.361/8.333)=4.003 \\qquad \\dots$"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- so the code implementation would look like the following: "
},
{
"cell_type": "code",
"collapsed": true,
"input": "def sqrtNR(x,epsilon):\n assert x>=0, 'x must be non negative, not'+str(x)\n assert epsilon>0, 'epsilon must be positive, not'+str(epsilon)\n x=float(x)\n guess=x/2.0\n #guess=0.001\n diff=guess**2-x\n ctr=1\n while abs(diff)>epsilon and ctr<=100:\n #print 'error:',diff,'guess:',guess\n guess=guess-diff/(2.0*guess)\n diff=guess**2-x\n ctr+=1\n assert ctr<=100, 'iteration count exceeded'\n print 'Newton-Raphson-method, numerical iterations:',ctr,'estimate:',guess\n return guess",
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 108
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- it is important to note, that this method wouldn't work, if our initial guess would be 0, so we have to be careful with these methods "
},
{
"cell_type": "code",
"collapsed": true,
"input": "def compareBiNR():\n print ' sqrt(2,0.01)'\n sqrtBi(2,0.01)\n sqrtNR(2,0.01)\n print \n print ' sqrt(2,0.0001)'\n sqrtBi(2,0.0001)\n sqrtNR(2,0.0001)\n print\n print ' sqrt(2,0.000001)'\n sqrtBi(2,0.000001)\n sqrtNR(2,0.000001)",
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 109
},
{
"cell_type": "code",
"collapsed": false,
"input": "compareBiNR()",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": " sqrt(2,0.01)\nbisection method, numerical iterations: 8 estimate: 1.4140625\nNewton-Raphson-method, numerical iterations: 3 estimate: 1.41666666667\n\n sqrt(2,0.0001)\nbisection method, numerical iterations: 14 estimate: 1.41418457031\nNewton-Raphson-method, numerical iterations: 4 estimate: 1.41421568627\n\n sqrt(2,0.000001)\nbisection method, numerical iterations: 22 estimate: 1.41421365738\nNewton-Raphson-method, numerical iterations: 5 estimate: 1.41421356237\n"
}
],
"prompt_number": 110
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- so we can see, that the Newton-Raphson-method is much more efficient"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "###Answers can be wrong"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- it is important to realize, that just because the computer says so, it isn't necessarily right\n- So it is important to ask yourself, why you believe what the computer says\n- for example if we get an answer like this we should become suspicious:"
},
{
"cell_type": "code",
"collapsed": false,
"input": "print ' sqrt(12345678,0.0001)'\nsqrtBi(123456789,0.0001)\nsqrtNR(123456789,0.0001)\nprint",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": " sqrt(12345678,0.0001)\nbisection method, numerical iterations: 53 estimate: 11111.1110606\nNewton-Raphson-method, numerical iterations: 18 estimate: 11111.1110606\n\n"
}
],
"prompt_number": 111
},
{
"cell_type": "markdown",
"metadata": {},
"source": "###Lists"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- so far we have looked at the following non scalar types: \n - Tuples \n - Strings\n- Both of them were immutable, that means we can't change them, but what we can do is create new ones, which are similar to the old ones\n- But we now want to look at some mutable non scalars\n- The most important ones are Lists\n- Elements of Lists can be numbers, strings, and even other Lists: "
},
{
"cell_type": "code",
"collapsed": false,
"input": "L=[1,'MIT',3.3,['a']]\nprint L",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": "[1, 'MIT', 3.3, ['a']]\n"
}
],
"prompt_number": 112
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- we can get elements out of lists, just as we do with tuples"
},
{
"cell_type": "code",
"collapsed": true,
"input": "Techs=['MIT','CalTech']",
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 113
},
{
"cell_type": "code",
"collapsed": false,
"input": "Techs[0]",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 114,
"text": "'MIT'"
}
],
"prompt_number": 114
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- it is important to note, that an empty list, does have the value, which is an empty list, not None\n- we can append lists with elements:"
},
{
"cell_type": "code",
"collapsed": true,
"input": "Ivys=['Harvard','Yale','Brown']",
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 115
},
{
"cell_type": "code",
"collapsed": true,
"input": "Univs=[]",
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 116
},
{
"cell_type": "code",
"collapsed": false,
"input": "Univs.append(Techs)\nprint Univs",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": "[['MIT', 'CalTech']]\n"
}
],
"prompt_number": 117
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- we should note here, that we have appended a list with a list, so that in the list Univs there is now one element, which is a list\n- The append command is actually a new thing, which is called method, it is a function with two arguments with a special syntax, which is quite a sensible thing, as we will see later\n- we can also add various different Lists together:"
},
{
"cell_type": "code",
"collapsed": false,
"input": "Univs.append(Ivys)\nprint Univs",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": "[['MIT', 'CalTech'], ['Harvard', 'Yale', 'Brown']]\n"
}
],
"prompt_number": 118
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- we can also use loops over elements of lists: "
},
{
"cell_type": "code",
"collapsed": false,
"input": "for e in Univs:\n print e\n for c in e: \n print c",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": "['MIT', 'CalTech']\nMIT\nCalTech\n['Harvard', 'Yale', 'Brown']\nHarvard\nYale\nBrown\n"
}
],
"prompt_number": 119
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- so what this does is printing the elements of the list Univs and then printing the elements of the elements, which are the elects of Techs and Ivys. \n- we can also remove elements from Lists: "
},
{
"cell_type": "code",
"collapsed": false,
"input": "Ivys.remove('Harvard')\nprint Univs",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": "[['MIT', 'CalTech'], ['Yale', 'Brown']]\n"
}
],
"prompt_number": 120
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- It is important to note here, that we actually changed the list, and didn't just redefine it. \n- We can concatenate lists together by using lists, to get a flattered list of different lists: "
},
{
"cell_type": "code",
"collapsed": false,
"input": "Univs=Techs+Ivys\nprint Univs",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": "['MIT', 'CalTech', 'Yale', 'Brown']\n"
}
],
"prompt_number": 121
},
{
"cell_type": "markdown",
"metadata": {},
"source": "##Lecture 7"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "###List assignment "
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- we can bound elements of the list now to values: "
},
{
"cell_type": "code",
"collapsed": false,
"input": "Ivys[1]=-15\nprint Ivys",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": "['Yale', -15]\n"
}
],
"prompt_number": 122
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- it is important to note, that assignments in Lsits are different to assignments for integers or floats \n- By assigning a name to a list we create the list\n- we can now assign different names to the list \n- we can also mutate the elements of the list using the names \n- but we can also bind the names to other elements "
},
{
"cell_type": "code",
"collapsed": false,
"input": "L1=[1,2,3]\nL2=L1\nprint L1\nprint L2",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": "[1, 2, 3]\n[1, 2, 3]\n"
}
],
"prompt_number": 123
},
{
"cell_type": "code",
"collapsed": false,
"input": "L1[0]=4\nprint L2",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": "[4, 2, 3]\n"
}
],
"prompt_number": 124
},
{
"cell_type": "code",
"collapsed": false,
"input": "L2[1]=6\nprint L1",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": "[4, 6, 3]\n"
}
],
"prompt_number": 125
},
{
"cell_type": "code",
"collapsed": false,
"input": "L1=[]\nprint L1\nprint L2",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": "[]\n[4, 6, 3]\n"
}
],
"prompt_number": 126
},
{
"cell_type": "markdown",
"metadata": {},
"source": "###Dictionaries"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- ther is another type of grouping elements called dictionaries\n- dictionaries have the following properties: \n - mutable \n - heterogeneous \n - not ordered \n - generalized indexing\n- generalized indeying means, that we can assign a key to every values, by which it can be called\n- dictionaries are created as followed: "
},
{
"cell_type": "code",
"collapsed": false,
"input": "E2F={'one':'un','soccer':'football','never':'jemais'}\nprint E2F",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": "{'soccer': 'football', 'never': 'jemais', 'one': 'un'}\n"
}
],
"prompt_number": 127
},
{
"cell_type": "code",
"collapsed": false,
"input": "E2F['soccer']",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 128,
"text": "'football'"
}
],
"prompt_number": 128
},
{
"cell_type": "code",
"collapsed": false,
"input": "E2F['football']",
"language": "python",
"metadata": {},
"outputs": [
{
"ename": "KeyError",
"evalue": "'football'",
"output_type": "pyerr",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-129-5b221446c4c4>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mE2F\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'football'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;31mKeyError\u001b[0m: 'football'"
]
}
],
"prompt_number": 129
},
{
"cell_type": "code",
"collapsed": false,
"input": "E2F[0]",
"language": "python",
"metadata": {},
"outputs": [
{
"ename": "KeyError",
"evalue": "0",
"output_type": "pyerr",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-130-af0a66a240a1>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mE2F\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;31mKeyError\u001b[0m: 0"
]
}
],
"prompt_number": 130
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- if we want to assign into both directions, we have to do so specifically: "
},
{
"cell_type": "code",
"collapsed": false,
"input": "N2S={'one':1,'two':2,1:'one',2:'two'}\nprint N2S",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": "{1: 'one', 2: 'two', 'two': 2, 'one': 1}\n"
}
],
"prompt_number": 131
},
{
"cell_type": "code",
"collapsed": false,
"input": "print N2S.keys()",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": "[1, 2, 'two', 'one']\n"
}
],
"prompt_number": 132
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- we can also delete elements of lists"
},
{
"cell_type": "code",
"collapsed": false,
"input": "del N2S['one']\nprint N2S",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": "{1: 'one', 2: 'two', 'two': 2}\n"
}
],
"prompt_number": 133
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- we could implement keys with lists, but dictionaries provide a pretty useful syntax\n- and they are faster, because they use a technique called hashing, which retrieves keys in constant time, not depending on the numbers of elements "
},
{
"cell_type": "markdown",
"metadata": {},
"source": "###Structuring with functions"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- we want to look how to use the idea of functions to organize code\n- for looking at this explicitly we want to look at an example \n- so let's say we want to find the length of the hypothenuse of a right triangle \n- so let's look at some pseudo code (code in no particular language) to solve this problem"
},
{
"cell_type": "raw",
"metadata": {},
"source": "input value for base as float and assign name b \ninput value for height as float and assign name h \nfind the square-rout of b*b+h*h\nsave the output as a float to the name hyp\nprint out the value of hey "
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- this pseudo code tells us the following things: \n - listing modules \n - specifring values \n - determining flow of control \n - abstraction of "
},
{
"cell_type": "code",
"collapsed": false,
"input": "def hypothenus(): \n import math \n inputOK=False\n while not inputOK:\n b=input('Enter base:')\n if type(b)==type(1.0): \n inputOK=True \n else: \n print 'Error, base must be a floating point number.'\n \n inputOK=False \n while not inputOK:\n h=input('Enter height:')\n if type(h)==type(1.0): \n inputOK=True \n else: \n print 'Error, height must be a floating point number.'\n\n hyp=math.sqrt(b**2+h**2)\n print 'base: '+str(b)+', height: '+str(h)+', hypothenus: '+str(hyp)",
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 134
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- we can realize here, that the mechanism to make sure, we get a float is used to times in this code\n- there's an obvious pattern between these codees \n- so in order to create a function for this we can ask ourself what's the difference between the two code blocks \n- and we can see that the only differences are in what we ask for and what we return \n- so let's wright a function for this: "
},
{
"cell_type": "code",
"collapsed": true,
"input": "def getFloat(RequestMessage,ErrorMessage):\n inputOK=False\n while not inputOK:\n value=input(RequestMessage)\n if type(value)==type(1.0): \n inputOK=True \n else: \n print ErrorMessage\n return value ",
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 135
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- we can then wright the above code as: "
},
{
"cell_type": "code",
"collapsed": true,
"input": "def hypothenus(): \n import math \n b=getFloat('Enter base:','Error, base must be a floating point number!')\n h=getFloat('Enter height:','Error, height must be a floating point number!')\n hyp=math.sqrt(b**2+h**2)\n print 'base: '+str(b)+', height: '+str(h)+', hypothenus: '+str(hyp)",
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 136
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- so there are a few advantages of this: \n - we have less code \n - we seperated implementation from functionality "
},
{
"cell_type": "markdown",
"metadata": {},
"source": "###Efficiency"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- we can distinguish between different types of algorithms according to there efficiencies \n- if we want to construct a fast program, the best approach is mostly not to create a genial new algorithm but to make use of already existent very fast algorithms \n- so how we have to learn to choose the right algorithms\n- so how can we map a problem into a class of algorithms with some efficiency? \n- in order to learn this, we have to measure the space and time of an algorithm\n - space refers to the memory needed to complete the computations \n - time refers to the time the algorithm will be running \n- in order to find the time, we will need to determine the number of basic steps needed as a function of the input size \n- we are going to use the random access model \n - we assume, that the length of time to take me to any location of memory \n - we will assume, that the basic primitive steps will take the same amount of time \n- so we want to count the amount of basic computations \n - for the best case\n - for the worst case \n - for the expected average case \n- we want to look at the worst cases here "
},
{
"cell_type": "markdown",
"metadata": {},
"source": "##Lecture 8"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- lets try to find the basic steps of the following exponential operation: "
},
{
"cell_type": "code",
"collapsed": true,
"input": "def exp1(a,b):\n ans=1\n while b>0:\n ans *= a\n b -= 1\n return 1",
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 137
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- the number of steps $S$ would be $S(b)=2+3b$\n- so basically we won't be interested in the additive constant, because it will be neglectable for large $b$\n- and we will also want to mainly look at the kind of growth, so we will want to neglect the multiplicitiv constant \n- what we want to look at is the rate of growth as the sice of the problem growth \n- so we will want to use the asymptotic big O notation \n - which gives an upper limit to the growth of the function as the input gets large \n - for example we wright $f(x)\\in \\mathcal{O}(n^2)$, where n represents $a$ measure of the size of $x$ \n- so for our algorithm above we could wrigut $exp1(x)\\in\\mathcal{O}(b)$\n- let's look at another implementation of exp:"
},
{
"cell_type": "code",
"collapsed": true,
"input": "def exp2(a,b):\n if b==1:\n return a\n else: \n a*exp2(a,b-1)",
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 138
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- so whats the amount of basic steps in this recursive definition?\n- we can wright: $S(b)=3+S(b-1)=3+3+S(b-2)=3k+S(b-k)\\;\\;\\;\\;\\;\\;$ this is done, when $b-k=1$ then we have two more operations left, so we get $S(b)=3(b-1)+2=3b-1$\n- so we again get $exp2(x)\\in\\mathcal{O}(b)$\n- let's look at another implementation of our function \n- for this one we will use a little trick with a little trick: \n - $b \\text{ even}: a^b=a\\cdot a^{b/2}$\n - $b \\text{ odd}: a^b=a\\cdot a^{b-1}$"
},
{
"cell_type": "code",
"collapsed": true,
"input": "def exp3(a,b):\n if b==1:\n return a\n if (b%2)*2==b:\n return exp3(a*a,b/2)\n else: \n return a*exp3(a,b-1)",
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 139
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- so we for the number of steps if $b$ is even, we get: $S(b)=6+S(b/2)\\;\\;$, if $b$ is odd, we get: $S(b)=6+S(b-1)=12+S(\\frac{b-1}2)$\n- so we will generalize that as $S(b)=12+S(b/2)=12k+S(b/2^k)\\;\\;\\;$ which stops if we have $b/2^k=1$ which gives us $k=\\log_2(b)$\n- so we get $exp3\\in\\mathcal{O}(\\log b)$\n- so let's look at another algorithm: "
},
{
"cell_type": "code",
"collapsed": true,
"input": "def g(n,m):\n x=0\n for i in range(n):\n for j in range(m):\n x+=1\n return x ",
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 140
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- for which we will find the order: $g(x)\\in\\mathcal{O}(n\\cdot m)=\\mathcal{O}(n^2)$\n- and let's look to another problem, called the Towers of Hanoi (move ordered disks from one stag to another) "
},
{
"cell_type": "code",
"collapsed": false,
"input": "def Towers(size, fromStack, toStack, spareStack): \n if size==1:\n print 'Move disk from ',fromStack,'to ',toStack\n else: \n Towers(size-1,fromStack,spareStack,toStack)\n Towers(1,fromStack,toStack,spareStack)\n Towers(size-1,spareStack,toStack,fromStack)",
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 141
},
{
"cell_type": "code",
"collapsed": false,
"input": "Towers(3,'(1)','(2)','(3)')",
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": "Move disk from (1) to (2)\nMove disk from (1) to (3)\nMove disk from (2) to (3)\nMove disk from (1) to (2)\nMove disk from (3) to (1)\nMove disk from (3) to (2)\nMove disk from (1) to (2)\n"
}
],
"prompt_number": 142
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- The amount of basic steps for this will be: $S(n)=1+S(1)+2\\cdot S(n-1)=3+2\\cdot S(n-1)=\\sum_{k=1}^n 2^{k-1}\\cdot 3+2^n\\cdot T(n-k)$\n- Which gives us $Towers(x)\\in\\mathcal{O}(2^n)\\;$, an exponential order"
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- so let's compare these algorithms:\n- If we have a size of $n=1000\\;\\;$ and a nanosecond speed: \n - logarithmic: $10$ nanoseconds \n - linear: $1$ microsecond \n - quadratic: $1$ millisecond \n - exponential: $10^{284}$ years\n- so we should avoid exponential algorithms by any means "
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- let's look at another example: \n- searching through a sorted list\n- we could implement it like this: "
},
{
"cell_type": "code",
"collapsed": true,
"input": "def search(s,e):\n answer=None \n i=0\n numCompares=0\n while i<len(s) and answer==None: \n numCompares+=1\n print i, numCompares\n if e==s[i]:\n answer=True\n elif e<s[i]: \n answer=False \n i+=1\n print answer",
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 143
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- we get $search(s)\\in\\mathcal{O}(len(s))$\n- or we could use a binary search like the following: "
},
{
"cell_type": "code",
"collapsed": true,
"input": "def bsearch(s,e,first,last):\n print first,last\n if (last-first)<2:\n return s[first]==e or s[last]==e\n mid=first+(last-first)/2\n if s[mid]==e:\n return True \n if s[mid]>e:\n return bsearch(s,e,first,mid-1)\n return bsearch(s,e,mid+1,last)",
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 144
},
{
"cell_type": "markdown",
"metadata": {},
"source": "- and get $bsearch(s)\\in\\mathcal{O}(log(len(s)))$\n- we should also note, that it is important to understand how a list is build to determine the order \n- there are two implementations of lists: \n - in linked lists, each element of the list points to its value and to the next one, so in order to get to tone element, we need to access all elements before \n - in constant access lists, each element points to its value and theres a meta structure for accessing the list, so that each element can be accessed instantly "
}
],
"metadata": {}
}
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment