{ "cells": [ { "cell_type": "markdown", "id": "e0d8818d", "metadata": {}, "source": [ "## CS 201: Running Time of Programs\n", "
\n", "" ] }, { "cell_type": "markdown", "id": "6b96883d", "metadata": {}, "source": [ "
\n", "
\n", "The pseudocode for insertion sort from the Wikipedia article:\n", "
\n", "for i ← 1 to length(A)\n", " x ← A[i]\n", " j ← i\n", " while j > 0 and A[j-1] > x\n", " A[j] ← A[j-1]\n", " j ← j - 1\n", " A[j] ← x\n", "" ] }, { "cell_type": "markdown", "id": "b5d7e305", "metadata": {}, "source": [ "This is (slightly) incorrect: the array A has 0-based indexing,\n", "so when i = length(A), the array reference A[i] will be out of\n", "bounds; imagine the first line corrected to have length(A)-1 instead\n", "of length(A).\n", "We analyzed this program by thinking of it translated\n", "into TC-201 assembly language and estimating the number of TC-201\n", "assembly language instructions that would be executed to\n", "sort an array of n numbers." ] }, { "cell_type": "markdown", "id": "32b2529e", "metadata": {}, "source": [ "
\n", "The new element here is how to account for the time to access\n", "the array A.\n", "In this pseudocode, the array A is a finite sequence of mutable\n", " elements (like a vector in Racket) each of which is accessed by\n", "its index, a number from 0 to the length of the array minus 1.\n", " \n", "
\n",
" Here are examples of Racket vectors."
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "b329ea77",
"metadata": {},
"outputs": [],
"source": [
"(define v (make-vector 5 1))"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "9648e25c",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"'#(1 1 1 1 1)
"
],
"text/plain": [
"'#(1 1 1 1 1)"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"v"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "2e0c4e7c",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"#t
"
],
"text/plain": [
"#t"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(vector? v)"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "31632bc9",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"length: contract violation\n",
" expected: list?\n",
" given: '#(1 1 1 1 1)\n"
]
}
],
"source": [
"(length v)"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "128ec03d",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"5
"
],
"text/plain": [
"5"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(vector-length v)"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "4c38c624",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"1
"
],
"text/plain": [
"1"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(vector-ref v 0)"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "6cf13e9f",
"metadata": {},
"outputs": [],
"source": [
"(vector-set! v 0 8)"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "3ddb1e36",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"8
"
],
"text/plain": [
"8"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(vector-ref v 0)"
]
},
{
"cell_type": "markdown",
"id": "34c89b9d",
"metadata": {},
"source": [
"The vector-set!
bang (!) suffix indicates that the function has a side-effect.\n",
"It can alter the contents of the vector.\n",
"
\n",
" The important point here is that vector-length
and vector-ref
are constant time operations, $O(1)$,\n",
" unlike length
and list-ref
for lists which are $O(n)$.\n",
" The list operations must traverse the list from left to right. The vector \n",
" operations know exactly where to go, based on the index. "
]
},
{
"cell_type": "markdown",
"id": "776442b5",
"metadata": {},
"source": [
"
astart
.\n",
"Then the TC-201 instructions to find the value of $A[i]$\n",
"would load astart
into the accumulator, add the value of i
\n",
"to it, and store it in a temporary location, say temp
,\n",
"and then execute loadi temp
to get the value of $A[i]$ into\n",
"the accumulator.\n",
"This is a constant number of TC-201 instructions to access any\n",
"of the elements of the array.\n",
"To change the value of $A[i]$, we could use a similar address calculation\n",
"to get the memory address of the i-th element of $A$ into temp
,\n",
"and then execute load value
and storei temp
to change the\n",
"value of $A[i]$ to the number in the memory register value.\n",
"This is similarly a constant number of instructions.\n",
"Thus it makes sense to count array references as constant time operations.\n"
]
},