├── 001-hello.py ├── 01a-intro ├── 01a-intro.aux ├── 01a-intro.log ├── 01a-intro.nav ├── 01a-intro.out ├── 01a-intro.pdf ├── 01a-intro.snm ├── 01a-intro.tex ├── 01a-intro.toc ├── 01a-intro.vrb ├── images │ ├── 27.png │ ├── Alan Turing One Stamp.jpg │ ├── ForallyoucodersHarryspeakspython-32556.jpg │ ├── ForallyoucodersHarryspeakspython-32556.png │ ├── concentration-levels-2.png │ ├── concentration-levels.png │ ├── keep-calm-and-ask-for-help-5.png │ ├── keep-calm-and-ask-for-help.png │ ├── stamp.png │ └── syllabus.png ├── manchesterlogo.jpg ├── nalogo.pdf └── not-even-once │ ├── matplotlib-sphinxext-ipython_console_highlighting.png │ ├── not-even-once.png │ └── not-even-once.xcf ├── 01c-python_intro.ipynb ├── 02a-loops_conditionals.ipynb ├── 02b-exercises.ipynb ├── 02c-loops_conditionals.ipynb ├── 03a-functions.ipynb ├── 03b-exercises.ipynb ├── 03c-functions.ipynb ├── 04a-lists.ipynb ├── 04b-exercises.ipynb ├── 04c-lists.ipynb ├── 05a-strings.ipynb ├── 05b-exercises.ipynb ├── 05c-strings.ipynb ├── 06a-control_flow.ipynb ├── 06b-exercises.ipynb ├── 06c-control_flow.ipynb ├── 07a-modules.ipynb ├── 07b-exercises.ipynb ├── 07c-modules.ipynb ├── 08a-file_io.ipynb ├── 08b-exercises.ipynb ├── 08c-file_io.ipynb ├── 09a-analysis_of_algorithms.ipynb ├── 09b-exercises.ipynb ├── 09c-analysis_of_algorithms.ipynb ├── 10a-data_analysis.ipynb ├── 10a-europe-170013.png ├── 10a-europe.png ├── 10a-interpolation_methods.png ├── 10a-layer_images.png ├── 10a-temps.zip ├── 10c-data_analysis-02.png ├── 10c-data_analysis-03.png ├── 10c-data_analysis-04.png ├── 10c-data_analysis.ipynb ├── 11a-google.png ├── 11a-graphs.ipynb ├── 11a-graphs ├── konigsberg.dot ├── konigsberg.jpg ├── konigsberg.png └── konigsberg.py ├── 11a-isomorphic_graphs.png ├── 11a-konigsberg_bridges.jpg ├── 11a-konigsberg_bridges.svg ├── 11a-konigsberg_bridges2.svg ├── 11a-konigsberg_bridges_blank.jpg ├── 11a-konigsberg_bridges_graph.jpg ├── 11a-konigsberg_bridges_graphviz.png ├── 11a-non_isomorphic.png ├── 11a-trees_and_forests.png ├── 11c-flow-max_flow.png ├── 11c-flow-min_cut.png ├── 11c-flow.png ├── 11c-flow2-max_flow.png ├── 11c-flow2-min_cut.png ├── 11c-flow2.png ├── 11c-graphs.ipynb ├── 12a-chess.png ├── 12a-cosplays-resized ├── cosplay-fail-costume-thor.jpg ├── cosplayers_fail_25.jpg ├── funny-cosplay-costumes-3.png ├── funny-cosplay1.jpg ├── funny-tomato-cosplay-subway-670925.png ├── ninjaturtles.jpg ├── tumblr_mg1x8nGSLj1qza05bo1_500.jpg ├── war machine cosplay fail.png └── xmen-cosplay-18.jpg ├── 12a-cosplays.zip ├── 12a-cosplays ├── cosplay-fail-costume-thor.jpg ├── cosplayers_fail_25.jpg ├── funny-cosplay-costumes-3.png ├── funny-cosplay1.jpg ├── funny-tomato-cosplay-subway-670925.png ├── ninjaturtles.jpg ├── tumblr_mg1x8nGSLj1qza05bo1_500.jpg ├── war machine cosplay fail.png └── xmen-cosplay-18.jpg ├── 12a-pil.ipynb ├── 12a-pil ├── uniman ├── uniman-logo.jpg ├── uniman.gif ├── uniman.png └── uniman.py ├── 12a-uniman.gif ├── 12a-uniman.png ├── 12a-uniman.zip ├── 12c-pil.ipynb ├── 12c-pil ├── img_7840-hist.jpg ├── img_7840.jpg ├── spirals.png ├── test-graph.png ├── test-lab-bg-sol.png ├── test-lab-bg.png ├── test-lab-sol.png ├── test-lab.png ├── test-path.png └── test-tree.png ├── LICENSE └── README.md /001-hello.py: -------------------------------------------------------------------------------- 1 | print("Hello, World!") 2 | -------------------------------------------------------------------------------- /01a-intro/01a-intro.aux: -------------------------------------------------------------------------------- 1 | \relax 2 | \providecommand\hyper@newdestlabel[2]{} 3 | \providecommand\HyperFirstAtBeginDocument{\AtBeginDocument} 4 | \HyperFirstAtBeginDocument{\ifx\hyper@anchor\@undefined 5 | \global\let\oldcontentsline\contentsline 6 | \gdef\contentsline#1#2#3#4{\oldcontentsline{#1}{#2}{#3}} 7 | \global\let\oldnewlabel\newlabel 8 | \gdef\newlabel#1#2{\newlabelxx{#1}#2} 9 | \gdef\newlabelxx#1#2#3#4#5#6{\oldnewlabel{#1}{{#2}{#3}}} 10 | \AtEndDocument{\ifx\hyper@anchor\@undefined 11 | \let\contentsline\oldcontentsline 12 | \let\newlabel\oldnewlabel 13 | \fi} 14 | \fi} 15 | \global\let\hyper@last\relax 16 | \gdef\HyperFirstAtBeginDocument#1{#1} 17 | \providecommand\HyField@AuxAddToFields[1]{} 18 | \providecommand\HyField@AuxAddToCoFields[2]{} 19 | \@writefile{toc}{\beamer@endinputifotherversion {3.32pt}} 20 | \@writefile{nav}{\beamer@endinputifotherversion {3.32pt}} 21 | \select@language{english} 22 | \@writefile{toc}{\select@language{english}} 23 | \@writefile{lof}{\select@language{english}} 24 | \@writefile{lot}{\select@language{english}} 25 | \@writefile{nav}{\headcommand {\slideentry {0}{0}{1}{1/1}{}{0}}} 26 | \@writefile{nav}{\headcommand {\beamer@framepages {1}{1}}} 27 | \@writefile{nav}{\headcommand {\slideentry {0}{0}{2}{2/2}{}{0}}} 28 | \@writefile{nav}{\headcommand {\beamer@framepages {2}{2}}} 29 | \@writefile{toc}{\beamer@sectionintoc {1}{Basics}{3}{0}{1}} 30 | \@writefile{nav}{\headcommand {\sectionentry {1}{Basics}{3}{Basics}{0}}} 31 | \@writefile{nav}{\headcommand {\beamer@sectionpages {1}{2}}} 32 | \@writefile{nav}{\headcommand {\beamer@subsectionpages {1}{2}}} 33 | \@writefile{nav}{\headcommand {\slideentry {1}{0}{3}{3/3}{}{0}}} 34 | \@writefile{nav}{\headcommand {\beamer@framepages {3}{3}}} 35 | \@writefile{toc}{\beamer@subsectionintoc {1}{1}{The course and the lecturer}{4}{0}{1}} 36 | \@writefile{nav}{\headcommand {\beamer@subsectionentry {0}{1}{1}{4}{The course and the lecturer}}\headcommand {\beamer@subsectionpages {3}{3}}} 37 | \@writefile{nav}{\headcommand {\slideentry {1}{1}{1}{4/4}{The course and the lecturer}{0}}} 38 | \@writefile{nav}{\headcommand {\beamer@framepages {4}{4}}} 39 | \@writefile{toc}{\beamer@sectionintoc {2}{Aims of the course}{5}{0}{2}} 40 | \@writefile{nav}{\headcommand {\sectionentry {2}{Aims of the course}{5}{Aims of the course}{0}}} 41 | \@writefile{nav}{\headcommand {\beamer@sectionpages {3}{4}}} 42 | \@writefile{nav}{\headcommand {\beamer@subsectionpages {4}{4}}} 43 | \@writefile{nav}{\headcommand {\slideentry {2}{0}{2}{5/5}{}{0}}} 44 | \@writefile{nav}{\headcommand {\beamer@framepages {5}{5}}} 45 | \@writefile{toc}{\beamer@subsectionintoc {2}{1}{Where does this course stand}{6}{0}{2}} 46 | \@writefile{nav}{\headcommand {\beamer@subsectionentry {0}{2}{1}{6}{Where does this course stand}}\headcommand {\beamer@subsectionpages {5}{5}}} 47 | \@writefile{nav}{\headcommand {\slideentry {2}{1}{1}{6/6}{Where does this course stand}{0}}} 48 | \@writefile{nav}{\headcommand {\beamer@framepages {6}{6}}} 49 | \@writefile{nav}{\headcommand {\slideentry {2}{1}{2}{7/10}{Where does this course stand}{0}}} 50 | \@writefile{nav}{\headcommand {\beamer@framepages {7}{10}}} 51 | \@writefile{nav}{\headcommand {\slideentry {2}{1}{3}{11/13}{Where does this course stand}{0}}} 52 | \@writefile{nav}{\headcommand {\beamer@framepages {11}{13}}} 53 | \@writefile{toc}{\beamer@subsectionintoc {2}{2}{A note on the language}{14}{0}{2}} 54 | \@writefile{nav}{\headcommand {\beamer@subsectionentry {0}{2}{2}{14}{A note on the language}}\headcommand {\beamer@subsectionpages {6}{13}}} 55 | \@writefile{nav}{\headcommand {\slideentry {2}{2}{1}{14/15}{A note on the language}{0}}} 56 | \@writefile{nav}{\headcommand {\beamer@framepages {14}{15}}} 57 | \@writefile{toc}{\beamer@subsectionintoc {2}{3}{Lectures and lab classes}{16}{0}{2}} 58 | \@writefile{nav}{\headcommand {\beamer@subsectionentry {0}{2}{3}{16}{Lectures and lab classes}}\headcommand {\beamer@subsectionpages {14}{15}}} 59 | \@writefile{nav}{\headcommand {\slideentry {2}{3}{1}{16/16}{Lectures and lab classes}{0}}} 60 | \@writefile{nav}{\headcommand {\beamer@framepages {16}{16}}} 61 | \@writefile{toc}{\beamer@subsectionintoc {2}{4}{Marking}{17}{0}{2}} 62 | \@writefile{nav}{\headcommand {\beamer@subsectionentry {0}{2}{4}{17}{Marking}}\headcommand {\beamer@subsectionpages {16}{16}}} 63 | \@writefile{nav}{\headcommand {\slideentry {2}{4}{1}{17/17}{Marking}{0}}} 64 | \@writefile{nav}{\headcommand {\beamer@framepages {17}{17}}} 65 | \@writefile{toc}{\beamer@sectionintoc {3}{How to tackle this course}{18}{0}{3}} 66 | \@writefile{nav}{\headcommand {\sectionentry {3}{How to tackle this course}{18}{How to tackle this course}{0}}} 67 | \@writefile{nav}{\headcommand {\beamer@sectionpages {5}{17}}} 68 | \@writefile{nav}{\headcommand {\beamer@subsectionpages {17}{17}}} 69 | \@writefile{nav}{\headcommand {\slideentry {3}{0}{2}{18/18}{}{0}}} 70 | \@writefile{nav}{\headcommand {\beamer@framepages {18}{18}}} 71 | \@writefile{nav}{\headcommand {\slideentry {3}{0}{3}{19/21}{}{0}}} 72 | \@writefile{nav}{\headcommand {\beamer@framepages {19}{21}}} 73 | \@writefile{nav}{\headcommand {\slideentry {3}{0}{4}{22/24}{}{0}}} 74 | \@writefile{nav}{\headcommand {\beamer@framepages {22}{24}}} 75 | \@writefile{nav}{\headcommand {\slideentry {3}{0}{5}{25/27}{}{0}}} 76 | \@writefile{nav}{\headcommand {\beamer@framepages {25}{27}}} 77 | \@writefile{nav}{\headcommand {\slideentry {3}{0}{6}{28/31}{}{0}}} 78 | \@writefile{nav}{\headcommand {\beamer@framepages {28}{31}}} 79 | \@writefile{nav}{\headcommand {\slideentry {3}{0}{7}{32/35}{}{0}}} 80 | \@writefile{nav}{\headcommand {\beamer@framepages {32}{35}}} 81 | \@writefile{nav}{\headcommand {\slideentry {3}{0}{8}{36/36}{}{0}}} 82 | \@writefile{nav}{\headcommand {\beamer@framepages {36}{36}}} 83 | \@writefile{toc}{\beamer@sectionintoc {4}{Some final remarks}{37}{0}{4}} 84 | \@writefile{nav}{\headcommand {\sectionentry {4}{Some final remarks}{37}{Some final remarks}{0}}} 85 | \@writefile{nav}{\headcommand {\beamer@sectionpages {18}{36}}} 86 | \@writefile{nav}{\headcommand {\beamer@subsectionpages {18}{36}}} 87 | \@writefile{nav}{\headcommand {\slideentry {4}{0}{9}{37/37}{}{0}}} 88 | \@writefile{nav}{\headcommand {\beamer@framepages {37}{37}}} 89 | \@writefile{toc}{\beamer@subsectionintoc {4}{1}{Asking for help}{38}{0}{4}} 90 | \@writefile{nav}{\headcommand {\beamer@subsectionentry {0}{4}{1}{38}{Asking for help}}\headcommand {\beamer@subsectionpages {37}{37}}} 91 | \@writefile{nav}{\headcommand {\slideentry {4}{1}{1}{38/38}{Asking for help}{0}}} 92 | \@writefile{nav}{\headcommand {\beamer@framepages {38}{38}}} 93 | \@writefile{nav}{\headcommand {\slideentry {4}{1}{2}{39/40}{Asking for help}{0}}} 94 | \@writefile{nav}{\headcommand {\beamer@framepages {39}{40}}} 95 | \@writefile{toc}{\beamer@subsectionintoc {4}{2}{Useful references}{41}{0}{4}} 96 | \@writefile{nav}{\headcommand {\beamer@subsectionentry {0}{4}{2}{41}{Useful references}}\headcommand {\beamer@subsectionpages {38}{40}}} 97 | \@writefile{nav}{\headcommand {\slideentry {4}{2}{1}{41/41}{Useful references}{0}}} 98 | \@writefile{nav}{\headcommand {\beamer@framepages {41}{41}}} 99 | \@writefile{nav}{\headcommand {\slideentry {4}{2}{2}{42/42}{Useful references}{0}}} 100 | \@writefile{nav}{\headcommand {\beamer@framepages {42}{42}}} 101 | \@writefile{nav}{\headcommand {\slideentry {4}{2}{3}{43/45}{Useful references}{0}}} 102 | \@writefile{nav}{\headcommand {\beamer@framepages {43}{45}}} 103 | \@writefile{nav}{\headcommand {\slideentry {4}{2}{4}{46/46}{Useful references}{0}}} 104 | \@writefile{nav}{\headcommand {\beamer@framepages {46}{46}}} 105 | \@writefile{nav}{\headcommand {\beamer@partpages {1}{46}}} 106 | \@writefile{nav}{\headcommand {\beamer@subsectionpages {41}{46}}} 107 | \@writefile{nav}{\headcommand {\beamer@sectionpages {37}{46}}} 108 | \@writefile{nav}{\headcommand {\beamer@documentpages {46}}} 109 | \@writefile{nav}{\headcommand {\def \inserttotalframenumber {25}}} 110 | -------------------------------------------------------------------------------- /01a-intro/01a-intro.nav: -------------------------------------------------------------------------------- 1 | \beamer@endinputifotherversion {3.32pt} 2 | \headcommand {\slideentry {0}{0}{1}{1/1}{}{0}} 3 | \headcommand {\beamer@framepages {1}{1}} 4 | \headcommand {\slideentry {0}{0}{2}{2/2}{}{0}} 5 | \headcommand {\beamer@framepages {2}{2}} 6 | \headcommand {\sectionentry {1}{Basics}{3}{Basics}{0}} 7 | \headcommand {\beamer@sectionpages {1}{2}} 8 | \headcommand {\beamer@subsectionpages {1}{2}} 9 | \headcommand {\slideentry {1}{0}{3}{3/3}{}{0}} 10 | \headcommand {\beamer@framepages {3}{3}} 11 | \headcommand {\beamer@subsectionentry {0}{1}{1}{4}{The course and the lecturer}}\headcommand {\beamer@subsectionpages {3}{3}} 12 | \headcommand {\slideentry {1}{1}{1}{4/4}{The course and the lecturer}{0}} 13 | \headcommand {\beamer@framepages {4}{4}} 14 | \headcommand {\sectionentry {2}{Aims of the course}{5}{Aims of the course}{0}} 15 | \headcommand {\beamer@sectionpages {3}{4}} 16 | \headcommand {\beamer@subsectionpages {4}{4}} 17 | \headcommand {\slideentry {2}{0}{2}{5/5}{}{0}} 18 | \headcommand {\beamer@framepages {5}{5}} 19 | \headcommand {\beamer@subsectionentry {0}{2}{1}{6}{Where does this course stand}}\headcommand {\beamer@subsectionpages {5}{5}} 20 | \headcommand {\slideentry {2}{1}{1}{6/6}{Where does this course stand}{0}} 21 | \headcommand {\beamer@framepages {6}{6}} 22 | \headcommand {\slideentry {2}{1}{2}{7/10}{Where does this course stand}{0}} 23 | \headcommand {\beamer@framepages {7}{10}} 24 | \headcommand {\slideentry {2}{1}{3}{11/13}{Where does this course stand}{0}} 25 | \headcommand {\beamer@framepages {11}{13}} 26 | \headcommand {\beamer@subsectionentry {0}{2}{2}{14}{A note on the language}}\headcommand {\beamer@subsectionpages {6}{13}} 27 | \headcommand {\slideentry {2}{2}{1}{14/15}{A note on the language}{0}} 28 | \headcommand {\beamer@framepages {14}{15}} 29 | \headcommand {\beamer@subsectionentry {0}{2}{3}{16}{Lectures and lab classes}}\headcommand {\beamer@subsectionpages {14}{15}} 30 | \headcommand {\slideentry {2}{3}{1}{16/16}{Lectures and lab classes}{0}} 31 | \headcommand {\beamer@framepages {16}{16}} 32 | \headcommand {\beamer@subsectionentry {0}{2}{4}{17}{Marking}}\headcommand {\beamer@subsectionpages {16}{16}} 33 | \headcommand {\slideentry {2}{4}{1}{17/17}{Marking}{0}} 34 | \headcommand {\beamer@framepages {17}{17}} 35 | \headcommand {\sectionentry {3}{How to tackle this course}{18}{How to tackle this course}{0}} 36 | \headcommand {\beamer@sectionpages {5}{17}} 37 | \headcommand {\beamer@subsectionpages {17}{17}} 38 | \headcommand {\slideentry {3}{0}{2}{18/18}{}{0}} 39 | \headcommand {\beamer@framepages {18}{18}} 40 | \headcommand {\slideentry {3}{0}{3}{19/21}{}{0}} 41 | \headcommand {\beamer@framepages {19}{21}} 42 | \headcommand {\slideentry {3}{0}{4}{22/24}{}{0}} 43 | \headcommand {\beamer@framepages {22}{24}} 44 | \headcommand {\slideentry {3}{0}{5}{25/27}{}{0}} 45 | \headcommand {\beamer@framepages {25}{27}} 46 | \headcommand {\slideentry {3}{0}{6}{28/31}{}{0}} 47 | \headcommand {\beamer@framepages {28}{31}} 48 | \headcommand {\slideentry {3}{0}{7}{32/35}{}{0}} 49 | \headcommand {\beamer@framepages {32}{35}} 50 | \headcommand {\slideentry {3}{0}{8}{36/36}{}{0}} 51 | \headcommand {\beamer@framepages {36}{36}} 52 | \headcommand {\sectionentry {4}{Some final remarks}{37}{Some final remarks}{0}} 53 | \headcommand {\beamer@sectionpages {18}{36}} 54 | \headcommand {\beamer@subsectionpages {18}{36}} 55 | \headcommand {\slideentry {4}{0}{9}{37/37}{}{0}} 56 | \headcommand {\beamer@framepages {37}{37}} 57 | \headcommand {\beamer@subsectionentry {0}{4}{1}{38}{Asking for help}}\headcommand {\beamer@subsectionpages {37}{37}} 58 | \headcommand {\slideentry {4}{1}{1}{38/38}{Asking for help}{0}} 59 | \headcommand {\beamer@framepages {38}{38}} 60 | \headcommand {\slideentry {4}{1}{2}{39/40}{Asking for help}{0}} 61 | \headcommand {\beamer@framepages {39}{40}} 62 | \headcommand {\beamer@subsectionentry {0}{4}{2}{41}{Useful references}}\headcommand {\beamer@subsectionpages {38}{40}} 63 | \headcommand {\slideentry {4}{2}{1}{41/41}{Useful references}{0}} 64 | \headcommand {\beamer@framepages {41}{41}} 65 | \headcommand {\slideentry {4}{2}{2}{42/42}{Useful references}{0}} 66 | \headcommand {\beamer@framepages {42}{42}} 67 | \headcommand {\slideentry {4}{2}{3}{43/45}{Useful references}{0}} 68 | \headcommand {\beamer@framepages {43}{45}} 69 | \headcommand {\slideentry {4}{2}{4}{46/46}{Useful references}{0}} 70 | \headcommand {\beamer@framepages {46}{46}} 71 | \headcommand {\beamer@partpages {1}{46}} 72 | \headcommand {\beamer@subsectionpages {41}{46}} 73 | \headcommand {\beamer@sectionpages {37}{46}} 74 | \headcommand {\beamer@documentpages {46}} 75 | \headcommand {\def \inserttotalframenumber {25}} 76 | -------------------------------------------------------------------------------- /01a-intro/01a-intro.out: -------------------------------------------------------------------------------- 1 | \BOOKMARK [2][]{Outline0.1}{Basics}{}% 1 2 | \BOOKMARK [3][]{Outline0.1.1.4}{The course and the lecturer}{Outline0.1}% 2 3 | \BOOKMARK [2][]{Outline0.2}{Aims of the course}{}% 3 4 | \BOOKMARK [3][]{Outline0.2.1.6}{Where does this course stand}{Outline0.2}% 4 5 | \BOOKMARK [3][]{Outline0.2.2.14}{A note on the language}{Outline0.2}% 5 6 | \BOOKMARK [3][]{Outline0.2.3.16}{Lectures and lab classes}{Outline0.2}% 6 7 | \BOOKMARK [3][]{Outline0.2.4.17}{Marking}{Outline0.2}% 7 8 | \BOOKMARK [2][]{Outline0.3}{How to tackle this course}{}% 8 9 | \BOOKMARK [2][]{Outline0.4}{Some final remarks}{}% 9 10 | \BOOKMARK [3][]{Outline0.4.1.38}{Asking for help}{Outline0.4}% 10 11 | \BOOKMARK [3][]{Outline0.4.2.41}{Useful references}{Outline0.4}% 11 12 | -------------------------------------------------------------------------------- /01a-intro/01a-intro.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/01a-intro/01a-intro.pdf -------------------------------------------------------------------------------- /01a-intro/01a-intro.snm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/01a-intro/01a-intro.snm -------------------------------------------------------------------------------- /01a-intro/01a-intro.tex: -------------------------------------------------------------------------------- 1 | \documentclass[xcolor=dvipsnames, 12pt]{beamer} 2 | 3 | \usepackage{appendixnumberbeamer} 4 | \usepackage{graphicx} 5 | %\usepackage{url} 6 | \usepackage[english]{babel} 7 | \usepackage[utf8]{inputenc} 8 | \usepackage[T1]{fontenc} 9 | \usepackage{marvosym} 10 | \usepackage{ulem} 11 | \usepackage{listings} 12 | \usepackage{units} 13 | 14 | \setbeamertemplate{navigation symbols}{} 15 | 16 | \mode 17 | { 18 | \usetheme{Madrid} 19 | \usefonttheme[onlylarge]{structuresmallcapsserif} 20 | \usefonttheme[onlysmall]{structurebold} 21 | \setbeamerfont{frametitle}{size=\large} 22 | \setbeamerfont{title}{size=\large} 23 | \setbeamerfont{section in toc}{size=\normalsize} 24 | \setbeamercovered{invisible} 25 | } 26 | 27 | \definecolor{UniManPurple}{rgb}{0.31,0.,0.49} 28 | \definecolor{UniManYellow}{rgb}{1.,0.85,0.} 29 | \usecolortheme[rgb={0.31,0.,0.49}]{structure} % UM colorf 30 | \newcommand{\MYTITLECOLOUR} {\textcolor[rgb]{1.,0.85,0.}} % UM yellow 31 | \newcommand{\PURPLE} {\textcolor[rgb]{0.31,0.,0.49}} % UM purple 32 | \newcommand{\BF}[1]{\begin{frame}{\MYTITLECOLOUR{#1}}} % UM yellow 33 | \definecolor{silver}{gray}{0.61} 34 | 35 | \lstset{ % 36 | captionpos=n, 37 | language=Python, 38 | basicstyle=\tt 39 | } 40 | 41 | \newenvironment{myFrame}[1]% 42 | {\begin{frame}{\MYTITLECOLOUR{#1}}}% 43 | {\end{frame}} 44 | 45 | \AtBeginSection[] 46 | { 47 | \begin{myFrame}{Outline} 48 | \tableofcontents[currentsection, currentsubsection, hideothersubsections] 49 | \end{myFrame} 50 | } 51 | 52 | % http://tex.stackexchange.com/questions/67064/a-thicker-wave-underline 53 | \catcode`\@=11 % 54 | \font\uwavefont=lasyb10 scaled 652 55 | \def\uwave{% 56 | \bgroup 57 | \markoverwith{% 58 | \lower3.5\p@\hbox{\uwavefont\char58}% 59 | }% 60 | \ULon 61 | } 62 | 63 | \begin{document} 64 | 65 | 66 | \hypersetup{ 67 | hidelinks=false, 68 | colorlinks=true, 69 | linkcolor=blue, 70 | urlcolor=blue, 71 | citecolor=blue, 72 | anchorcolor=blue 73 | } 74 | \makeatletter 75 | \Hy@colorlinkstrue 76 | \Hy@ocgcolorlinkstrue 77 | \Hy@frenchlinkstrue 78 | \def\Hy@colorlink#1{% 79 | \begingroup 80 | \HyColor@UseColor#1% 81 | }% 82 | \def\Hy@endcolorlink{\endgroup}% 83 | %\def\@pdfborder{0 0 0.5 [3 3]}% 84 | %\let\@pdfborderstyle S 85 | \makeatother 86 | 87 | 88 | 89 | %\title[\MYTITLECOLOUR{Programming}]{\MYTITLECOLOUR{Programming with Python}} 90 | \title{\MYTITLECOLOUR{Programming with Python}} 91 | 92 | \author[V. \v{S}ego]{ 93 | \textbf{\PURPLE{Vedran \v{S}ego}} {\tt <\href{mailto:vsego@vsego.org}{vsego@vsego.org}>} 94 | } 95 | \date{29.1.2015.} 96 | 97 | \titlegraphic{\includegraphics[width=2.7cm]{manchesterlogo}\hspace*{4.75cm}~% 98 | \includegraphics[height=1cm]{nalogo}} 99 | 100 | \begin{frame}[plain] 101 | %\titlepage 102 | \centering 103 | \setbeamercolor{block body}{bg=UniManPurple,fg=UniManYellow} 104 | \begin{block}{}\centering 105 | \vskip3mm 106 | \usebeamerfont{title}\inserttitle\par 107 | \vspace*{4mm} 108 | \end{block} 109 | \usebeamerfont{author}\insertauthor\par 110 | \usebeamerfont{institute}\insertinstitute\par 111 | \usebeamerfont{date}\insertdate\vskip-4mm 112 | \includegraphics[height=.6\textheight]{images/ForallyoucodersHarryspeakspython-32556.png}\par 113 | \usebeamercolor[fg]{titlegraphic}\inserttitlegraphic 114 | \end{frame} 115 | 116 | \begin{myFrame}{Outline} 117 | \tableofcontents[hideothersubsections] 118 | \end{myFrame} 119 | 120 | \section{Basics} 121 | 122 | \subsection{The course and the lecturer} 123 | 124 | \begin{myFrame}{Who? What? Where?} 125 | \vskip-2mm\hfill\includegraphics[height=29mm]{images/stamp.png}\vskip-19mm 126 | \begin{itemize} 127 | \item Name: Vedran \v{S}ego 128 | \item Office: 1.218 129 | \item E-mail: \href{mailto:vsego@vsego.org}{\texttt{vsego@vsego.org}} \par 130 | Please use: 131 | \begin{itemize} 132 | \item only \alert{plain text} (no HTML nor non-standard characters), 133 | \item \alert{clear, informative subjects}. 134 | \end{itemize} 135 | \item Office hours: Friday, 12:00--13:00 136 | \item The course website:\par 137 | \href{http://vsego.org/math20622}{http://vsego.org/math20622} or \href{http://vsego.org/math20622}{http://vsego.org/python} 138 | \end{itemize} 139 | \end{myFrame} 140 | 141 | 142 | 143 | \section{Aims of the course} 144 | 145 | \subsection{Where does this course stand} 146 | 147 | \begin{myFrame}{Where can I use any of this?} 148 | While we shall cover none of these topic, you should become able to ``dig out'' on your own how to tackle the problems in: 149 | \begin{enumerate} 150 | \item Matrix Analysis (MATH36001) -- SciPy and NumPy modules; 151 | \item Combinatorics and Graph Theory (MATH39001) -- modules {\tt math}, {\tt itertools}, {\tt combinatorics}, {\tt pyncomb}, {\tt qombinatorics}, {\tt networkx}, built-in lists and dictionaries (see \href{http://www.python-course.eu/graphs_python.php}{here}); 152 | \item Mathematical Biology (MATH35032) -- {\tt SciPy} module for ODEs, {\tt PyMOOSE} module, built-in lists and dictionaries; 153 | \item Problem Solving by Computer (MATH36032) -- Python and MATLAB are quite similar (and somewhat a competition); 154 | \item Mathematical Programming (MATH39012) -- modules {\tt PyLPSolve}, {\tt CVXOpt}, {\tt PyGLPK}, {\tt PyMathProg}. 155 | \end{enumerate} 156 | And these are just some of the $3^\text{rd}$ year undergraduate courses. 157 | \end{myFrame} 158 | 159 | \begin{myFrame}{In this course\dots} 160 | \dots{}we aim to learn how to: 161 | \begin{enumerate} 162 | \item analyze a problem, 163 | \item construct an algorithm that solves it, 164 | \item write a program that implements the said algorithm. 165 | \end{enumerate}\vskip2ex 166 | \onslide<2-> 167 | Be careful! 168 | \begin{itemize} 169 | \item Where do I expect ``\alert{trouble}''? \par 170 | Point 2: the so called {\itshape algorithmic way of thinking}. \par 171 | \onslide<3-> 172 | \item Why? \par 173 | This is \alert{fundamentally new} to those with no experience with programming. 174 | \end{itemize}\vskip2ex 175 | \onslide<4->{ 176 | {\bfseries Our language of choice:} Python 3 {\small (with some effort, fairly simple!)} 177 | } 178 | \end{myFrame} 179 | 180 | \begin{myFrame}{However,\dots} 181 | \dots{}we do \alert{{\bfseries not} aim} to: 182 | \begin{itemize} 183 | \item make you into World class programmers (this would take at least a whole programme and does not fit in a single course), 184 | \item address all the features and the libraries of Python (this would take even longer), 185 | \item learn ``dark'' tricks that almost all languages have. 186 | \end{itemize}\vskip3ex 187 | \onslide<2-> 188 | \alert{\bfseries Our aim} is ``only'' to lay a strong foundation for your future programming requirements, be they in Python or some other language or a similar tool.\vskip3ex 189 | \onslide<3-> 190 | Don't worry, this is \alert{not as easy as it sounds}. \Smiley{} 191 | \end{myFrame} 192 | 193 | \subsection{A note on the language} 194 | 195 | \begin{myFrame}{Father and son} 196 | Python currently has two branches: 197 | \begin{itemize} 198 | \item Python 2: old(-ish), well established, widely used; 199 | \item Python 3 (\alert{our choice}): newer, better designed, also widely used, gaining acceptance, some modules are not converted (yet), but almost all widely used either are converted or will soon be. 200 | \end{itemize}\vskip2ex 201 | The two are very similar, but there are some significant differences! \par 202 | \hskip7mm $\Rightarrow$ Some of these will be addressed as necessary. \vskip2ex 203 | \onslide<2-> 204 | Our focus is on \alert{algorithms}, not on the programming language! \par 205 | \hskip7mm $\Rightarrow$ Python specifics will be avoided as much as possible. \par 206 | \hskip7mm \phantom{$\Rightarrow$} {\small (but they will be shown for those interested in Python itself)} 207 | \end{myFrame} 208 | 209 | \subsection{Lectures and lab classes} 210 | 211 | \begin{myFrame}{Lectures and lab classes} 212 | \begin{itemize} 213 | \item Week 1: 214 | \begin{itemize} 215 | \item This lecture: about the course. 216 | \item Lab class (tomorrow): the first lecture. 217 | \end{itemize} 218 | \item From the second week on: 219 | \begin{itemize} 220 | \item Lectures: covering the new material. 221 | \item Lab class: students solve problems on computers. 222 | \end{itemize} 223 | \end{itemize} 224 | \end{myFrame} 225 | 226 | \subsection{Marking} 227 | 228 | \begin{myFrame}{Marking} 229 | \begin{itemize} 230 | \item Six one-hour tests during the lab classes (30\%): 231 | \begin{itemize} 232 | \item The \alert{best five} will be taken into account. 233 | \item The first one is in week 3. 234 | \item Two problems on each; 3 points per problem. 235 | \item Small(-ish) programs done on computers. 236 | \item Covering the material up to the previous week. 237 | \end{itemize} 238 | \item Coursework at the end of semester (70\%): 239 | \begin{itemize} 240 | \item A project to program at home. 241 | \end{itemize} 242 | \end{itemize} 243 | \end{myFrame} 244 | 245 | 246 | 247 | \section{How to tackle this course} 248 | 249 | \begin{myFrame}{How to tackle this course?} 250 | \begin{center} 251 | {\itshape Programming is a skill. It cannot be learnt; it has to be crafted.}\par 252 | \hfill --- prof.\ Saša Singer, University of Zagreb 253 | \end{center} 254 | \onslide<2-> 255 | This means: 256 | \begin{itemize} 257 | \item Traditional ``learning by reading'' is of \alert{little use}. 258 | \item Trial-and-error \alert{on a computer} is the only way to learn! 259 | \item Programming cannot be learnt the night (or even a day or two) before the exam! 260 | \end{itemize} 261 | \onslide<3-> 262 | Why? 263 | \begin{itemize} 264 | \item Remember the ``fundamentally different algorithmic way of thinking'' from a few slides before? 265 | \item Too many details to consider -- \alert{\bfseries experience is crucial!} \par 266 | (and you're here to get some of it) 267 | \end{itemize} 268 | \vskip2ex 269 | \end{myFrame} 270 | 271 | \begin{frame}[fragile]{\MYTITLECOLOUR{How to actually do this? (1)}} 272 | \begin{itemize} 273 | \item \alert{Copy/paste} (from the ready made examples and solutions) \alert{is {\bfseries not} your friend!} If you must use such a solution, \alert{retype} it, so you notice the important details! \par 274 | \onslide<2-> 275 | For example, these four are \alert{different types} of data, mostly with \alert{very different properties}:\vskip-2mm 276 | {\small \begin{lstlisting} 277 | f = ( "x", 17, "y", 19, "z", 23 ) 278 | b = [ "x", 17, "y", 19, "z", 23 ] 279 | r = { "x", 17, "y", 19, "z", 23 } 280 | j = { "x": 17, "y": 19, "z": 23 } 281 | \end{lstlisting}} 282 | Will you notice and remember the type of brackets or which of the comma/colon was used if you just copy/paste a program with only \alert{one} of these? \par 283 | \onslide<3-> 284 | How about the difference between these two?\vskip-2mm 285 | {\small \begin{lstlisting} 286 | f = h 287 | g = h(x) 288 | \end{lstlisting}} 289 | \end{itemize} 290 | \end{frame} 291 | 292 | \begin{myFrame}{How to actually do this? (2)} 293 | \begin{itemize} 294 | \item Using a solution from a lecture or some other source is fine a \alert{first few times} when you encounter a new subject, but even then do \alert{\bfseries NOT} just retype.\par 295 | Run the program and \alert{test it} (give it some input and check that the output is correct). \par 296 | \onslide<2-> 297 | Take a break from it and, some hours later, \alert{try to write your own solution} to the same problem, without looking at or trying to recall the ``official'' solution. 298 | \onslide<3-> 299 | \item \alert{\bfseries Do NOT learn chunks of code by heart!} \par 300 | These cannot be just ``reused''; \alert{they must be {\bfseries understood}!} \par 301 | Otherwise, you get a wrong impression of ``understanding'', which \alert{backfires} in exams and practical situations. 302 | \end{itemize} 303 | \end{myFrame} 304 | 305 | \begin{myFrame}{How to actually do this? (3)}{} 306 | {\large\bfseries Write programs on your own!} 307 | \onslide<2-> 308 | \begin{itemize} 309 | \item \alert{Read the errors and warnings} that Python writes out. \par 310 | These are crucial to understand what went wrong! 311 | \onslide<3-> 312 | \item As before, \alert{test your program!} Run it several times, give it some input, and \alert{check the results}! \par 313 | % An example: where does a plane go? To Birmingham... UK or Alabama? 314 | If they are wrong, read your code and try to figure which part(s) produce a result different from what you expected. 315 | \onslide<4-> 316 | \item Test the \alert{boundary cases}! \par 317 | Does your expansion to prime factors work if the input itself is a prime number? What if it's a negative number? \par 318 | Does your algorithm work properly with the first/last member of the list, or only with the ones in the middle? How about an empty list? \par 319 | \dots 320 | \end{itemize} 321 | \end{myFrame} 322 | 323 | \begin{myFrame}{How to actually do this? (4)}{} 324 | What if it doesn't work out? 325 | \onslide<2-> 326 | \begin{enumerate} 327 | \setcounter{enumi}{-1} 328 | \item Try until you run out of ideas. 329 | \item If you cannot make the program work as it should, read the solution and \alert{analyze it}. Try to figure out how it works, how it was constructed, and why your own didn't work. 330 | \item Then return to it later and try to solve the problem without using the solution (reading Python documentation is always fine). 331 | \item If that fails, go back to step 1. 332 | \item If you have to do this for (almost) all problems, seek help with the staff. \alert{Do not wait for the exams} to address the issue! \par 333 | \alert{This process takes time and effort!} 334 | \end{enumerate} 335 | \onslide<3->{ 336 | {\bfseries Remember:} Your solution need not be the same as the ``official'' one, but it has to produce the correct results. 337 | 338 | (Almost) all problems have many (more or less different) solutions.\vskip1ex 339 | } 340 | \onslide<4-> 341 | By the way, the above is an example of an algorithm. \Smiley{} 342 | \end{myFrame} 343 | 344 | \begin{myFrame}{How to actually do this? ($9\,\unitfrac{3}{4}$)} 345 | \begin{center} 346 | How you approach these classes might also have a wee bit of an impact on the whole "crafting your programming skills" process... \Smiley{} \vskip.7ex 347 | \includegraphics[width=.87\paperwidth]{images/concentration-levels.png} \vskip-.7ex 348 | {\tiny [\href{http://kindofnormal.com/truthfacts/2015/01/27}{Image source}]} 349 | \end{center} 350 | \end{myFrame} 351 | 352 | 353 | 354 | \section{Some final remarks} 355 | 356 | \subsection{Asking for help} 357 | 358 | \begin{myFrame}{Asking for help (1)} 359 | If you encounter a problem, address it immediately -- \alert{most of the lectures rely on the \uwave{understanding} of the previous ones!} \par 360 | \begin{columns}[T] 361 | \begin{column}{0.96\textwidth} 362 | You can ask: 363 | \begin{itemize} 364 | \item teaching assistants, 365 | \item me, 366 | \item your colleagues (be careful, though), 367 | \item on-line. \par 368 | I suggest \href{http://stackoverflow.com/}{Stack Overflow}. Before asking a question there, \alert{read their instructions!} The community is very helpful, but they require effort and will not just solve your problems for you. 369 | \end{itemize} 370 | \end{column} 371 | \begin{column}{0pt} 372 | \vspace*{2mm}\hskip-19mm\includegraphics[width=19mm]{images/keep-calm-and-ask-for-help.png} 373 | \end{column} 374 | \end{columns} 375 | \end{myFrame} 376 | 377 | \begin{myFrame}{Asking for help (2)} 378 | At a more advanced level: 379 | \begin{itemize} 380 | \item \href{http://codereview.stackexchange.com/}{Code Review Stack Exchange} -- get expert opinion and advice on your \alert{properly working} code; 381 | \item \href{http://programmers.stackexchange.com/}{Programmers Stack Exchange} -- for conceptual questions about software development. 382 | \end{itemize} 383 | As before, \alert{read their instructions before asking a question!}\vskip2ex 384 | \onslide<2->{ 385 | {\bfseries Hint:} There is also \href{http://math.stackexchange.com/}{Mathematics Stack Exchange}\dots 386 | } 387 | \end{myFrame} 388 | 389 | \subsection{Useful references} 390 | 391 | \begin{frame}[fragile]{\MYTITLECOLOUR{References (1)}} 392 | Some useful references: 393 | \begin{itemize} 394 | \item For most of the questions, it is enough to Google \par 395 | {\tt python3 whatever you want to know} 396 | \item The official \href{https://docs.python.org/}{Python 3 documentation} (there is also a \href{https://docs.python.org/2.7/}{Python 2 documentation}, if you ever need it), 397 | \item Built-in help, invoked from Python itself: 398 | \begin{lstlisting} 399 | help(print) 400 | \end{lstlisting} 401 | or 402 | \begin{lstlisting} 403 | import numpy 404 | help(numpy) 405 | \end{lstlisting} 406 | \item Aforementioned Stack Exchange sites. 407 | \end{itemize} 408 | \end{frame} 409 | 410 | 411 | \begin{myFrame}{References (2)} 412 | \begin{center} 413 | \vskip-5mm\includegraphics[width=83mm]{images/syllabus.png} 414 | \end{center}\vskip-3mm 415 | For those preferring dead wood books, 416 | \begin{itemize} 417 | \item Mark Lutz, ``Learning Python''. (no, I am not Mark Lutz \Smiley{}) 418 | \end{itemize} 419 | For those already familiar with programming, just not in Python: 420 | \begin{itemize} 421 | \item Mark Pilgrim, ``\href{http://www.diveintopython3.net/}{Dive into Python 3}'' (freely downloadable HTML and PDF); you can also buy a dead wood version, or install it for free on Android devices. \par 422 | There is a \href{http://www.diveintopython.net/}{Python 2 version} as well. 423 | \end{itemize} 424 | \end{myFrame} 425 | 426 | \begin{frame}[fragile]{\MYTITLECOLOUR{Homework}} 427 | \begin{itemize} 428 | \item Install Python 3 (the instructions are on the course web site) on your home computer. 429 | \item Try running this program to verify that your Python installation works properly: 430 | \begin{lstlisting} 431 | import this 432 | \end{lstlisting} 433 | Yes, there is only one line and there are no interpunctions. \par 434 | It should print a poem ``The Zen of Python'', by Tim Peters. 435 | \onslide<2-> 436 | And yes, there is some weird humor in Python. After all, it was named after (somewhat famous) Monty Python. \par 437 | \onslide<3-> 438 | But don't worry, none of it affects ``real'' programming\dots 439 | \end{itemize} 440 | \end{frame} 441 | 442 | \begin{frame}[plain] 443 | \begin{center} 444 | {\large That's all for today (unless, of course, there are questions)}\vskip.17ex 445 | \includegraphics[height=.5\textheight]{not-even-once/not-even-once.png}\vskip.17ex 446 | {\bfseries\LARGE Thank you for your attention!} 447 | \end{center} 448 | \end{frame} 449 | 450 | 451 | 452 | \end{document} 453 | -------------------------------------------------------------------------------- /01a-intro/01a-intro.toc: -------------------------------------------------------------------------------- 1 | \beamer@endinputifotherversion {3.32pt} 2 | \select@language {english} 3 | \beamer@sectionintoc {1}{Basics}{3}{0}{1} 4 | \beamer@subsectionintoc {1}{1}{The course and the lecturer}{4}{0}{1} 5 | \beamer@sectionintoc {2}{Aims of the course}{5}{0}{2} 6 | \beamer@subsectionintoc {2}{1}{Where does this course stand}{6}{0}{2} 7 | \beamer@subsectionintoc {2}{2}{A note on the language}{14}{0}{2} 8 | \beamer@subsectionintoc {2}{3}{Lectures and lab classes}{16}{0}{2} 9 | \beamer@subsectionintoc {2}{4}{Marking}{17}{0}{2} 10 | \beamer@sectionintoc {3}{How to tackle this course}{18}{0}{3} 11 | \beamer@sectionintoc {4}{Some final remarks}{37}{0}{4} 12 | \beamer@subsectionintoc {4}{1}{Asking for help}{38}{0}{4} 13 | \beamer@subsectionintoc {4}{2}{Useful references}{41}{0}{4} 14 | -------------------------------------------------------------------------------- /01a-intro/01a-intro.vrb: -------------------------------------------------------------------------------- 1 | \frametitle{\MYTITLECOLOUR {Homework}} 2 | \begin{itemize} 3 | \item Install Python 3 (the instructions are on the course web site) on your home computer. 4 | \item Try running this program to verify that your Python installation works properly: 5 | \begin{lstlisting} 6 | import this 7 | \end{lstlisting} 8 | Yes, there is only one line and there are no interpunctions. \par 9 | It should print a poem ``The Zen of Python'', by Tim Peters. 10 | \onslide<2-> 11 | And yes, there is some weird humor in Python. After all, it was named after (somewhat famous) Monty Python. \par 12 | \onslide<3-> 13 | But don't worry, none of it affects ``real'' programming\dots 14 | \end{itemize} 15 | -------------------------------------------------------------------------------- /01a-intro/images/27.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/01a-intro/images/27.png -------------------------------------------------------------------------------- /01a-intro/images/Alan Turing One Stamp.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/01a-intro/images/Alan Turing One Stamp.jpg -------------------------------------------------------------------------------- /01a-intro/images/ForallyoucodersHarryspeakspython-32556.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/01a-intro/images/ForallyoucodersHarryspeakspython-32556.jpg -------------------------------------------------------------------------------- /01a-intro/images/ForallyoucodersHarryspeakspython-32556.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/01a-intro/images/ForallyoucodersHarryspeakspython-32556.png -------------------------------------------------------------------------------- /01a-intro/images/concentration-levels-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/01a-intro/images/concentration-levels-2.png -------------------------------------------------------------------------------- /01a-intro/images/concentration-levels.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/01a-intro/images/concentration-levels.png -------------------------------------------------------------------------------- /01a-intro/images/keep-calm-and-ask-for-help-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/01a-intro/images/keep-calm-and-ask-for-help-5.png -------------------------------------------------------------------------------- /01a-intro/images/keep-calm-and-ask-for-help.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/01a-intro/images/keep-calm-and-ask-for-help.png -------------------------------------------------------------------------------- /01a-intro/images/stamp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/01a-intro/images/stamp.png -------------------------------------------------------------------------------- /01a-intro/images/syllabus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/01a-intro/images/syllabus.png -------------------------------------------------------------------------------- /01a-intro/manchesterlogo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/01a-intro/manchesterlogo.jpg -------------------------------------------------------------------------------- /01a-intro/nalogo.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/01a-intro/nalogo.pdf -------------------------------------------------------------------------------- /01a-intro/not-even-once/matplotlib-sphinxext-ipython_console_highlighting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/01a-intro/not-even-once/matplotlib-sphinxext-ipython_console_highlighting.png -------------------------------------------------------------------------------- /01a-intro/not-even-once/not-even-once.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/01a-intro/not-even-once/not-even-once.png -------------------------------------------------------------------------------- /01a-intro/not-even-once/not-even-once.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/01a-intro/not-even-once/not-even-once.xcf -------------------------------------------------------------------------------- /02b-exercises.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Programming with Python\n", 8 | "#### Vedran Šego, [vsego.org](http://vsego.org/)\n", 9 | "\n", 10 | "## Exercises: Loops and Conditionals\n", 11 | "\n", 12 | "Here are some problems to be solved as an exercise. While you are welcome to use anything that comes in standard Python distributions, you are also strongly encouraged to use only what we have learned so far. Overcomplicating can often lead to errors or too slow programs.\n", 13 | "\n", 14 | "In this problem sheet we provide some test data for you to test your programs with. In future, these will not be provided. You should always analize the problems at hand and find some data for testing. A few random inputs are always a good choice, as well as those from the boundary cases (highly dependent on the problem itself).\n", 15 | "\n", 16 | "Some creative thinking and/or Googling might be required to solve some of these problems. However, none of them require knowlege of any material beyond what we have already covered. Ask for help if you fail to solve them on your own!" 17 | ] 18 | }, 19 | { 20 | "cell_type": "markdown", 21 | "metadata": {}, 22 | "source": [ 23 | "## Notes for the problems below\n", 24 | "\n", 25 | "\"Odd/even digits\" are determined by their value, not their position. For example, the odd digits of number $8417$ are $1$ and $7$, and the desired sum is $1+7 = 8$. The same goes for the even digits.\n", 26 | "\n", 27 | "Be careful with the digits. If a number can be negative, you need to lose the sign. Otherwise, you will get wrong results. For example, `-17 % 10 == 3` while `17 % 3 == 7`." 28 | ] 29 | }, 30 | { 31 | "cell_type": "markdown", 32 | "metadata": {}, 33 | "source": [ 34 | "## Problems" 35 | ] 36 | }, 37 | { 38 | "cell_type": "markdown", 39 | "metadata": {}, 40 | "source": [ 41 | "**Problem 1.** Write a program that loads one integer and prints the sum of its odd digits. \n", 42 | "The output has to be in the form\n", 43 | "\n", 44 | "> The sum of the odd digits in number $n$ is $d$.\n", 45 | "\n", 46 | "**Test data:**\n", 47 | "\n", 48 | "* Input: $-131723$\n", 49 | "* Output: `The sum of the odd digits in number -131723 is 15.` \n", 50 | " ($1+3+1+7+3 = 15$)" 51 | ] 52 | }, 53 | { 54 | "cell_type": "markdown", 55 | "metadata": {}, 56 | "source": [ 57 | "**Problem 2.** Write a program that loads integers until a zero is loaded and then prints the maximum among them and which one was it (not taking the zero into the account). If there is more than one maximum, use the first one among them as a solution.\n", 58 | "\n", 59 | "**Test data:**\n", 60 | "\n", 61 | "* Input: $-19, -17, -23, -17, 0$\n", 62 | "* Output: `The maximum number is #2 and its value is -17.`\n", 63 | "\n", 64 | "Be careful about the case when only a zero is loaded.\n", 65 | "\n", 66 | "\n", 67 | "\n", 68 | "**Problem 2a.** Do the same, but in case that there is more than one maximum, use the **last** one among them.\n", 69 | "\n", 70 | "**Hint:** Observe the \"`<`\" (or \"`>`\") sign that you have used in Problem 2. All you need to do in this problem is change it a bit.\n", 71 | "\n", 72 | "**Test data:**\n", 73 | "\n", 74 | "* Input: $-19, -17, -23, -17, 0$\n", 75 | "* Output: `The maximum number is #4 and its value is -17.`\n", 76 | "\n", 77 | "Be careful about the case when only a zero is loaded." 78 | ] 79 | }, 80 | { 81 | "cell_type": "markdown", 82 | "metadata": {}, 83 | "source": [ 84 | "**Problem 3.** Write a program that loads a natural number (a non-negative integer) `n` and then loads `n` integers. The program has to print the sum of the maximum digits of all the loaded numbers. If a number has multiple maximum digits, they are still taken into the sum only once ($1777$ only adds $7$ to the sum, not $7+7+7$).\n", 85 | "\n", 86 | "**Test data:**\n", 87 | "\n", 88 | "* Input: $3, -1719, 1777, 111$ ($3$ means that we're loading $3$ numbers)\n", 89 | "* Output: `17` \n", 90 | " ($9+7+1 = 17$)" 91 | ] 92 | }, 93 | { 94 | "cell_type": "markdown", 95 | "metadata": {}, 96 | "source": [ 97 | "**Problem 4.** Solve the previous problem by taking multiple maximum digits into account as many times as they appear ($1777$ adds $21 = 7+7+7$ to the sum).\n", 98 | "\n", 99 | "**Hints**:\n", 100 | "\n", 101 | "* Distinguish the cases `d > md`, `d == md` and `d < md` (where `d` is the currently observed digit and `md` is currently the biggest one). In one case, increase a counter which will be used to keep track of how many times has this maximum appeared in the number; in another case, reset that counter and save the new maximum (in the third case, nothing is done with these two). Once you're done with a number, you should know the value of its largest digit, as well as the number of times it appeared in that number. \n", 102 | " Be careful with where in the code you are reseting both the maximum digit (this hint also applies to Problem 3) and the counter of that digit's occurences in the number.\n", 103 | " \n", 104 | "* Alternatively, you can first find the maxinum digit `md` and then go again through the number and count all digits equal to `md`.\n", 105 | "\n", 106 | "**Test data:**\n", 107 | "\n", 108 | "* Input: $3, -1719, 1777, 111$\n", 109 | "* Output: `33` \n", 110 | " ($1 \\cdot 9 + 3 \\cdot 7 + 3 \\cdot 1 = 33$)" 111 | ] 112 | }, 113 | { 114 | "cell_type": "markdown", 115 | "metadata": {}, 116 | "source": [ 117 | "**Problem 5.** Write a program that inputs integers until it gets a zero and prints the one with the maximum sum of its odd digits. If there is more than one such number, print the first one.\n", 118 | "\n", 119 | "**Explanation:**\n", 120 | "\n", 121 | "Read the problem text carefuly, because it may be a bit confusing.\n", 122 | "\n", 123 | "What we want is to load some numbers, then:\n", 124 | "\n", 125 | "1. For **each** of those numbers compute the sum of its odd digits.\n", 126 | "\n", 127 | "2. Find maximum **among these sums** and print the corresponding **number**. \n", 128 | " Be careful **not** to print that sum nor the absolute value of a number, instead of a number itself.\n", 129 | "\n", 130 | "Rewriting the problem in steps like these above can help you focus on parts of a problem in order to solve it properly.\n", 131 | "\n", 132 | "**Hints:**\n", 133 | "\n", 134 | "* Remember that the algorithm from the lectures removes digits from a number, so using that number as a terminating condition of the loop has to be done carefully. One way to do so is with the auxiliary variable (`tmp` in the code in the lectures), but - given the nature of the problem - this might be more convenient\n", 135 | "```python\n", 136 | " n = input(\"The first number: \")\n", 137 | " while n != 0:\n", 138 | " # do what needs to be done #\n", 139 | " n = input(\"The next number: \")\n", 140 | "```\n", 141 | " If you are familiar with `break` (which the lectures will cover later), you might want to use it for a cleaner solution.\n", 142 | "\n", 143 | "* You will need a variable to store the maximum and the sum. Be careful where you initialize these!\n", 144 | "\n", 145 | "* The desired output is a number, not its sum of odd digits! When finding a new maximum, you will need to rember both the number (for the output) and the sum of its odd digits (for future comparisons).\n", 146 | "\n", 147 | "**Test data:**\n", 148 | "\n", 149 | "* Input: $13$, $-17$, $888$, $616$, $0$\n", 150 | "* Output: $-17$ \n", 151 | " (the required sums are: $4$, $8$, $0$, $1$, so $17$ has the biggest sum of odd digits)" 152 | ] 153 | } 154 | ], 155 | "metadata": {}, 156 | "nbformat": 4, 157 | "nbformat_minor": 0 158 | } 159 | -------------------------------------------------------------------------------- /02c-loops_conditionals.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "slideshow": { 7 | "slide_type": "slide" 8 | } 9 | }, 10 | "source": [ 11 | "# Programming with Python (lab classes)\n", 12 | "#### Vedran Šego, [vsego.org](http://vsego.org/)\n", 13 | "\n", 14 | "## Content:\n", 15 | "\n", 16 | "1. Loops and conditionals" 17 | ] 18 | }, 19 | { 20 | "cell_type": "markdown", 21 | "metadata": { 22 | "slideshow": { 23 | "slide_type": "slide" 24 | } 25 | }, 26 | "source": [ 27 | "**Problem 1.** Write a program that loads one integer $n$, a digit $d$, and two nonnegative integers $a$ and $b$ such that $a > b$ (verify that the input satisfies these conditions) and prints the largest integer $x$ such that:\n", 28 | "\n", 29 | "1. $0 \\le x \\le n$,\n", 30 | "\n", 31 | "2. $x$ is a perfect square of some integer (i.e., there exists $y \\in \\mathbb{Z}$ such that $x = y^2$),\n", 32 | "\n", 33 | "3. the last digit of $x$ is $d$,\n", 34 | "\n", 35 | "4. the remainder of the division of $x$ by $a$ is equal to $b$.\n", 36 | "\n", 37 | "If there is no such number, the program has to print an appropriate message." 38 | ] 39 | }, 40 | { 41 | "cell_type": "markdown", 42 | "metadata": {}, 43 | "source": [ 44 | "**Hints:**\n", 45 | "\n", 46 | "1. Verifying the input means checking that $0 \\le d \\le 9$ and that $a > b \\ge 0$. There is no need to check that any of the loaded numbers are integers, as this will be handled by the `int` funtion that crashes the program if something other than integer is given (which can be handled, but we'll get to that later on).\n", 47 | "\n", 48 | "2. Checking that a certain number is a perfect square is not very hard, but there can be far too many candidates. For example, if $n = 1024 = 32^2$, there are only $33$ perfect squares in the set $\\{0, 1, \\dots, n\\}$, but we would have to check all $1025$ nonnegative integers smaller than or equal to $n$. \n", 49 | " A better approach is to have a loop go through the values of $y$ (from zero to $\\lfloor \\sqrt{n} \\rfloor$), compute $x = y^2$, and then check the conditions 3 and 4." 50 | ] 51 | }, 52 | { 53 | "cell_type": "markdown", 54 | "metadata": {}, 55 | "source": [ 56 | "**Some running examples**\n", 57 | "\n", 58 | "Input \\#1:\n", 59 | "\n", 60 | " n = 73\n", 61 | " d = 9\n", 62 | " a = 3\n", 63 | " b = 1\n", 64 | " The desired number: 49\n", 65 | "\n", 66 | "Input \\#2:\n", 67 | "\n", 68 | " n = 200\n", 69 | " d = 9\n", 70 | " a = 3\n", 71 | " b = 1\n", 72 | " The desired number: 169\n", 73 | "\n", 74 | "Input \\#3:\n", 75 | "\n", 76 | " n = 47\n", 77 | " d = 9\n", 78 | " a = 3\n", 79 | " b = 1\n", 80 | " No such number exists!" 81 | ] 82 | }, 83 | { 84 | "cell_type": "markdown", 85 | "metadata": { 86 | "slideshow": { 87 | "slide_type": "slide" 88 | } 89 | }, 90 | "source": [ 91 | "**Problem 2.** Using the idea from the second hint for the previous problem, write a program that loads an integer $n$ and prints how many integers $x$ there are such that\n", 92 | "\n", 93 | "* $x$ is a perfect square,\n", 94 | "\n", 95 | "* $1 < x \\le n$,\n", 96 | "\n", 97 | "* $n$ is divisible by $x$." 98 | ] 99 | }, 100 | { 101 | "cell_type": "markdown", 102 | "metadata": { 103 | "slideshow": { 104 | "slide_type": "slide" 105 | } 106 | }, 107 | "source": [ 108 | "**Problem 3.** Write a program that loads a natural number $n$ and prints in how many ways can $n$ be written as a sum of consecutive natural numbers (including the one-element sum of $n$ alone).\n", 109 | "\n", 110 | "For example, $15$ can be written as $15$, $7+8$, $4+5+6$, or $1+2+3+4+5$, so the program should print `4`." 111 | ] 112 | }, 113 | { 114 | "cell_type": "markdown", 115 | "metadata": {}, 116 | "source": [ 117 | "**Hint:** You may use the formula for the sum of the first $n$ natural numbers:\n", 118 | "\n", 119 | "$$1 + 2 + 3 + \\cdots + n = \\frac{n}{2}(n+1).$$" 120 | ] 121 | }, 122 | { 123 | "cell_type": "markdown", 124 | "metadata": {}, 125 | "source": [ 126 | "**Problem 4.** Write a program that loads two integers and computes their greatest common divisors using the [Euclid's algorithm](http://en.wikipedia.org/wiki/Euclidean_algorithm) (for example, the one from [MATH10101](http://www.maths.manchester.ac.uk/~mdc/MATH10101.htm#LectureNotes)) and prints it." 127 | ] 128 | }, 129 | { 130 | "cell_type": "markdown", 131 | "metadata": {}, 132 | "source": [ 133 | "**Problem 5.** Write a program that loads two integers and computes their [lowest common multiplier](http://en.wikipedia.org/wiki/Least_common_multiple)." 134 | ] 135 | }, 136 | { 137 | "cell_type": "markdown", 138 | "metadata": {}, 139 | "source": [ 140 | "**Hint:** The simplest approach comes from the formula:\n", 141 | "$$\\operatorname{lcm}(m, n) \\operatorname{gcd}(m,n) = |mn|.$$\n", 142 | "Using this is generally not advisable, as $mn$ can be too big for most of the programming languages (while $\\operatorname{lcm}(m, n)$ is still small enough), but Python doesn't impose a limit on the size of integers, so you can use this here.\n", 143 | "\n", 144 | "However, do try to avoid computing anything that is bigger than $\\operatorname{lcm}(m,n)$ (a hint within a hint: commutativity).\n", 145 | "\n", 146 | "There are, of course, other ways of doing this. Some of these shall be addressed later, when we deal with prime numbers." 147 | ] 148 | }, 149 | { 150 | "cell_type": "markdown", 151 | "metadata": {}, 152 | "source": [ 153 | "**Problem 6.** Write a program that loads a natural number and checks if it is a [palindrome](http://en.wikipedia.org/wiki/Palindrome)." 154 | ] 155 | }, 156 | { 157 | "cell_type": "markdown", 158 | "metadata": {}, 159 | "source": [ 160 | "**Hint:** How would you reverse the order of the digits in a number?" 161 | ] 162 | }, 163 | { 164 | "cell_type": "markdown", 165 | "metadata": {}, 166 | "source": [ 167 | "**Problem 7.** Write a program that loads a natural number and checks if its digits come in\n", 168 | "\n", 169 | "1. a descending order (for example: $731$, but not $331$ or $713$)?\n", 170 | "\n", 171 | "2. a non-increasing order (for example: $731$ or $331$, but not $713$)?" 172 | ] 173 | }, 174 | { 175 | "cell_type": "markdown", 176 | "metadata": {}, 177 | "source": [ 178 | "**Hint:** We know how to read a number digit by digit. So, if we save the previous digit when getting the next one, we shall have both and we'll be able to compare them." 179 | ] 180 | }, 181 | { 182 | "cell_type": "markdown", 183 | "metadata": {}, 184 | "source": [ 185 | "**Problem 8.** Write a program that loads an integer and prints its\n", 186 | "\n", 187 | "1. second digit from the left,\n", 188 | "\n", 189 | "2. third digit from the right.\n", 190 | "\n", 191 | "If the number doesn't have two digits, then its second digit from the left doesn't exist and the program should print an informative message instead of that nonexistent digit. On the other hand, if the number has less than tree digits, its third digit from the right is zero." 192 | ] 193 | }, 194 | { 195 | "cell_type": "markdown", 196 | "metadata": {}, 197 | "source": [ 198 | "**Problem 9.** Write a program that loads a natural number $n$ and prints Fibonacci numbers $F_0, F_1, \\dots, F_n$, defined by\n", 199 | "$$F_0 = 0, \\quad F_1 = 1, \\quad F_{k+2} = F_{k+1} + F_{k}, \\quad k \\in \\mathbb{N}_0.$$" 200 | ] 201 | } 202 | ], 203 | "metadata": {}, 204 | "nbformat": 4, 205 | "nbformat_minor": 0 206 | } 207 | -------------------------------------------------------------------------------- /03b-exercises.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Programming with Python\n", 8 | "#### Vedran Šego, [vsego.org](http://vsego.org/)\n", 9 | "\n", 10 | "## Exercises: Functions\n", 11 | "\n", 12 | "When asked to write a function as a part of a problem, also write a program that lets us test that function. This program should get whatever input is meaningful for testing this function, call it with these arguments, and print (in some form) what it returned." 13 | ] 14 | }, 15 | { 16 | "cell_type": "markdown", 17 | "metadata": {}, 18 | "source": [ 19 | "**Problem 1.** Write a function `max_digit(n, d, r)` that works like `digit_sum` from the lectures but, instead of returning the sum of the digits of `n`, returns the maximum digit of `n` that gives the reminder `r` when divided by `d`. Assign the appropriate default values for any of the parameters for which it makes sense to do so.\n", 20 | "\n", 21 | "Notice that this maximum is undefined for some numbers. Situations like this are usually handled with exceptions, which will be covered later in this course. For now, detect the problematic case(s) and return an invalid value `-1`.\n", 22 | "\n", 23 | "Do not forget to write a program that tests this function, i.e., that loads numbers `n`, `d`, and `r`, and prints maximum digit of `n` that gives the reminder `r` when divided by `d`. If such a digit doesn't exist, the program has to print an appropriate message (instead of printing `-1`)." 24 | ] 25 | }, 26 | { 27 | "cell_type": "markdown", 28 | "metadata": {}, 29 | "source": [ 30 | "**Problem 2.** Write a function `binom(n, k)` that returns the [binomial coefficient](http://en.wikipedia.org/wiki/Binomial_coefficient)\n", 31 | "$$\\binom{n}{k} := \\frac{n!}{k!(n-k)!}$$\n", 32 | "for given natural numbers `n` and `k`. Return zero when $n < 0$ or $k < 0$.\n", 33 | "\n", 34 | "Be careful to compute and return an integer (not a floating point number).\n", 35 | "\n", 36 | "Also, write `binomf(n, k)` which does the same thing using the floating point arithmetics (but otherwise exactly the same algorithm).\n", 37 | "\n", 38 | "Write a program that will load `n` and `k`, and print `binom(n, k)`, `binomf(n, k)`, and the difference of these two values. See what happens for fairly large inputs (for example, `(n, k) = (100, 50)`).\n", 39 | "\n", 40 | "If you want to make a more general function that will work correctly for all real values of $n$, you can check your results at [Wolfram|Alpha](http://www.wolframalpha.com/), for example like [this](http://www.wolframalpha.com/input/?i=binomial%28100%2C50%29)." 41 | ] 42 | }, 43 | { 44 | "cell_type": "markdown", 45 | "metadata": {}, 46 | "source": [ 47 | "**Problem 3.** Write a function `prime(n)` that returns `True` if `n` is a [prime number](http://en.wikipedia.org/wiki/Prime_number) and `False` otherwise. You may use the definition as a criterion:\n", 48 | "\n", 49 | "> A number $n$ is prime if it is a natural number with exactly two distinct divisors. \n", 50 | "> Equivalently, $n$ is prime if $n > 1$ and is not divisible by any integer strictly between 1 and `n`.\n", 51 | "\n", 52 | "We shall look at a more efficient algorithm in one of the future lectures.\n", 53 | "\n", 54 | "Write a program that loads integers until it gets a negative number of a zero. Using the function `prime(n)`, the program should print the product of all the loaded prime numbers. If no primes were loaded, the program should instead write an appropriate descriptive message." 55 | ] 56 | }, 57 | { 58 | "cell_type": "markdown", 59 | "metadata": {}, 60 | "source": [ 61 | "**Problem 4.** We say that a number $n$ is *rich* if its absolute value is smaller than the sum of all its divisors except itself. For example, $12 < 1+2+3+4+6 = 16$ is considered rich, while $16 > 1+2+4+8 = 15$ is not.\n", 62 | "\n", 63 | "Write a function `rich(n)` that returns `True` if `n` is rich and `False` otherwise.\n", 64 | "\n", 65 | "Further, write a program that loads a number $k \\in \\mathbb{N}$ and prints all the rich numbers between $1$ and $k$ (inclusive).\n", 66 | "\n", 67 | "For example, the rich numbers smaller than $50$ are: $12, 18, 20, 24, 30, 36, 40, 42, 48$." 68 | ] 69 | }, 70 | { 71 | "cell_type": "markdown", 72 | "metadata": {}, 73 | "source": [ 74 | "## Recursive functions\n", 75 | "\n", 76 | "The next two problems go beyond the scope of the course. However, they may be useful, especially to those students interested in combinatorics, so they are here for those who want to try them.\n", 77 | "\n", 78 | "**These two will not be part of any exams!**" 79 | ] 80 | }, 81 | { 82 | "cell_type": "markdown", 83 | "metadata": {}, 84 | "source": [ 85 | "**Problem 5.** Write a function `f` that takes an integer parameter `x` and returns the value\n", 86 | "$$f(x) = \\begin{cases}\n", 87 | " f(17 - |x|), & x < 2, \\\\\n", 88 | " f(d), & \\text{$x$ is a composite number and $d$ is its largest divisor such that $d < x$}, \\\\\n", 89 | " x, & \\text{otherwise}.\n", 90 | "\\end{cases}$$\n", 91 | "We say that $x$ is a composite number if $x > 1$ and $x$ is not a prime.\n", 92 | "\n", 93 | "Write a program that loads `x` until it loads `x = 0` and writes the value `f(x)` for each of the loaded numbers." 94 | ] 95 | }, 96 | { 97 | "cell_type": "markdown", 98 | "metadata": {}, 99 | "source": [ 100 | "**Problem 6.** Write a function `f` that takes an integer parameter `x` and returns the value\n", 101 | "$$f(x) = \\begin{cases}\n", 102 | " x^2, & x < 9, \\\\\n", 103 | " f(g(x)), & \\text{$x \\ge 9$ is even}, \\\\\n", 104 | " f(h(x+1)), & \\text{otherwise},\n", 105 | "\\end{cases}$$\n", 106 | "where $g(x) = \\left\\lceil \\frac{x}{2} \\right\\rceil$ is the [ceiling](http://en.wikipedia.org/wiki/Floor_and_ceiling_functions) of $\\frac{x}{2}$ and $h(x) = \\left\\lfloor \\frac{x}{2} + 1 \\right\\rfloor$ is the floor of $\\frac{x}{2}+1$.\n", 107 | "\n", 108 | "Write a program that loads `x` until it loads `x = 0` and writes the value `f(x)` for each of the loaded numbers." 109 | ] 110 | }, 111 | { 112 | "cell_type": "markdown", 113 | "metadata": {}, 114 | "source": [ 115 | "**Hints for Problems 5 and 6:**\n", 116 | "\n", 117 | "* These are simple examples of [recursive functions](http://en.wikipedia.org/wiki/Recursion_%28computer_science%29#Recursive_functions_and_algorithms). A function in Python (and most other modern languages) can invoke itself just like it can invoke any other function. However, there are two major things to remember:\n", 118 | " * As we have mentioned before, the local variables are local to each invocation. So, if a function that invokes itself has a parameter `x`, then there will be two variables `x` in the memory, each belonging to its own invocation. The two are in no way related (apart from having the same name), and each invocation will see only its own `x`.\n", 119 | " * There must exist values of the input parameters for which the function does not invoke itself (so called *terminating cases*). Without that, the function will invoke itself indefinitely (or, more precisely, until the program runs out of the available memory).\n", 120 | "\n", 121 | "* Here is a sketch how such a function may look:\n", 122 | "\n", 123 | " ```python3\n", 124 | " def f(x):\n", 125 | " if some_condition:\n", 126 | " return f(some_expression)\n", 127 | " if some other condition:\n", 128 | " return f(some_other_expression)\n", 129 | " ...\n", 130 | " return an_expression_that_covers_the_case_when_no_prior_condition_was_met\n", 131 | " ```\n", 132 | "\n", 133 | "* Write auxiliary functions (the one for finding $d$ in Problem 5, $h$ and $g$ in Problem 6), to make it easier to organize and read your code." 134 | ] 135 | } 136 | ], 137 | "metadata": {}, 138 | "nbformat": 4, 139 | "nbformat_minor": 0 140 | } 141 | -------------------------------------------------------------------------------- /03c-functions.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Programming with Python (lab classes)\n", 8 | "#### Vedran Šego, [vsego.org](http://vsego.org/)\n", 9 | "\n", 10 | "## Content:\n", 11 | "\n", 12 | "1. Functions" 13 | ] 14 | }, 15 | { 16 | "cell_type": "markdown", 17 | "metadata": {}, 18 | "source": [ 19 | "**Reminder:** When asked to write a function as a part of a problem, also write a program that lets us test that function. This program should get whatever input is meaningful for testing this function, call it with these arguments, and print (in some form) what it returned." 20 | ] 21 | }, 22 | { 23 | "cell_type": "markdown", 24 | "metadata": {}, 25 | "source": [ 26 | "**Problem 1.** Write a program that loads a natural number `n` and then `n` integers. The program has to compute the sum of the digits of each of these numbers, and then the product of these sums. In the end, the program has to print the sum of the digits of the computed product.\n", 27 | "\n", 28 | "More formally, if $\\operatorname{sd}(x)$ denotes the sum of the digits of $x$, and $x_1,x_2,\\dots,x_n$ denote the loaded numbers, then the program has to print\n", 29 | "$$\\operatorname{sd}\\left(\\prod_{k=1}^n \\operatorname{sd}(x_k)\\right).$$" 30 | ] 31 | }, 32 | { 33 | "cell_type": "markdown", 34 | "metadata": {}, 35 | "source": [ 36 | "**Problem 2. ** Write a function `sdr` takes integer arguments `n` and `r`. If $r \\le 0$, it returns $n$. If $r > 0$, it returns\n", 37 | "$$\\operatorname{sd}^r(n) := (\\underbrace{\\operatorname{sd} \\circ \\operatorname{sd} \\circ \\cdots \\circ \\operatorname{sd}}_{r})(n) = \\underbrace{\\operatorname{sd}(\\operatorname{sd}(\\dots\\operatorname{sd}}_{r}(n)\\dots)),$$\n", 38 | "where $\\operatorname{sd}(n)$ denotes the sum of the digits of $n$.\n", 39 | "\n", 40 | "If `r` is undefined (i.e., if the function is called with only one argument), the function returns `sdr(n, r)` for the largest `r` for which it makes sense. In this case, explain your stopping criteria in detail.\n", 41 | "\n", 42 | "Write a program that will allows us to test all the possible inputs." 43 | ] 44 | }, 45 | { 46 | "cell_type": "markdown", 47 | "metadata": {}, 48 | "source": [ 49 | "**Problem 3.** Write a function `get_digit(n, left, right)`. The function returns\n", 50 | "* `d`-th digit of `n` from the left if the function was called as `get_digit(n, left=d)`, \n", 51 | " If the required digit doesn't exist, the function must return -1.\n", 52 | "* `d`-th digit of `n` from the right if the function was called as `get_digit(n, right=d)`, or\n", 53 | " If the required digit doesn't exist, the function must return 0.\n", 54 | "* -1 otherwise, i.e., for `get_digit(n)` and `get_digit(n, left=d1, right=d2)`." 55 | ] 56 | }, 57 | { 58 | "cell_type": "markdown", 59 | "metadata": {}, 60 | "source": [ 61 | "**Problem 4.** Write a function `rev(n)` that returns the value of the integer argument `n` with its digits order reversed ($1719 \\mapsto 9171$). The sign of the number must remain unchanged ($-1719 \\mapsto -9171$).\n", 62 | "\n", 63 | "Write a program that loads a natural number `n` and then `n` integers. The program has to print which of the numbers (first, second, etc.; you can write $k$-th as `number #k`) has the largest reversed value.\n", 64 | "\n", 65 | "**Hint:** We know how to take the last digit $d$ out of a number $x$. However, we can add that digit to the end of a new number $y$ by computing $y = 10y + d$. Doing so for all digits will produce the reversed number." 66 | ] 67 | } 68 | ], 69 | "metadata": {}, 70 | "nbformat": 4, 71 | "nbformat_minor": 0 72 | } 73 | -------------------------------------------------------------------------------- /04b-exercises.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Programming with Python\n", 8 | "#### Vedran Šego, [vsego.org](http://vsego.org/)\n", 9 | "\n", 10 | "## Exercises: Lists" 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "metadata": {}, 16 | "source": [ 17 | "### A note on testing the programs with lists\n", 18 | "\n", 19 | "You can load a list of numbers using one of several methods. For example, you can load a list of integers like this:\n", 20 | "```python\n", 21 | "L = list()\n", 22 | "n = int(input(\"The number of list elements: \"))\n", 23 | "for k in range(n):\n", 24 | " L.append(int(input(str(k+1) + \". element: \")))\n", 25 | "```\n", 26 | "However, while testing your program, it gets boring to retype the list with each run. Instead of the above, do this:\n", 27 | "```python\n", 28 | "def load_a_list_of_ints():\n", 29 | " \"\"\"\n", 30 | " Loads a list of integers by first asking for its length.\n", 31 | " \"\"\"\n", 32 | " L = list()\n", 33 | " n = int(input(\"The number of list elements: \"))\n", 34 | " for k in range(n):\n", 35 | " L.append(int(input(str(k+1) + \". element: \")))\n", 36 | " return L\n", 37 | "\n", 38 | "#x = load_a_list_of_ints()\n", 39 | "x = [ 17, 23, 11, 13, 19 ]\n", 40 | "the_rest_of_your_code()\n", 41 | "```\n", 42 | "In other words, make an input function (`load_a_list_of_ints` in the above example), comment out its call\n", 43 | "```python\n", 44 | "#x = load_a_list_of_ints()\n", 45 | "```\n", 46 | "and set a fixed value for the list:\n", 47 | "```python\n", 48 | "x = [ 17, 23, 11, 13, 19 ]\n", 49 | "```\n", 50 | "\n", 51 | "After your code works properly for that one example, you can try a few more by changing the value of `x`.\n", 52 | "\n", 53 | "In the end, remove or comment out the fixed value of `x`:\n", 54 | "```python\n", 55 | "#x = [ 17, 23, 11, 13, 19 ]\n", 56 | "```\n", 57 | "uncomment the input, i.e., remove `#` from `#x = load_a_list_of_ints()` so you get\n", 58 | "```python\n", 59 | "x = load_a_list_of_ints()\n", 60 | "```\n", 61 | "and test that the program properly loads a list and does with it what needs to be done.\n", 62 | "\n", 63 | "Of course, the same approach can be used with the other input methods that we've seen in lectures. Furthermore, the `break` statement (which we shall see later on) in some of those can be replaced with `return L`." 64 | ] 65 | }, 66 | { 67 | "cell_type": "markdown", 68 | "metadata": {}, 69 | "source": [ 70 | "## The problems\n", 71 | "\n", 72 | "**Problem 1.** Without using Python's built-in functions for reversing lists, write your own function `my_reverse` that accepts a single parameter `L` (a list) and reverses its elements." 73 | ] 74 | }, 75 | { 76 | "cell_type": "markdown", 77 | "metadata": {}, 78 | "source": [ 79 | "**Hint:** Swap the first and the last element, then the second and the second to last, etc. Where should this swapping stop?" 80 | ] 81 | }, 82 | { 83 | "cell_type": "markdown", 84 | "metadata": {}, 85 | "source": [ 86 | "**Problem 2.** Without using Python's built-in functions for reversing lists, write your own function `my_reverse` that accepts a single parameter `L` (a list) and returns a new list with the same elements but in a reverse order. The list `L` has to remain unchanged." 87 | ] 88 | }, 89 | { 90 | "cell_type": "markdown", 91 | "metadata": {}, 92 | "source": [ 93 | "**Problem 3.** Without using Python's built-in functions for sorting lists, write your own function `my_sort` that accepts a single parameter L (a list) and sorts it." 94 | ] 95 | }, 96 | { 97 | "cell_type": "markdown", 98 | "metadata": {}, 99 | "source": [ 100 | "**Hint:** How would you sort a sequence of numbers IRL (*in real life*) if you had them each written on its own piece of paper?\n", 101 | "\n", 102 | "One way to do it: take a look at the first, the second,... $k$-th number. For each of them find the smallest one behind it. Then swap that one with the $k$-th one (unless the $k$-th one is that smallest one), and move to the next, $(k+1)$-th one. This is called *selection sort*.\n", 103 | "\n", 104 | "**Note:** This is an exercise in list manipulations. When sorting in Python, always use its own sorting functions, as these implement much faster algorithms." 105 | ] 106 | }, 107 | { 108 | "cell_type": "markdown", 109 | "metadata": {}, 110 | "source": [ 111 | "**Problem 4.** Without using Python's built-in functions for sorting lists, write your own function `my_sort` that accepts a single parameter L (a list) and returns a new list with the same elements but in an ascending order. The list `L` has to remain unchanged." 112 | ] 113 | }, 114 | { 115 | "cell_type": "markdown", 116 | "metadata": {}, 117 | "source": [ 118 | "**Problem 5.** Write a function that takes two parameters: a sorted list `L` (you don't have to check that it is sorted) and a variable `el`. The function has to return `None` if `el` is not in the list, or its index if it is.\n", 119 | "\n", 120 | "Do not use sets and similar methods, nor Python's built-in functions like [`index`](https://docs.python.org/3/tutorial/datastructures.html#more-on-lists).\n", 121 | "\n", 122 | "Instead, implement a [binary search algorithm](http://en.wikipedia.org/wiki/Binary_search_algorithm). This is the same algorithm that you use when searching for something in a *sorted* index at the end of a book: look at the middle term and decide where to look next (to the left or the right) and proceed until the element is found or you realize that it doesn't exist. Each step cuts the number of candidates in half (so, a list with $2^{\\color{red}{10}} = 1024$ elements is searched in at most $\\color{red}{10}$ steps).\n", 123 | "\n", 124 | "Searching the internet for a simple explanation of how it works would probably be useful here." 125 | ] 126 | }, 127 | { 128 | "cell_type": "markdown", 129 | "metadata": {}, 130 | "source": [ 131 | "**Note:** Python has a module [`bisect`](https://docs.python.org/3/library/bisect.html) which, as its documentation says, provides support for maintaining a list in sorted order without having to sort the list after each insertion. However, it can also be used for binary search." 132 | ] 133 | }, 134 | { 135 | "cell_type": "markdown", 136 | "metadata": {}, 137 | "source": [ 138 | "## Further help\n", 139 | "\n", 140 | "Detailed explanations of the solutions for the problems in this exercise are given in the lab classes notes." 141 | ] 142 | } 143 | ], 144 | "metadata": {}, 145 | "nbformat": 4, 146 | "nbformat_minor": 0 147 | } 148 | -------------------------------------------------------------------------------- /05b-exercises.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Programming with Python\n", 8 | "#### Vedran Šego, [vsego.org](http://vsego.org/)\n", 9 | "\n", 10 | "## Exercises: Strings and generators" 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "metadata": {}, 16 | "source": [ 17 | "**Problem 1.** Write a function `copy_rev(s)` that takes a string `s` and returns a new string that consists of an original string `s` followed by its reverse copy.\n", 18 | "\n", 19 | "For example, `copy_rev(\"aBcd\")` should return `\"aBcddcBa\"`." 20 | ] 21 | }, 22 | { 23 | "cell_type": "markdown", 24 | "metadata": {}, 25 | "source": [ 26 | "**Problem 2.** Write functions\n", 27 | "* `copy_to_len_whole(s, l)` that returns the maximum length string made of copies of `s` (only the whole `s`, no slicing) with the length at most `l`,\n", 28 | "* `copy_to_len_sliced(s, l)` that returns the maximum length string made of copies of `s` with the length exactly `l`; if the length of `s` doesn't match, it ends with the beginning slice of `s`.\n", 29 | "\n", 30 | "For example,\n", 31 | "* `copy_to_len_whole(\"12345\", 17)` should return `\"123451234512345\"` (length 15);\n", 32 | "* `copy_to_len_sliced(\"12345\", 17)` should return `\"12345123451234512\"` (length 17).\n", 33 | "\n", 34 | "You may assume that `s` is not an empty string and that `l >= 0`." 35 | ] 36 | }, 37 | { 38 | "cell_type": "markdown", 39 | "metadata": {}, 40 | "source": [ 41 | "**Problem 3.** Write functions\n", 42 | "* `fade_copies_left(s)` that returns the string made by concatenating `s` with its left slices of decreasing sizes, i.e., with the `s` without the last character, then with `s` without the last two characters, etc;\n", 43 | "* `fade_copies_right(s)` that returns the string made by concatenating `s` with its right slices of decreasing sizes, i.e., with the `s` without the first character, then with `s` without the first two characters, etc.\n", 44 | "\n", 45 | "For example,\n", 46 | "* `fade_copies_left(\"abcde\")` should return `\"abcdeabcdabcaba\"`;\n", 47 | "* `fade_copies_right(\"abcde\")` should return `\"abcdebcdecdedee\"`." 48 | ] 49 | }, 50 | { 51 | "cell_type": "markdown", 52 | "metadata": {}, 53 | "source": [ 54 | "**Problem 4.** We define words as sequences of non-space characters separated by a single space.\n", 55 | "\n", 56 | "Write a function `last_word(s)` that returns the last word in `s`, i.e., the substring beginning after the last occurence of the space character `\" \"` in `s` all the way to the end. If the string `s` ends with a space, the function returns an empty string `\"\"`. If the string contains no spaces, the whole string is its last word.\n", 57 | "\n", 58 | "Further, write a program that loads an integer `n` and then `n` strings which it prints sorted by the last word." 59 | ] 60 | }, 61 | { 62 | "cell_type": "markdown", 63 | "metadata": {}, 64 | "source": [ 65 | "**Problem 5.** We define words as sequences of non-space characters separated by a sequence of consecutive spaces (one or more of them).\n", 66 | "\n", 67 | "Write a function `second_word(s)` that returns the second word in `s`. Words are mutually separated by one or more spaces. You may assume that `s` will not start with a space.\n", 68 | "\n", 69 | "For example, in the string \"This is a sentence.\" the second word is \"is\" even though there are 5 spaces before it." 70 | ] 71 | } 72 | ], 73 | "metadata": {}, 74 | "nbformat": 4, 75 | "nbformat_minor": 0 76 | } 77 | -------------------------------------------------------------------------------- /05c-strings.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Programming with Python (lab classes)\n", 8 | "#### Vedran Šego, [vsego.org](http://vsego.org/)\n", 9 | "\n", 10 | "## Content:\n", 11 | "\n", 12 | "1. Strings\n", 13 | "\n", 14 | "2. Generators" 15 | ] 16 | }, 17 | { 18 | "cell_type": "markdown", 19 | "metadata": {}, 20 | "source": [ 21 | "**Problem 1.** Write a program that loads a list of strings and prints them sorted, ignoring their character case (so called **case insensitive** comparison).\n", 22 | "\n", 23 | "For example:\n", 24 | "* case sensitive: `\"John\" < \"alien\"`, because all capital letters come before all lower case letters;\n", 25 | "* case insensitive: `\"John\" > \"alien\"`, because the case is ignored, so it is the same as `\"john\" > \"alien\"`).\n", 26 | "\n", 27 | "**Note:** The original strings in the list should not be altered in any way!\n", 28 | "\n", 29 | "**Hint:** Using [`str.tolower()`](https://docs.python.org/3/library/stdtypes.html#str.lower) in combination with the `key` argument of `sort` and a `lambda`-function might help you." 30 | ] 31 | }, 32 | { 33 | "cell_type": "markdown", 34 | "metadata": {}, 35 | "source": [ 36 | "**Problem 2.** Write a function `del_double(s, char_del, char_double)` that returns a new string obtained from `s` by removing all the occurrences of the character `char_del` and doubling all the occurrences of the character `char_double`. If `char_del` is not given, nothing should be removed. Similarly, if `char_double` is not given, nothing should be doubled.\n", 37 | "\n", 38 | "For example,\n", 39 | "* `del_double(\"abcdbacabcd\", \"b\", \"d\")` should return `\"acddacacdd\"`,\n", 40 | "* `del_double(\"abcdbacabcd\", \"b\")` should return `\"acdacacd\"`,\n", 41 | "* `del_double(\"abcdbacabcd\", s_double=\"d\")` should return `\"abcddbacabcdd\"`,\n", 42 | "* `del_double(s)` should return a copy of `s`.\n", 43 | "\n", 44 | "If `char_del == char_double`, then no doubling will take place because the deletions will remove all the occurences of `char_del` (which are the same as the occurences of `char_double`).\n", 45 | "\n", 46 | "**Note:** In `del_double`, you may assume that `len(char_del) == len(char_double) == 1`, but make sure that this is correct when loading the data.\n", 47 | "\n", 48 | "**Hint:** Write an auxiliary function that will take three characters `c`, `c_del`, and `c_double`, and return\n", 49 | "* an empty string if `c == c_del`,\n", 50 | "* double `c` if `c == c_double`,\n", 51 | "* `c` otherwise.\n", 52 | "\n", 53 | "Then use this function in a list comprehension that traverses through the string `s`." 54 | ] 55 | }, 56 | { 57 | "cell_type": "markdown", 58 | "metadata": {}, 59 | "source": [ 60 | "**Problem 3.** Write a function `time_diff(t1, t2)` that returns the absolute time difference between the times `t1` and `t2`. Each of them is given as a string formated either as `hh:mm:ss` or as `mm:ss`. The returned difference should have the same format (`hh` part should be omitted if it equals zero), with each part taking up at least two digits.\n", 61 | "\n", 62 | "For example,\n", 63 | "* `time_diff(\"17:19:23\", \"13:11:7\")` should return `\"04:08:16\"`;\n", 64 | "* `time_diff(\"13:11:7\", \"17:19:23\")` should also return `\"04:08:16\"` (because the function returns the absolute time difference);\n", 65 | "* `time_diff(\"17:19:23\", \"11:7\")` should return `\"17:08:16\"`;\n", 66 | "* `time_diff(\"17:19:23\", \"17:11:7\")` should return `\"08:16\"`.\n", 67 | "\n", 68 | "**Hint:** Write two auxiliary functions, `str2time` and `time2str`, that will convert the string of the described format to the number of seconds since the beginning of the day (`3600*hh+60*mm+ss`) and vice versa." 69 | ] 70 | }, 71 | { 72 | "cell_type": "markdown", 73 | "metadata": {}, 74 | "source": [ 75 | "**Problem 4.** Write a function `remove(s, chrs, case_sensitive)` that returns a string obtained from `s` by removing all the characters present in `chrs`. The parameter `case_sensitive` is Boolean; if it is `True`, the matching is case sensitive; otherwise it is insensitive. If the function is invoked with only two arguments, the match should be case sensitive.\n", 76 | "\n", 77 | "For example, `remove(s, \"0123456789\")` would return the copy of `s` without any digits it may have had. So, `remove(\"a12b0 c\", \"0123\")` would return `\"ab c\"`. Similarly, `remove(s, \"A\")` would return a copy of `s` without upper case letters \"`A`\" (but all lower case letters \"`a`\" would remain intact). However, `remove(s, \"A\", True)` would return a copy of `s` without any letters \"`A`\", lower case or upper case.\n", 78 | "\n", 79 | "Preferably, use a generator expression to create this new string." 80 | ] 81 | }, 82 | { 83 | "cell_type": "markdown", 84 | "metadata": {}, 85 | "source": [ 86 | "**Program 5.** Write a function `load_a_list_of_ints_as_a_string()` that loads a list of integers with a singe call to `input`. Assume that the it will be given in the form `\"x1,x2,...,xn\"`. For example, `\"17,-19,23\"` (without spaces or any characters other than a single comma between each two neighbour integers).\n", 87 | "\n", 88 | "Write a program that uses this function to load a list of integers, and print it sorted in a descended order." 89 | ] 90 | } 91 | ], 92 | "metadata": {}, 93 | "nbformat": 4, 94 | "nbformat_minor": 0 95 | } 96 | -------------------------------------------------------------------------------- /06b-exercises.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Programming with Python\n", 8 | "#### Vedran Šego, [vsego.org](http://vsego.org/)\n", 9 | "\n", 10 | "## Exercises: Control flow" 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "metadata": {}, 16 | "source": [ 17 | "The usage of `break` and `continue` can always be avoided with more or less effort (often with at least some loss of readability of the code). However, try to use them where viable, as these are very useful constructs. Most of the following problems can benefit from the usage of these statements.\n", 18 | "\n", 19 | "As always, write the programs that test your functions. From now on, if a function raises an exception, the program must catch it and deal with it in a meaningful fashion (usually print an appropriate descriptive message)." 20 | ] 21 | }, 22 | { 23 | "cell_type": "markdown", 24 | "metadata": {}, 25 | "source": [ 26 | "**Problem 1.** Write a function `print_first_prime(L)` that **prints** the first prime number in the list `L`.\n", 27 | "\n", 28 | "If there are no primes in the list, the function prints an appropriate descriptive message." 29 | ] 30 | }, 31 | { 32 | "cell_type": "markdown", 33 | "metadata": {}, 34 | "source": [ 35 | "**Problem 2.** Write a function `first_prime(L)` that **returns** the first prime number in the list `L`.\n", 36 | "\n", 37 | "If there are no primes in the list, the function raises an appropriate exception." 38 | ] 39 | }, 40 | { 41 | "cell_type": "markdown", 42 | "metadata": {}, 43 | "source": [ 44 | "**Problem 3.** Write a function `first_plus_last_prime(L)` that returns the sum of the first and the last prime number in the list `L`.\n", 45 | "\n", 46 | "If there are no primes in the list, the function returns zero. If there is only one, the function returns its double value (because it is at the same time the first and the last one in the list)." 47 | ] 48 | }, 49 | { 50 | "cell_type": "markdown", 51 | "metadata": {}, 52 | "source": [ 53 | "**Problem 4.** (Problem 1 from the \"Functions\" exercises) Write a function `max_digit(n, d, r)` that works like `digit_sum` from the \"Functions\" lectures but, instead of returning the sum of the digits of `n`, returns the maximum digit of `n` that gives the reminder `r` when divided by `d`. Assign the appropriate default values for any of the parameters for which it makes sense to do so.\n", 54 | "\n", 55 | "Notice that this maximum is undefined for some numbers. If this happens, raise an appropriate exception." 56 | ] 57 | }, 58 | { 59 | "cell_type": "markdown", 60 | "metadata": {}, 61 | "source": [ 62 | "**Problem 5.** (Problem 3 from the \"Functions\" lab class) Write a function `get_digit(n, left, right)`. The function\n", 63 | "* returns `d`-th digit of `n` from the left if the function was called as `get_digit(n, left=d)`, \n", 64 | " If the required digit doesn't exist, the function must raise a `ValueError` exception.\n", 65 | "* returns `d`-th digit of `n` from the right if the function was called as `get_digit(n, right=d)`, or\n", 66 | " if the required digit doesn't exist, the function must return 0.\n", 67 | "* raises a custom exception (so, make your own instead of using `ValueError` or another predefined one) otherwise, i.e., for `get_digit(n)` and `get_digit(n, left=d1, right=d2)`." 68 | ] 69 | } 70 | ], 71 | "metadata": {}, 72 | "nbformat": 4, 73 | "nbformat_minor": 0 74 | } 75 | -------------------------------------------------------------------------------- /06c-control_flow.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Programming with Python (lab classes)\n", 8 | "#### Vedran Šego, [vsego.org](http://vsego.org/)\n", 9 | "\n", 10 | "## Content:\n", 11 | "\n", 12 | "1. Control flow" 13 | ] 14 | }, 15 | { 16 | "cell_type": "markdown", 17 | "metadata": {}, 18 | "source": [ 19 | "**Important:** Make your programs as impervious to crashes as you can.\n", 20 | "\n", 21 | "For example, in the problems where integers need to be loaded, make sure that if anything else is loaded, the program asks again for the same input until it is done right.\n", 22 | "\n", 23 | "However, you should always allow your programs to be interrupted by `Ctrl+C`, so never use the `except:` clause without specifying which exception do you want to catch." 24 | ] 25 | }, 26 | { 27 | "cell_type": "markdown", 28 | "metadata": {}, 29 | "source": [ 30 | "**Problem 1.** Write a program that loads a list of integers until it loads a zero (which does not get added to the list). The program then has to print the sums of all rightmost digits, all the second to rightmost ones, etc.\n", 31 | "\n", 32 | "For example, the list\n", 33 | "$[ \\color{blue}1\\color{red}7, \\color{blue}1\\color{red}9, \\color{blue}2\\color{red}3, \\color{orange}1\\color{green}7\\color{blue}1\\color{red}9, \\color{green}1\\color{blue}2\\color{red}7 ]$\n", 34 | "will produce\n", 35 | "$\\color{red}7 + \\color{red}9 + \\color{red}3 + \\color{red}9 + \\color{red}7 = 35$,\n", 36 | "$\\color{blue}1 + \\color{blue}1 + \\color{blue}2 + \\color{blue}1 + \\color{blue}2 = 7$,\n", 37 | "$\\color{green}7 + \\color{green}1 = 8$,\n", 38 | "$\\color{orange}1 = 1$,\n", 39 | "so the output should be\n", 40 | "\n", 41 | " The sum of the 1. digits from the right: 35\n", 42 | " The sum of the 2. digits from the right: 7\n", 43 | " The sum of the 3. digits from the right: 8\n", 44 | " The sum of the 4. digits from the right: 1\n", 45 | "\n", 46 | "As mentioned above, make sure that the program doesn't crash even if the user inputs floats or some text instead of integers (in which case the same input should be requested again)." 47 | ] 48 | }, 49 | { 50 | "cell_type": "markdown", 51 | "metadata": {}, 52 | "source": [ 53 | "**Problem 2.** Write a program that loads a list of integers as a string (all the numbers are separated by a single comma) and prints the frequency of each digit.\n", 54 | "\n", 55 | "For example, if the list $[\\color{red}17, \\color{red}19, \\color{blue}2\\color{green}3, \\color{red}17\\color{red}19, \\color{red}1\\color{blue}27]$ is given, then a digit $\\color{red}1$ appears $5$ times, a digit $\\color{blue}2$ appears $2$ times, a digit $\\color{green}3$ appears only once, etc., so the program should print:\n", 56 | "\n", 57 | " A digit 0 has appeared in none of the numbers.\n", 58 | " A digit 1 has appeared 5 times.\n", 59 | " A digit 2 has appeared 2 times.\n", 60 | " A digit 3 has appeared once.\n", 61 | " A digit 4 has appeared in none of the numbers.\n", 62 | " A digit 5 has appeared in none of the numbers.\n", 63 | " A digit 6 has appeared in none of the numbers.\n", 64 | " A digit 7 has appeared 3 times.\n", 65 | " A digit 8 has appeared in none of the numbers.\n", 66 | " A digit 9 has appeared 2 times.\n", 67 | "\n", 68 | "Try to get exactly the same output for this example (notice the difference in the format of the output message for the digits that appeared only once, more than once, or not a single time)." 69 | ] 70 | }, 71 | { 72 | "cell_type": "markdown", 73 | "metadata": {}, 74 | "source": [ 75 | "**Problem 3.** Solve the previous problem, but instead of a list of integers analyze a line of text (i.e., a string) and count the frequencies of all of its characters.\n", 76 | "\n", 77 | "**Hint:** Instead of counting the frequences in a list (which was convenient for the digits `0,1,...,9`) as in the solution of the previous problem, a different data structure might be more useful here." 78 | ] 79 | } 80 | ], 81 | "metadata": {}, 82 | "nbformat": 4, 83 | "nbformat_minor": 0 84 | } 85 | -------------------------------------------------------------------------------- /07b-exercises.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Programming with Python\n", 8 | "#### Vedran Šego, [vsego.org](http://vsego.org/)\n", 9 | "\n", 10 | "## Exercises: Modules" 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "metadata": {}, 16 | "source": [ 17 | "**Problem 1.** Write a module with three functions:\n", 18 | "* `has_prime_perm(n)` that returns `True` if any [permutation](http://en.wikipedia.org/wiki/Permutation) of `n`'s digits form a prime number, and\n", 19 | "* `has_only_prime_perms(n)` that returns `True` if all of the permutations of `n`'s digits form prime numbers, and\n", 20 | "* `prime_perms(n)` that returns either a list or a generator of all the prime numbers that can be formed by permuting the digits of `n`.\n", 21 | "\n", 22 | "Negative numbers have no prime permutations.\n", 23 | "\n", 24 | "Make sure that it is possible to run the module as an ordinary program, in which case it should load `n` and print the return values of all three functions.\n", 25 | "\n", 26 | "The module may contain other functions.\n", 27 | "\n", 28 | "**Hint:** Use [`itertools` module](https://docs.python.org/3/library/itertools.html) to find all the permutations of a number's digits." 29 | ] 30 | }, 31 | { 32 | "cell_type": "markdown", 33 | "metadata": {}, 34 | "source": [ 35 | "**Problem 2.** Write a program to detect an average number of swaps of the selection sort of a list of length `n` with a given sample size with and without repeating elements.\n", 36 | "\n", 37 | "**Hint:** Computing the actual average number of swaps would require generating and sorting lists of all possible orderings, which is $n^n$ lists with not necessarily distinct elements and $n! = n (n-1) \\cdots 1$ lists with distinct elements. Even for a length as small as $n = 10$, we would have to generate and sort $10^{10}$ lists.\n", 38 | "\n", 39 | "Instead, load another number, let us call it `sample_size`, and the do the following:\n", 40 | "1. Generate `sample_size` random lists with elements from $\\{0,1,\\dots,n-1\\}$. This will allow element repetitions, since you will do no checks to avoid that. Sort the lists, counting the swaps.\n", 41 | "2. Start with some list, say `list(range(n))`, permute it randomly `sample_size` times (which will produce lists with only distinct elements), and then sort the obtained permutations, counting the swaps.\n", 42 | "\n", 43 | "Functions for both purposes can be found in [`random` module](https://docs.python.org/3/library/random.html)." 44 | ] 45 | }, 46 | { 47 | "cell_type": "markdown", 48 | "metadata": {}, 49 | "source": [ 50 | "**Problem 3.** Write a program that loads a text, line by line, until it loads an empty line. It then prints how many Python keywords were in it. You may assume that all the words are separated by one or more spaces.\n", 51 | "\n", 52 | "**Hint:** The only new issue here is how to recognize a Python **keyword**. Luckily, there is a standard Python module for that, and it can be found in [this list](https://docs.python.org/3/py-modindex.html).\n", 53 | "\n", 54 | "**Problem 3a.** Print how many times each of the keywords has appeared.\n", 55 | "\n", 56 | "**Hint:** Use a dictionary." 57 | ] 58 | } 59 | ], 60 | "metadata": {}, 61 | "nbformat": 4, 62 | "nbformat_minor": 0 63 | } 64 | -------------------------------------------------------------------------------- /07c-modules.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Programming with Python (lab classes)\n", 8 | "#### Vedran Šego, [vsego.org](http://vsego.org/)\n", 9 | "\n", 10 | "## Content:\n", 11 | "\n", 12 | "1. Modules" 13 | ] 14 | }, 15 | { 16 | "cell_type": "markdown", 17 | "metadata": {}, 18 | "source": [ 19 | "**Problem 1.** Write a module `symtoep` for creating various [symmetric](http://en.wikipedia.org/wiki/Symmetric_matrix) [Toeplitz matrices](http://en.wikipedia.org/wiki/Toeplitz_matrix) with the following functions:\n", 20 | "\n", 21 | "* `general(L)` that returns a symmetric Toeplitz matrix with the first row equal to the elements of the list `L`.\n", 22 | "\n", 23 | "* `tridiagonal(n, d, sd)` that returns a [tridiagonal](http://en.wikipedia.org/wiki/Tridiagonal_matrix) symmetric Toeplitz matrix of order `n`, with the float number `d` on the diagonal and the float number `sd` right below and above it (the rest of the elements are zero).\n", 24 | "\n", 25 | "* `filled(n, d, nd)` that returns a symmetric Toeplitz matrix of order `n`, with the float number `d` on the diagonal and all the non-diagonal elements equal to `nd`.\n", 26 | "\n", 27 | "* `menu()` that displays a choice\n", 28 | " ```\n", 29 | " Load a symmetric Toeplitz matrix:\n", 30 | " 1. General symmetric Toeplitz matrix\n", 31 | " 2. Tridiagonal symmetric Toeplitz matrix\n", 32 | " 3. Filled symmetric Toeplitz matrix\n", 33 | " Your choice (1-3):\n", 34 | " ```\n", 35 | " and asks the user to choose. Then,\n", 36 | " * if the user chooses `\"1\"`, the function asks for a list `L` of numbers (preferably as a string of comma-separated floats, but you can use some other method as well), and then returns `general(L)`,\n", 37 | " * if the user chooses `\"2\"`, the function asks for an integer `n` and floats `d` and `sd`, and returns `tridiagonal(n, d, sd)`.\n", 38 | " * if the user chooses `\"3\"`, the function asks for an integer `n` and floats `d` and `nd`, and returns `filled(n, d, sd)`.\n", 39 | " * if the user chooses anything else, the choice is redisplayed and user is asked to choose again.\n", 40 | "\n", 41 | "When run like a program, this module should do nothing.\n", 42 | "\n", 43 | "Toeplitz matrices are those that have constant elements on all diagonals.\n", 44 | "* An example of a symmetric Toeplitz matrix of order $3$:\n", 45 | "$$\\begin{bmatrix} 1 & 2 & 3 & 4 & 5 \\\\ 2 & 1 & 2 & 3 & 4 \\\\ 3 & 2 & 1 & 2 & 3 \\\\ 4 & 3 & 2 & 1 & 2 \\\\ 5 & 4 & 3 & 2 & 1 \\end{bmatrix}$$\n", 46 | "* An example of a tridiagonal (all elements other than those on the main and its neighbour diagonals are zero) symmetric Toeplitz matrix of order $3$:\n", 47 | "$$\\begin{bmatrix} 1 & 2 & 0 & 0 & 0 \\\\ 2 & 1 & 2 & 0 & 0 \\\\ 0 & 2 & 1 & 2 & 0 \\\\ 0 & 0 & 2 & 1 & 2 \\\\ 0 & 0 & 0 & 2 & 1 \\end{bmatrix}$$\n", 48 | "* An example of a \"filled\" symmetric Toeplitz matrix of order $3$:\n", 49 | "$$\\begin{bmatrix} 1 & 2 & 2 & 2 & 2 \\\\ 2 & 1 & 2 & 2 & 2 \\\\ 2 & 2 & 1 & 2 & 2 \\\\ 2 & 2 & 2 & 1 & 2 \\\\ 2 & 2 & 2 & 2 & 1 \\end{bmatrix}$$\n", 50 | "\n", 51 | "All the functions have to return the matrices as `NumPy`'s `matrix` type, which is easily created from a list or any other two-dimensional array-like type, using the function [`numpy.matrix`](http://docs.scipy.org/doc/numpy/reference/generated/numpy.matrix.html). For example, the first of the three matrices shown above can be created as follows:" 52 | ] 53 | }, 54 | { 55 | "cell_type": "code", 56 | "execution_count": 1, 57 | "metadata": { 58 | "collapsed": false 59 | }, 60 | "outputs": [ 61 | { 62 | "name": "stdout", 63 | "output_type": "stream", 64 | "text": [ 65 | "[[1 2 3 4 5]\n", 66 | " [2 1 2 3 4]\n", 67 | " [3 2 1 2 3]\n", 68 | " [4 3 2 1 2]\n", 69 | " [5 4 3 2 1]]\n" 70 | ] 71 | } 72 | ], 73 | "source": [ 74 | "import numpy as np\n", 75 | "L = list(range(1,6))\n", 76 | "res = list()\n", 77 | "for i in range(5):\n", 78 | " row = list()\n", 79 | " for j in range(5):\n", 80 | " row.append(L[abs(i-j)])\n", 81 | " res.append(row)\n", 82 | "res = np.matrix(res)\n", 83 | "print(res)" 84 | ] 85 | }, 86 | { 87 | "cell_type": "markdown", 88 | "metadata": {}, 89 | "source": [ 90 | "It can be done more easily using a generator expression:" 91 | ] 92 | }, 93 | { 94 | "cell_type": "code", 95 | "execution_count": 2, 96 | "metadata": { 97 | "collapsed": false 98 | }, 99 | "outputs": [ 100 | { 101 | "name": "stdout", 102 | "output_type": "stream", 103 | "text": [ 104 | "[[1 2 3 4 5]\n", 105 | " [2 1 2 3 4]\n", 106 | " [3 2 1 2 3]\n", 107 | " [4 3 2 1 2]\n", 108 | " [5 4 3 2 1]]\n" 109 | ] 110 | } 111 | ], 112 | "source": [ 113 | "import numpy as np\n", 114 | "L = list(range(1,6))\n", 115 | "res = np.matrix([[L[abs(i-j)] for i in range(5)] for j in range(5)])\n", 116 | "print(res)" 117 | ] 118 | }, 119 | { 120 | "cell_type": "markdown", 121 | "metadata": {}, 122 | "source": [ 123 | "You may implement the functions `tridiagonal(n, d, sd)` and `filled(n, d, nd)` either on their own or simply by creating `L` and calling `general(L)`. The former approach is prefered, in which case [`numpy.zeros`](http://docs.scipy.org/doc/numpy/reference/generated/numpy.zeros.html), [`numpy.ones`](http://docs.scipy.org/doc/numpy/reference/generated/numpy.ones.html), [`numpy.fill_diagonal`](http://docs.scipy.org/doc/numpy/reference/routines.indexing.html), and [`numpy.tri`](http://docs.scipy.org/doc/numpy/reference/generated/numpy.tri.html#numpy.tri) may help you, along with the matrix addition (done with the usual plus `+` operator) and multiplication with a constant (done with the usual multiplication `*` operator). These functions are much faster than setting the elements index by index, but you are free to work without them." 124 | ] 125 | }, 126 | { 127 | "cell_type": "markdown", 128 | "metadata": {}, 129 | "source": [ 130 | "**Problem 2.** Using the module `symtoep`, write a program that loads a matrix (one of the 3 supported types), and then prints it and its eigenvalues.\n", 131 | "\n", 132 | "To compute the eigenvalues of a symmetric matrix, use [`scipy.linalg.eigvalsh`](http://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.linalg.eigvalsh.html). If, for some reason, SciPy doesn't work, use [`numpy.linalg.eigvalsh`](http://docs.scipy.org/doc/numpy/reference/generated/numpy.linalg.eigvalsh.html).\n", 133 | "\n", 134 | "Ideally, make your program run properly with either (but this is not a must). For example,\n", 135 | "```python\n", 136 | "try:\n", 137 | " import scipy.linalg as la\n", 138 | "except ImportError:\n", 139 | " import numpy.linalg as la\n", 140 | "...\n", 141 | "print(la.eigvalsh(A))\n", 142 | "```" 143 | ] 144 | }, 145 | { 146 | "cell_type": "markdown", 147 | "metadata": {}, 148 | "source": [ 149 | "**Problem 3.** Using the module `symtoep`, write a program that loads a matrix (one of the 3 supported types), and then prints it and a message explaining if it is positive semidefinite or not.\n", 150 | "\n", 151 | "To test positive semidefiniteness, try to compute the [Cholesky factorization](http://en.wikipedia.org/wiki/Cholesky_decomposition), using either [`scipy.linalg.cholesky`](http://docs.scipy.org/doc/scipy/reference/generated/scipy.linalg.cholesky.html) or [`numpy.linalg.cholesky`](http://docs.scipy.org/doc/numpy/reference/generated/numpy.linalg.cholesky.html). If the computation fails (i.e., a `numpy.linalg.linalg.LinAlgError` exception is raised), the matrix is not positive semidefinite. Otherwise, it is.\n", 152 | "\n", 153 | "The same remarks from Problem 2 regarding the import of SciPy/NumPy modules apply." 154 | ] 155 | } 156 | ], 157 | "metadata": {}, 158 | "nbformat": 4, 159 | "nbformat_minor": 0 160 | } 161 | -------------------------------------------------------------------------------- /08b-exercises.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Programming with Python\n", 8 | "#### Vedran Šego, [vsego.org](http://vsego.org/)\n", 9 | "\n", 10 | "## Exercises: File I/O" 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "metadata": {}, 16 | "source": [ 17 | "**Reminder:** To test your solutions, you need to create one or more text files. You can do so in Spyder, Notepad, or any other text editor." 18 | ] 19 | }, 20 | { 21 | "cell_type": "markdown", 22 | "metadata": {}, 23 | "source": [ 24 | "**Problem 1.** Write a program that loads names of two files. Each file contains integers, one per each line. The program has to print a message describing if the sets of numbers contained in those files are equal, or the first one is a proper subset of the second one, or the second one is a proper subset of the first one, or neither.\n", 25 | "\n", 26 | "**Hint:** Since the program needs to read from two files, make a function that reads a file into a set and returns that set." 27 | ] 28 | }, 29 | { 30 | "cell_type": "markdown", 31 | "metadata": {}, 32 | "source": [ 33 | "**Problem 2.** Write a program that loads a name of a text file and reverses the order of its lines (overwriting the original file). You may assume that the file ends with an empty line (i.e., all lines end with a new line character).\n", 34 | "\n", 35 | "**Hint:** Read the file, line by line, reverse it, and save it." 36 | ] 37 | }, 38 | { 39 | "cell_type": "markdown", 40 | "metadata": {}, 41 | "source": [ 42 | "**Problem 3.** Write a program that loads an integer `n` and a file name, and then creates a text file with that name containing the [multiplication table](http://en.wikipedia.org/wiki/Multiplication_table) for all numbers between 1 and `abs(n)` (including both of them).\n", 43 | "\n", 44 | "Save the table in the following format:\n", 45 | "\n", 46 | " * | 1 | 2 | 3 | 4 | 5 \n", 47 | " ----|----|----|----|----|----\n", 48 | " 1 | 1 | 2 | 3 | 4 | 5 \n", 49 | " 2 | 2 | 4 | 6 | 8 | 10 \n", 50 | " 3 | 3 | 6 | 9 | 12 | 15 \n", 51 | " 4 | 4 | 8 | 12 | 16 | 20 \n", 52 | " 5 | 5 | 10 | 15 | 20 | 25 \n", 53 | "\n", 54 | "So, a `*` in the top left cell, a horizontal dashed line after the header, and all the numbers should be centered in 2 characters more than is needed to display $n^2$.\n", 55 | "\n", 56 | "**A note on the purpose of these tables (not part of the problem):** Text formatted as required by this problem can be used in [GFM](http://github.github.com/github-flavored-markdown/) as tables. For example, the above text is displayed like this:\n", 57 | "\n", 58 | " * | 1 | 2 | 3 | 4 | 5 \n", 59 | "----|----|----|----|----|----\n", 60 | " 1 | 1 | 2 | 3 | 4 | 5 \n", 61 | " 2 | 2 | 4 | 6 | 8 | 10 \n", 62 | " 3 | 3 | 6 | 9 | 12 | 15 \n", 63 | " 4 | 4 | 8 | 12 | 16 | 20 \n", 64 | " 5 | 5 | 10 | 15 | 20 | 25 \n", 65 | " \n", 66 | "A bit more advanced version is to replace each `\"----\"` with \"`:--:`\":\n", 67 | "\n", 68 | " * | 1 | 2 | 3 | 4 | 5 \n", 69 | " :--:|:--:|:--:|:--:|:--:|:--:\n", 70 | " 1 | 1 | 2 | 3 | 4 | 5 \n", 71 | " 2 | 2 | 4 | 6 | 8 | 10 \n", 72 | " 3 | 3 | 6 | 9 | 12 | 15 \n", 73 | " 4 | 4 | 8 | 12 | 16 | 20 \n", 74 | " 5 | 5 | 10 | 15 | 20 | 25 \n", 75 | "\n", 76 | "This achieves the centered display of the numbers when processed as GFM:\n", 77 | "\n", 78 | " * | 1 | 2 | 3 | 4 | 5 \n", 79 | ":--:|:--:|:--:|:--:|:--:|:--:\n", 80 | " 1 | 1 | 2 | 3 | 4 | 5 \n", 81 | " 2 | 2 | 4 | 6 | 8 | 10 \n", 82 | " 3 | 3 | 6 | 9 | 12 | 15 \n", 83 | " 4 | 4 | 8 | 12 | 16 | 20 \n", 84 | " 5 | 5 | 10 | 15 | 20 | 25 " 85 | ] 86 | } 87 | ], 88 | "metadata": {}, 89 | "nbformat": 4, 90 | "nbformat_minor": 0 91 | } 92 | -------------------------------------------------------------------------------- /08c-file_io.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Programming with Python (lab classes)\n", 8 | "#### Vedran Šego, [vsego.org](http://vsego.org/)\n", 9 | "\n", 10 | "## Content:\n", 11 | "\n", 12 | "1. Files" 13 | ] 14 | }, 15 | { 16 | "cell_type": "markdown", 17 | "metadata": {}, 18 | "source": [ 19 | "Download the file [`Met_Office_2011_Air_Data.csv`](http://www.metoffice.gov.uk/media/csv/4/9/Met_Office_2011_Air_Data.csv) from [data.gov.uk](http://data.gov.uk/dataset/flight-data-2011/resource/e1be1a0a-565a-40cd-a8a7-e0bdf4f50dcc)." 20 | ] 21 | }, 22 | { 23 | "cell_type": "markdown", 24 | "metadata": {}, 25 | "source": [ 26 | "**Problem 1.** Write a program that reads the file `Met_Office_2011_Air_Data.csv` and prints:\n", 27 | "\n", 28 | "* Total cost for all the flights,\n", 29 | "\n", 30 | "* Total cost per each air carrier, sorted by that cost (i.e., the last carrier will be the one with whom the spending was biggest)." 31 | ] 32 | }, 33 | { 34 | "cell_type": "markdown", 35 | "metadata": {}, 36 | "source": [ 37 | "**Problem 2.** Write a program that inputs a journey finishing point and then reads the file `Met_Office_2011_Air_Data.csv` and prints total and average cost for all the journeys with that finishing point. The matching has to be case insensitive." 38 | ] 39 | }, 40 | { 41 | "cell_type": "markdown", 42 | "metadata": {}, 43 | "source": [ 44 | "**Problem 3.** Write a program that reads the file `Met_Office_2011_Air_Data.csv` and in the directory `output` creates the files `single.csv` and `return.csv`, containing only the data for single and return flights, respectively. It has to copy all the data except the \"Ticket Single or Return\" column and both files have to be proper CSV files (with headers, and a comma as the column separator).\n", 45 | "\n", 46 | "Use the function [`os.path.exists`](https://docs.python.org/3/library/os.path.html#os.path.exists) to check if the output directory exists, the function [`os.mkdir`](https://docs.python.org/3/library/os.html#os.mkdir) to create it, and the function [`os.path.join`](https://docs.python.org/3/library/os.path.html#os.path.join) to join the directory name with filenames to create the output files' path names." 47 | ] 48 | }, 49 | { 50 | "cell_type": "markdown", 51 | "metadata": {}, 52 | "source": [ 53 | "**Problem 4.** How many public toilets are there in each of the Australian towns, and how many of them are there in each of the Australian states? Of those towns that have a public toilet, which ones have the longest name and which one has the most toilets (and how many)?\n", 54 | "\n", 55 | "**Hint:** Write a program that will answer these questions by analyzing the data that can be obtained [here](https://data.gov.au/dataset/national-public-toilet-map/resource/9fee88ed-dc75-4b6c-88b7-c8a6f04f86e7)." 56 | ] 57 | } 58 | ], 59 | "metadata": {}, 60 | "nbformat": 4, 61 | "nbformat_minor": 0 62 | } 63 | -------------------------------------------------------------------------------- /09b-exercises.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Programming with Python\n", 8 | "#### Vedran Šego, [vsego.org](http://vsego.org/)\n", 9 | "\n", 10 | "## Exercises: Analysis of algorithms" 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "metadata": {}, 16 | "source": [ 17 | "**Problem 1.** Write a function `LCM(a, b)` that returns the [least common multiple](http://en.wikipedia.org/wiki/Least_common_multiple) of integers `a` and `b`. Avoid computing any products bigger than `LCM(a, b)` itself (big products may cause [overflow errors](http://en.wikipedia.org/wiki/Arithmetic_overflow) in many languages; in others, like Python, they can cause slower computation).\n", 18 | "\n", 19 | "If either `a = 0` or `b = 0`, we define `LCM(a, b) = 0`.\n", 20 | "\n", 21 | "**Hint:** Use the [formula based on the prime factorization of a number](http://en.wikipedia.org/wiki/Least_common_multiple#Finding_least_common_multiples_by_prime_factorization)." 22 | ] 23 | }, 24 | { 25 | "cell_type": "markdown", 26 | "metadata": {}, 27 | "source": [ 28 | "**Problem 2.** Write a function `LCM(L)` that returns the [least common multiple](http://en.wikipedia.org/wiki/Least_common_multiple) of all the elements in list `L`. Avoid computing any products bigger than `LCM(L)` itself.\n", 29 | "\n", 30 | "If either of the elements in `L` is a zero, we define `LCM(L) = 0`.\n", 31 | "\n", 32 | "**Hint:** Use the [formula based on the prime factorization of a number](http://en.wikipedia.org/wiki/Least_common_multiple#Finding_least_common_multiples_by_prime_factorization).\n", 33 | "\n", 34 | "**Note:** Make sure that the function works properly for any list `L`, including an empty one (this should raise an appropriate error).\n", 35 | "\n", 36 | "**Problem 2a.** Try to write `LCM` in a way that it can be invoked by an arbitrary number of arguments, i.e., `LCM(a)`, `LCM(a, b)`, `LCM(a, b, c)`, etc.\n", 37 | "\n", 38 | "**Note:** Problem 2a is not covered in the course materials and, as such, it requires some Googling efforts. It will not be a part of the tests." 39 | ] 40 | }, 41 | { 42 | "cell_type": "markdown", 43 | "metadata": {}, 44 | "source": [ 45 | "**Problem 3a.** What is the worst-case complexity of\n", 46 | "1. the sequential search?\n", 47 | "2. the selection sort?\n", 48 | "3. the binary search algorithm?\n", 49 | "\n", 50 | "**Problem 3b.** Assume that you have an unsorted list. Which of the following is faster and why?\n", 51 | "1. search for an element in the list sequentially, **or**\n", 52 | "2. sort the list using the selection sort and then search for the element using the binary search algorithm." 53 | ] 54 | } 55 | ], 56 | "metadata": {}, 57 | "nbformat": 4, 58 | "nbformat_minor": 0 59 | } 60 | -------------------------------------------------------------------------------- /09c-analysis_of_algorithms.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Programming with Python (lab classes)\n", 8 | "#### Vedran Šego, [vsego.org](http://vsego.org/)\n", 9 | "\n", 10 | "## Content:\n", 11 | "\n", 12 | "1. Analysis of algorithms" 13 | ] 14 | }, 15 | { 16 | "cell_type": "markdown", 17 | "metadata": {}, 18 | "source": [ 19 | "**Problem 1.** Write a function `sum_dif(L)` that returns the sum of absolute differences of all the unordered pairs (subsets with exactly two elements) of the elements in the ascendinly sorted list `L`. In other words, if we denote the elements of `L` as $a_1, a_2, \\dots, a_n$, then the function returns\n", 20 | "$$\\operatorname{sum\\_dif}(L) = \\sum_{i=1}^{n-1} \\sum_{j=i+1}^n | a_i - a_j |.$$\n", 21 | "\n", 22 | "In your function's docstring explain what is the complexity of your algorithm.\n", 23 | "\n", 24 | "**Note:** For a hint on how to make an algorithm of a linear complexity, see [here](http://codereview.stackexchange.com/a/32938/26493). This is a nice example of a mathematical \"trickery\" used to improve the complexity, but it will not be a part of any examination. Also, notice that this algorithm can improve the computation even if the list is not sorted, since the sorting itself can be done in $O(n\\log n)$ time, which is faster that $O(n^2)$ required by the naive \"by the definition\" algorithm." 25 | ] 26 | }, 27 | { 28 | "cell_type": "markdown", 29 | "metadata": {}, 30 | "source": [ 31 | "**Problem 2.** We define the \"Look and Say\" sequence of numbers:\n", 32 | "$$L_1 := 1, \\quad L_2 := 11, \\quad L_3 := 21, \\quad L_4 := 1211, \\quad L_5 := 111221, \\quad L_6 := 312211, \\quad L_7 := 13112221, \\dots$$\n", 33 | "in the following way:\n", 34 | "1. The first number is $L_1 := 1$.\n", 35 | "2. If the $i$-th number is $L_i =\\underbrace{a_1a_1\\dots{}a_1}_{k_1}\\underbrace{a_2a_2\\dots{}a_2}_{k_2}\\dots\\underbrace{a_ma_m\\dots{}a_m}_{k_m}$, where $a_j \\ne a_{j+1}$ for all $j=1,2,\\dots,m-1$, then the $(i+1)$-st number is $L_{i+1} := k_1a_1k_2a_2\\dots{}k_ma_m$.\n", 36 | "\n", 37 | "The first five numbers are constructed as follows:\n", 38 | "* The first number is $L_1 = 1$, which has only $\\color{red}{1}$ digit $\\color{blue}{1}$. Hence, the second number is $L_2 = \\color{red}{1}\\color{blue}{1}$.\n", 39 | "* The second number, $L_2 = 11$, has $\\color{red}{2}$ digits $\\color{blue}{1}$, so the third number is $L_3 = \\color{red}{2}\\color{blue}{1}$.\n", 40 | "* The third number, $L_3 = 21$, has $\\color{red}{1}$ digit $\\color{blue}{2}$ and $\\color{orange}{1}$ digit $\\color{green}{1}$, so the fourth number is $L_4 = \\color{red}{1}\\color{blue}{2}\\color{orange}{1}\\color{green}{1}$.\n", 41 | "* The fourth number, $L_4 = 1211$, has $\\color{red}{1}$ digit $\\color{blue}{1}$, $\\color{orange}{1}$ digit $\\color{green}{2}$, and $\\color{purple}{2}$ digits $\\color{navy}{1}$, so the fifth number is $L_5 = \\color{red}{1}\\color{blue}{1}\\color{orange}{1}\\color{green}{2}\\color{purple}{2}\\color{navy}{1}$.\n", 42 | "\n", 43 | "Write a function `look_and_say(a, b)` that returns the list of numbers $L_a, L_{a+1}, \\dots, L_{b-1}$. If $a \\ge b$, the returned list should be empty. If $a \\le 0$, the function should raise a `ValueError` exception.\n", 44 | "\n", 45 | "**Note:** Instead of a list, it is prefered to make `look_and_say` a generator, but this is beyond what will be asked for in the examinations and is hence left as an exercise for the students that are interested in doing it that way.\n", 46 | "\n", 47 | "**Hints:**\n", 48 | "\n", 49 | "1. Creating the $(i+1)$-st number is easier done if the $i$-th number is first converted to a string or, better yet, if one works with strings all the time and then converts them to integers just before returning them or adding them to a list.\n", 50 | "\n", 51 | "2. To find out how many consecutive digits are equal to each other, start with the first and increase index while they are. Be careful not to increase the index beyond the last one (`len(s)-1`).\n", 52 | "\n", 53 | "**Side-problem:** Try to prove that:\n", 54 | "* none of the elements in the \"Look and Say\" sequence have digits other than $1$, $2$, and $3$, and\n", 55 | "* every $L_n$ for $n \\ge 6$ has digits $1$, $2$, and $3$ (all three of them, and none other)." 56 | ] 57 | }, 58 | { 59 | "cell_type": "markdown", 60 | "metadata": {}, 61 | "source": [ 62 | "**Problem 3.** Write a function `lists_intersection(L1, L2)` that returns the list of all elements that appear in both of the lists `L1` and `L2` (all three represent ordered [multisets](http://en.wikipedia.org/wiki/Multiset)). If an element `x` appears in `L1` a total of `r1` times and in `L2` a total of `r2` times, it has to appear in the resulting list `min(r1, r2)` times. The lists `L1` and `L2` must remain unchanged.\n", 63 | "\n", 64 | "All the elements in all three lists are assumed to be strings. The result list should be sorted by the elements' values.\n", 65 | "\n", 66 | "**Hint:** Converting these lists to sets and finding their intersection can help you find what elements belong to the intersection, but you still need to count how many instances go to the result list." 67 | ] 68 | } 69 | ], 70 | "metadata": {}, 71 | "nbformat": 4, 72 | "nbformat_minor": 0 73 | } 74 | -------------------------------------------------------------------------------- /10a-europe-170013.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/10a-europe-170013.png -------------------------------------------------------------------------------- /10a-europe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/10a-europe.png -------------------------------------------------------------------------------- /10a-interpolation_methods.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/10a-interpolation_methods.png -------------------------------------------------------------------------------- /10a-layer_images.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/10a-layer_images.png -------------------------------------------------------------------------------- /10a-temps.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/10a-temps.zip -------------------------------------------------------------------------------- /10c-data_analysis-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/10c-data_analysis-02.png -------------------------------------------------------------------------------- /10c-data_analysis-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/10c-data_analysis-03.png -------------------------------------------------------------------------------- /10c-data_analysis-04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/10c-data_analysis-04.png -------------------------------------------------------------------------------- /10c-data_analysis.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Programming with Python (lab classes)\n", 8 | "#### Vedran Šego, [vsego.org](http://vsego.org/)\n", 9 | "\n", 10 | "## Content:\n", 11 | "\n", 12 | "1. Histograms of the historical data" 13 | ] 14 | }, 15 | { 16 | "cell_type": "markdown", 17 | "metadata": {}, 18 | "source": [ 19 | "In the problems below we define a *location* as a `(latitude, longitude)` tuple, and a *season* as one of the codes associated with the temperate seasons, as defined by the readme file of the data used in the lectures:\n", 20 | "\n", 21 | "* `\"13\"`: Winter,\n", 22 | "* `\"14\"`: Spring,\n", 23 | "* `\"15\"`: Summer,\n", 24 | "* `\"16\"`: Autumn.\n", 25 | "\n", 26 | "A [*histogram*](http://en.wikipedia.org/wiki/Histogram) is a graphical representation of the distribution of data. In essence, it is a plot that has ranges of values (often called *bins*) on the x-axis and the numbers of values that fall into those bins on the y-axis.\n", 27 | "\n", 28 | "For example, Summers (code `\"15\"`) around the [Alan Turing Building (53.468001, -2.231462)](https://maps.google.co.uk/maps?q=53.468001,+-2.231462) have the following histogram values, given the bin size 0.25:\n", 29 | "\n", 30 | " 12.365: 1\n", 31 | " 12.615: 1\n", 32 | " 12.865: 5\n", 33 | " 13.115: 6\n", 34 | " 13.365: 11\n", 35 | " 13.615: 23\n", 36 | " 13.865: 40\n", 37 | " 14.115: 51\n", 38 | " 14.365: 55\n", 39 | " 14.615: 67\n", 40 | " 14.865: 62\n", 41 | " 15.115: 61\n", 42 | " 15.365: 45\n", 43 | " 15.615: 25\n", 44 | " 15.865: 13\n", 45 | " 16.115: 15\n", 46 | " 16.365: 16\n", 47 | " 16.615: 1\n", 48 | " 16.865: 2\n", 49 | " 17.115: 3\n", 50 | "\n", 51 | "The values on the left are the midpoint values of the bins. So, the above listing means that, between the years 1500 and 2002, the average Summer temperature was:\n", 52 | "\n", 53 | "* once between $12.365-0.25/2=12.24$ and $12.365+0.25/2=12.49$,\n", 54 | "\n", 55 | "* once between $12.615-0.25/2=12.490$ and $12.615+0.25/2=12.74$,\n", 56 | "\n", 57 | "* five times between $12.865-0.25/2=12.74$ and $12.865+0.25/2=12.99$, etc." 58 | ] 59 | }, 60 | { 61 | "cell_type": "markdown", 62 | "metadata": {}, 63 | "source": [ 64 | "**Problem 1.** Write a function\n", 65 | "```python\n", 66 | "hist(latitude, longitude, season=None, minv=None, maxv=None, bin_size=0.1)\n", 67 | "```\n", 68 | "that returns a tuple of two lists:\n", 69 | "\n", 70 | "* the list of midpoints (the left column in the above example), and\n", 71 | "* the list of counts of values in the corresponding bins of the size `bin_size` (the right column in the above example),\n", 72 | "\n", 73 | "for the area to which the `(latitude, longitude)` position belongs. The parameters `minv` and `maxv` define the overall range of the considered temperatures (i.e., the minimum and the maximum value on the x-axis if the histogram is plotted). If either is undefined, the function uses the minimum or the maximum value, respectively, for that location and a given season.\n", 74 | "\n", 75 | "If `season is None`, the histogram values are computed for all the seasons.\n", 76 | "\n", 77 | "For convenience, feel free to add this new function to the `seasons` module (from the lectures, downloadable [here](http://localhost:8888/notebooks/10a-temps.zip) (22MB) along with the data files).\n", 78 | "\n", 79 | "**A suggestion:** Write a function `ll2idx(latitude, longitude)` that returns the index of the column containing the temperatures for the area that contains the location `(latitude, longitude)`. The function should raise a `ValueError` exception in case the coordinates fall outside of the map and the programs using it should catch it.\n", 80 | "\n", 81 | "**Problem 1a.** Write a program that uses this function to display the histogram for a given location in the above numerical way:\n", 82 | "\n", 83 | " mid_temperature_1: number_of_temperatures_in_the_range_1\n", 84 | " mid_temperature_2: number_of_temperatures_in_the_range_2\n", 85 | " ...\n", 86 | " mid_temperature_n: number_of_temperatures_in_the_range_n\n", 87 | "\n", 88 | "**Problem 1b.** Write a program that uses this function to display the histogram \"drawing\" like this:\n", 89 | "\n", 90 | " [12.240, 12.490): * (1)\n", 91 | " [12.490, 12.740): * (1)\n", 92 | " [12.740, 12.990): ***** (5)\n", 93 | " [12.990, 13.240): ****** (6)\n", 94 | " [13.240, 13.490): *********** (11)\n", 95 | " [13.490, 13.740): *********************** (23)\n", 96 | " [13.740, 13.990): **************************************** (40)\n", 97 | " [13.990, 14.240): *************************************************** (51)\n", 98 | " [14.240, 14.490): ******************************************************* (55)\n", 99 | " [14.490, 14.740): ******************************************************************* (67)\n", 100 | " [14.740, 14.990): ************************************************************** (62)\n", 101 | " [14.990, 15.240): ************************************************************* (61)\n", 102 | " [15.240, 15.490): ********************************************* (45)\n", 103 | " [15.490, 15.740): ************************* (25)\n", 104 | " [15.740, 15.990): ************* (13)\n", 105 | " [15.990, 16.240): *************** (15)\n", 106 | " [16.240, 16.490): **************** (16)\n", 107 | " [16.490, 16.740): * (1)\n", 108 | " [16.740, 16.990): ** (2)\n", 109 | " [16.990, 17.240): *** (3)" 110 | ] 111 | }, 112 | { 113 | "cell_type": "markdown", 114 | "metadata": {}, 115 | "source": [ 116 | "___\n", 117 | "\n", 118 | "**Note:** The problems below include plotting with Matplotlib. The easiest way to get these done is to find similar examples in [Matplotlib gallery](http://matplotlib.org/gallery.html) and then adapt them to your needs with the help of the specific function's documentation.\n", 119 | "___" 120 | ] 121 | }, 122 | { 123 | "cell_type": "markdown", 124 | "metadata": {}, 125 | "source": [ 126 | "**Problem 2.** Write a program that uses the histogram data from the above and plots a bar-type histogram using [matplotlib.pyplot.bar](http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.bar). For the above input, the plot should look like this:\n", 127 | "\n", 128 | "![Histogram for Manchester's Summers](10c-data_analysis-02.png)" 129 | ] 130 | }, 131 | { 132 | "cell_type": "markdown", 133 | "metadata": {}, 134 | "source": [ 135 | "**Problem 3.** A *normalized histogram* is the one in which the values on the y-axis are the percentages in the overall sum of all values. For example, a histogram with the bin counts `[2,3,7,5,3]` would be plotted as `[\"10%\", \"15%\", \"35%\", \"25%\", \"15%\"]`, because $2$ is $10\\%$ of $2+3+7+5+3=20$, and $3$ is $15\\%$, etc.\n", 136 | "\n", 137 | "Write a program that uses [matplotlib.pyplot.hist](http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.hist) to plot a normalized histogram for a given location, season (can be ommitted, in order to use the data for all the seasons) and number of bins. The plot should be displayed on the screen and saved to the disk.\n", 138 | "\n", 139 | "For example, the histogram for the Summers (code `\"15\"`) around the [Alan Turing Building (53.468001, -2.231462)] and with 17 bins should look like this:\n", 140 | "\n", 141 | "![Histogram for Manchester's Summers](10c-data_analysis-03.png)" 142 | ] 143 | }, 144 | { 145 | "cell_type": "markdown", 146 | "metadata": {}, 147 | "source": [ 148 | "**Problem 4.** Write a program that uses [matplotlib.pyplot.hist](http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.hist) to plot (non-normalized) histograms for a given location and number of bins. The plot should be displayed on the screen and saved to the disk and it should contain each of the seasons (Winter in blue, Spring in green, Summer in red, and Autumn in orange) plotted as a separate *steppfilled* area, all in the same plot.\n", 149 | "\n", 150 | "For example, the histogram for the area around the [Alan Turing Building (53.468001, -2.231462)](https://maps.google.co.uk/maps?q=53.468001,+-2.231462) and with 17 bins should look like this:\n", 151 | "\n", 152 | "![Histogram for all four seasons in Manchester](10c-data_analysis-04.png)\n", 153 | "\n", 154 | "**Hint:** The semi-transparency effect below is achieved with the `alpha=0.5` argument." 155 | ] 156 | } 157 | ], 158 | "metadata": {}, 159 | "nbformat": 4, 160 | "nbformat_minor": 0 161 | } 162 | -------------------------------------------------------------------------------- /11a-google.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/11a-google.png -------------------------------------------------------------------------------- /11a-graphs.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "slideshow": { 7 | "slide_type": "slide" 8 | } 9 | }, 10 | "source": [ 11 | "# Programming with Python\n", 12 | "#### Vedran Šego, [vsego.org](http://vsego.org/)\n", 13 | "\n", 14 | "## Contents:\n", 15 | "\n", 16 | "1. Graphs" 17 | ] 18 | }, 19 | { 20 | "cell_type": "markdown", 21 | "metadata": { 22 | "slideshow": { 23 | "slide_type": "slide" 24 | } 25 | }, 26 | "source": [ 27 | "# Graphs\n", 28 | "\n", 29 | "## Königsberg bridges\n", 30 | "\n", 31 | "The [introductory notes](http://www.maths.manchester.ac.uk/~mrm/Teaching/DiscreteMaths/LectureNotes/IntroToGraphs.pdf) of [MATH20902 - Discrete Mathematics](http://www.maths.manchester.ac.uk/study/undergraduate/courses/mathematics-bsc/course-unit-spec/?unitcode=MATH20902) start with the description of the well-known [Königsberg bridge problem](http://en.wikipedia.org/wiki/Seven_Bridges_of_K%C3%B6nigsberg):\n", 32 | "\n", 33 | "
\n", 34 | "\n", 35 | "The panel on the left shows the seven bridges and four land masses that provide the setting for the Königsberg bridge problem, which asks whether it is possible to make a circular walking tour of the city that crosses every bridge exactly once. The panel on the right includes a graph-theoretic abstraction that helps one prove that no such tour exists." 36 | ] 37 | }, 38 | { 39 | "cell_type": "markdown", 40 | "metadata": { 41 | "slideshow": { 42 | "slide_type": "subslide" 43 | } 44 | }, 45 | "source": [ 46 | "First we need to find the official term for \"a graph in which we can visit each edge exactly once\". Let us [ask Google](https://www.google.com/search?q=graph+path+visit+all+edges):\n", 47 | "![](11a-google.png)\n", 48 | "\n", 49 | "Opening that page will, indeed, tell us that what we really want is to check if the graph above is *Eulerian* (i.e., we can visit all the nodes by passing each edge exactly once and endig up where we started)." 50 | ] 51 | }, 52 | { 53 | "cell_type": "markdown", 54 | "metadata": { 55 | "slideshow": { 56 | "slide_type": "subslide" 57 | } 58 | }, 59 | "source": [ 60 | "### Ask Python\n", 61 | "\n", 62 | "Python's package for working with graphs is [NetworkX](http://networkx.github.io/). To observe its basic functionality, let us solve the above.\n", 63 | "\n", 64 | "Let us create an empty multigraph (some nodes will be connected by more than one edge):" 65 | ] 66 | }, 67 | { 68 | "cell_type": "code", 69 | "execution_count": null, 70 | "metadata": { 71 | "collapsed": false 72 | }, 73 | "outputs": [], 74 | "source": [ 75 | "import networkx as nx\n", 76 | "\n", 77 | "G = nx.MultiGraph()" 78 | ] 79 | }, 80 | { 81 | "cell_type": "markdown", 82 | "metadata": { 83 | "slideshow": { 84 | "slide_type": "subslide" 85 | } 86 | }, 87 | "source": [ 88 | "Now, add the nodes:" 89 | ] 90 | }, 91 | { 92 | "cell_type": "code", 93 | "execution_count": null, 94 | "metadata": { 95 | "collapsed": false 96 | }, 97 | "outputs": [], 98 | "source": [ 99 | "G.add_nodes_from([\"C\", \"A\", \"D\", \"B\"])" 100 | ] 101 | }, 102 | { 103 | "cell_type": "markdown", 104 | "metadata": { 105 | "slideshow": { 106 | "slide_type": "subslide" 107 | } 108 | }, 109 | "source": [ 110 | "Add the edges:" 111 | ] 112 | }, 113 | { 114 | "cell_type": "code", 115 | "execution_count": null, 116 | "metadata": { 117 | "collapsed": false 118 | }, 119 | "outputs": [], 120 | "source": [ 121 | "G.add_edges_from([(\"C\",\"A\"), (\"C\",\"A\"), (\"A\",\"B\"), (\"A\",\"B\"), (\"C\", \"D\"), (\"A\", \"D\"), (\"B\", \"D\")])" 122 | ] 123 | }, 124 | { 125 | "cell_type": "markdown", 126 | "metadata": { 127 | "slideshow": { 128 | "slide_type": "subslide" 129 | } 130 | }, 131 | "source": [ 132 | "Print nodes and edges, to make sure all is fine:" 133 | ] 134 | }, 135 | { 136 | "cell_type": "code", 137 | "execution_count": null, 138 | "metadata": { 139 | "collapsed": false 140 | }, 141 | "outputs": [], 142 | "source": [ 143 | "print(\"Nodes:\", G.nodes())\n", 144 | "print(\"Edges:\", G.edges())" 145 | ] 146 | }, 147 | { 148 | "cell_type": "markdown", 149 | "metadata": { 150 | "slideshow": { 151 | "slide_type": "subslide" 152 | } 153 | }, 154 | "source": [ 155 | "Come on, you can do better than that!" 156 | ] 157 | }, 158 | { 159 | "cell_type": "code", 160 | "execution_count": null, 161 | "metadata": { 162 | "collapsed": false 163 | }, 164 | "outputs": [], 165 | "source": [ 166 | "print(\"Nodes:\", \", \".join(sorted(G.nodes())))\n", 167 | "print(\"Edges:\", \", \".join(sorted(\"{{{}}}\".format(\",\".join(sorted(t))) for t in G.edges())))" 168 | ] 169 | }, 170 | { 171 | "cell_type": "markdown", 172 | "metadata": { 173 | "slideshow": { 174 | "slide_type": "subslide" 175 | } 176 | }, 177 | "source": [ 178 | "So, is this graph Eulerian?" 179 | ] 180 | }, 181 | { 182 | "cell_type": "code", 183 | "execution_count": null, 184 | "metadata": { 185 | "collapsed": false 186 | }, 187 | "outputs": [], 188 | "source": [ 189 | "print(nx.is_eulerian(G))" 190 | ] 191 | }, 192 | { 193 | "cell_type": "markdown", 194 | "metadata": { 195 | "slideshow": { 196 | "slide_type": "subslide" 197 | } 198 | }, 199 | "source": [ 200 | "No, it is not. We can even get Python to print it more nicely:" 201 | ] 202 | }, 203 | { 204 | "cell_type": "code", 205 | "execution_count": null, 206 | "metadata": { 207 | "collapsed": false 208 | }, 209 | "outputs": [], 210 | "source": [ 211 | "print(\"The graph {} Eulerian.\".format(\"is\" if nx.is_eulerian(G) else \"is not\"))" 212 | ] 213 | }, 214 | { 215 | "cell_type": "markdown", 216 | "metadata": { 217 | "slideshow": { 218 | "slide_type": "subslide" 219 | } 220 | }, 221 | "source": [ 222 | "Let us now require to pass the bridges $c$ (top left) and $f$ (lower right) twice. How do we do that?" 223 | ] 224 | }, 225 | { 226 | "cell_type": "markdown", 227 | "metadata": { 228 | "slideshow": { 229 | "slide_type": "subslide" 230 | } 231 | }, 232 | "source": [ 233 | "Instead of messing with the graph theory and adding additional parameter \"you may pass this edge <this many> times\", we simply add two more edges and keep the constraint \"pass each edge exactly once\":\n", 234 | "\n", 235 | "
" 236 | ] 237 | }, 238 | { 239 | "cell_type": "code", 240 | "execution_count": null, 241 | "metadata": { 242 | "collapsed": false, 243 | "slideshow": { 244 | "slide_type": "subslide" 245 | } 246 | }, 247 | "outputs": [], 248 | "source": [ 249 | "import networkx as nx\n", 250 | "\n", 251 | "G = nx.MultiGraph()\n", 252 | "\n", 253 | "G.add_nodes_from([\"C\", \"A\", \"D\", \"B\"])\n", 254 | "G.add_edges_from([\n", 255 | " (\"C\",\"A\"), (\"C\",\"A\"), (\"A\",\"B\"), (\"A\",\"B\"), (\"C\", \"D\"), (\"A\", \"D\"), (\"B\", \"D\"),\n", 256 | " (\"A\", \"C\"), (\"B\", \"D\") # new edges\n", 257 | "])\n", 258 | "\n", 259 | "print(\"Nodes:\", \", \".join(sorted(G.nodes())))\n", 260 | "print(\"Edges:\", \", \".join(sorted(\"{{{}}}\".format(\",\".join(sorted(t))) for t in G.edges())))\n", 261 | "print(\"The graph {} Eulerian.\".format(\"is\" if nx.is_eulerian(G) else \"is not\"))\n", 262 | "print(\"Eulerian circuit:\", list(nx.eulerian_circuit(G)))\n", 263 | "ec = list(nx.eulerian_circuit(G))\n", 264 | "print(\"A bit prettier: {}->{}\".format(ec[0][0], \"->\".join(t[1] for t in ec)))" 265 | ] 266 | }, 267 | { 268 | "cell_type": "markdown", 269 | "metadata": { 270 | "slideshow": { 271 | "slide_type": "subslide" 272 | } 273 | }, 274 | "source": [ 275 | "## Isomorphic (\"pretty much identical\") graphs\n", 276 | "\n", 277 | "The [notes of the second MATH20902 lecture](http://www.maths.manchester.ac.uk/~mrm/Teaching/DiscreteMaths/LectureNotes/RepresentingGraphs.pdf) introduce the term *graph isomorphism* which defines when two graphs can be considered the same. The lectures also provide an example of three (not obviously) isomporhic graphs:\n", 278 | "\n", 279 | "![](11a-isomorphic_graphs.png)" 280 | ] 281 | }, 282 | { 283 | "cell_type": "markdown", 284 | "metadata": { 285 | "slideshow": { 286 | "slide_type": "subslide" 287 | } 288 | }, 289 | "source": [ 290 | "Let us first create these graphs in Python:" 291 | ] 292 | }, 293 | { 294 | "cell_type": "code", 295 | "execution_count": null, 296 | "metadata": { 297 | "collapsed": false 298 | }, 299 | "outputs": [], 300 | "source": [ 301 | "import networkx as nx\n", 302 | "\n", 303 | "G1 = nx.Graph()\n", 304 | "G1.add_edges_from([\n", 305 | " (1,2), (2,4), (4,3), (3,1),\n", 306 | " (1,5), (2,6), (4,8), (3,7),\n", 307 | " (5,6), (6,8), (8,7), (7,5),\n", 308 | "])\n", 309 | "G2 = nx.Graph()\n", 310 | "G2.add_edges_from([\n", 311 | " (\"000\", \"001\"), (\"000\", \"010\"), (\"000\", \"100\"),\n", 312 | " (\"011\", \"001\"), (\"011\", \"010\"), (\"011\", \"111\"),\n", 313 | " (\"110\", \"010\"), (\"110\", \"100\"), (\"110\", \"111\"),\n", 314 | " (\"101\", \"001\"), (\"101\", \"100\"), (\"101\", \"111\"),\n", 315 | "])\n", 316 | "G3 = nx.Graph()\n", 317 | "G3.add_edges_from([\n", 318 | " (\"a\",\"b\"), (\"b\",\"d\"), (\"d\",\"c\"), (\"c\",\"a\"),\n", 319 | " (\"a\",\"e\"), (\"b\",\"f\"), (\"d\",\"h\"), (\"c\",\"g\"),\n", 320 | " (\"e\",\"f\"), (\"f\",\"h\"), (\"h\",\"g\"), (\"g\",\"e\"),\n", 321 | "])" 322 | ] 323 | }, 324 | { 325 | "cell_type": "markdown", 326 | "metadata": { 327 | "slideshow": { 328 | "slide_type": "-" 329 | } 330 | }, 331 | "source": [ 332 | "**Note:** As you can see, we don't need to add the nodes explicitly (except those that have no edges connected to them)." 333 | ] 334 | }, 335 | { 336 | "cell_type": "markdown", 337 | "metadata": { 338 | "slideshow": { 339 | "slide_type": "subslide" 340 | } 341 | }, 342 | "source": [ 343 | "Now we can easily check if they are isommorphic:" 344 | ] 345 | }, 346 | { 347 | "cell_type": "code", 348 | "execution_count": null, 349 | "metadata": { 350 | "collapsed": false 351 | }, 352 | "outputs": [], 353 | "source": [ 354 | "print(\"Are G1 and G2 isomorphic?\", nx.is_isomorphic(G1, G2))\n", 355 | "print(\"Are G1 and G3 isomorphic?\", nx.is_isomorphic(G1, G3))\n", 356 | "print(\"Are G2 and G3 isomorphic?\", nx.is_isomorphic(G2, G3))" 357 | ] 358 | }, 359 | { 360 | "cell_type": "markdown", 361 | "metadata": { 362 | "slideshow": { 363 | "slide_type": "subslide" 364 | } 365 | }, 366 | "source": [ 367 | "The lecture notes also explain how hard of a task it is to determine if two graphs are isomorphic or not, it gives some criterions to help us find the negative answer more quickly in many cases, and it gives the following two graphs that evade the (fast) criterion of degree sequences:\n", 368 | "\n", 369 | "![Two non-isomorphic graphs](11a-non_isomorphic.png)" 370 | ] 371 | }, 372 | { 373 | "cell_type": "markdown", 374 | "metadata": { 375 | "slideshow": { 376 | "slide_type": "subslide" 377 | } 378 | }, 379 | "source": [ 380 | "These criteria are also supported by NetworkX, so let us test all that this module has to offer:" 381 | ] 382 | }, 383 | { 384 | "cell_type": "code", 385 | "execution_count": null, 386 | "metadata": { 387 | "collapsed": false 388 | }, 389 | "outputs": [], 390 | "source": [ 391 | "import networkx as nx\n", 392 | "\n", 393 | "G1 = nx.Graph()\n", 394 | "G1.add_edges_from([\n", 395 | " (\"v1\", \"v2\"), (\"v2\", \"v3\"), (\"v3\", \"v4\"), (\"v4\", \"v5\"), (\"v2\", \"v5\")\n", 396 | "])\n", 397 | "\n", 398 | "G2 = nx.Graph()\n", 399 | "G2.add_edges_from([\n", 400 | " (\"u1\", \"u2\"), (\"u2\", \"u3\"), (\"u3\", \"u4\"), (\"u4\", \"u5\"), (\"u3\", \"u5\")\n", 401 | "])\n", 402 | "\n", 403 | "print(\"Could G1 and G2 be isomorphic (faster)?\", nx.faster_could_be_isomorphic(G1, G2))\n", 404 | "print(\"Could G1 and G2 be isomorphic (fast)?\", nx.fast_could_be_isomorphic(G1, G2))\n", 405 | "print(\"Could G1 and G2 be isomorphic?\", nx.could_be_isomorphic(G1, G2))\n", 406 | "print(\"Are G1 and G2 isomorphic?\", nx.is_isomorphic(G1, G2))" 407 | ] 408 | }, 409 | { 410 | "cell_type": "markdown", 411 | "metadata": { 412 | "slideshow": { 413 | "slide_type": "subslide" 414 | } 415 | }, 416 | "source": [ 417 | "The functions used here are:\n", 418 | "\n", 419 | "* [faster_could_be_isomorphic](https://networkx.github.io/documentation/latest/reference/generated/networkx.algorithms.isomorphism.faster_could_be_isomorphic.html) -- checks for matching degree sequences,\n", 420 | "\n", 421 | "* [fast_could_be_isomorphic](https://networkx.github.io/documentation/latest/reference/generated/networkx.algorithms.isomorphism.fast_could_be_isomorphic.html) -- checks for matching degree and triangle sequences,\n", 422 | "\n", 423 | "* [could_be_isomorphic](https://networkx.github.io/documentation/latest/reference/generated/networkx.algorithms.isomorphism.could_be_isomorphic.html) -- checks for matching degree, triangle, and number of cliques sequences,\n", 424 | "\n", 425 | "* [is_isomorphic](https://networkx.github.io/documentation/latest/reference/generated/networkx.algorithms.isomorphism.is_isomorphic.html) -- returns `True` if the graphs are isomorphic and `False` otherwise. It can be slow on big graphs." 426 | ] 427 | }, 428 | { 429 | "cell_type": "markdown", 430 | "metadata": { 431 | "slideshow": { 432 | "slide_type": "subslide" 433 | } 434 | }, 435 | "source": [ 436 | "## Plotting graphs\n", 437 | "\n", 438 | "NetworkX has some ability to plot graphs, but this is not its primary purpose. There are several interfaces that can be used, but some of them have to be installed separately. However, the support for plotting graphs via Matplotlib usually comes with the default installation. Let us first prepare Matplotlib for use in this document:" 439 | ] 440 | }, 441 | { 442 | "cell_type": "code", 443 | "execution_count": null, 444 | "metadata": { 445 | "collapsed": false 446 | }, 447 | "outputs": [], 448 | "source": [ 449 | "%matplotlib inline\n", 450 | "import matplotlib.pylab as pylab\n", 451 | "pylab.rcParams['figure.figsize'] = (4, 3)" 452 | ] 453 | }, 454 | { 455 | "cell_type": "markdown", 456 | "metadata": { 457 | "slideshow": { 458 | "slide_type": "subslide" 459 | } 460 | }, 461 | "source": [ 462 | "Here is a simple way to draw the previous two graphs:" 463 | ] 464 | }, 465 | { 466 | "cell_type": "code", 467 | "execution_count": null, 468 | "metadata": { 469 | "collapsed": false 470 | }, 471 | "outputs": [], 472 | "source": [ 473 | "import matplotlib.pyplot as plt\n", 474 | "\n", 475 | "nx.draw_networkx(G1)\n", 476 | "plt.axis(\"off\")\n", 477 | "plt.show()\n", 478 | "\n", 479 | "nx.draw_networkx(G2)\n", 480 | "plt.axis(\"off\")\n", 481 | "plt.show()" 482 | ] 483 | }, 484 | { 485 | "cell_type": "markdown", 486 | "metadata": { 487 | "slideshow": { 488 | "slide_type": "subslide" 489 | } 490 | }, 491 | "source": [ 492 | "Sometimes, it may be more convenient to draw graphs by putting their nodes on a circle:" 493 | ] 494 | }, 495 | { 496 | "cell_type": "code", 497 | "execution_count": null, 498 | "metadata": { 499 | "collapsed": false 500 | }, 501 | "outputs": [], 502 | "source": [ 503 | "nx.draw_networkx(G1, pos=nx.circular_layout(G1))\n", 504 | "plt.axis(\"off\")\n", 505 | "plt.show()\n", 506 | "\n", 507 | "nx.draw_networkx(G2, pos=nx.circular_layout(G2))\n", 508 | "plt.axis(\"off\")\n", 509 | "plt.show()" 510 | ] 511 | }, 512 | { 513 | "cell_type": "markdown", 514 | "metadata": { 515 | "slideshow": { 516 | "slide_type": "subslide" 517 | } 518 | }, 519 | "source": [ 520 | "Other (automatic) layouts are possible as well. You can find them [here](https://networkx.github.io/documentation/latest/reference/drawing.html#module-networkx.drawing.layout)." 521 | ] 522 | }, 523 | { 524 | "cell_type": "markdown", 525 | "metadata": { 526 | "slideshow": { 527 | "slide_type": "subslide" 528 | } 529 | }, 530 | "source": [ 531 | "We can also do plenty of other customizations, like positions of nodes, the sizes of the nodes, color changes, and custom edge width:" 532 | ] 533 | }, 534 | { 535 | "cell_type": "code", 536 | "execution_count": null, 537 | "metadata": { 538 | "collapsed": false 539 | }, 540 | "outputs": [], 541 | "source": [ 542 | "plt.figure(figsize=(6,2)) \n", 543 | "nx.draw_networkx(G1,\n", 544 | " pos={\"v1\": (0,1), \"v2\": (2,1), \"v3\": (3.5,2), \"v4\": (5,1), \"v5\": (3.5,0)},\n", 545 | " node_size=750, node_color=\"yellow\",\n", 546 | " edge_color=\"red\", width=2\n", 547 | ")\n", 548 | "plt.axis(\"off\")\n", 549 | "plt.show()" 550 | ] 551 | }, 552 | { 553 | "cell_type": "markdown", 554 | "metadata": { 555 | "slideshow": { 556 | "slide_type": "subslide" 557 | } 558 | }, 559 | "source": [ 560 | "We can also use the fact that Matplotlib can process $\\LaTeX$. With a more precise color adjustment (using the [HTML color codes](http://html-color-codes.info/)) and changing the thickness of the nodes circles, we can get a plot fairly similar to the one from the lecture notes:" 561 | ] 562 | }, 563 | { 564 | "cell_type": "code", 565 | "execution_count": null, 566 | "metadata": { 567 | "collapsed": false 568 | }, 569 | "outputs": [], 570 | "source": [ 571 | "G2 = nx.Graph()\n", 572 | "G2.add_edges_from([\n", 573 | " (\"$u_1$\", \"$u_2$\"), (\"$u_2$\", \"$u_3$\"), (\"$u_3$\", \"$u_4$\"), (\"$u_4$\", \"$u_5$\"), (\"$u_3$\", \"$u_5$\")\n", 574 | "])\n", 575 | "plt.figure(figsize=(6,2))\n", 576 | "nx.draw_networkx(G2,\n", 577 | " pos={\"$u_1$\": (0,1), \"$u_2$\": (2,1), \"$u_3$\": (4,1), \"$u_4$\": (5.5,2), \"$u_5$\": (5.5,0)},\n", 578 | " font_size=17,\n", 579 | " node_size=750, node_color=\"#caeeeb\", linewidths=2,\n", 580 | " width=2\n", 581 | ")\n", 582 | "plt.axis(\"off\")\n", 583 | "plt.show()" 584 | ] 585 | }, 586 | { 587 | "cell_type": "markdown", 588 | "metadata": { 589 | "slideshow": { 590 | "slide_type": "subslide" 591 | } 592 | }, 593 | "source": [ 594 | "Plotting multigraphs, however, requires more advanced solutions, because the simple one that we used above will not show multiple edges, as we can see if we try to plot the original Königsberg bridges graph (the one with the exactly one walk over each bridge):" 595 | ] 596 | }, 597 | { 598 | "cell_type": "code", 599 | "execution_count": null, 600 | "metadata": { 601 | "collapsed": false 602 | }, 603 | "outputs": [], 604 | "source": [ 605 | "import networkx as nx\n", 606 | "\n", 607 | "G = nx.MultiGraph()\n", 608 | "\n", 609 | "# The original Königsberg bridges graph\n", 610 | "G.add_nodes_from([\"C\", \"A\", \"D\", \"B\"])\n", 611 | "G.add_edges_from([\n", 612 | " (\"C\",\"A\"), (\"C\",\"A\"), (\"A\",\"B\"), (\"A\",\"B\"), (\"C\", \"D\"), (\"A\", \"D\"), (\"B\", \"D\"),\n", 613 | "])\n", 614 | "\n", 615 | "nx.draw_networkx(G, pos=nx.circular_layout(G))\n", 616 | "plt.axis(\"off\")\n", 617 | "plt.show()" 618 | ] 619 | }, 620 | { 621 | "cell_type": "markdown", 622 | "metadata": { 623 | "slideshow": { 624 | "slide_type": "subslide" 625 | } 626 | }, 627 | "source": [ 628 | "For those interested in better visual representations of graphs, you can plot your graphs using [draw_graphviz](https://networkx.github.io/documentation/latest/reference/generated/networkx.drawing.nx_pylab.draw_graphviz.html#networkx.drawing.nx_pylab.draw_graphviz). However, this requires [Graphviz](http://www.graphviz.org/) and its [Python module](https://pypi.python.org/pypi/graphviz).\n", 629 | "\n", 630 | "Without extra installations, you also export your graphs as [DOT files](http://www.graphviz.org/Documentation/dotguide.pdf) which can then be handled or drawn by Graphviz or some other program recognizing the format, without installing Graphviz Python module.\n", 631 | "\n", 632 | "Without much adjustments, the Königsberg bridges graph plotted with Graphviz looks like this:\n", 633 | "\n", 634 | "![Königsberg bridges graph plotted with Graphviz](11a-konigsberg_bridges_graphviz.png)\n", 635 | "\n", 636 | "As a program specialized for plotting graphs, [Graphviz can do much more](http://www.graphviz.org/Gallery.php)." 637 | ] 638 | }, 639 | { 640 | "cell_type": "markdown", 641 | "metadata": { 642 | "slideshow": { 643 | "slide_type": "subslide" 644 | } 645 | }, 646 | "source": [ 647 | "## Paths and trees\n", 648 | "\n", 649 | "The [notes of the third MATH20902 lecture](http://www.maths.manchester.ac.uk/~mrm/Teaching/DiscreteMaths/LectureNotes/WalksTrailsAndPaths.pdf) introduce walks, trails, paths, and many other terms which go beyond the scope of this lecture. In the [notes of the fourth MATH20902 lecture](http://www.maths.manchester.ac.uk/~mrm/Teaching/DiscreteMaths/LectureNotes/TreesAndForests.pdf), this builds up to trees and forests. Let us observe the following four graphs from that lecture's Figure 4.1:\n", 650 | "\n", 651 | "![Trees and forests](11a-trees_and_forests.png)" 652 | ] 653 | }, 654 | { 655 | "cell_type": "markdown", 656 | "metadata": { 657 | "slideshow": { 658 | "slide_type": "subslide" 659 | } 660 | }, 661 | "source": [ 662 | "First, we define these graphs:" 663 | ] 664 | }, 665 | { 666 | "cell_type": "code", 667 | "execution_count": null, 668 | "metadata": { 669 | "collapsed": false 670 | }, 671 | "outputs": [], 672 | "source": [ 673 | "import networkx as nx\n", 674 | "\n", 675 | "white = nx.Graph()\n", 676 | "white.add_path([1, 2, 3, 4, 5])\n", 677 | "white.add_edges_from([(2,6), (3,7)])\n", 678 | "\n", 679 | "yellow = nx.Graph()\n", 680 | "yellow.add_path(list(range(1,9))) # from bottom left to the lower one on the far right\n", 681 | "yellow.add_edges_from([\n", 682 | " (2,9), # far left\n", 683 | " (3,10), # next to it\n", 684 | " (4,11), (11,12), (11,13), # the left \"Y\"\n", 685 | " (5,14), (14,15), (14,16), # the bottom right \"Y\"\n", 686 | " (6,17), (7,18) # the remaining two branches on the top right\n", 687 | "])\n", 688 | "\n", 689 | "green = nx.Graph()\n", 690 | "green.add_edges_from([\n", 691 | " (1,2), (3,4), # two small trees\n", 692 | "])\n", 693 | "green.add_path([5, 6, 7]) # the V-shaped tree\n", 694 | "\n", 695 | "grey = nx.Graph()\n", 696 | "grey.add_path([list(range(1,10))]) # from top right, through the cycle, until almost closed\n", 697 | "grey.add_edges_from([\n", 698 | " (3,9), # close the cycle\n", 699 | " (8,10), # the node inside the cycle\n", 700 | " (2,11), (4,12), (5,13) # the remaining nodes and edges\n", 701 | "])" 702 | ] 703 | }, 704 | { 705 | "cell_type": "markdown", 706 | "metadata": {}, 707 | "source": [ 708 | "So, which of these are trees?" 709 | ] 710 | }, 711 | { 712 | "cell_type": "markdown", 713 | "metadata": { 714 | "slideshow": { 715 | "slide_type": "subslide" 716 | } 717 | }, 718 | "source": [ 719 | "NetworkX documentation isn't helping much. There is no `is_tree` function nor anything similar. However, the solution is not hard: we can use Theorem 4.13 from the aforementioned notes:\n", 720 | "\n", 721 | "> Theorem 4.13 (Jungnickel’s Theorem 1.2.8). For a graph $G(V, E)$ on $|V| = n$ vertices, any two of the following imply the third: \n", 722 | "(a) $G$ is connected. \n", 723 | "(b) $G$ is acyclic. \n", 724 | "(c) $G$ has $n-1$ edges.\n", 725 | "\n", 726 | "So, we can just compare the number of edges and the number of nodes and check that the graph is connected. A [simple Googling](https://www.google.co.uk/search?q=networkx+check+if+a+graph+is+a+tree) will even give us a ready-made solution by the user Aric in [this answer](http://stackoverflow.com/a/16628381/1667018) on Stack Overflow:" 727 | ] 728 | }, 729 | { 730 | "cell_type": "code", 731 | "execution_count": null, 732 | "metadata": { 733 | "collapsed": false, 734 | "slideshow": { 735 | "slide_type": "subslide" 736 | } 737 | }, 738 | "outputs": [], 739 | "source": [ 740 | "def is_tree(G):\n", 741 | " \"\"\"\n", 742 | " Returns `True` if `G` is a tree and `False` otherwise.\n", 743 | " \"\"\"\n", 744 | " if nx.number_of_nodes(G) != nx.number_of_edges(G) + 1:\n", 745 | " return False\n", 746 | " return nx.is_connected(G)" 747 | ] 748 | }, 749 | { 750 | "cell_type": "markdown", 751 | "metadata": {}, 752 | "source": [ 753 | "Let us now check our three graphs:" 754 | ] 755 | }, 756 | { 757 | "cell_type": "code", 758 | "execution_count": null, 759 | "metadata": { 760 | "collapsed": false 761 | }, 762 | "outputs": [], 763 | "source": [ 764 | "print(\"Is the white graph a tree?\", is_tree(white))\n", 765 | "print(\"Is the yellow graph a tree?\", is_tree(yellow))\n", 766 | "print(\"Is the green graph a tree?\", is_tree(green))\n", 767 | "print(\"Is the grey graph a tree?\", is_tree(grey))" 768 | ] 769 | }, 770 | { 771 | "cell_type": "markdown", 772 | "metadata": {}, 773 | "source": [ 774 | "Let us now plot the yellow graph:" 775 | ] 776 | }, 777 | { 778 | "cell_type": "code", 779 | "execution_count": null, 780 | "metadata": { 781 | "collapsed": false 782 | }, 783 | "outputs": [], 784 | "source": [ 785 | "pos = {\n", 786 | " # Main path\n", 787 | " 1: (0.1,0),\n", 788 | " 2: (1,0.9),\n", 789 | " 3: (1.9,1.7),\n", 790 | " 4: (3,2.2),\n", 791 | " 5: (4,2),\n", 792 | " 6: (4.5,2.5),\n", 793 | " 7: (5.5,2.2),\n", 794 | " 8: (6.5,1.5),\n", 795 | " # Far left\n", 796 | " 9: (0,1),\n", 797 | " # Next to it\n", 798 | " 10: (0.5,2.3),\n", 799 | " # The left \"Y\"\n", 800 | " 11: (2.1,2.7),\n", 801 | " 12: (1,2.9),\n", 802 | " 13: (1.2,3.5),\n", 803 | " # The bottom right \"Y\"\n", 804 | " 14: (5,1.5),\n", 805 | " 15: (4.5,0.75),\n", 806 | " 16: (5.7,0.7),\n", 807 | " # The remaining two branches on the top right\n", 808 | " 17: (5.5,3.2),\n", 809 | " 18: (6.5,2.6),\n", 810 | "}\n", 811 | "plt.figure(figsize=(7,4))\n", 812 | "nx.draw_networkx(yellow,\n", 813 | " pos=pos,\n", 814 | " node_size=350, node_color=\"#fdde57\", linewidths=1,\n", 815 | " width=1\n", 816 | ")\n", 817 | "plt.axis(\"off\")\n", 818 | "plt.show()" 819 | ] 820 | }, 821 | { 822 | "cell_type": "markdown", 823 | "metadata": { 824 | "slideshow": { 825 | "slide_type": "subslide" 826 | } 827 | }, 828 | "source": [ 829 | "Not a perfect match of the positions, but close enough to see that it is the same graph." 830 | ] 831 | }, 832 | { 833 | "cell_type": "markdown", 834 | "metadata": { 835 | "slideshow": { 836 | "slide_type": "subslide" 837 | } 838 | }, 839 | "source": [ 840 | "Now, let us plot the same graph without the labels:" 841 | ] 842 | }, 843 | { 844 | "cell_type": "code", 845 | "execution_count": null, 846 | "metadata": { 847 | "collapsed": false 848 | }, 849 | "outputs": [], 850 | "source": [ 851 | "plt.figure(figsize=(7,4))\n", 852 | "nx.draw(yellow,\n", 853 | " pos=pos,\n", 854 | " node_size=350, node_color=\"#fdde57\", linewidths=1,\n", 855 | " width=1\n", 856 | ")\n", 857 | "plt.axis(\"off\")\n", 858 | "plt.show()" 859 | ] 860 | }, 861 | { 862 | "cell_type": "markdown", 863 | "metadata": { 864 | "slideshow": { 865 | "slide_type": "subslide" 866 | } 867 | }, 868 | "source": [ 869 | "And now let us plot the graph in the way that the leaves remain yellow, but the rest of the nodes are white.\n", 870 | "\n", 871 | "To achieve this, we shall plot our graph in three steps:\n", 872 | "\n", 873 | "1. Draw the edges,\n", 874 | "\n", 875 | "2. Draw the leaves,\n", 876 | "\n", 877 | "3. Draw the remaining nodes." 878 | ] 879 | }, 880 | { 881 | "cell_type": "code", 882 | "execution_count": null, 883 | "metadata": { 884 | "collapsed": false, 885 | "slideshow": { 886 | "slide_type": "subslide" 887 | } 888 | }, 889 | "outputs": [], 890 | "source": [ 891 | "plt.figure(figsize=(7,4))\n", 892 | "\n", 893 | "# Draw the edges\n", 894 | "nx.draw_networkx_edges(yellow,\n", 895 | " pos=pos,\n", 896 | " width=1\n", 897 | ")\n", 898 | "# Draw the leaves\n", 899 | "nx.draw_networkx_nodes(yellow,\n", 900 | " pos=pos,\n", 901 | " node_size=350, node_color=\"#fdde57\", linewidths=1,\n", 902 | " nodelist=[node for node in yellow.nodes() if len(yellow.neighbors(node)) == 1]\n", 903 | ")\n", 904 | "# Draw the remaining nodes\n", 905 | "nx.draw_networkx_nodes(yellow,\n", 906 | " pos=pos,\n", 907 | " node_size=350, node_color=\"white\", linewidths=1,\n", 908 | " nodelist=[node for node in yellow.nodes() if len(yellow.neighbors(node)) != 1]\n", 909 | ")\n", 910 | "plt.axis(\"off\")\n", 911 | "plt.show()" 912 | ] 913 | }, 914 | { 915 | "cell_type": "markdown", 916 | "metadata": { 917 | "slideshow": { 918 | "slide_type": "subslide" 919 | } 920 | }, 921 | "source": [ 922 | "Let us draw the same, but with the labels and with the path $(10, 3, 4, 5, 14, 15)$ marked light green (*lime*):" 923 | ] 924 | }, 925 | { 926 | "cell_type": "code", 927 | "execution_count": null, 928 | "metadata": { 929 | "collapsed": false, 930 | "slideshow": { 931 | "slide_type": "-" 932 | } 933 | }, 934 | "outputs": [], 935 | "source": [ 936 | "plt.figure(figsize=(7,4))\n", 937 | "\n", 938 | "path = [10, 3, 4, 5, 14, 15]\n", 939 | "\n", 940 | "# Draw the edges\n", 941 | "nx.draw_networkx_edges(yellow,\n", 942 | " pos=pos,\n", 943 | " width=1\n", 944 | ")\n", 945 | "# Draw the leaves\n", 946 | "nx.draw_networkx_nodes(yellow,\n", 947 | " pos=pos,\n", 948 | " node_size=450, node_color=\"#fdde57\", linewidths=1,\n", 949 | " nodelist=[node for node in yellow.nodes() if len(yellow.neighbors(node)) == 1]\n", 950 | ")\n", 951 | "# Draw the remaining nodes\n", 952 | "nx.draw_networkx_nodes(yellow,\n", 953 | " pos=pos,\n", 954 | " node_size=450, node_color=\"white\", linewidths=1,\n", 955 | " nodelist=[node for node in yellow.nodes() if len(yellow.neighbors(node)) != 1]\n", 956 | ")\n", 957 | "# Draw labels\n", 958 | "nx.draw_networkx_labels(yellow,\n", 959 | " pos=pos,\n", 960 | ")\n", 961 | "\n", 962 | "# Draw the path nodes in light red with a \"glow\" effect\n", 963 | "# (actually, a \"strong\" red with a low alpha and thick lines)\n", 964 | "nodes = nx.draw_networkx_nodes(yellow,\n", 965 | " pos=pos,\n", 966 | " alpha=0.2,\n", 967 | " node_size=450, node_color=\"lime\", linewidths=5,\n", 968 | " nodelist=path\n", 969 | ")\n", 970 | "nodes.set_edgecolor('lime')\n", 971 | "nx.draw_networkx_edges(yellow,\n", 972 | " pos=pos,\n", 973 | " alpha=0.2, edge_color=\"lime\",\n", 974 | " width=5,\n", 975 | " edgelist=[ (f,t) for f,t in zip(path, path[1:])]\n", 976 | ")\n", 977 | "\n", 978 | "plt.axis(\"off\")\n", 979 | "plt.show()" 980 | ] 981 | }, 982 | { 983 | "cell_type": "markdown", 984 | "metadata": { 985 | "slideshow": { 986 | "slide_type": "subslide" 987 | } 988 | }, 989 | "source": [ 990 | "**Note:** Be careful when plotting graphs in several steps, as the positions of the nodes are given randomly by some layouts (for example, the [*spring* layout](https://networkx.github.io/documentation/latest/reference/generated/networkx.drawing.layout.spring_layout.html)). For example, our above \"yellow leaves, white inner nodes, no labels\" plot, with the positions defined by the `spring_layout` function, might not look as glamourous as before:" 991 | ] 992 | }, 993 | { 994 | "cell_type": "code", 995 | "execution_count": null, 996 | "metadata": { 997 | "collapsed": false, 998 | "slideshow": { 999 | "slide_type": "-" 1000 | } 1001 | }, 1002 | "outputs": [], 1003 | "source": [ 1004 | "plt.figure(figsize=(7,4))\n", 1005 | "\n", 1006 | "# Draw the edges\n", 1007 | "nx.draw_networkx_edges(yellow,\n", 1008 | " pos=nx.spring_layout(yellow),\n", 1009 | " width=1\n", 1010 | ")\n", 1011 | "# Draw the leaves\n", 1012 | "nx.draw_networkx_nodes(yellow,\n", 1013 | " pos=nx.spring_layout(yellow),\n", 1014 | " node_size=350, node_color=\"#fdde57\", linewidths=1,\n", 1015 | " nodelist=[node for node in yellow.nodes() if len(yellow.neighbors(node)) == 1]\n", 1016 | ")\n", 1017 | "# Draw the remaining nodes\n", 1018 | "nx.draw_networkx_nodes(yellow,\n", 1019 | " pos=nx.spring_layout(yellow),\n", 1020 | " node_size=350, node_color=\"white\", linewidths=1,\n", 1021 | " nodelist=[node for node in yellow.nodes() if len(yellow.neighbors(node)) != 1]\n", 1022 | ")\n", 1023 | "plt.axis(\"off\")\n", 1024 | "plt.show()" 1025 | ] 1026 | }, 1027 | { 1028 | "cell_type": "markdown", 1029 | "metadata": { 1030 | "slideshow": { 1031 | "slide_type": "subslide" 1032 | } 1033 | }, 1034 | "source": [ 1035 | "The proper way to do this is to preserve the positions in a variable and then use it in all three calls to the `draw_networkx_*` functions:" 1036 | ] 1037 | }, 1038 | { 1039 | "cell_type": "code", 1040 | "execution_count": null, 1041 | "metadata": { 1042 | "collapsed": false, 1043 | "slideshow": { 1044 | "slide_type": "-" 1045 | } 1046 | }, 1047 | "outputs": [], 1048 | "source": [ 1049 | "plt.figure(figsize=(7,4))\n", 1050 | "\n", 1051 | "# Define the positions via Fruchterman-Reingold force-directed algorithm\n", 1052 | "spos = nx.spring_layout(yellow)\n", 1053 | "\n", 1054 | "# Draw the edges\n", 1055 | "nx.draw_networkx_edges(yellow,\n", 1056 | " pos=spos,\n", 1057 | " width=1\n", 1058 | ")\n", 1059 | "# Draw the leaves\n", 1060 | "nx.draw_networkx_nodes(yellow,\n", 1061 | " pos=spos,\n", 1062 | " node_size=350, node_color=\"#fdde57\", linewidths=1,\n", 1063 | " nodelist=[node for node in yellow.nodes() if len(yellow.neighbors(node)) == 1]\n", 1064 | ")\n", 1065 | "# Draw the remaining nodes\n", 1066 | "nx.draw_networkx_nodes(yellow,\n", 1067 | " pos=spos,\n", 1068 | " node_size=350, node_color=\"white\", linewidths=1,\n", 1069 | " nodelist=[node for node in yellow.nodes() if len(yellow.neighbors(node)) != 1]\n", 1070 | ")\n", 1071 | "plt.axis(\"off\")\n", 1072 | "plt.show()" 1073 | ] 1074 | }, 1075 | { 1076 | "cell_type": "markdown", 1077 | "metadata": {}, 1078 | "source": [ 1079 | "Not the prettiest sight, but at least it is correct now. " 1080 | ] 1081 | }, 1082 | { 1083 | "cell_type": "markdown", 1084 | "metadata": { 1085 | "slideshow": { 1086 | "slide_type": "subslide" 1087 | } 1088 | }, 1089 | "source": [ 1090 | "Here is a simple display of all the available layouts in action (each one twice, to see which are randomized):" 1091 | ] 1092 | }, 1093 | { 1094 | "cell_type": "code", 1095 | "execution_count": null, 1096 | "metadata": { 1097 | "collapsed": false 1098 | }, 1099 | "outputs": [], 1100 | "source": [ 1101 | "for layout in [ nx.circular_layout, nx.random_layout,\n", 1102 | " nx.shell_layout, nx.spring_layout, nx.spectral_layout ]:\n", 1103 | " for k in range(1,3):\n", 1104 | "\n", 1105 | " print(\"{} ({})\".format(layout.__name__, k))\n", 1106 | "\n", 1107 | " plt.figure(figsize=(7,4))\n", 1108 | "\n", 1109 | " # Define the positions via Fruchterman-Reingold force-directed algorithm\n", 1110 | " spos = layout(yellow)\n", 1111 | "\n", 1112 | " # Draw the edges\n", 1113 | " nx.draw_networkx_edges(yellow,\n", 1114 | " pos=spos,\n", 1115 | " width=1\n", 1116 | " )\n", 1117 | " # Draw the leaves\n", 1118 | " nx.draw_networkx_nodes(yellow,\n", 1119 | " pos=spos,\n", 1120 | " node_size=350, node_color=\"#fdde57\", linewidths=1,\n", 1121 | " nodelist=[node for node in yellow.nodes() if len(yellow.neighbors(node)) == 1]\n", 1122 | " )\n", 1123 | " # Draw the remaining nodes\n", 1124 | " nx.draw_networkx_nodes(yellow,\n", 1125 | " pos=spos,\n", 1126 | " node_size=350, node_color=\"white\", linewidths=1,\n", 1127 | " nodelist=[node for node in yellow.nodes() if len(yellow.neighbors(node)) != 1]\n", 1128 | " )\n", 1129 | " plt.axis(\"off\")\n", 1130 | " plt.show()" 1131 | ] 1132 | }, 1133 | { 1134 | "cell_type": "markdown", 1135 | "metadata": { 1136 | "slideshow": { 1137 | "slide_type": "subslide" 1138 | } 1139 | }, 1140 | "source": [ 1141 | "## What more can be done?\n", 1142 | "\n", 1143 | "We can do a lot more:\n", 1144 | "\n", 1145 | "* The plots can be saved, the same way anything else in Matplotlib is saved: using the [savefig](http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.savefig) function.\n", 1146 | "\n", 1147 | "* We can work with weighted and with [directed graphs](http://networkx.lanl.gov/reference/classes.digraph.html).\n", 1148 | "\n", 1149 | "* We can do most of the usual things that are done with graphs, using NetworkX' rich [algorithms collection](https://networkx.github.io/documentation/latest/reference/algorithms.html)." 1150 | ] 1151 | } 1152 | ], 1153 | "metadata": { 1154 | "celltoolbar": "Slideshow" 1155 | }, 1156 | "nbformat": 4, 1157 | "nbformat_minor": 0 1158 | } 1159 | -------------------------------------------------------------------------------- /11a-graphs/konigsberg.dot: -------------------------------------------------------------------------------- 1 | graph { 2 | B -- A [key=0]; 3 | B -- A [key=1]; 4 | B -- D [key=0]; 5 | C -- A [key=0]; 6 | C -- A [key=1]; 7 | C -- D [key=0]; 8 | A -- D [key=0]; 9 | } 10 | -------------------------------------------------------------------------------- /11a-graphs/konigsberg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/11a-graphs/konigsberg.jpg -------------------------------------------------------------------------------- /11a-graphs/konigsberg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/11a-graphs/konigsberg.png -------------------------------------------------------------------------------- /11a-graphs/konigsberg.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import networkx as nx 4 | import matplotlib.pyplot as plt 5 | from PIL import Image 6 | from os import system 7 | 8 | #G = nx.complete_graph(5) 9 | G = nx.MultiGraph() 10 | 11 | #G.add_nodes_from(["C", "A", "D", "B"]) 12 | #G.add_edges_from([{"C","A"}, {"C","A"}, {"A","B"}, {"A","B"}, {"C", "D"}, {"A", "D"}, {"B", "D"}]) 13 | G.add_edges_from([("C","A"), ("C","A"), ("A","B"), ("A","B"), ("C", "D"), ("A", "D"), ("B", "D")]) 14 | #G.add_edges_from([("C","A"), ("A","B"), ("C", "D"), ("A", "D"), ("B", "D")]) 15 | #G.add_edges_from([("C","A"), ("C","A"), ("A","B"), ("A","B"), ("C", "D"), ("A", "D"), ("B", "D"), ("A", "C"), ("B", "D")]) 16 | print("Nodes:", G.nodes()) 17 | print("Edges:", G.edges()) 18 | print("Nodes:", ", ".join(sorted(G.nodes()))) 19 | print("Edges:", ", ".join(sorted("{{{}}}".format(",".join(sorted(t))) for t in G.edges()))) 20 | print("The graph {} Eulerian.".format("is" if nx.is_eulerian(G) else "is not")) 21 | 22 | spt = nx.minimum_spanning_edges(G, data=False) 23 | print(list(spt)) 24 | #print("Edges:", ", ".join(sorted("{{{}}}".format(",".join(sorted(t))) for t in spt))) 25 | #nx.set_node_attributes(G, "pos", {"C": { "pos": (0,2) }, "A": { "pos": (0,1) }, "D": { "pos": (1,0) }, "B": (0,0)}) 26 | #nx.draw_networkx(G, pos={"C": (0,2), "A": (0,1), "D": (1,0), "B": (0,0)}) 27 | #plt.axis("off") 28 | #plt.show() 29 | 30 | #nx.write_dot(G, "konigsberg.dot") 31 | #system("circo -T png konigsberg.dot > konigsberg.png") 32 | #img = Image.open('konigsberg.png') 33 | #img.show() 34 | -------------------------------------------------------------------------------- /11a-isomorphic_graphs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/11a-isomorphic_graphs.png -------------------------------------------------------------------------------- /11a-konigsberg_bridges.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/11a-konigsberg_bridges.jpg -------------------------------------------------------------------------------- /11a-konigsberg_bridges_blank.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/11a-konigsberg_bridges_blank.jpg -------------------------------------------------------------------------------- /11a-konigsberg_bridges_graph.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/11a-konigsberg_bridges_graph.jpg -------------------------------------------------------------------------------- /11a-konigsberg_bridges_graphviz.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/11a-konigsberg_bridges_graphviz.png -------------------------------------------------------------------------------- /11a-non_isomorphic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/11a-non_isomorphic.png -------------------------------------------------------------------------------- /11a-trees_and_forests.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/11a-trees_and_forests.png -------------------------------------------------------------------------------- /11c-flow-max_flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/11c-flow-max_flow.png -------------------------------------------------------------------------------- /11c-flow-min_cut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/11c-flow-min_cut.png -------------------------------------------------------------------------------- /11c-flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/11c-flow.png -------------------------------------------------------------------------------- /11c-flow2-max_flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/11c-flow2-max_flow.png -------------------------------------------------------------------------------- /11c-flow2-min_cut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/11c-flow2-min_cut.png -------------------------------------------------------------------------------- /11c-flow2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/11c-flow2.png -------------------------------------------------------------------------------- /11c-graphs.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Programming with Python (lab classes)\n", 8 | "#### Vedran Šego, [vsego.org](http://vsego.org/)\n", 9 | "\n", 10 | "## Content:\n", 11 | "\n", 12 | "1. Flow networks" 13 | ] 14 | }, 15 | { 16 | "cell_type": "markdown", 17 | "metadata": {}, 18 | "source": [ 19 | "**Note:** Some older versions of Anaconda have an old version of NetworkX that lacks some of the functionality needed to solve the problems below. Execute this program:\n", 20 | "```python\n", 21 | "import networkx\n", 22 | "print(networkx.__version__)\n", 23 | "```\n", 24 | "and if it prints the version smaller than 1.9.1, uninstall your Anaconda and download and install the new version.\n", 25 | "\n", 26 | "As a quick fix, you can instead download [networkx-anaconda_patch.zip](networkx-anaconda_patch.zip) (3.1MiB) and unzip it in the same directory in which you will write the solutions for the problems below." 27 | ] 28 | }, 29 | { 30 | "cell_type": "markdown", 31 | "metadata": {}, 32 | "source": [ 33 | "A [*flow network*](http://en.wikipedia.org/wiki/Flow_network) is a directed graph in which every arc (a directed edge) has a real-numbered, nonnegative *capacity*, and in which two nodes are distinguished from the others: the *source* (a node in which no arcs enter) and the *sink* (a node which no arcs leave). Here is an example of a flow:\n", 34 | "\n", 35 | "![Flow](11c-flow.png)\n", 36 | "\n", 37 | "The basic idea is to see how much of *something* can be \"sent\" through the network in a way that\n", 38 | "\n", 39 | "1. we never overflow the capacity of any of the edges, and\n", 40 | "\n", 41 | "2. each node except the source and the sink recieves and sends the same amount of *something* (i.e., nothing is retained nor created).\n", 42 | "\n", 43 | "This has a plethora of applications in modeling of electrical networks, internet traffic, public transportation, water supply networks, transportation of goods, international travel, etc.\n", 44 | "\n", 45 | "The most common questions here are:\n", 46 | "\n", 47 | "1. What is the capacity of the network, i.e., how much can we send from the source to the sink?\n", 48 | "\n", 49 | "2. What are the weak links in the network, i.e., where can we improve the network?\n", 50 | "\n", 51 | "The answer to the first one is the [maximum flow of the network](http://en.wikipedia.org/wiki/Maximum_flow_problem), while the answer to the second one is its *minimum cut* (the set of edges of the minimum total capacity that, when cut, split the graph in two or more unconnected components). Incidentally, [these two are the same](http://en.wikipedia.org/wiki/Max-flow_min-cut_theorem). For the above flow, the minimum cut is marked on the following image:\n", 52 | "\n", 53 | "![Minimum cut](11c-flow-min_cut.png)\n", 54 | "\n", 55 | "The maximum flow is simply the sum of the capacities of all the edges of the minimum cut. In our example, this is $5$.\n", 56 | "\n", 57 | "While it is nice to know *how much* we can send via network, it would also be nice to find out *how to actually achieve it*. For our problem, here is one such solution:\n", 58 | "\n", 59 | "![Maximum flow](11c-flow-max_flow.png)\n", 60 | "\n", 61 | "The numbers on the arcs now represent how much is transported through them. The function that assigns these numbers to the arcs (visualised in the above image) is called a *flow*." 62 | ] 63 | }, 64 | { 65 | "cell_type": "markdown", 66 | "metadata": {}, 67 | "source": [ 68 | "**Problem 1.** Write a module with a function\n", 69 | "```python\n", 70 | "def csv2digraph(fname, encoding=\"utf8\", delimiter=\",\", has_header=True, default_capacity=1):\n", 71 | "```\n", 72 | "that reads the CSV file `fname` with the columns \"From\", \"To\", and \"Weight\", creates a [networkx.DiGraph](http://networkx.lanl.gov/reference/classes.digraph.html) with the arcs (directed edges) corresponding to that info, and returns it.\n", 73 | "\n", 74 | "If `has_header` is `True`, the first line of the file is considered a header and is skipped. In case some of the capacity data is missing or malformed (not convertible to a number), the value `default_capacity` is used instead.\n", 75 | "\n", 76 | "If something is wrong with the file, the function should raise (actually, just pass on) the appropriate [OSError](https://docs.python.org/3/library/exceptions.html#os-exceptions) exception.\n", 77 | "\n", 78 | "**Hint:** To add an arc from `node_from` to `node_to` with a capacity `cap`, use\n", 79 | "```python\n", 80 | "networkx.add_edge(node_from, node_to, capacity=cap)\n", 81 | "```\n", 82 | "Since the data from the CSV files is loaded as strings, convert the capacities to integers. Those for which this conversion failes, should be converted to floats, and -- if that fails as well -- their value should be set to `default_capacity`.\n", 83 | "\n", 84 | "**Example:** The graphs that are plotted above are defined with the following CSV file:\n", 85 | "```\n", 86 | "From,To,Weight\n", 87 | "01,02,2\n", 88 | "01,03,5\n", 89 | "02,04,1\n", 90 | "02,05,2\n", 91 | "03,05,2\n", 92 | "03,06,1\n", 93 | "04,07,2\n", 94 | "05,07,5\n", 95 | "05,08,2\n", 96 | "05,09,1\n", 97 | "06,10,1\n", 98 | "04,11,2\n", 99 | "06,11,5\n", 100 | "07,12,2\n", 101 | "08,12,5\n", 102 | "09,12,2\n", 103 | "10,12,3\n", 104 | "11,12,7\n", 105 | "```" 106 | ] 107 | }, 108 | { 109 | "cell_type": "markdown", 110 | "metadata": {}, 111 | "source": [ 112 | "**Problem 2.** Add to the module the function `is_network(G)` that returns `True` if `G` is a [flow network](http://en.wikipedia.org/wiki/Flow_network) and `False` otherwise.\n", 113 | "\n", 114 | "You need to check that `G` has exactly one source and one sink, and that all of the capacities are convertible to floats (the `csv2digraph` function should make sure of that, but it is possible to create `G` without using that function).\n", 115 | "\n", 116 | "**Hint:** Additional functions `sources(G)`, `source(G)`, `sinks(G)`, and `sink(G)` could be useful for implementing this function and for solving the remaining problems in this document." 117 | ] 118 | }, 119 | { 120 | "cell_type": "markdown", 121 | "metadata": {}, 122 | "source": [ 123 | "**Problem 3.** Add to the module the function `network_layout(G)` that returns the layout for a network-like plotting of `G` (if `G` is not a network, it should raise a custom `NotNetworkError` exception).\n", 124 | "\n", 125 | "A layout is a dictionary in which the keys are the node labels and the values are tuples of their positions (in any scale). For example, the graphs above use the following layout:\n", 126 | "```python\n", 127 | "{\n", 128 | " '01': (0, 2.0),\n", 129 | " '02': (1, 1.5),\n", 130 | " '03': (1, 2.5),\n", 131 | " '04': (2, 1.0),\n", 132 | " '05': (2, 2.0),\n", 133 | " '06': (2, 3.0),\n", 134 | " '07': (3, 0.0),\n", 135 | " '08': (3, 1.0),\n", 136 | " '09': (3, 2.0),\n", 137 | " '10': (3, 3.0),\n", 138 | " '11': (3, 4.0),\n", 139 | " '12': (4, 2.0)\n", 140 | "}\n", 141 | "```" 142 | ] 143 | }, 144 | { 145 | "cell_type": "markdown", 146 | "metadata": {}, 147 | "source": [ 148 | "___\n", 149 | "The following problems involve plotting graphs. In order to do that more easily, find what is required (minimum cut arcs and maximum flow) and print them first to see the format of the data. Then use that data for plotting." 150 | ] 151 | }, 152 | { 153 | "cell_type": "markdown", 154 | "metadata": {}, 155 | "source": [ 156 | "**Problem 4.** Write a program that inputs the name of a CSV file, creates a digraph from its data, and plots it in a manner similar to the first image above. The graph should be shown on the screen and saved to the file with the same name as the CSV file, but with the extension changed to `\"png\"`.\n", 157 | "\n", 158 | "If you make a plotting function in the module, it should always check if the graph that it gets is a network." 159 | ] 160 | }, 161 | { 162 | "cell_type": "markdown", 163 | "metadata": {}, 164 | "source": [ 165 | "**Problem 5.** Write a program that inputs the name of a CSV file, creates a digraph from its data, finds its maximum flow value (how much can be sent through the network) and minimal cut, prints the former and plots the network in a manner similar to the second image above. The graph should be shown on the screen and saved to the file with the same name as the CSV file, but with the extension changed to `\"png\"`.\n", 166 | "\n", 167 | "Note that there can be more than one minimum cut (for example, in some of the graphs that have all their capacities set to the same value), so your drawing might differ from the above. However, the value of the maximum flow is unique for every flow network (as it must correspond to the total capacity of the edges in the minimum cut)." 168 | ] 169 | }, 170 | { 171 | "cell_type": "markdown", 172 | "metadata": {}, 173 | "source": [ 174 | "**Problem 6.** Write a program that inputs the name of a CSV file, creates a digraph from its data, finds one of its maximum flows and plots it in a manner similar to the third image above. The graph should be shown on the screen and saved to the file with the same name as the CSV file, but with the extension changed to `\"png\"`.\n", 175 | "\n", 176 | "Note that there can be more than one maximum flow (for example, in most of the graphs that have all their capacities set to the same value), so your drawing might differ from the above." 177 | ] 178 | }, 179 | { 180 | "cell_type": "markdown", 181 | "metadata": {}, 182 | "source": [ 183 | "## An additional example\n", 184 | "\n", 185 | "For the following CSV file:\n", 186 | "```\n", 187 | "From,To,Capacity\n", 188 | "01,02,1\n", 189 | "01,03,3\n", 190 | "01,04,5\n", 191 | "01,05,5\n", 192 | "01,06,3\n", 193 | "01,07,1\n", 194 | "02,08,1\n", 195 | "02,09,2\n", 196 | "03,09,3\n", 197 | "03,10,4\n", 198 | "04,10,5\n", 199 | "04,11,6\n", 200 | "05,11,6\n", 201 | "05,12,5\n", 202 | "06,12,4\n", 203 | "06,13,3\n", 204 | "07,13,2\n", 205 | "07,14,1\n", 206 | "08,15,2\n", 207 | "09,15,2\n", 208 | "10,15,2\n", 209 | "10,15,2\n", 210 | "11,15,2\n", 211 | "11,16,2\n", 212 | "12,15,2\n", 213 | "12,16,2\n", 214 | "13,16,2\n", 215 | "14,16,2\n", 216 | "09,16,2\n", 217 | "15,17,11\n", 218 | "16,17,11\n", 219 | "```\n", 220 | "the graphs plotted by the solutions of the above problems should look like this:\n", 221 | "![A flow network](11c-flow2.png)\n", 222 | "
A flow network
\n", 223 | "![Minimum cut](11c-flow2-min_cut.png)\n", 224 | "
A minimum cut
\n", 225 | "![Maximum flow](11c-flow2-max_flow.png)\n", 226 | "
A maximum flow
\n", 227 | "The maximum flow value is $17$." 228 | ] 229 | } 230 | ], 231 | "metadata": {}, 232 | "nbformat": 4, 233 | "nbformat_minor": 0 234 | } 235 | -------------------------------------------------------------------------------- /12a-chess.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/12a-chess.png -------------------------------------------------------------------------------- /12a-cosplays-resized/cosplay-fail-costume-thor.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/12a-cosplays-resized/cosplay-fail-costume-thor.jpg -------------------------------------------------------------------------------- /12a-cosplays-resized/cosplayers_fail_25.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/12a-cosplays-resized/cosplayers_fail_25.jpg -------------------------------------------------------------------------------- /12a-cosplays-resized/funny-cosplay-costumes-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/12a-cosplays-resized/funny-cosplay-costumes-3.png -------------------------------------------------------------------------------- /12a-cosplays-resized/funny-cosplay1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/12a-cosplays-resized/funny-cosplay1.jpg -------------------------------------------------------------------------------- /12a-cosplays-resized/funny-tomato-cosplay-subway-670925.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/12a-cosplays-resized/funny-tomato-cosplay-subway-670925.png -------------------------------------------------------------------------------- /12a-cosplays-resized/ninjaturtles.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/12a-cosplays-resized/ninjaturtles.jpg -------------------------------------------------------------------------------- /12a-cosplays-resized/tumblr_mg1x8nGSLj1qza05bo1_500.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/12a-cosplays-resized/tumblr_mg1x8nGSLj1qza05bo1_500.jpg -------------------------------------------------------------------------------- /12a-cosplays-resized/war machine cosplay fail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/12a-cosplays-resized/war machine cosplay fail.png -------------------------------------------------------------------------------- /12a-cosplays-resized/xmen-cosplay-18.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/12a-cosplays-resized/xmen-cosplay-18.jpg -------------------------------------------------------------------------------- /12a-cosplays.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/12a-cosplays.zip -------------------------------------------------------------------------------- /12a-cosplays/cosplay-fail-costume-thor.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/12a-cosplays/cosplay-fail-costume-thor.jpg -------------------------------------------------------------------------------- /12a-cosplays/cosplayers_fail_25.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/12a-cosplays/cosplayers_fail_25.jpg -------------------------------------------------------------------------------- /12a-cosplays/funny-cosplay-costumes-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/12a-cosplays/funny-cosplay-costumes-3.png -------------------------------------------------------------------------------- /12a-cosplays/funny-cosplay1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/12a-cosplays/funny-cosplay1.jpg -------------------------------------------------------------------------------- /12a-cosplays/funny-tomato-cosplay-subway-670925.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/12a-cosplays/funny-tomato-cosplay-subway-670925.png -------------------------------------------------------------------------------- /12a-cosplays/ninjaturtles.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/12a-cosplays/ninjaturtles.jpg -------------------------------------------------------------------------------- /12a-cosplays/tumblr_mg1x8nGSLj1qza05bo1_500.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/12a-cosplays/tumblr_mg1x8nGSLj1qza05bo1_500.jpg -------------------------------------------------------------------------------- /12a-cosplays/war machine cosplay fail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/12a-cosplays/war machine cosplay fail.png -------------------------------------------------------------------------------- /12a-cosplays/xmen-cosplay-18.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/12a-cosplays/xmen-cosplay-18.jpg -------------------------------------------------------------------------------- /12a-pil/uniman: -------------------------------------------------------------------------------- 1 | ./uniman.py && convert img000*png -delay 20 -dispose 2 uniman.gif && rm -f img*.png 2 | -------------------------------------------------------------------------------- /12a-pil/uniman-logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/12a-pil/uniman-logo.jpg -------------------------------------------------------------------------------- /12a-pil/uniman.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/12a-pil/uniman.gif -------------------------------------------------------------------------------- /12a-pil/uniman.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/12a-pil/uniman.png -------------------------------------------------------------------------------- /12a-pil/uniman.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | """ 4 | Create an animated GIF of a rotating logo of The University of Manchester. 5 | """ 6 | 7 | from PIL import Image 8 | import numpy as np 9 | from math import cos, sin, pi 10 | 11 | sides = 4 12 | dh = 30 13 | steps = 11 14 | fname = "uniman.png" 15 | 16 | def find_coeffs(pa, pb): 17 | """ 18 | Return the coefficients matrix. 19 | 20 | `pb` is the four vertices in the current plane, and 21 | `pa` contains four vertices in the resulting plane. 22 | 23 | Taken from [here](http://stackoverflow.com/a/14178717/1667018). 24 | """ 25 | matrix = [] 26 | for p1, p2 in zip(pa, pb): 27 | matrix.append([p1[0], p1[1], 1, 0, 0, 0, -p2[0]*p1[0], -p2[0]*p1[1]]) 28 | matrix.append([0, 0, 0, p1[0], p1[1], 1, -p2[1]*p1[0], -p2[1]*p1[1]]) 29 | 30 | A = np.matrix(matrix, dtype=np.float) 31 | B = np.array(pb).reshape(8) 32 | 33 | res = np.dot(np.linalg.inv(A.T * A) * A.T, B) 34 | return np.array(res).reshape(8) 35 | 36 | logo = Image.open(fname) 37 | width, height = logo.size 38 | 39 | phi = 0 40 | r = width/2 41 | shift = 2*pi/sides 42 | 43 | for idx,phi in enumerate(np.arange(0, pi/2, pi/2/steps)): 44 | print("Creating image #{}...".format(idx+1)) 45 | im = Image.new("RGB", (width, height), "white") 46 | for alpha in np.arange(3/4*pi, 7/4*pi, shift): 47 | (x0, y0) = (r * (1+cos(alpha+phi)), dh * (1+sin(alpha+phi))) 48 | (x1, y1) = (r * (1+cos(alpha+phi+1.01*shift)), dh * (1+sin(alpha+phi+1.01*shift))) 49 | coeffs = find_coeffs( 50 | [(x0, y0), (x1, y1), (x1, height-y1), (x0, height-y0)], 51 | [(0, 0), (width, 0), (width, height), (0, height)] 52 | ) 53 | logo_tr = logo.transform((width, height), Image.PERSPECTIVE, coeffs, Image.BICUBIC) 54 | im.paste(logo_tr, (0, 0), logo_tr) 55 | im.save("img{:05d}.png".format(idx)) 56 | 57 | -------------------------------------------------------------------------------- /12a-uniman.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/12a-uniman.gif -------------------------------------------------------------------------------- /12a-uniman.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/12a-uniman.png -------------------------------------------------------------------------------- /12a-uniman.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/12a-uniman.zip -------------------------------------------------------------------------------- /12c-pil.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Programming with Python (lab classes)\n", 8 | "#### Vedran Šego, [vsego.org](http://vsego.org/)\n", 9 | "\n", 10 | "## Content:\n", 11 | "\n", 12 | "1. PIL" 13 | ] 14 | }, 15 | { 16 | "cell_type": "markdown", 17 | "metadata": {}, 18 | "source": [ 19 | "**Problem 1.** Write a module with a function `spiral(im, box, r, dx, dy, phi=0, color)` that draws a spiral inside the `PIL.Image` object `im`, defined by the box `box` (4-member tuple), with `r` revolutions, starting at the angle `phi`. The parameters `dx` and `dy` represent how much do the `x` and the `y` radius change in each revolution.\n", 20 | "\n", 21 | "For example, the code\n", 22 | "```python\n", 23 | "im = Image.new(\"RGB\", (400, 300), \"white\")\n", 24 | "spiral(im, (0,150,200,300), 7, 13, 7, color=\"red\")\n", 25 | "spiral(im, (400,0,200,150), 17, 2, 4, color=\"navy\")\n", 26 | "```\n", 27 | "should produce the following image:\n", 28 | "![](12c-pil/spirals.png)\n", 29 | "\n", 30 | "**Hint:** A spiral can be drawn as a sequence of short line segments." 31 | ] 32 | }, 33 | { 34 | "cell_type": "markdown", 35 | "metadata": {}, 36 | "source": [ 37 | "**Problem 2.** Write a module for drawing chess board configurations. For example, the image of the final configuration of the [Immortal game](http://en.wikipedia.org/wiki/Immortal_Game) should look like this:\n", 38 | "![Final configuration of the Immortal game](12a-chess.png)\n", 39 | "Choose some appropriate input format and data structures to hold all the needed information. The images for the pieces can be found in the internet (for example, the ones in the [Wikipedia's article](http://en.wikipedia.org/wiki/Chess_piece) can be downloaded as big as $2000{\\rm px} \\times 2000{\\rm px}$). The module should handle resizing of the pieces' images to any user-given dimensions.\n", 40 | "\n", 41 | "Include an argument that will change from whose perspective the board is drawn (from the perspective of White, the bottom row is 1 and the top one is 8, while Black views from the opposite direction, seeing the row 8 at the bottom and the row 1 at the top).\n", 42 | "\n", 43 | "A module like that could be used to draw the whole games (as a series of images or as a single big one) or to make a [GUI](http://en.wikipedia.org/wiki/Graphical_user_interface) application for either playing or analyzing chess." 44 | ] 45 | }, 46 | { 47 | "cell_type": "markdown", 48 | "metadata": {}, 49 | "source": [ 50 | "**Problem 3.** Make a program that loads the name of an image file and creates an image containing both the loaded image and its histograms for each of its color components (red, green, and blue). The histogram should be saved as `\"original_filename-hist.original_extension\"` and displayed on the screen. Here is a sample of what it should look like for [this image](12c-pil/img_7840.jpg):\n", 51 | "\n", 52 | "![Image with histagram](12c-pil/img_7840-hist.jpg)\n", 53 | "\n", 54 | "**Hint:** A Matplotlib figure can be directly converted to a PIL drawing (search the internet to find out how), allowing you to directly merge the original image and its histograms into a single image. A less elegant solution is to save the histograms figure as an image, and then open it with PIL to add the original image on top of it." 55 | ] 56 | }, 57 | { 58 | "cell_type": "markdown", 59 | "metadata": {}, 60 | "source": [ 61 | "**Problem 4.** Make a program that will generate a random labyrinth with a given number of rows and columns, and draw it with and without a solution (two images), like this:\n", 62 | "\n", 63 | "
\n", 64 | "\n", 65 | "Alternatively, you can add a background image:\n", 66 | "\n", 67 | "
\n", 68 | "\n", 69 | "**How to generate a random labyrinth?**\n", 70 | "\n", 71 | "While this may seem like a very hard problem, it can be done fairly easily with a bit of help from the graph theory and Python's NetworkX module.\n", 72 | "\n", 73 | "To create a random labyrinth with `r` rows and `c` columns, first create a grid graph with $r \\times c$ nodes, assigning each of the edges a random weight, like this:\n", 74 | "![Basic graph as a grid](12c-pil/test-graph.png)\n", 75 | "The nodes represent the blocks in the labyrinth, while the edges represent the possible locations for the walls or the openings.\n", 76 | "\n", 77 | "Then compute its [minimum spanning tree](http://en.wikipedia.org/wiki/Minimum_spanning_tree) $T$ using [one of these NetworkX functions](https://networkx.github.io/documentation/latest/reference/algorithms.mst.html):\n", 78 | "![Spanning tree; the edges define halls](12c-pil/test-tree.png)\n", 79 | "Notice that the spanning tree defines the halls of our labyrinth.\n", 80 | "\n", 81 | "The random weights ensure that we get different minimum spanning trees for different graphs, and the fact that we are using trees ensures that there are no cycles while the graph/labyrinth remains connected (i.e., there is exactly one path between each pair of blocks).\n", 82 | "\n", 83 | "All that we need to do now is draw this as a labyrinth, using PIL's [ImageDraw.Draw.rectangle function](http://effbot.org/imagingbook/imagedraw.htm#tag-ImageDraw.Draw.rectangle). You can also use the [ImageDraw.Draw.line function](http://effbot.org/imagingbook/imagedraw.htm#tag-ImageDraw.Draw.line), but this will give you less control over how the walls are drawn.\n", 84 | "\n", 85 | "Note that we need to draw the walls of the labyrinth, while our tree contains its halls, i.e., we need to draw the walls corresponding with the grey edges on the previous image. This means that we need to draw a wall between neightbour blocks $(f,t)$ if and only if $(f,t)$ is **not** and edge in $T$. This might seem like a job for a [complement graph](http://en.wikipedia.org/wiki/Complement_graph) (implemented as [networkx.complement](http://networkx.lanl.gov/archive/networkx-1.1/reference/generated/networkx.complement.html)), but it is not, because the complement graph would also contain the edges between the non-neighbour nodes. However, a simple `if edge not in tree.edges()` does the trick.\n", 86 | "\n", 87 | "**How to solve the labyrinth?**\n", 88 | "\n", 89 | "Finally, to generate the solution of the labyrinth, choose two blocks for the enterance and the exit, and find the path between them inside the tree $T$. This path is unique, but NetworkX doesn't have a \"find the unique path in a tree\" functon. However, it does have various [shortest path functions](https://networkx.github.io/documentation/latest/reference/algorithms.shortest_paths.html) which will do the job. For our example, such path looks like this:\n", 90 | "![Minimum path, defining the solution](12c-pil/test-path.png)\n", 91 | "\n", 92 | "Again, all that is left is drawing this solution on the previously drawn image of the labyrinth.\n", 93 | "\n", 94 | "**Note:** In order to print these images easily, PIL can save them directly as PDF files." 95 | ] 96 | } 97 | ], 98 | "metadata": {}, 99 | "nbformat": 4, 100 | "nbformat_minor": 0 101 | } 102 | -------------------------------------------------------------------------------- /12c-pil/img_7840-hist.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/12c-pil/img_7840-hist.jpg -------------------------------------------------------------------------------- /12c-pil/img_7840.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/12c-pil/img_7840.jpg -------------------------------------------------------------------------------- /12c-pil/spirals.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/12c-pil/spirals.png -------------------------------------------------------------------------------- /12c-pil/test-graph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/12c-pil/test-graph.png -------------------------------------------------------------------------------- /12c-pil/test-lab-bg-sol.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/12c-pil/test-lab-bg-sol.png -------------------------------------------------------------------------------- /12c-pil/test-lab-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/12c-pil/test-lab-bg.png -------------------------------------------------------------------------------- /12c-pil/test-lab-sol.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/12c-pil/test-lab-sol.png -------------------------------------------------------------------------------- /12c-pil/test-lab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/12c-pil/test-lab.png -------------------------------------------------------------------------------- /12c-pil/test-path.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/12c-pil/test-path.png -------------------------------------------------------------------------------- /12c-pil/test-tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rougier/python-lecture-notes/63f12e060fc7390c10ae0d63e91bfde0a16702a0/12c-pil/test-tree.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | 341 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Programming with Python (MATH20622) 2 | 3 | ## Lecture notes from the course taught at the [University of Manchester](http://www.manchester.ac.uk/) in the academic year 2014/15. 4 | 5 | Notes: 6 | 7 | The exercises are meant to be solved at home, prior to lab classes. Lab classes problems are meant to be solved by students during the lab classes (and finished at home), but you are welcome to try them at home as well. 8 | 9 | The standard form for the name of the solution files is "name-xx-yy.py". Those files that have additional parts in their names are aimed at the students interested in more advanced programming, usually incorporating more than what is covered by the materials so far, and – as such – will not be part of that week's tests. 10 | 11 | For example, the files named in the form "name-xx-yy-py.py" are so called "Pythonic solutions" that use more advanced Python constructs (some of which will be covered in the later lectures). 12 | 13 | Each solution has a short description in its docstring, emphasising when it is not a "standard" solution. 14 | 15 | **Week 1:** Introductions 16 | 17 | * Lecture: [The course introduction](01a-intro/01a-intro.pdf) 18 | * Lab class: [Python introduction, input/output, variables, operators](01c-python_intro.ipynb) 19 | 20 | **Week 2:** Loops and conditionals 21 | 22 | * [Lecture](02a-loops_conditionals.ipynb) 23 | * [Exercises](02b-exercises.ipynb) 24 | * [Lab class](02c-loops_conditionals.ipynb) 25 | 26 | **Week 3:** Functions 27 | 28 | * [Lecture](03a-functions.ipynb) 29 | * [Exercises](03b-exercises.ipynb) 30 | * [Lab class](03c-functions.ipynb) 31 | 32 | **Week 4:** Lists and other iterables 33 | 34 | * [Lecture](04a-lists.ipynb) 35 | * [Exercises](04b-exercises.ipynb) 36 | * [Lab class](04c-lists.ipynb) 37 | 38 | **Week 5:** Strings, generators, and generator expressions 39 | 40 | * [Lecture](05a-strings.ipynb) 41 | * [Exercises](05b-exercises.ipynb) 42 | * [Lab class](05c-strings.ipynb) 43 | 44 | **Week 6:** Control flow 45 | 46 | * [Lecture](06a-control_flow.ipynb) 47 | * [Exercises](06b-exercises.ipynb) 48 | * [Lab class](06c-control_flow.ipynb) 49 | 50 | **Week 7:** Modules 51 | 52 | * [Lecture](07a-modules.ipynb) 53 | * [Exercises](07b-exercises.ipynb) 54 | * [Lab class](07c-modules.ipynb) 55 | 56 | **Week 8:** Files I/O 57 | 58 | * [Lecture](08a-file_io.ipynb) 59 | * [Exercises](08b-exercises.ipynb) 60 | * [Lab class](08c-file_io.ipynb) 61 | 62 | **Week 9:** Analysis of algorithms 63 | 64 | * [Lecture](09a-analysis_of_algorithms.ipynb) 65 | * [Exercises](09b-exercises.ipynb) 66 | * [Lab class](09c-analysis_of_algorithms.ipynb) 67 | 68 | **Week 10:** Data analysis 69 | 70 | * [Lecture](10a-data_analysis.ipynb) 71 | * [Lab class](10c-data_analysis.ipynb) 72 | 73 | **Week 11:** Graphs 74 | 75 | * [Lecture](11a-graphs.ipynb) 76 | * [Lab class](11c-graphs.ipynb) 77 | 78 | **Week 12:** PIL - Python Imaging Library 79 | 80 | * [Lecture](12a-pil.ipynb) 81 | * [Lab class](12c-pil.ipynb) 82 | --------------------------------------------------------------------------------