
{
"cell_type": "markdown",
"id": "f9953d3d",
"metadata": {},
"source": [
"\n", "With that understanding of array references, \n", "a straightforward translation of a for-loop into TC-201 instructions,\n", "and\n", "the observation that assignment, addition, subtraction and comparison\n", "are constant time operations,\n", "our conclusions about the running time of this\n", "implementation of insertion sort were: \n", "best case time of Theta(n) (Θ(n))\n", "and worst case time of Theta(n2) (Θ(n2)).\n", "\n", "
\n",
"See tc201sort.rkt. We also modified \n",
"simulate-lite
to return how many steps were executed.\n",
"\n",
"
\n", "Please see the notes:\n", "\n", "Running time of a program for a simpler example.\n" ] }, { "cell_type": "markdown", "id": "99c9ada6", "metadata": {}, "source": [ "
\n", "
\n", "Please see the notes:\n", "\n", "Running time of a program and\n", "\n", "List representation.\n", "For the insert procedure, see \n", "\n", "Sorting.\n" ] }, { "cell_type": "markdown", "id": "24efe880", "metadata": {}, "source": [ "
\n",
"Closures are a way of providing a local environment for a function definition that \n",
" is distinct from the global environment. Here is an example - first with a global\n",
" scope and then with a local, lexical scope."
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "d4906910",
"metadata": {},
"outputs": [],
"source": [
"(define (make-global-adder)\n",
" (lambda (y) (+ x y)))"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "e4fe5bd5",
"metadata": {},
"outputs": [],
"source": [
"(define x 10)"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "4a74d58d",
"metadata": {},
"outputs": [],
"source": [
"(define addx (make-global-adder))"
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "c298ea90",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"10
"
],
"text/plain": [
"10"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"x"
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "5d21f25f",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"13
"
],
"text/plain": [
"13"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(addx 3)"
]
},
{
"cell_type": "code",
"execution_count": 14,
"id": "c20ea29a",
"metadata": {},
"outputs": [],
"source": [
"(define x 20)"
]
},
{
"cell_type": "code",
"execution_count": 15,
"id": "2cebcf97",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"23
"
],
"text/plain": [
"23"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(addx 3)"
]
},
{
"cell_type": "markdown",
"id": "68f15790",
"metadata": {},
"source": [
"The function addx
depends on the current value of x, rather than\n",
"the value of x at the time the function was defined. Here is another (better) way."
]
},
{
"cell_type": "code",
"execution_count": 16,
"id": "38e9ce98",
"metadata": {},
"outputs": [],
"source": [
"(define (make-adder x)\n",
" (lambda (y) (+ x y)))"
]
},
{
"cell_type": "code",
"execution_count": 17,
"id": "9f755f86",
"metadata": {},
"outputs": [],
"source": [
"(define add2 (make-adder 2))\n",
"(define add3 (make-adder 3))"
]
},
{
"cell_type": "code",
"execution_count": 18,
"id": "f72f66f0",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"10
"
],
"text/plain": [
"10"
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(add2 8)"
]
},
{
"cell_type": "code",
"execution_count": 19,
"id": "3bbfb9a0",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"11
"
],
"text/plain": [
"11"
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(add3 8)"
]
},
{
"cell_type": "markdown",
"id": "b197dc91",
"metadata": {},
"source": [
"In make-adder
the variable x
is local and in lexical scope for\n",
"the lambda expression. When the lambda expression executes, it uses the value of x
that we in effect when make-adder
was called."
]
},
{
"cell_type": "markdown",
"id": "6cfc5598",
"metadata": {},
"source": [
"make-adder
creates a closure that combines a local environment, defining x, with a function definition. We will see that closures provide a way to \n",
"implement object oriented programming, where an object contains both data and methods (procedures)."
]
},
{
"cell_type": "markdown",
"id": "8e147292",
"metadata": {},
"source": [
"
\n", "Summary. Running times of insertion sort and merge sort.\n", "
\n", "\n", "\n",
"Please see the notes:\n",
"\n",
"Sorting.\n"
]
},
{
"cell_type": "markdown",
"id": "36ded973",
"metadata": {},
"source": [
"Above, we used a modified version of simulate-lite
to measure how many steps were executed by our TC201 program.\n",
"
\n",
" Racket has procedures to measure the execution time of your code. First, we define three \n",
" procedures to sum up the first n integers. The first is the vanilla recursive definition."
]
},
{
"cell_type": "code",
"execution_count": 20,
"id": "5b310006",
"metadata": {},
"outputs": [],
"source": [
"(define (sum1 n)\n",
" (if (zero? n)\n",
" 0\n",
" (+ n (sum1 (- n 1)))))"
]
},
{
"cell_type": "markdown",
"id": "76fcdb50",
"metadata": {},
"source": [
"The second is the tail-recursive version."
]
},
{
"cell_type": "code",
"execution_count": 21,
"id": "583353cf",
"metadata": {},
"outputs": [],
"source": [
"(define (sum2 n [result 0])\n",
" (if (zero? n)\n",
" result\n",
" (sum2 (- n 1) (+ n result))))"
]
},
{
"cell_type": "markdown",
"id": "c3944a77",
"metadata": {},
"source": [
"The third is Gauss's closed form definition."
]
},
{
"cell_type": "code",
"execution_count": 22,
"id": "e4e27d07",
"metadata": {},
"outputs": [],
"source": [
"(define (sum3 n)\n",
" (/ (* n (+ n 1))\n",
" 2))"
]
},
{
"cell_type": "markdown",
"id": "99e2545d",
"metadata": {},
"source": [
"We use the Racket procedure time-apply to measure the execution time."
]
},
{
"cell_type": "code",
"execution_count": 23,
"id": "8a68fb8d",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"'(500000500000)
"
],
"text/plain": [
"'(500000500000)"
]
},
"execution_count": 23,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"text/html": [
"159
"
],
"text/plain": [
"159"
]
},
"execution_count": 23,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"text/html": [
"160
"
],
"text/plain": [
"160"
]
},
"execution_count": 23,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"text/html": [
"73
"
],
"text/plain": [
"73"
]
},
"execution_count": 23,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(time-apply sum1 '(1000000))"
]
},
{
"cell_type": "markdown",
"id": "99afc498",
"metadata": {},
"source": [
"time-apply
returns four values: a list containing the result(s) of applying proc to the arguments in lst, the number of milliseconds of CPU time required to obtain this result, the number of “real” milliseconds required for the result, and the number of milliseconds of CPU time (included in the first result) spent on garbage collection."
]
},
{
"cell_type": "code",
"execution_count": 24,
"id": "c652b121",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"'(500000500000)
"
],
"text/plain": [
"'(500000500000)"
]
},
"execution_count": 24,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"text/html": [
"6
"
],
"text/plain": [
"6"
]
},
"execution_count": 24,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"text/html": [
"6
"
],
"text/plain": [
"6"
]
},
"execution_count": 24,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"text/html": [
"0
"
],
"text/plain": [
"0"
]
},
"execution_count": 24,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(time-apply sum2 '(1000000))"
]
},
{
"cell_type": "code",
"execution_count": 25,
"id": "1b87abf7",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"'(500000500000)
"
],
"text/plain": [
"'(500000500000)"
]
},
"execution_count": 25,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"text/html": [
"0
"
],
"text/plain": [
"0"
]
},
"execution_count": 25,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"text/html": [
"0
"
],
"text/plain": [
"0"
]
},
"execution_count": 25,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"text/html": [
"0
"
],
"text/plain": [
"0"
]
},
"execution_count": 25,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(time-apply sum3 '(1000000))"
]
},
{
"cell_type": "markdown",
"id": "ea3ae2c8",
"metadata": {},
"source": [
"Tail-recursion is considerably faster than plain recursion, and require no garbage collection. That means that it does not run out of free memory.\n",
"
\n",
"The closed form solution is virtually instantaneous. We need a more fine grained measure of \n",
" time. We will use Racket's current-inexact-milliseconds function."
]
},
{
"cell_type": "code",
"execution_count": 26,
"id": "0cfa8c22",
"metadata": {},
"outputs": [],
"source": [
"(define (timeit func args)\n",
" (let ((start (current-inexact-milliseconds))\n",
" (val (apply func args))\n",
" (end (current-inexact-milliseconds)))\n",
" (list val (- end start))))"
]
},
{
"cell_type": "code",
"execution_count": 27,
"id": "36ff0c32",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"'(500000500000 150.05908203125)
"
],
"text/plain": [
"'(500000500000 150.05908203125)"
]
},
"execution_count": 27,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(timeit sum1 '(1000000))"
]
},
{
"cell_type": "code",
"execution_count": 28,
"id": "f9fd3eee",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"'(500000500000 6.009033203125)
"
],
"text/plain": [
"'(500000500000 6.009033203125)"
]
},
"execution_count": 28,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(timeit sum2 '(1000000))"
]
},
{
"cell_type": "code",
"execution_count": 29,
"id": "4e20f93b",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"'(500000500000 0.0)
"
],
"text/plain": [
"'(500000500000 0.0)"
]
},
"execution_count": 29,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(timeit sum3 '(1000000))"
]
},
{
"cell_type": "markdown",
"id": "e31a39fd",
"metadata": {},
"source": [
"We will revisit these methods below in the section on plotting the results."
]
},
{
"cell_type": "markdown",
"id": "e5b9c2e2",
"metadata": {},
"source": [
"
\n", "
\n", "This topic is useful for solving problem 7 in hw 8.\n", "
\n", "Please see the notes:\n", "\n", "Environments in Racket and the Mutator set!.\n", "
\n",
"counter.rkt\n"
]
},
{
"cell_type": "markdown",
"id": "48742502",
"metadata": {},
"source": [
"In a setting of pure functional programming, calling a procedure\n",
"with the same arguments will always produce the same result.\n",
"This is not the case with Racket's library procedure random
.\n",
"Calling (random 10)
might return 6 one time and 0 the next.\n",
"The random
procedure has some local state that changes with\n",
"each call and allows it to produce different responses to\n",
"the same argument.\n",
"An \"object\" in the sense of object oriented programming can\n",
"be considered to be a bundle of data and procedures (or \"methods\")\n",
"to operate on the data.\n",
"We can represent an object in Racket as a procedure with\n",
"local state.\n",
"\n",
"\n",
"
\n",
" Before we do that, we look at one of Racket's mutators, namely set!
- \n",
" pronounced set-bang.\n",
"The exclamation point is part of the name of the procedure, and\n",
"is a convention to indicate that the procedure is a mutator, that is,\n",
"changes the value of a variable or other data.\n",
" The form of set!
is\n",
"
\n", " (set! variable expression)\n", "\n", "The expression is evaluated to get a value, and\n", "then the variable is looked up in the relevant environment\n", "(just as we would look it up to find its value) -- in that\n", "environment its binding is changed to the value of the\n", "expression.\n", "Note that the variable must already be defined in order\n", "to use it in a set! expression.\n", "Attempting to set! a variable that is not defined is an error.\n", "This is analogous to having to declare a variable before it\n", "can have a value assigned to it.\n", "" ] }, { "cell_type": "markdown", "id": "a236f47b", "metadata": {}, "source": [ "
\n",
" Example of the use of set!
in the top-level environment."
]
},
{
"cell_type": "code",
"execution_count": 30,
"id": "dedc14c1",
"metadata": {},
"outputs": [],
"source": [
"(define count 0)"
]
},
{
"cell_type": "code",
"execution_count": 31,
"id": "5e1e7eef",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"0
"
],
"text/plain": [
"0"
]
},
"execution_count": 31,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"count"
]
},
{
"cell_type": "code",
"execution_count": 32,
"id": "756c5e00",
"metadata": {},
"outputs": [],
"source": [
"(set! count (+ 1 count))"
]
},
{
"cell_type": "code",
"execution_count": 33,
"id": "51d44f8d",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"1
"
],
"text/plain": [
"1"
]
},
"execution_count": 33,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"count"
]
},
{
"cell_type": "markdown",
"id": "effef060",
"metadata": {},
"source": [
"Evaluating the expression (define count 0)
adds count to\n",
"the top-level environment with its value bound to 0.\n",
"Then evaluating the expression (set! count (+ 1 count))
\n",
"evaluates the expression (+ 1 count)
in the usual way to\n",
"get $1$, and looks up count
, finding it in the top-level\n",
"environment, where its value is currently $0$.\n",
"The value of count
is changed to $1$ in the top-level\n",
"environment; now when its value is looked up, it will be $1$.\n",
"\n",
"\n",
"
\n",
"This behavior is enough to define a simple counter procedure\n",
"which will return different values for the same arguments,\n",
" depending on the value of count
.\n",
"We write the following procedure."
]
},
{
"cell_type": "code",
"execution_count": 34,
"id": "118e4962",
"metadata": {},
"outputs": [],
"source": [
"(define (counter cmd)\n",
" (case cmd\n",
" [(increment!) (set! count (+ 1 count))]\n",
" [(zero!) (set! count 0)])\n",
" count)"
]
},
{
"cell_type": "code",
"execution_count": 35,
"id": "b9a6a807",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"2
"
],
"text/plain": [
"2"
]
},
"execution_count": 35,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(counter 'increment!)"
]
},
{
"cell_type": "code",
"execution_count": 36,
"id": "9a78d8fb",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"3
"
],
"text/plain": [
"3"
]
},
"execution_count": 36,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(counter 'increment!)"
]
},
{
"cell_type": "code",
"execution_count": 37,
"id": "7a9f9ec0",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"4
"
],
"text/plain": [
"4"
]
},
"execution_count": 37,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(counter 'increment!)"
]
},
{
"cell_type": "code",
"execution_count": 38,
"id": "b6857c3f",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"4
"
],
"text/plain": [
"4"
]
},
"execution_count": 38,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"count"
]
},
{
"cell_type": "code",
"execution_count": 39,
"id": "ce05c62e",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"0
"
],
"text/plain": [
"0"
]
},
"execution_count": 39,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(counter 'zero!)"
]
},
{
"cell_type": "code",
"execution_count": 40,
"id": "640afbf2",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"0
"
],
"text/plain": [
"0"
]
},
"execution_count": 40,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"count"
]
},
{
"cell_type": "markdown",
"id": "cff3a28f",
"metadata": {},
"source": [
"Note that when this procedure refers to count
,\n",
"the search to find the relevant environment finds it\n",
"in the top-level environment, (where we assume we\n",
"previously defined it and incremented it to 1.)\n",
"Thus in this case the variable count
functions as\n",
"a \"global\" variable, accessible everywhere in the\n",
"file.\n",
"(We could also have written counter
without the case\n",
"statement, using a cond
expression and equal?
tests.)\n",
"\n",
"\n",
"
\n",
"One property we might want for an object is that its\n",
"data is not global, but local and private to the\n",
"object, so that it cannot be read or changed without\n",
"invoking the \"methods\" (or procedures) associated with\n",
"the object.\n",
"We can achieve this goal with the following definition.\n",
"Assume that we have re-entered the Racket interpreter\n",
"afresh, so that the preceding definition of count and\n",
"counter are gone.\n"
]
},
{
"cell_type": "code",
"execution_count": 41,
"id": "32aeb4a3",
"metadata": {},
"outputs": [],
"source": [
"(define counter1\n",
" (let ((count 0))\n",
" (lambda (cmd)\n",
" (case cmd\n",
" [(increment!) (set! count (+ 1 count))]\n",
" [(zero!) (set! count 0)])\n",
" count)))"
]
},
{
"cell_type": "code",
"execution_count": 42,
"id": "936da2cf",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"1
"
],
"text/plain": [
"1"
]
},
"execution_count": 42,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(counter1 'increment!)"
]
},
{
"cell_type": "code",
"execution_count": 43,
"id": "02a0178c",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"2
"
],
"text/plain": [
"2"
]
},
"execution_count": 43,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(counter1 'increment!)"
]
},
{
"cell_type": "code",
"execution_count": 44,
"id": "84380491",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"0
"
],
"text/plain": [
"0"
]
},
"execution_count": 44,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"count"
]
},
{
"cell_type": "markdown",
"id": "47980975",
"metadata": {},
"source": [
"This creates a procedure named counter1
with a private local\n",
"variable count
, whose value can only be inspected\n",
"and changed by calls to the procedure.\n",
"This protects against other procedures accidentally or\n",
"deliberately changing the value of count other than through\n",
"the interface provided by this procedure.\n",
"For an analysis of (a variant of) this procedure, and\n",
"a higher-level counter-creation procedure, in terms of\n",
"Racket environments, please see the notes:\n",
"\n",
"Environments in Racket and the Mutator set!.\n",
"
\n",
"If we arrange the lets and lambdas in a different fashion,\n",
"we get a counter procedure that UTTERLY FAILS at its task."
]
},
{
"cell_type": "code",
"execution_count": 45,
"id": "e2c106f1",
"metadata": {},
"outputs": [],
"source": [
"(define not-a-counter\n",
" (lambda (cmd)\n",
" (let ((count 0))\n",
" (case cmd\n",
" [(increment!) (set! count (+ 1 count)) count]\n",
" [(zero!) (set! count 0) count]))))"
]
},
{
"cell_type": "markdown",
"id": "aa1ac640",
"metadata": {},
"source": [
"As examples of the behavior of this procedure, we have the\n",
"following."
]
},
{
"cell_type": "code",
"execution_count": 46,
"id": "9d7f8797",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"1
"
],
"text/plain": [
"1"
]
},
"execution_count": 46,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(not-a-counter 'increment!)"
]
},
{
"cell_type": "code",
"execution_count": 47,
"id": "8f710795",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"0
"
],
"text/plain": [
"0"
]
},
"execution_count": 47,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(not-a-counter 'zero!)"
]
},
{
"cell_type": "code",
"execution_count": 48,
"id": "6629cfc8",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"1
"
],
"text/plain": [
"1"
]
},
"execution_count": 48,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(not-a-counter 'increment!)"
]
},
{
"cell_type": "code",
"execution_count": 49,
"id": "09e6b802",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"1
"
],
"text/plain": [
"1"
]
},
"execution_count": 49,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(not-a-counter 'increment!)"
]
},
{
"cell_type": "markdown",
"id": "d5ea37e5",
"metadata": {},
"source": [
"Think about what is happening in terms of environments to\n",
"keep this from behaving like a counter."
]
},
{
"cell_type": "code",
"execution_count": 50,
"id": "cd1240d4",
"metadata": {},
"outputs": [],
"source": [
"(define counter2\n",
" (let ((count 0))\n",
" (lambda cmd\n",
" (if (null? cmd)\n",
" count\n",
" (begin\n",
" (case (car cmd)\n",
" [(increment!) (set! count (+ 1 count))]\n",
" [(zero!) (set! count 0)])\n",
" count)))))"
]
},
{
"cell_type": "code",
"execution_count": 51,
"id": "c761551b",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"0
"
],
"text/plain": [
"0"
]
},
"execution_count": 51,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(counter2)"
]
},
{
"cell_type": "code",
"execution_count": 52,
"id": "6ef1c7a5",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"1
"
],
"text/plain": [
"1"
]
},
"execution_count": 52,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(counter2 'increment!)"
]
},
{
"cell_type": "code",
"execution_count": 53,
"id": "b07b5bb4",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"2
"
],
"text/plain": [
"2"
]
},
"execution_count": 53,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(counter2 'increment!)"
]
},
{
"cell_type": "code",
"execution_count": 54,
"id": "7dcfb6b7",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"2
"
],
"text/plain": [
"2"
]
},
"execution_count": 54,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(counter2)"
]
},
{
"cell_type": "code",
"execution_count": 55,
"id": "19a79d22",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"0
"
],
"text/plain": [
"0"
]
},
"execution_count": 55,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(counter2 'zero!)"
]
},
{
"cell_type": "code",
"execution_count": 56,
"id": "dd491c52",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"0
"
],
"text/plain": [
"0"
]
},
"execution_count": 56,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(counter2)"
]
},
{
"cell_type": "markdown",
"id": "68019aa2",
"metadata": {},
"source": [
"
counter2
, but with the option of specifying any initial value, not just $0$."
]
},
{
"cell_type": "code",
"execution_count": 57,
"id": "87e71268",
"metadata": {},
"outputs": [],
"source": [
"(define make-counter\n",
" (lambda (count)\n",
" (lambda (command)\n",
" (case command\n",
" ((zero!) (set! count 0) count)\n",
" ((increment!) (set! count (+ 1 count)) count)\n",
" ((value) count)\n",
" (else 'error)))))"
]
},
{
"cell_type": "code",
"execution_count": 58,
"id": "973d8137",
"metadata": {},
"outputs": [],
"source": [
"(define c1 (make-counter 10))"
]
},
{
"cell_type": "code",
"execution_count": 59,
"id": "a77fe420",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"10
"
],
"text/plain": [
"10"
]
},
"execution_count": 59,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(c1 'value)"
]
},
{
"cell_type": "code",
"execution_count": 60,
"id": "3aef8587",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"11
"
],
"text/plain": [
"11"
]
},
"execution_count": 60,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(c1 'increment!)"
]
},
{
"cell_type": "code",
"execution_count": 61,
"id": "46615b30",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"0
"
],
"text/plain": [
"0"
]
},
"execution_count": 61,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(c1 'zero!)"
]
},
{
"cell_type": "code",
"execution_count": 62,
"id": "35dc38d8",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"'error
"
],
"text/plain": [
"'error"
]
},
"execution_count": 62,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(c1 'x)"
]
},
{
"cell_type": "markdown",
"id": "0c7dafe7",
"metadata": {},
"source": [
"### Using a Closure to Create a Stack\n",
"\n",
"Object-oriented programming creates entities that combine data with procedures.\n",
"\n",
"In racket, we can use closures for a similar effect. \n",
"\n",
"Below we create a Racket procedure (make-stack name)
that takes a symbol name and returns a Racket procedure that implements a stack object with local storage including a list representing a push down stack - a last-in, first-out (LIFO) data structure, which can process the following commands: \n",
"\n",
"#t
"
],
"text/plain": [
"#t"
]
},
"execution_count": 171,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(s1 'empty?)"
]
},
{
"cell_type": "code",
"execution_count": 172,
"id": "9c5c0024",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"0
"
],
"text/plain": [
"0"
]
},
"execution_count": 172,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(s1 'size)"
]
},
{
"cell_type": "code",
"execution_count": 173,
"id": "42309dcd",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"'stack1
"
],
"text/plain": [
"'stack1"
]
},
"execution_count": 173,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(s1 'name)"
]
},
{
"cell_type": "code",
"execution_count": 174,
"id": "7025b39d",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"5
"
],
"text/plain": [
"5"
]
},
"execution_count": 174,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(s1 'push 5)"
]
},
{
"cell_type": "code",
"execution_count": 175,
"id": "c1cdcfa6",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"#f
"
],
"text/plain": [
"#f"
]
},
"execution_count": 175,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(s1 'empty?)"
]
},
{
"cell_type": "code",
"execution_count": 176,
"id": "6172a5c4",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"7
"
],
"text/plain": [
"7"
]
},
"execution_count": 176,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(s1 'push 7)"
]
},
{
"cell_type": "code",
"execution_count": 177,
"id": "6184c963",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"9
"
],
"text/plain": [
"9"
]
},
"execution_count": 177,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(s1 'push 9)"
]
},
{
"cell_type": "code",
"execution_count": 178,
"id": "a0603bea",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"3
"
],
"text/plain": [
"3"
]
},
"execution_count": 178,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(s1 'size)"
]
},
{
"cell_type": "code",
"execution_count": 179,
"id": "806ae9c7",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"9
"
],
"text/plain": [
"9"
]
},
"execution_count": 179,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(s1 'pop)"
]
},
{
"cell_type": "code",
"execution_count": 180,
"id": "3c87edf6",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"2
"
],
"text/plain": [
"2"
]
},
"execution_count": 180,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(s1 'size)"
]
},
{
"cell_type": "code",
"execution_count": 181,
"id": "c1da2740",
"metadata": {},
"outputs": [],
"source": [
"(define s2 (make-stack 'stack2))"
]
},
{
"cell_type": "code",
"execution_count": 182,
"id": "24f4a0aa",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"'stack1
"
],
"text/plain": [
"'stack1"
]
},
"execution_count": 182,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(s1 'name)"
]
},
{
"cell_type": "code",
"execution_count": 183,
"id": "e1f0a47a",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"'stack2
"
],
"text/plain": [
"'stack2"
]
},
"execution_count": 183,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(s2 'name)"
]
},
{
"cell_type": "code",
"execution_count": 184,
"id": "af4108b6",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"'Error:stack-empty
"
],
"text/plain": [
"'Error:stack-empty"
]
},
"execution_count": 184,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(s2 'pop)"
]
},
{
"cell_type": "code",
"execution_count": 185,
"id": "18c2ee87",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"'Error:usage:push_element
"
],
"text/plain": [
"'Error:usage:push_element"
]
},
"execution_count": 185,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(s2 'push)"
]
},
{
"cell_type": "code",
"execution_count": 186,
"id": "cc79560e",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"#f
"
],
"text/plain": [
"#f"
]
},
"execution_count": 186,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(s1 'equal? s2)"
]
},
{
"cell_type": "code",
"execution_count": 187,
"id": "5cca1ef6",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"#t
"
],
"text/plain": [
"#t"
]
},
"execution_count": 187,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(s1 'equal? s1)"
]
},
{
"cell_type": "code",
"execution_count": 188,
"id": "d27a940e",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"'(7 5)
"
],
"text/plain": [
"'(7 5)"
]
},
"execution_count": 188,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(s1 'show)"
]
},
{
"cell_type": "code",
"execution_count": 189,
"id": "fd3395ba",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"7
"
],
"text/plain": [
"7"
]
},
"execution_count": 189,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(s1 'peek)"
]
},
{
"cell_type": "code",
"execution_count": 190,
"id": "c4d4e326",
"metadata": {},
"outputs": [],
"source": [
"(define s3 (s1 'copy 'stack3))"
]
},
{
"cell_type": "code",
"execution_count": 191,
"id": "0fa98a9e",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"'stack3
"
],
"text/plain": [
"'stack3"
]
},
"execution_count": 191,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(s3 'name)"
]
},
{
"cell_type": "code",
"execution_count": 192,
"id": "d7ba254f",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"'(7 5)
"
],
"text/plain": [
"'(7 5)"
]
},
"execution_count": 192,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(s3 'show)"
]
},
{
"cell_type": "code",
"execution_count": 193,
"id": "aba53db0",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"#f
"
],
"text/plain": [
"#f"
]
},
"execution_count": 193,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(s3 'empty?)"
]
},
{
"cell_type": "code",
"execution_count": 194,
"id": "f52feec9",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"#t
"
],
"text/plain": [
"#t"
]
},
"execution_count": 194,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(s1 'equal? s3)"
]
},
{
"cell_type": "markdown",
"id": "dddf1be8",
"metadata": {},
"source": [
"What is the run time complexity of the following stack operations, using big-O notation?\n",
"\n",
"\n", " See also Big-O Cheat Sheet" ] }, { "cell_type": "code", "execution_count": 195, "id": "fd9ad335", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "instantiate-linklet: mismatch;\n", " reference to a variable that is uninitialized;\n", " possibly, bytecode file needs re-compile because dependencies changed\n", " name: has-x-selection?\n", " exporting instance: \"/usr/share/racket/pkgs/gui-lib/mred/private/wx/platform.rkt\"\n", " importing instance: \"/usr/share/racket/pkgs/gui-lib/mred/private/wx/common/clipboard.rkt\"\n", " context...:\n", " temp37_0\n", " for-loop\n", " run-module-instance!125\n", " for-loop\n", " [repeats 1 more time]\n", " run-module-instance!125\n", " for-loop\n", " [repeats 1 more time]\n", " run-module-instance!125\n", " for-loop\n", " [repeats 1 more time]\n", " run-module-instance!125\n", " for-loop\n", " [repeats 1 more time]\n", " run-module-instance!125\n", " for-loop\n", " ...\n" ] } ], "source": [ "(require plot)" ] }, { "cell_type": "code", "execution_count": null, "id": "53578c16", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "id": "fa48d903", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Racket", "language": "racket", "name": "racket" }, "language_info": { "codemirror_mode": "scheme", "file_extension": ".rkt", "mimetype": "text/x-racket", "name": "Racket", "pygments_lexer": "racket", "version": "7.4" } }, "nbformat": 4, "nbformat_minor": 5 }