I am working on the file "Python/Chapter-06/Calculator-Frame.ipynb".
The first task is:
Normally, I would just write
%run Stack.ipynb
here.  As this does not work in Deepnote, I have included the implementation of the class Stack here.
Can you write Python code for it?

class Stack:
    def __init__(self):
        self.mStackElements = []

    def push(self, e):
        self.mStackElements.append(e)

    def pop(self):
        assert len(self.mStackElements) > 0, "popping empty stack"
        self.mStackElements = self.mStackElements[:-1]

    def top(self):
        assert len(self.mStackElements) > 0, "top of empty stack"
        return self.mStackElements[-1]

    def isEmpty(self):
        return self.mStackElements == []

    def copy(self):
        C = Stack()
        C.mStackElements = self.mStackElements[:]
        return C

    def __str__(self):
        C = self.copy()
        result = C._convert()
        return result

    def _convert(self):
        if self.isEmpty():
            return '|'
        t = self.top()
        self.pop()
        return self._convert() + ' ' + str(t) + ' |'

def createStack(L):
    S = Stack()
    n = len(L)
    for i in range(n):
        S.push(L[i])
    return S


I am working on the file "Python/Chapter-06/Calculator-Frame.ipynb".
The first task is:
The cell below should output the number 0.7390851332151607.
Can you write Python code for it?

computeZero('log exp x - cos(sqrt(x**2))', 0, 1)


I am working on the file "Python/Chapter-06/Calculator-Frame.ipynb".
The first task is:
The class Calculator supports three member variables:
  - the token stack mTokens,
  - the operator stack mOperators,
  - the argument stack mArguments,
  - the floating point number mValue, which is the current value of x.
The constructor takes a list of tokens TL and initializes the token stack with these
tokens.
Can you write Python code for it?

class Calculator:
    def __init__(self, TL, x):
        self.mTokens     = createStack(TL)
        self.mOperators  = Stack()
        self.mArguments  = Stack()
        self.mValue      = x


I am working on the file "Python/Chapter-06/Calculator-Frame.ipynb".
The first task is:
The function $\texttt{evalBefore}(o_1, o_2)$ receives to strings representing arithmetical operators.  It returns True if the operator $o_1$ should be evaluated before the operator $o_2$ in an arithmetical expression of the form $a \;\texttt{o}_1\; b \;\texttt{o}_2\; c$.  In order to determine whether $o_1$ should be evaluated before $o_2$ it uses the
precedence and the associativity of the operators.
Its behavior is specified by the following rules:
- $\texttt{precedence}(o_1) > \texttt{precedence}(o_2) \rightarrow \texttt{evalBefore}(\texttt{o}_1, \texttt{o}_2) = \texttt{True}$,
- $o_1 = o_2 \wedge \neg\texttt{isUnaryOperator}(o_1)\rightarrow \texttt{evalBefore}(\texttt{o}_1, \texttt{o}_2) = \texttt{isLeftAssociative}(o_1)$,
- $\texttt{isUnaryOperator}(o_1) \wedge \texttt{isUnaryOperator}(o_2) \rightarrow
   \texttt{evalBefore}(\texttt{o}_1, \texttt{o}_2) = \texttt{False}$,
- $\texttt{precedence}(o_1) = \texttt{precedence}(o_2) \wedge o_1 \not= o_2 \wedge
   \neg\texttt{isUnaryOperator}(o_1) \rightarrow
   \texttt{evalBefore}(\texttt{o}_1, \texttt{o}_2) = \texttt{True}$,
- $\texttt{precedence}(o_1) < \texttt{precedence}(o_2) \rightarrow \texttt{evalBefore}(\texttt{o}_1, \texttt{o}_2) = \texttt{False}$.
Can you write Python code for it?

def evalBefore(stackOp, nextOp):
    "your code here"
    assert False, f'incomplete case distinction in evalBefore({stackOp}, {nextOp})'


I am working on the file "Python/Chapter-06/Calculator-Frame.ipynb".
The first task is:
The function $\texttt{evaluate}(\texttt{self})$ evaluates the expression that is given by the tokens on the mTokenStack.
There are two phases:
1. The first phase is the reading phase. In this phase
   the tokens are removed from the token stack mTokens.
2. The second phase is the evaluation phase.  In this phase,
   the remaining operators on the operator stack mOperators are evaluated.  Note that some operators are already
   evaluated in the reading phase.
We can describe what happens in the reading phase using
rewrite rules that describe how the three stacks mTokens, mArguments and mOperators
are changed in each step.  Here, a step is one iteration of the first while-loop of the function evaluate.
The following rewrite rules are executed until the token stack mTokens is empty.
1. If the token on top of the token stack is an integer, it is removed from the token stack and pushed onto the argument stack.
   The operator stack remains unchanged in this case.
   $$\begin{array}{lc}
     \texttt{mTokens} = \texttt{mTokensRest} + [\texttt{token} ] & \wedge \
     \texttt{isInteger}(\texttt{token}) & \Rightarrow \[0.2cm]
     \texttt{mArguments}' = \texttt{mArguments} + [\texttt{token}] & \wedge \
     \texttt{mTokens}' = \texttt{mTokensRest} & \wedge \
     \texttt{mOperators}' = \texttt{mOperators}
     \end{array}
   $$
   Here, the primed variable $\texttt{mArguments}'$ refers to the argument stack after  $\texttt{token}$
   has been pushed onto it.
In the following rules we implicitly assume that the token on top of the token stack is not an integer but
   rather a parenthesis or a proper operator.  In order to be more concise, we suppress this precondition from the
   following rewrite rules.
2. If the operator stack is empty, the next token is pushed onto the operator stack.
   $$\begin{array}{lc}
     \texttt{mTokens} = \texttt{mTokensRest} + [\texttt{op} ] & \wedge \
     \texttt{mOperators} = [] & \Rightarrow...
Can you write Python code for it?

def evaluate(self):
    "your code here"
    return self.mArguments.top()

Calculator.evaluate = evaluate
del evaluate


I am working on the file "Python/Chapter-06/Calculator-Frame.ipynb".
The first task is:
The function $\texttt{findZero}(f, a, b, n)$ takes a function $f$ and two numbers $a$ and $b$ such that

$a < b$,
$f(a) \leq 0$, and
$0 \leq f(b)$.

It uses the bisection method to find a number $x \in [a, b]$ such that $f(x) \approx 0$.
Can you write Python code for it?

def findZero(f, a, b, n):
    assert a < b    , f'{a} has to be less than b'
    assert f(a) * f(b) <= 0, f'f({a}) * f({b}) > 0'
    if f(a) <= 0 <= f(b):
        for k in range(n):
            c = 0.5 * (a + b)
            # print(f'f({c}) = {f(c)}, {b-a}')
            if f(c) < 0:
                a = c
            elif f(c) > 0:
                b = c
            else:
                return c
    else:
        for k in range(n):
            c = 0.5 * (a + b)
            # print(f'f({c}) = {f(c)}, {b-a}')
            if f(c) > 0:
                a = c
            elif f(c) < 0:
                b = c
            else:
                return c
    return (a + b) / 2

def f(x):
    return 2 - x ** 2

r = findZero(f, 0, 2, 54)
r

r * r


I am working on the file "Python/Chapter-06/Calculator-Frame.ipynb".
The first task is:
The function $\texttt{isConstOperator}(o)$ returns True of $o$ is a constant like eor pi.
The variable x is also considered as a constant operator.
Can you write Python code for it?

def isConstOperator(op):
    "your code here"


I am working on the file "Python/Chapter-06/Calculator-Frame.ipynb".
The first task is:
The function $\texttt{isLeftAssociative}(o)$ returns True of $o$ is left associative.
Can you write Python code for it?

def isLeftAssociative(op):
    "your code here"
    assert False, f'unkown operator in isLeftAssociative: {op}'


I am working on the file "Python/Chapter-06/Calculator-Frame.ipynb".
The first task is:
The function $\texttt{isUnaryOperator}(o)$ returns True of $o$ is a unary operator.
Can you write Python code for it?

def isUnaryOperator(op):
    "your code here"


I am working on the file "Python/Chapter-06/Calculator-Frame.ipynb".
The first task is:
The function $\texttt{isWhiteSpace}(s)$ checks whether $s$ contains only blanks and tabulators.
Can you write Python code for it?

def isWhiteSpace(s):
    whitespace = re.compile(r'[ \t]+')
    return whitespace.fullmatch(s)


I am working on the file "Python/Chapter-06/Calculator-Frame.ipynb".
The first task is:
The function $\texttt{precedence}(o)$ calculates the precedence of the operator $o$.
Can you write Python code for it?

def precedence(op):
    "your code here"
    assert False, f'unkown operator in precedence: {op}'


I am working on the file "Python/Chapter-06/Calculator-Frame.ipynb".
The first task is:
The function $\texttt{toFloat}(s)$ tries to convert the string $s$ to a floating point number.  If this works out, this number is returned.  Otherwise, the string $s$ is returned unchanged.
Can you write Python code for it?

def toFloat(s):
    try:
        return float(s)
    except ValueError:
        return s

toFloat('0.123')

toFloat('+')


I am working on the file "Python/Chapter-06/Calculator-Frame.ipynb".
The first task is:
The function computeZero takes three arguments:
* s is a string that can be interpreted as a function $f$ of the variable x.
  For example, s could be equal to 'x * x - 2.0'.
* left and right are floating point numbers.
It is required that the function $f$ changes signs in the interval $[\texttt{left}, \texttt{right}]$.
Then computeZero returns a floating point value $x_0$ such that $f(x_0) \approx 0$.
Can you write Python code for it?

def computeZero(s, left, right):
    TL = tokenize(s)

    def f(x):
        c = Calculator(TL, x)
        return c.evaluate()

    return findZero(f, left, right, 54);


I am working on the file "Python/Chapter-06/Calculator-Frame.ipynb".
The first task is:
The function testEvaluateExpr takes three arguments:
- s is a string that can be interpreted as an arithmetic expression.
  This string might contain the variable $x$. In this arithmetic expression,
  unary function symbols need not be  be followed by parenthesis.
- t is a string that contains an arithmetic expression. The syntax
  of this expression has to follow the rules of the programming language
  python.
- x is a floating point value.  This value is supposed to be the value of
  the variable $x$ that might occur in s and t.
The function evaluates susing the class Calculator, while t is evaluated
using the predefined function eval.  If the results differ, an exception is raised.
Can you write Python code for it?

def testEvaluateExpr(s, t, x):
    TL = tokenize(s)
    C = Calculator(TL, x)
    r1 = C.evaluate()
    r2 = eval(t, { 'math': math }, { 'x': x })
    assert r1 == r2, f'{r1} != {r2}'

testEvaluateExpr('sin cos x', 'math.sin(math.cos(x))', 0)

testEvaluateExpr('sin x**2', 'math.sin(math.pi)**2', math.pi)

testEvaluateExpr('log e ** x + 1 * 2 - 3', 'math.log(math.e**x) + 1 * 2 - 3 ', 1)


I am working on the file "Python/Chapter-06/Calculator-Frame.ipynb".
The first task is:
The method $\texttt{popAndEvaluate}(\texttt{self})$ removes an operator from the operator stack and removes the corresponding arguments from the
arguments stack.  It evaluates the operator and pushes the result on the argument stack.
Can you write Python code for it?

def popAndEvaluate(self):
    "your code here"

Calculator.popAndEvaluate = popAndEvaluate
del popAndEvaluate


I am working on the file "Python/Chapter-06/Calculator-Frame.ipynb".
The first task is:
The method __str__ is used to convert an object of class Calculator to a string.
Can you write Python code for it?

def toString(self):
    return '\n'.join(['_'*50,
                      'TokenStack: ' + str(self.mTokens),
                      'Arguments:  ' + str(self.mArguments),
                      'Operators:  ' + str(self.mOperators),
                      '_'*50])

Calculator.__str__ = toString
del toString


I am working on the file "Python/Chapter-06/Calculator-Frame.ipynb".
The first task is:
The module math provides a number of mathematical functions like exp, sin, log etc.
Can you write Python code for it?


I am working on the file "Python/Chapter-06/Calculator.ipynb".
The first task is:
The Shunting Yard Algorithm (Operator Precedence Parsing)
The function $\texttt{toInt}(s)$ tries to convert the string $s$ to an integer.  If this works out, the integer is returned.  Otherwise, the string $s$ is returned unchanged.
Can you write Python code for it?

def toInt(s):
    try:
        return int(s)
    except ValueError:
        return s

toInt('123')

toInt('**')


I am working on the file "Python/Chapter-06/Calculator.ipynb".
The first task is:
The function $\texttt{evaluate}(\texttt{self})$ evaluates the expression that is given by the tokens on the mTokenStack.
There are two phases:
1. The first phase is the reading phase. In this phase
   the tokens are removed from the token stack mTokens.
2. The second phase is the evaluation phase.  In this phase,
   the remaining operators on the operator stack mOperators are evaluated.  Note that some operators are already
   evaluated in the reading phase.
We can describe what happens in the reading phase using
rewrite rules that describe how the three stacks mTokens, mArguments and mOperators
are changed in each step.  Here, a step is one iteration of the first while-loop of the function evaluate.
The following rewrite rules are executed until the token stack mTokens is empty.
1. If the token on top of the token stack is an integer, it is removed from the token stack and pushed onto the argument stack.
   The operator stack remains unchanged in this case.
   $$\begin{array}{lc}
     \texttt{mTokens} = \texttt{mTokensRest} + [\texttt{token} ] & \wedge \
     \texttt{isInteger}(\texttt{token}) & \Rightarrow \[0.2cm]
     \texttt{mArguments}' = \texttt{mArguments} + [\texttt{token}] & \wedge \
     \texttt{mTokens}' = \texttt{mTokensRest} & \wedge \
     \texttt{mOperators}' = \texttt{mOperators}
     \end{array}
   $$
   Here, the primed variable $\texttt{mArguments}'$ refers to the argument stack after  $\texttt{token}$
   has been pushed onto it.
In the following rules we implicitly assume that the token on top of the token stack is not an integer but
   rather a parenthesis or a proper operator.  In order to be more concise, we suppress this precondition from the
   following rewrite rules.
2. If the operator stack is empty, the next token is pushed onto the operator stack.
   $$\begin{array}{lc}
     \texttt{mTokens} = \texttt{mTokensRest} + [\texttt{op} ] & \wedge \
     \texttt{mOperators} = [] & \Rightarrow...
Can you write Python code for it?

def evaluate(self):
    while not self.mTokens.isEmpty():
        print(self) # only for debugging
        nextOp = self.mTokens.top(); self.mTokens.pop()
        if isinstance(nextOp, int):
            self.mArguments.push(nextOp)
            continue
        if self.mOperators.isEmpty():
            self.mOperators.push(nextOp)
            continue
        if nextOp == "(":
            self.mOperators.push(nextOp)
            continue
        stackOp = self.mOperators.top()
        if stackOp == "(" and nextOp == ")":
            self.mOperators.pop()
            continue
        if nextOp == ")":
            self.popAndEvaluate()
            self.mTokens.push(nextOp)
            continue
        if stackOp == '(':
            self.mOperators.push(nextOp)
            continue
        if evalBefore(stackOp, nextOp):
            self.popAndEvaluate()
            self.mTokens.push(nextOp)
        else:
            self.mOperators.push(nextOp)
    while not self.mOperators.isEmpty():
        print(self) # only for debugging
        self.popAndEvaluate()
    print(self)
    return self.mArguments.top()

Calculator.evaluate = evaluate
del evaluate


I am working on the file "Python/Chapter-06/Calculator.ipynb".
The first task is:
The function $\texttt{tokenize}(s)$ takes a string $s$ representing an arithmetic expression and splits this string into a list of tokens.
The string regExp in the implementation below is interpreted as follows:

The r in front of the apostrophe ' specifies that the regular expression is defined as a raw string.
    In a raw string the backslash does not have to be escaped because it is treated as a literal character.
The regular expression is divided into three parts. These parts are separated by the character |.
[0-9]+ matches a natural number.  For example, it matches 0 or 123.  It would also match a string like 007.
     The + at the end of the substring [0-9]+ specifies that there are any positive number of the characters in the range [0-9].
\*\* matches the operator **.
[()+*/%-] matches a parenthesis or an arithmetical operator.  Note that we have
     to put the symbol - last in this group as otherwise this symbol would be
     interpreted as a range operator.
Can you write Python code for it?


I am working on the file "Python/Chapter-06/Calculator.ipynb".
The first task is:
The function evalBefore(o1, o2) receives to strings representing arithmetical operators.  It returns True if the operator $o_1$ should be evaluated before the operator $o_2$ in an arithmetical expression of the form $a \;\texttt{o}_1\; b \;\texttt{o}_2\; c$.  In order to determine whether $o_1$ should be evaluated before $o_2$ it uses the precedence and the associativity of the operators.
Its behavior is specified by the following rules:
- $\texttt{precedence}(o_1) > \texttt{precedence}(o_2) \rightarrow \texttt{evalBefore}(\texttt{o}_1, \texttt{o}_2) = \texttt{True}$,
- $o_1 = o_2 \rightarrow \texttt{evalBefore}(\texttt{o}_1, \texttt{o}_2) = \texttt{isLeftAssociative}(o_1)$,
- $\texttt{precedence}(o_1) = \texttt{precedence}(o_2) \wedge o_1 \not= o_2 \rightarrow \texttt{evalBefore}(\texttt{o}_1, \texttt{o}_2) = \texttt{True}$,
- $\texttt{precedence}(o_1) < \texttt{precedence}(o_2) \rightarrow \texttt{evalBefore}(\texttt{o}_1, \texttt{o}_2) = \texttt{False}$.
Can you write Python code for it?

def evalBefore(stackOp, nextOp):
    if precedence(stackOp) > precedence(nextOp):
        return True
    if stackOp == nextOp:
        return isLeftAssociative(stackOp)
    if precedence(stackOp) == precedence(nextOp) and stackOp != nextOp:
        return True
    if precedence(stackOp) < precedence(nextOp):
        return False
    assert False, f'incomplete case distinction in evalBefore({stackOp}, {nextOp})'

%%capture
%run Stack.ipynb


I am working on the file "Python/Chapter-06/Calculator.ipynb".
The first task is:
The method __str__ is used to convert an object of class Calculator to a string.
Can you write Python code for it?

def toString(self):
    return '\n'.join(['_'*50,
                      'Tokens:    ', str(self.mTokens),
                      'Arguments: ', str(self.mArguments),
                      'Operators: ', str(self.mOperators),
                      '_'*50])

Calculator.__str__ = toString
del toString

Calculator.__repr__ = Calculator.__str__


I am working on the file "Python/Chapter-06/Ordered-Binary-Tree.ipynb".
The first task is:
Given a binary tree t the method t._assignIDs(NodeDict) assigns a unique identifier with each node.  The dictionary NodeDict maps these identifiers to the nodes where they occur.
Can you write Python code for it?

def _assignIDs(self, NodeDict):
    OrderedBinaryTree.sNodeCount += 1
    self.mID = OrderedBinaryTree.sNodeCount
    NodeDict[self.mID] = self
    if self.isEmpty():
        return
    self.mLeft ._assignIDs(NodeDict)
    self.mRight._assignIDs(NodeDict)

OrderedBinaryTree._assignIDs = _assignIDs
del _assignIDs


I am working on the file "Python/Chapter-06/Ordered-Binary-Tree.ipynb".
The first task is:
Given an ordered binary tree $b$, the method $b.\texttt{keyList}()$ returns the list of all keys occurring in $b$.
Note that this list has to be sorted ascendingly.
Can you write Python code for it?

def keyList(self):
    if self.isEmpty():
        return []
    return self.mLeft.keyList() + [self.mKey] + self.mRight.keyList()

OrderedBinaryTree.keyList = keyList
del keyList

import graphviz as gv


I am working on the file "Python/Chapter-06/Ordered-Binary-Tree.ipynb".
The first task is:
Given an ordered binary tree $t$, a key $k$ and a value $v$, the expression $t.\texttt{insert}(k, v)$ updates the tree $t$ such that the key $k$ is associated with the value $v$.
The method insert is defined inductively as follows:
  - $\texttt{Nil}.\texttt{insert}(k,v) = \texttt{Node}(k,v, \texttt{Nil}, \texttt{Nil})$,
If the tree is empty, the information to be stored is stored at the root.

$\texttt{Node}(k,v_2,l,r).\texttt{insert}(k,v_1) = \texttt{Node}(k, v_1, l, r)$,
If the key $k$ is located at the root, we overwrite the old information.
  - $k_1 < k_2 \rightarrow
\texttt{Node}(k_2, v_2, l, r).\texttt{insert}(k_1, v_1) = \texttt{Node}\bigl(k_2, v_2, l.\texttt{insert}(k_1, v_1), r\bigr)$,
If the key $k_1$, which is the key for which we want to store a value, is less than the key
$k_2$ at the root, then we have to insert the information in the left subtree.
  - $k_1 > k_2 \rightarrow
     \texttt{Node}(k_2, v_2, l, r).\texttt{insert}(k_1, v_1) =
     \texttt{Node}\bigl(k_2, v_2, l, r.\texttt{insert}(k_1, v_1)\bigr)$,
If the key $k_1$, which is the key for which we want to store a value, is bigger than the key
$k_2$ at the root, then we have to insert the information in the right subtree.
Can you write Python code for it?

def insert(self, key, value):
    if self.isEmpty():
        self.mKey   = key
        self.mValue = value
        self.mLeft  = OrderedBinaryTree()
        self.mRight = OrderedBinaryTree()
    elif self.mKey == key:
        self.mValue = value
    elif key < self.mKey:
        self.mLeft.insert(key, value)
    else:
        self.mRight.insert(key, value)

OrderedBinaryTree.insert = insert
del insert


I am working on the file "Python/Chapter-06/Ordered-Binary-Tree.ipynb".
The first task is:
Ordered Binary Trees
This notebook implements ordered binary trees.  In order to define this notion, we first have to define
the concept of ordered binary trees.  In the following, assume a set $\texttt{Key}$ and a set $\texttt{Value}$ are given.   Then, the
set $\mathcal{B}$ of all ordered binary trees is defined inductively.
  - $\texttt{Nil} \in \mathcal{B}$
  - $\texttt{Node}(k, v, l, r) \in \mathcal{B}$  iff the following conditions hold:
      - $k \in\texttt{Key}$,
      - $v \in\texttt{Value}$,
      - $l \in\mathcal{B}$,
      - $r \in\mathcal{B}$,
      - all keys that occur in the left subtree $l$ are smaller than $k$,
      - all keys that occur in the right subtree $r$ are bigger than $k$,
    therefore $l < k < r$.

The class OrderedBinaryTree represents the nodes of an ordered binary tree.
  - $\texttt{Nil}$           is created as $\texttt{OrderedBinaryTree}()$.
  - $\texttt{Node}(k,v,l,r)$ is created as follows:
    t = OrderedBinaryTree()
    t.mKey   = k
    t.mValue = v
    t.mLeft  = l
    t.mRight = r
The constructor below creates the empty tree.
Can you write Python code for it?

class OrderedBinaryTree:
    def __init__(self):
        self.mKey   = None
        self.mValue = None
        self.mLeft  = None
        self.mRight = None


I am working on the file "Python/Chapter-06/Ordered-Binary-Tree.ipynb".
The first task is:
The function $\texttt{demo}()$ creates a small ordered binary tree.
Can you write Python code for it?

def demo():
    m = OrderedBinaryTree()
    m.insert("anton",  123)
    m.insert("hugo" ,  345)
    m.insert("gustav", 789)
    m.insert("jens",   234)
    m.insert("hubert", 432)
    m.insert("andre",  342)
    m.insert("philipp", 342)
    m.insert("rene",   345)
    m.insert("ans", 123)
    m.insert("alfa", 123)
    m.insert("algo", 345)
    return m

t = demo()
t.toDot()

t.delete('anton')
t.toDot()

t.delete('gustav')
t.toDot()

t.delete('hubert')
t.toDot()


I am working on the file "Python/Chapter-06/Stack.ipynb".
The first task is:
By defining the function S.__repr__() for stack objects, we can print stacks in Jupyter notebooks without calling the function print.
Can you write Python code for it?

Stack.__repr__ = Stack.__str__

S

for i in range(10):
    print(S.top())
    S.pop()
    print(S)


I am working on the file "Python/Chapter-06/Stack.ipynb".
The first task is:
Next we define a constructor for this class.  The function stack(S) takes an uninitialized, empty object S
and initializes its member variable mStackElements.  This member variable is a list containing the data
stored in the stack.
Can you write Python code for it?


I am working on the file "Python/Chapter-06/Stack.ipynb".
The first task is:
Next, we add the method push to the class Stack.  The method $\texttt{push}(S, e)$ pushes $e$ onto the stack $S$.
Can you write Python code for it?

def push(S, e):
    S.mStackElements += [e]


I am working on the file "Python/Chapter-06/Stack.ipynb".
The first task is:
The method S.copy() creates a shallow copy of the given stack, i.e. the copy contains the same objects as
the stack S.
Can you write Python code for it?

def copy(S):
    C = Stack()
    C.mStackElements = S.mStackElements[:]
    return C

Stack.copy = copy
del copy


I am working on the file "Python/Chapter-06/Stack.ipynb".
The first task is:
The method S.isEmpty() checks whether the stack S is empty.
Can you write Python code for it?

def isEmpty(S):
    return S.mStackElements == []

Stack.isEmpty = isEmpty
del isEmpty


I am working on the file "Python/Chapter-06/Stack.ipynb".
The first task is:
The method S.toStr() converts a stack S into a string.  Note that we assign it to the method __str__.  This method is called automatically when an object of class Stack is cast into a string.
Can you write Python code for it?

def toStr(S):
    C = S.copy()
    result = C._convert()
    dashes = "-" * len(result)
    return '\n'.join([dashes, result, dashes])

Stack.__str__ = toStr
del toStr


I am working on the file "Python/Chapter-06/Stack.ipynb".
The first task is:
The method convert converts a stack into a string.
Can you write Python code for it?

def convert(S):
    if S.isEmpty():
        return '|'
    top = S.top()
    S.pop()
    return S._convert() + ' ' + str(top) + ' |'

Stack._convert = convert
del convert


I am working on the file "Python/Chapter-06/Stack.ipynb".
The first task is:
The method top returns the element that is on top of the stack.
It is an error to call this method if the stack is empty.
Can you write Python code for it?

def top(S):
    assert len(S.mStackElements) > 0, "top of empty stack"
    return S.mStackElements[-1]

Stack.top = top
del top


I am working on the file "Python/Chapter-06/Stack.ipynb".
The first task is:
We add this method to the class Stack.
Can you write Python code for it?


I am working on the file "Python/Chapter-06/Trie.ipynb".
The first task is:
Finally, we specify the function
$$\texttt{findPrefix}:\mathbb{T} \times \Sigma^ \rightarrow \texttt{Set}(\Sigma^)$$
so that given a trie $T$ and a prefix $p$, the expression $T.\texttt{findPrefix}(p)$ finds all
strings $s \in T$ that have the prefix $p$, i.e. that can be written in the form $s=p+r$:
$$ T.\texttt{findPrefix}(p) = \bigl{ p+r \mid p+r \in T \bigr}. $$
Having defined the auxiliary function _findPrefix, the function findPrefix can be
implemented as follows:
$$ T.\texttt{findPrefix}(s) = T.\texttt{replacePrefix}(s, s). $$
Can you write Python code for it?

def findPrefix(self, s):
    return self.replacePrefix(s, s)

Trie.findPrefix = findPrefix
del findPrefix


I am working on the file "Python/Chapter-06/Trie.ipynb".
The first task is:
For a trie  $t \in \mathbb{T}$ and a string $w \in \Sigma^*$ the value $t.\texttt{delete}(w)$
is defined by induction on the length of  $w$.
  - $\texttt{Trie}(v,C,T).\texttt{delete}(\varepsilon) = \texttt{Trie}(\Omega,C,T)$
The value that is associated with the empty  string $\varepsilon$ is stored at the root of the
trie where is can be deleted without further ado.

$\begin{array}[t]{ll}
     t_i.\texttt{delete}(r).\texttt{isEmpty}()   & \rightarrow \
     \texttt{Trie}(v, [c_1,\cdots,c_i,\cdots,c_n],[t_1,\cdots,t_i,\cdots,t_n]).\texttt{delete}(c_ir)
     & = \
     \qquad
     \texttt{Trie}(v, [c_1,\cdots,c_{i-1},c_{i+1},\cdots,c_n],[t_1,\cdots,t_{i-1},t_{i+1},\cdots,t_n]).
     \end{array}
    $
If  the key that is to be deleted starts with the character $c_i$ and if deletion of  the key
$r$ in the $i$th  trie $t_i$ yields an empty
trie, then both the $i^\mathrm{th}$ character $c_i$ and the $i^\mathrm{th}$ trie $t_i$ are deleted.
  - $\begin{array}[t]{ll}
 \neg t_i.\texttt{delete}(r).\texttt{isEmpty}()   & \rightarrow \
 \texttt{Trie}(v, [c_1,\cdots,c_i,\cdots,c_n],[t_1,\cdots,t_i,\cdots,t_n]).\texttt{delete}(c_ir)
 & = \
 \qquad \texttt{Trie}(v, [c_1,\cdots,c_i,\cdots,c_n],[t_1,\cdots,t_i.\texttt{delete}(r),\cdots,t_n]).
 \end{array}
$
If  the key that is to be deleted starts with the character $c_i$ and if deletion of  the key
$r$ in the $i^\mathrm{th}$  trie $t_i$ yields a non-empty trie, then the key $r$ has to be deleted recursively
in the trie $t_i$.
  - $c \notin C \rightarrow \texttt{Trie}(v, C, T).\texttt{delete}(cr) =
   \texttt{Trie}(v, C, T)$.
If  the key that is to be deleted starts with the character $c$ and  $c$ does not occur in
the list of characters $C$, then the trie does not contain the key $cr$ and therefore there
is nothing  to do:  The trie is left unchanged.
Can you write Python code for it?

def delete(self, s):
    if s == '':
        self.mValue = None
        return
    c, r = s[0], s[1:]
    for i, ci in enumerate(self.mChars):
        if c == ci:
            self.mTries[i].delete(r)
            if self.mTries[i].isEmpty():
                self.mChars.pop(i)
                self.mTries.pop(i)
            return

Trie.delete = delete
del delete


I am working on the file "Python/Chapter-06/Trie.ipynb".
The first task is:
Graphical Representation via GraphViz
Can you write Python code for it?

import graphviz as gv

def toDot(self):
    Trie.sTrieCount = 0 # this is a static variable of the class Trie
    dot = gv.Digraph(node_attr={'shape': 'record', 'style': 'rounded'})
    TrieDict = {}
    self._assignIDs(TrieDict)
    for id, t in TrieDict.items():
        if t.mValue != None:
            dot.node(id, label='{' + t.mParent + '|' + str(t.mValue) + '}')
        else:
            dot.node(id, label=t.mParent)
    for id, t in TrieDict.items():
        for x in t.mTries:
            dot.edge(id, x.mID)
    return dot

Trie.toDot = toDot
del toDot

def _assignIDs(self, TrieDict):
    Trie.sTrieCount += 1
    self.mID = str(Trie.sTrieCount)
    TrieDict[self.mID] = self
    for t in self.mTries:
        t._assignIDs(TrieDict)

Trie._assignIDs = _assignIDs
del _assignIDs


I am working on the file "Python/Chapter-06/Trie.ipynb".
The first task is:
In order to implement deletion in tries, we need the auxiliary function isEmpty.  Its signature is given as
$$ \texttt{isEmpty}: \mathbb{T} \rightarrow \mathbb{B}. $$
For a trie $t$, we have $t.\texttt{isEmpty}() = \texttt{True}$ if and only if the trie $t$ does not
store any key.  The following formula specifies the function $\texttt{isEmpty}$:
$$ \texttt{Trie}(v, L, T).\texttt{isEmpty}() = \mathtt{True} \Leftrightarrow v = \Omega \wedge L = []. $$
Note that the condition $L = []$ implies $T = []$.
Can you write Python code for it?

def isEmpty(self):
    return self.mValue == None and self.mChars == []

Trie.isEmpty = isEmpty
del isEmpty


I am working on the file "Python/Chapter-06/Trie.ipynb".
The first task is:
In order to specify the meaning of the class Trie we define the function find,
which can be used to re<u>trie</u>ve the values stored in a trie.
This function has the signature
$$ \texttt{find}: \mathbb{T} \times \Sigma^* \rightarrow \texttt{Value} \cup { \Omega}. $$
For a trie $t$ and a string $s$, the expression $t.\texttt{find}(s)$ returns the
value that is associated with the key $s$ in the trie $t$.  The expression
$\texttt{Trie}(v,C!s,T!s).\texttt{find}(s)$ is defined by induction on the length of the  string $s$:
  - $\texttt{Trie}(v, C!s, T!s).\texttt{find}(\varepsilon) = v$.
The value associated with the empty string $\varepsilon$ is stored at the root of the trie.

$c = c_i \rightarrow
     \texttt{Trie}(v, [c_1, \cdots, c_n], [t_1, \cdots, t_n]).\texttt{find}(cr) = t_i.\texttt{find}(r)
    $
The trie $\texttt{Trie}(v, [c_1, \cdots, c_n], [t_1, \cdots, t_n])$ associates a value with
the key $cr$ if the list $[c_1, \cdots, c_n]$ has a position $i$ such that $c$ equals $c_i$
and, furthermore, the trie  $t_i$ associates a value with the key  $r$.
  - $ c \not\in C!s \rightarrow
 \texttt{Trie}(v, C!s, T!s).\texttt{find}(cr) = \Omega
$
If $c$ does not occur in the list $C!s$, then the trie $\texttt{Trie}(v, C!s, T!s)$ does not store a value for
the key $cr$.
Can you write Python code for it?

def find(self, s):
    if s == '':
        return self.mValue
    c, r = s[0], s[1:]
    for i, ci in enumerate(self.mChars):
        if c == ci:
            return self.mTries[i].find(r)
    return None # not necessary

Trie.find = find
del find

list(enumerate(['a', 'b', 'c']))


I am working on the file "Python/Chapter-06/Trie.ipynb".
The first task is:
Let us compute all key stored in this trie, as these are the prime numbers.
Can you write Python code for it?

print(sorted([int(p) for p in S.allKeys()]))


I am working on the file "Python/Chapter-06/Trie.ipynb".
The first task is:
Let us compute the prime numbers less than $100$.  Note that we have to convert numbers to strings in order to be able to use tries.
Can you write Python code for it?

S = Trie()
for i in range(2, 101):
    S.insert(str(i), i)
for i in range(2, 51):
    for j in range(i, 100 // i + 1):
        S.delete(str(i * j))
S.toDot()


I am working on the file "Python/Chapter-06/Trie.ipynb".
The first task is:
Testing
Can you write Python code for it?

t = Trie()
t.toDot()

t.insert("Hans", 1)
t.toDot()

t.insert("Hanna", 2)
t.toDot()

t.insert("Hilde", 3)
t.toDot()

t.insert("Hugo", 4)
t.toDot()

t.insert('Hildegard', 6)
t.toDot()

t.findPrefix('Hi')

t.insert("Harro", 5)
t.toDot()

t.insert("Heike", 6)
t.toDot()

t.insert("Heiko", 7)
t.toDot()

t.find('Hilde')

t.insert("Harald", 8)
t.insert("Hasso", 9)
t.insert("Haley", 1)
t.insert("Hanny", 1)
t.insert("Happy", 1)
t.insert("Harlene", 1)
t.insert("Harley", 1)
t.insert("Harmony", 1)
t.insert("Harriet", 1)
t.insert("Harrietta", 1)
t.insert("Hazel", 1)
t.insert("Heather", 1)
t.insert("Hedwig", 1)
t.insert("Hedy", 1)
t.insert("Heidi", 1)
t.insert("Helaina", 1)
t.insert("Helaine", 1)
t.insert("Helen", 1)
t.insert("Helena", 1)
t.insert("Helene", 1)
t.insert("Helga", 1)
t.insert("Hendrika", 1)
t.insert("Henrietta", 1)
t.insert("Henriette", 1)
t.insert("Hermione", 1)
t.insert("Herta", 1)
t.insert("Hilary", 1)
t.insert("Hilda", 1)
t.toDot()

t.findPrefix('Hea')

t.findPrefix('Hel')

t.delete('Hanny')
t.toDot()

t.insert('Auto', 7)
t.toDot()

t.allKeys()

t.delete("Hans")
t.delete("Hanna")
t.delete("Hilde")
t.delete("Hugo")
t.delete("Harro")
t.delete("Heike")
t.delete("Heiko")
t.delete("Harald")
t.delete("Hasso")
t.delete("Haley")
t.delete("Hanny")
t.delete("Happy")
t.delete("Harlene")
t.delete("Harley")
t.delete("Harmony")
t.delete("Harriet")
t.delete("Harrietta")
t.delete("Hazel")
t.delete("Heather")
t.delete("Hedwig")
t.delete("Hedy")
t.delete("Heidi")
t.delete("Helaina")
t.delete("Helaine")
t.delete("Helen")
t.delete("Helena")
t.delete("Helene")
t.delete("Helga")
t.delete("Hendrika")
t.delete("Henrietta")
t.delete("Henriette")
t.delete("Hermione")
t.delete("Herta")
t.delete("Hilary")
t.delete("Hilda")
t.toDot()


I am working on the file "Python/Chapter-06/Trie.ipynb".
The first task is:
The signature of the method $\texttt{insert}$ is given as follows:
$$ \texttt{insert}: \mathbb{T} \times \Sigma^ \times \texttt{Value} \rightarrow \mathbb{T}. $$
The result of evaluating
$$ \texttt{Trie}(v_1, [c_1, \cdots, c_n], [t_1, \cdots, t_n]).\texttt{insert}(w, v_2) $$
for a string $w\in \Sigma^$ and a value $v_2 \in \texttt{Value}$ is defined by induction on the
length of $w$:
  - $\texttt{Trie}(v_1,L,T).\texttt{insert}(\varepsilon, v_2) = \texttt{Trie}(v_2,L,T)$.
If a new value $v_2$ is associated with the empty string $\varepsilon$, then the old value
$v_1$, which had been stored at the root before, is overwritten.

$\texttt{Trie}\bigl(v_1,[c_1,\cdots,c_i,\cdots,c_n], [t_1,\cdots,t_i,\cdots,t_n]\bigr).\texttt{insert}(c_ir,v_2) =
     \texttt{Trie}\bigl(v_1,[c_1,\cdots,c_i,\cdots,c_n], [t_1,\cdots,t_i.\texttt{insert}(r,v_2),\cdots,t_n]\bigr)$.
In order to associate a value $v_2$ with the string $c_ir$ in the trie
$$ \texttt{Trie}\bigl(v_1,[c_1,\cdots,c_i,\cdots,c_n], [t_1,\cdots,t_i,\cdots,t_n]\bigr) $$
we have to recursively associate the value $v_2$ with the string $r$ in the trie $t_i$.
  - $c \not\in{c_1,\cdots,c_n} \;\rightarrow\;\texttt{Trie}\bigl(v_1,[c_1,\cdots,c_n], [t_1,\cdots,t_n]\bigr).\texttt{insert}(cr,v_2) =
 \texttt{Trie}\bigl(v_1,[c_1,\cdots,c_n,c], [t_1,\cdots,t_n,\texttt{Trie}(\Omega,[],[]).\texttt{insert}(r,v_2)]\bigr)$.
If we want to associate a value $v$ with the key $cr$ in the trie
$\texttt{Trie}\bigl(v_1,[c_1,\cdots,c_n], [t_1,\cdots,t_n]\bigr)$ then, if the character $c$
does not occur in the list $[c_1,\cdots,c_n]$, we first have to create a new empty trie.
This trie has the form
$$ \texttt{Trie}(\Omega, [], []). $$
Next, we associate the value $v_2$ with the key $r$ in this empty trie.  Finally,
we append the character $c$ to the end of the list $[c_1,\cdots,c_n]$ and append the trie
$$ \texttt{Trie}(\Omega, [], []).\texttt{insert}(r,v_2) $$
to the end of the list $[t_1,\cdots,t_n]$.
Can you write Python code for it?

def insert(self, s, v):
    if s == '':
        self.mValue = v
        return
    c, r = s[0], s[1:]
    for i, ci in enumerate(self.mChars):
        if c == ci:
            self.mTries[i].insert(r, v)
            return
    t = Trie()
    t.insert(r, v)
    t.mParent = c # necessary for visualization
    self.mChars.append(c)
    self.mTries.append(t)

Trie.insert = insert
del insert


I am working on the file "Python/Chapter-06/Trie.ipynb".
The first task is:
Tries
A trie is a data structure that implements the abstract data type of a dictionary in the case that the keys are strings.
The set $\mathbb{T}$ of all tries is defined inductively using the constructor
$$ \texttt{Trie}: \texttt{Value} \times \texttt{List}(\Sigma) \times\texttt{List}(\mathbb{T}) \rightarrow \mathbb{T}. $$
Here $\Sigma$ is the alphabet, i.e. the set of characters.
The inductive definition of the set $\mathbb{T}$ has only a single clause: If
  - $v \in \texttt{Value} \cup {\Omega}$,
  - $C!s = [c_1, \cdots, c_n] \in \texttt{List}(\Sigma)$ is a list of different characters of length $n$ and
  - $T!s = [t_1, \cdots, t_n] \in \texttt{List}(\mathbb{T})$ is a list of tries of the same length $n$,
then we have
$$ \texttt{Trie}(v, C!s, T!s) \in \mathbb{T}. $$
The class Trie defined below implements tries.  An object $t$ of the class Trie represents the trie
$$ \texttt{Trie}(t.\texttt{mValue}, t.\texttt{mChars}, t.\texttt{mTries}). $$
The constructor __init__ creates an empty trie.
Can you write Python code for it?

class Trie:
    def __init__(self):
        self.mValue  = None
        self.mChars  = []
        self.mTries  = []
        self.mParent = '' # only used by graphviz


I am working on the file "Python/Chapter-07/.ipynb_checkpoints/Heap-checkpoint.ipynb".
The first task is:
$\texttt{Node}(p,v,\texttt{Nil},r).\texttt{remove}() = r$
$\texttt{Node}(p,v,l,\texttt{Nil}).\texttt{remove}() = l$
$l = \texttt{Node}(p_1,v_1,l_1,r_1) \;\wedge\; r = \texttt{Node}(p_2,v_2,l_2,r_2) \;\wedge\; p_1 \leq p_2 \;\rightarrow
     \texttt{Node}(p,v,l,r).\texttt{remove}() =      \texttt{Node}(p_1,v_1,l.\texttt{remove}(),r)$
$l = \texttt{Node}(p_1,v_1,l_1,r_1) \;\wedge\; r = \texttt{Node}(p_2,v_2,l_2,r_2) \;\wedge\; p_1 > p_2 \rightarrow
     \texttt{Node}(p,v,l,r).\texttt{remove}() = \texttt{Node}(p_2,v_2,l,r.\texttt{remove}())$
Can you write Python code for it?

def remove(self):
    p, v, l, r = self._extract()
    if isinstance(l, Nil):
        return r
    if isinstance(r, Nil):
        return l
    p1, v1, l1, r1 = l._extract()
    p2, v2, l2, r2 = r._extract()
    if p1 <= p2:
        return Node(p1, v1, l.remove(), r)
    else:
        return Node(p2, v2, l, r.remove())

Node.remove = remove
del remove


I am working on the file "Python/Chapter-07/.ipynb_checkpoints/Heap-checkpoint.ipynb".
The first task is:
For the class Node, the function top is specified via the following equation:
- $\texttt{Node}(p,v,l,r).\texttt{top}() = (p,v)$
Can you write Python code for it?

def top(self):
    return self.mPriority, self.mValue

Node.top = top
del top


I am working on the file "Python/Chapter-07/.ipynb_checkpoints/Heap-checkpoint.ipynb".
The first task is:
Graphical Representation
Can you write Python code for it?


I am working on the file "Python/Chapter-07/.ipynb_checkpoints/Heap-checkpoint.ipynb".
The first task is:
Heapsort
Given a list L, the function heap_sort(L) returns a sorted version of L.  The algorithm works in two phases.
- In the first phase, all elements of the list L are inserted into the empty heap H, which is initially empty.
- In the second phase, the elements of H are extracted one by one beginning with the smallest elements.  These elements
  are appended to the list S, which is initially empty. When the function returns, H contains all the elements of L
  and is sorted ascendingly.
Can you write Python code for it?

def heap_sort(L):
    H = Nil()
    for p in L:
        H = H.insert(p, None)
    S = []
    display(H.toDot())
    while isinstance(H, Node):
        p, _ = H.top()
        S.append(p)
        H = H.remove()
    return S

heap_sort([77, 54, 68, 7, 13, 1, 4, 5, 6, 3, 12, 67, 12, 14, 23, 54, 67])


I am working on the file "Python/Chapter-07/.ipynb_checkpoints/Heap-checkpoint.ipynb".
The first task is:
Implementing the Method  remove

$\texttt{Nil}.\texttt{remove}() = \texttt{Nil}$
Can you write Python code for it?

def remove(self):
    return self

Nil.remove = remove


I am working on the file "Python/Chapter-07/.ipynb_checkpoints/Heap-checkpoint.ipynb".
The first task is:
Implementing the Method  top
For the class Nil, the function topis specified via a single equation:
 - $\texttt{Nil}.\texttt{top}() = \Omega$
Can you write Python code for it?

def top(self):
    return None

Nil.top = top


I am working on the file "Python/Chapter-07/.ipynb_checkpoints/Heap-checkpoint.ipynb".
The first task is:
The method $t.\texttt{collectIDs}(d)$ takes a binary trie $t$ and a dictionary $d$ and updates the dictionary so that the following holds:
$$ d[\texttt{id}] = n \quad \mbox{for every node $n$ in $t$.} $$
Here, $\texttt{id}$ is the unique identifier of the node $n$, i.e. $d$ associates the identifiers with the corresponding nodes.
Can you write Python code for it?

def _collectIDs(self, nodeDict):
    nodeDict[self.getID()] = self
    if isinstance(self, Node):
        self.mLeft ._collectIDs(nodeDict)
        self.mRight._collectIDs(nodeDict)

Heap._collectIDs = _collectIDs


I am working on the file "Python/Chapter-07/.ipynb_checkpoints/Heap-checkpoint.ipynb".
The first task is:
The method $t.\texttt{toDot}()$ takes a binary trie $t$ and returns a graph that depicts the tree $t$.
Can you write Python code for it?

def toDot(self):
    dot = gv.Digraph(node_attr={'shape': 'record', 'style': 'rounded'})
    nodeDict = {}
    self._collectIDs(nodeDict)
    for n, t in nodeDict.items():
        if isinstance(t, Nil):
            dot.node(n, label='', shape='point')
        elif isinstance(t, Node):
            if t.mValue != None:
                dot.node(n, label='{' + str(t.mPriority) + '|' + str(t.mValue) + '}')
            else:
                dot.node(n, label= str(t.mPriority))
        else:
            assert False, f'Unknown node {t}'
    for n, t in nodeDict.items():
        if isinstance(t, Node):
            dot.edge(n, t.mLeft .getID())
            dot.edge(n, t.mRight.getID())
    return dot

Heap.toDot = toDot


I am working on the file "Python/Chapter-07/2-3-Trees-Frame.ipynb".
The first task is:
$\displaystyle\texttt{Two}(l,k,r).\texttt{ins}(k) = \texttt{Two}(l,k,r)$
Can you write Python code for it?

toDotList([Method('k1 < k2:'), Two(Nil(), 'k1', Nil()), Method('.ins(k2)'), Three(Nil(), 'k1', Nil(), 'k2', Nil()) ])


I am working on the file "Python/Chapter-07/2-3-Trees-Frame.ipynb".
The first task is:
$\texttt{Four}(l, k_l, m_l, k_m, m_r, k_r, r).\texttt{grow}() =
     \texttt{Two}\bigl(\texttt{Two}(l, k_l, m_l), k_m, \texttt{Two}(m_r, k_r, r)\bigr)$
Can you write Python code for it?

def _grow(self):
    "your code here"

Four._grow = _grow


I am working on the file "Python/Chapter-07/2-3-Trees-Frame.ipynb".
The first task is:
$\texttt{Three}\bigl(\texttt{Four}(l_1,k_1,m_l,k_2,m_r,k_3,r_1), k_l, m, k_r, r\bigr).\texttt{restore}() =
     \texttt{Four}\bigl(\texttt{Two}(l_1, k_1, m_l), k_2, \texttt{Two}(m_r, k_3, r_1), k_l, m, k_r, r\bigr) $
Can you write Python code for it?


I am working on the file "Python/Chapter-07/2-3-Trees-Frame.ipynb".
The first task is:
$\texttt{Three}\bigl(l, k_l, \texttt{Four}(l_1,k_1,m_l,k_2,m_r,k_3,r_1), k_r, r\bigr).\texttt{restore}() =
     \texttt{Four}\bigl(l, k_l, \texttt{Two}(l_1, k_1, m_l), k_2, \texttt{Two}(m_r, k_3, r_1), k_r, r\bigr) $
Can you write Python code for it?


I am working on the file "Python/Chapter-07/2-3-Trees-Frame.ipynb".
The first task is:
$\texttt{Three}\bigl(l, k_l, m, k_r, \texttt{Four}(l_1,k_1,m_l,k_2,m_r,k_3,r_1)\bigr).\texttt{restore}() =
     \texttt{Four}\bigl(l, k_l, m, k_r, \texttt{Two}(l_1, k_1, m_l), k_2, \texttt{Two}(m_r, k_3, r_1)\bigr) $

Below I have collected all the equations specifying the implementation of restore for 3-nodes.
  - $\texttt{Three}\bigl(\texttt{Four}(l_1,k_1,m_l,k_2,m_r,k_3,r_1), k_l, m, k_r, r\bigr).\texttt{restore}() =
     \texttt{Four}\bigl(\texttt{Two}(l_1, k_1, m_l), k_2, \texttt{Two}(m_r, k_3, r_1), k_l, m, k_r, r\bigr) $
  - $\texttt{Three}\bigl(l, k_l, \texttt{Four}(l_1,k_1,m_l,k_2,m_r,k_3,r_1), k_r, r\bigr).\texttt{restore}() =
     \texttt{Four}\bigl(l, k_l, \texttt{Two}(l_1, k_1, m_l), k_2, \texttt{Two}(m_r, k_3, r_1), k_r, r\bigr) $
  - $\texttt{Three}\bigl(l, k_l, m, k_r, \texttt{Four}(l_1,k_1,m_l,k_2,m_r,k_3,r_1)\bigr).\texttt{restore}() =
     \texttt{Four}\bigl(l, k_l, m, k_r, \texttt{Two}(l_1, k_1, m_l), k_2, \texttt{Two}(m_r, k_3, r_1)\bigr) $
If neither of the child nodes of a 3-node is a 4-node, the node is returned unchanged.
Can you write Python code for it?

def _restore(self):
    "your code here"
    return self

Three._restore = _restore


I am working on the file "Python/Chapter-07/2-3-Trees-Frame.ipynb".
The first task is:
$k_1 < k_2 \rightarrow \texttt{Two}(\texttt{Nil},k_1,\texttt{Nil}).\texttt{ins}(k_2) = \texttt{Three}(\texttt{Nil},k_1,\texttt{Nil},k_2,\texttt{Nil})$
Can you write Python code for it?

toDotList([Method('k2 < k1:'), Two(Nil(), 'k1', Nil()), Method('.ins(k2)'), Three(Nil(), 'k2', Nil(), 'k1', Nil()) ])


I am working on the file "Python/Chapter-07/2-3-Trees-Frame.ipynb".
The first task is:
$k_2 < k_1 \rightarrow \texttt{Two}(\texttt{Nil},k_1,\texttt{Nil}).\texttt{ins}(k_2) = \texttt{Three}(\texttt{Nil},k_2,\texttt{Nil},k_1,\texttt{Nil})$
Can you write Python code for it?

toDotList([Method('k1 < k2:'), Two(Tree('l'), 'k1', Tree('r')), Method('.ins(k2)'), Two(Tree('l'), 'k1', Tree('r.ins(k2)')) ])


I am working on the file "Python/Chapter-07/2-3-Trees-Frame.ipynb".
The first task is:
Given a 2-node $t$ and a key $k$, the method $t.\texttt{member}(k)$ checks whether the key $k$ occurs in $t$.  It is specified as follows:
  - $\texttt{Two}(l,k,r).\texttt{member}(k) = \texttt{True}$,
  - $k_1 < k_2 \rightarrow \texttt{Two}(l,k_1,r).\texttt{member}(k_2) = r.\texttt{member}(k_2)$,
  - $k_1 > k_2 \rightarrow \texttt{Two}(l,k_1,r).\texttt{member}(k_2) = l.\texttt{member}(k_2)$.
Can you write Python code for it?

def member(self, key):
    l, k, r = self._extract()
    if k == key:
        return True
    elif key < k:
        return l.member(key)
    elif key > self.mKey:
        return r.member(key)

Two.member = member


I am working on the file "Python/Chapter-07/2-3-Trees-Frame.ipynb".
The first task is:
Graphically, the node $\texttt{Two}(l, k, r)$ is represented as shown below:
Can you write Python code for it?


I am working on the file "Python/Chapter-07/2-3-Trees-Frame.ipynb".
The first task is:
Insertings a key $k$ into an empty node returns a 2-node with two empty subtrees.
Can you write Python code for it?

toDotList([Nil(), Method('ins(k)'), Two(Nil(), 'k', Nil())])


I am working on the file "Python/Chapter-07/2-3-Trees-Frame.ipynb".
The first task is:
Let's generate 2-3 tree with random keys.
Can you write Python code for it?

import random as rnd

t = Nil()
for k in range(30):
    k = rnd.randrange(100)
    t = t.insert(k)
t.toDot()


I am working on the file "Python/Chapter-07/2-3-Trees-Frame.ipynb".
The first task is:
Lets us try to create a tree by inserting sorted numbers because that resulted in linear complexity for ordered binary trees.
Can you write Python code for it?

M = Nil()
for k in range(30):
    M = M.insert(k)
M.toDot()


I am working on the file "Python/Chapter-07/2-3-Trees-Frame.ipynb".
The first task is:
Methods of the Class Four
The method extract returns the member variables stored in a 4-node.
Can you write Python code for it?

def _extract(self):
    return self.mLeft, self.mKeyL, self.mMiddleL, self.mKeyM, self.mMiddleR, self.mKeyR, self.mRight

Four._extract = _extract


I am working on the file "Python/Chapter-07/2-3-Trees-Frame.ipynb".
The first task is:
Methods of the Class Nil
The empty tree does not contain any keys:
$$ \texttt{Nil}.\texttt{member}(k) = \texttt{False} $$
Can you write Python code for it?

def member(self, k):
    return False

Nil.member = member


I am working on the file "Python/Chapter-07/2-3-Trees-Frame.ipynb".
The first task is:
Methods of the Class One
Can you write Python code for it?

def _extract(self):
    return self.mChild

One._extract = _extract


I am working on the file "Python/Chapter-07/2-3-Trees-Frame.ipynb".
The first task is:
Testing
Can you write Python code for it?

m = Nil()
m.isNil()
m.toDot()

m = m.insert("anton")
m.toDot()

m = m.insert("hugo" )
m.toDot()

m = m.insert("gustav")
m.toDot()

m = m.insert("jens")
m.toDot()

m = m.insert("hubert")
m.toDot()

m = m.insert("andre")
m.toDot()

m = m.insert("philipp")
m.toDot()

m = m.insert("rene")
m.toDot()

m = m.insert("walter")
m.toDot()


I am working on the file "Python/Chapter-07/2-3-Trees-Frame.ipynb".
The first task is:
The class Four represents a 4-node.  It manages 7 member variables:
  - mLeft    is the left subtree $l$,
  - mKeyL    is the left key $k_L$,
  - mMiddleL is the middle left subtree $m_L$,
  - mKeyM    is the middle key,
  - mMiddleR is the middle right subtree $m_R$,
  - mKeyR    is the right key $k_r$,
  - mRight   is the right subtree.
Can you write Python code for it?

class Four(TwoThreeTree):
    def __init__(self, l, kl, ml, km, mr, kr, r):
        TwoThreeTree.__init__(self)
        self.mLeft    = l
        self.mKeyL    = kl
        self.mMiddleL = ml
        self.mKeyM    = km
        self.mMiddleR = mr
        self.mKeyR    = kr
        self.mRight   = r

    def __str__(self):
        return self._make_string(['mLeft', 'mKeyL', 'mMiddleL', 'mKeyM', 'mMiddleR', 'mKeyR', 'mRight'])

    def isFour(self):
        return True


I am working on the file "Python/Chapter-07/2-3-Trees-Frame.ipynb".
The first task is:
The class Nil represents an empty tree.  It has no member variables of its own.
Can you write Python code for it?

class Nil(TwoThreeTree):
    def __init__(self):
        TwoThreeTree.__init__(self)

    def isNil(self):
        return True

    def __str__(self):
        return 'Nil()'


I am working on the file "Python/Chapter-07/2-3-Trees-Frame.ipynb".
The first task is:
The class Onerepresents a 1-node.  These are nodes without a key that have only a single child.
Can you write Python code for it?

class One(TwoThreeTree):
    def __init__(self, child):
        TwoThreeTree.__init__(self)
        self.mChild = child

    def isOne(self):
        return True

    def __str__(self):
        return make_string(self, ['mChild'])


I am working on the file "Python/Chapter-07/2-3-Trees-Frame.ipynb".
The first task is:
The class Tree is not used in the implementation of 2-3 trees.  It is only used for displaying abstract subtrees in equations.
It is displayed as a triangle containing the string that is stored in the member variable mName.
Can you write Python code for it?

class Tree(TwoThreeTree):
    def __init__(self, name):
        TwoThreeTree.__init__(self)
        self.mName = name

    def __str__(self):
        return self.mName

    def isTree(self):
        return True


I am working on the file "Python/Chapter-07/2-3-Trees-Frame.ipynb".
The first task is:
The class Two represents a 2-node of the form $\texttt{Two}(l, k, r)$.  It manages three member variables:
  - mLeft  is the left subtree $l$,
  - mKey   is the key that is stored at this node,
  - mRight is the right subtree $r$.
Can you write Python code for it?

class Two(TwoThreeTree):
    def __init__(self, left, key, right):
        TwoThreeTree.__init__(self)
        self.mLeft  = left
        self.mKey   = key
        self.mRight = right

    def isTwo(self):
        return True

    def __str__(self):
        return self._make_string(['mLeft', 'mKey', 'mRight'])


I am working on the file "Python/Chapter-07/2-3-Trees-Frame.ipynb".
The first task is:
The function call $t.\texttt{restore}()$ takes a 2-3-4 tree $t$ that has at most one 4-node. This 4-node has to be a child
of the root.  It returns a 2-3-4 tree that has at most one 4-node.  This 4-node has to be the root node.
Graphically, it is specified as shown below.
Can you write Python code for it?

toDotList([Two(Four(Tree('l1'),'kl',Tree('ml'),'km', Tree('mr'),'kr',Tree('r1')), 'k', Tree('r')),
           Method('.restore()'),
           Three(Two(Tree('l1'),'kl',Tree('ml')), 'km', Two(Tree('mr'),'kr',Tree('r1')), 'k', Tree('r'))])


I am working on the file "Python/Chapter-07/2-3-Trees-Frame.ipynb".
The first task is:
The function call $t.\texttt{restore}()$ takes a 2-3-4 tree $t$ that has at most one 4-node. This 4-node has to be a child
of the root.  It returns a 2-3-4 tree that has at most one 4-node.  This 4-node has to be the root node.
The most important invariant satisfied by the method call $t.\texttt{ins}(k)$ is the fact that the tree
$t.\texttt{ins}(k)$ has the same height as the tree $t$.
The different cases that need to be handled by ins are shown graphically below:
Can you write Python code for it?


I am working on the file "Python/Chapter-07/2-3-Trees-Frame.ipynb".
The first task is:
The function make_string is a helper function used to shorten the implementation of __str__.
  - obj is the object that is to be rendered as a string
  - attributes is a list of those member variables that are used to produce the string
Can you write Python code for it?

def _make_string(self, attributes):
        # map the function __str__ to all attributes and join them with a comma
        name = self.__class__.__name__
        return f"{name}({', '.join(map(str, [getattr(self, at) for at in attributes]))})"

TwoThreeTree._make_string = _make_string


I am working on the file "Python/Chapter-07/2-3-Trees-Frame.ipynb".
The first task is:
The method $t.\texttt{collectIDs}(d)$ takes a tree $t$ and a dictionary $d$ and updates the dictionary so that the following holds:
$$ d[\texttt{id}] = n \quad \mbox{for every node $n$ in $t$.} $$
Here, $\texttt{id}$ is the unique identifier of the node $n$, i.e. $d$ associates the identifiers with the corresponding nodes.
Can you write Python code for it?

def _collectIDs(self, nodeDict):
    nodeDict[self.getID()] = self
    if self.isOne():
        self.mChild._collectIDs(nodeDict)
    elif self.isTwo():
        self.mLeft ._collectIDs(nodeDict)
        self.mRight._collectIDs(nodeDict)
    elif self.isThree():
        self.mLeft  ._collectIDs(nodeDict)
        self.mMiddle._collectIDs(nodeDict)
        self.mRight ._collectIDs(nodeDict)
    elif self.isFour():
        self.mLeft   ._collectIDs(nodeDict)
        self.mMiddleL._collectIDs(nodeDict)
        self.mMiddleR._collectIDs(nodeDict)
        self.mRight  ._collectIDs(nodeDict)

TwoThreeTree._collectIDs = _collectIDs


I am working on the file "Python/Chapter-07/2-3-Trees-Frame.ipynb".
The first task is:
The method $t.\texttt{ins}(k)$ takes a 2-3 tree $t$ and and a key $k$ and inserts the key $k$ into $t$.
It returns a 2-3-4 tree that has at most one 4-node, which has to be a child of the root
node.  The function $\texttt{ins}$ is recursive and uses the function $\texttt{restore}$ defined below.
The most important invariant satisfied by the method call $t.\texttt{ins}(k)$ is the fact that the tree
$t.\texttt{ins}(k)$ has the same height as the tree $t$.
The different cases that need to be handled by ins are shown graphically below:
Can you write Python code for it?

toDotList([Two(Tree('l'), 'k', Tree('r')), Method('.ins(k)'), Two(Tree('l'), 'k', Tree('r')) ])


I am working on the file "Python/Chapter-07/2-3-Trees-Frame.ipynb".
The first task is:
The method $t.\texttt{toDot}()$ takes a 2-3-4 tree $t$ and returns a graph that depicts the tree $t$.
Can you write Python code for it?

def toDot(self):
    dot = gv.Digraph(node_attr={'shape': 'record', 'style': 'rounded'})
    nodeDict = {}
    self._collectIDs(nodeDict)
    for n, t in nodeDict.items():
        if t.isNil():
            dot.node(str(n), label='', shape='point')
        elif t.isOne():
            dot.node(str(n), label='', shape='point')
        elif t.isTwo():
            dot.node(str(n), label=str(t.mKey))
        elif t.isThree():
            dot.node(str(n), label=str(t.mKeyL) + '|' + str(t.mKeyR))
        elif t.isFour():
            dot.node(str(n), label=str(t.mKeyL) + '|' + str(t.mKeyM) + '|' + str(t.mKeyR))
        elif t.isTree():
            dot.node(str(n), label=str(t.mName), shape='triangle')
        else:
            assert False, f'Unknown node {t}'
    for n, t in nodeDict.items():
        if t.isOne():
            dot.edge(str(n), str(t.mChild.getID()))
        if t.isTwo():
            dot.edge(str(n), str(t.mLeft .getID()))
            dot.edge(str(n), str(t.mRight.getID()))
        if t.isThree():
            dot.edge(str(n), str(t.mLeft  .getID()))
            dot.edge(str(n), str(t.mMiddle.getID()))
            dot.edge(str(n), str(t.mRight .getID()))
        if t.isFour():
            dot.edge(str(n), str(t.mLeft   .getID()))
            dot.edge(str(n), str(t.mMiddleL.getID()))
            dot.edge(str(n), str(t.mMiddleR.getID()))
            dot.edge(str(n), str(t.mRight  .getID()))
    return dot

TwoThreeTree.toDot = toDot


I am working on the file "Python/Chapter-07/2-3-Trees-Visualization.ipynb".
The first task is:
2-3 Trees
This notebook contains the code to visualize 2-3 trees.
Can you write Python code for it?


I am working on the file "Python/Chapter-07/2-3-Trees-Visualization.ipynb".
The first task is:
Deletion
The method $t.\texttt{delete}(k)$ is specified as follows:
 - $t.\texttt{delete}(x) = t.\texttt{del}(x).\texttt{repair}().\texttt{shrink}()$
When $t.\texttt{del}(e)$ is called, $t$ is a 1-2-3 tree containing at most one 1-node.  This 1-node must occur at the root of the tree.  The expression $t.\texttt{del}(e)$ returns the 1-2-3 tree that results from removing the element $e$ from the tree $t$.
The important invariant maintained by del is that the trees $t$ and $t.\texttt{del}(k)$ have the same height.
The method $t.\texttt{repair}()$ takes a 1-2-3 tree $t$ that contains at most a single 1-node.
If the tree $t$ has size $1$, then this 1-node may occur at the root.  Otherwise, the 1-node has to be a child of the root.
The method returns a 1-2-3 tree of the same size as $t$ where the 1-node can only occur at the root.
Can you write Python code for it?

toDotList([Two(One(Tree('L1')), 'k', Two(Tree('M1'), 'k1', Tree('R1'))), Method('.repair()'), One(Three(Tree('L1'), 'k', Tree('M1'), 'k1', Tree('R1')))])

toDotList([Two(Two(Tree('L1'), 'k1', Tree('M1')), 'k', One(Tree('R1'))), Method('.repair()'), One(Three(Tree('L1'), 'k1', Tree('M1'), 'k', Tree('R1')))])

toDotList([Two(One(Tree('A')), 'k', Three(Tree('B'), 'k1', Tree('C'), 'k2', Tree('D'))),
           Method('.repair()'),
           Two(Two(Tree('A'), 'k', Tree('B')), 'k1', Two(Tree('C'), 'k2', Tree('D')))
          ])

toDotList([Two(Three(Tree('A'), 'k1', Tree('B'), 'k2', Tree('C')), 'k', One(Tree('D'))),
           Method('.repair()'),
           Two(Two(Tree('A'), 'k1', Tree('B')), 'k2', Two(Tree('C'), 'k', Tree('D')))
          ])

toDotList([Three(One(Tree('A')), 'kL', Two(Tree('B'), 'k', Tree('C')), 'kR', Tree('R')),
           Method('.repair()'),
           Two(Three(Tree('A'), 'kL', Tree('B'), 'k', Tree('C')), 'kR', Tree('R'))
          ])

toDotList([Three(Two(Tree('A'), 'k', Tree('B')), 'kL', One(Tree('C')), 'kR', Tree('R')),
           Method('.repair()'),
           Two(Three(Tree('A'), 'k', Tree('B'), 'kL', Tree('C')), 'kR', Tree('R'))
          ])

toDotList([Three(Tree('L'), 'kL', Two(Tree('A'), 'k', Tree('B')), 'kR', One(Tree('C'))),
           Method('.repair()'),
           Two(Tree('L'), 'kL', Three(Tree('A'), 'k', Tree('B'), 'kR', Tree('C')))
          ])

toDotList([Three(One(Tree('A')), 'kL', Three(Tree('B'), 'k1', Tree('C'), 'k2', Tree('D')), 'kR', Tree('R')),
           Method('.repair()'),
           Three(Two(Tree('A'), 'kL', Tree('B')), 'k1', Two(Tree('C'), 'k2', Tree('D')), 'kR', Tree('R'))
          ])

toDotList([Three(Three(Tree('A'), 'k1', Tree('B'), 'k2', Tree('C')), 'kL', One(Tree('D')), 'kR', Tree('R')),
           Method('.repair()'),
           Three(Two(Tree('A'), 'k1', Tree('B')), 'k2', Two(Tree('C'), 'kL', Tree('D')), 'kR', Tree('R'))
          ])

toDotList([Three(Tree('L'), 'kL', Three(Tree('A'), 'k1', Tree('B'), 'k2', Tree('C')), 'kR',...


I am working on the file "Python/Chapter-07/2-3-Trees-Visualization.ipynb".
The first task is:
Finally, we specify the method shrink.  The only class where the implementation of shrink is nontrivial is the class One.
Can you write Python code for it?


I am working on the file "Python/Chapter-07/2-3-Trees-Visualization.ipynb".
The first task is:
Graphically, the node $\texttt{One}(t)$ is represented as shown below:
Can you write Python code for it?


I am working on the file "Python/Chapter-07/2-3-Trees-Visualization.ipynb".
The first task is:
Graphically, the node $\texttt{Three}(l, k_L, m, k_R, r)$ is represented as shown below:
Can you write Python code for it?

toDotList([Three(Tree('l'), 'kL', Tree('m'), 'kR', Tree('r'))])


I am working on the file "Python/Chapter-07/2-3-Trees-Visualization.ipynb".
The first task is:
Methods of the Class Four
Can you write Python code for it?

toDotList([Four(Tree('l'),'kl', Tree('ml'), 'km', Tree('mr'), 'kr', Tree('r')),
           Method('.grow()'),
           Two(Two(Tree('l'),'kl', Tree('ml')), 'km', Two(Tree('mr'), 'kr', Tree('r')))
          ])


I am working on the file "Python/Chapter-07/2-3-Trees-Visualization.ipynb".
The first task is:
Methods of the Class Nil
Insertings a key $k$ into an empty node returns a 2-node with two empty subtrees.
Can you write Python code for it?

toDotList([Nil(), Method('insert(k)'), Two(Nil(), 'k', Nil())])


I am working on the file "Python/Chapter-07/2-3-Trees-Visualization.ipynb".
The first task is:
Methods of the Class Three
The function call $t.\texttt{restore}()$ takes a 2-3-4 tree $t$ that has at most one 4-node. This 4-node has to be a child
of the root.  It returns a 2-3-4 tree that has at most one 4-node.  This 4-node has to be the root node.
The most important invariant satisfied by the method call $t.\texttt{ins}(k)$ is the fact that the tree
$t.\texttt{ins}(k)$ has the same height as the tree $t$.
The different cases that need to be handled by ins are shown graphically below:
Can you write Python code for it?


I am working on the file "Python/Chapter-07/2-3-Trees-Visualization.ipynb".
The first task is:
Methods of the Class Two
The method extract returns the member variables stored in a 2-node.  This is usefull to shorten the code since when we use this method, we don't have to prefix all variable names with self..
The method $t.\texttt{ins}(k)$ takes a 2-3 tree $t$ and and a key $k$ and inserts the key $k$ into $t$.
It returns a 2-3-4 tree that has at most one 4-node, which has to be a child of the root
node.  The function $\texttt{ins}$ is recursive and uses the function $\texttt{restore}$ defined below.
The most important invariant satisfied by the method call $t.\texttt{ins}(k)$ is the fact that the tree
$t.\texttt{ins}(k)$ has the same height as the tree $t$.
The different cases that need to be handled by ins are shown graphically below:
Can you write Python code for it?

toDotList([Two(Tree('l'), 'k', Tree('r')), Method('.ins(k)'), Two(Tree('l'), 'k', Tree('r')) ])

toDotList([Method('k1 < k2:'), Two(Nil(), 'k1', Nil()), Method('.ins(k2)'), Three(Nil(), 'k1', Nil(), 'k2', Nil()) ])

toDotList([Method('k2 < k1:'), Two(Nil(), 'k1', Nil()), Method('.ins(k2)'), Three(Nil(), 'k2', Nil(), 'k1', Nil()) ])

toDotList([Method('k1 < k2:'), Two(Tree('l'), 'k1', Tree('r')), Method('.ins(k2)'), Two(Tree('l'), 'k1', Tree('r.ins(k2)')) ])

toDotList([Method('k2 < k1:'), Two(Tree('l'), 'k1', Tree('r')), Method('.ins(k2)'), Two(Tree('l.ins(k2)'), 'k1', Tree('r')) ])


I am working on the file "Python/Chapter-07/2-3-Trees-Visualization.ipynb".
The first task is:
The class Four represents a 4-node.  It manages 7 member variables:
  - mLeft    is the left subtree $l$,
  - mKeyL    is the left key $k_L$,
  - mMiddleL is the middle left subtree $m_L$,
  - mKeyM    is the middle key,
  - mMiddleR is the middle right subtree $m_R$,
  - mKeyR    is the right key $k_r$,
  - mRight   is the right subtree.
Can you write Python code for it?


I am working on the file "Python/Chapter-07/2-3-Trees-Visualization.ipynb".
The first task is:
The class Method is not used in the implementation of 2-3 trees. It is only used for displaying method calls in equations. It is displayed as a rectangle containing the string that is stored in the member variable mLabel.
Can you write Python code for it?

class Method(TwoThreeTree):
    def __init__(self, label):
        TwoThreeTree.__init__(self)
        self.mLabel = label

    def __str__(self):
        return self.mLabel

    def isMethod(self):
        return True


I am working on the file "Python/Chapter-07/2-3-Trees-Visualization.ipynb".
The first task is:
The class Nil represents an empty tree.  It has no member variables of its own.
Can you write Python code for it?


I am working on the file "Python/Chapter-07/2-3-Trees-Visualization.ipynb".
The first task is:
The class Three represents a 3-node of the form $\texttt{Three}(l, k_L, m, k_R, r)$.  It manages 5 member variables:
  - mLeft   is the left subtree $l$,
  - mKeyL   is the left key $k_L$,
  - mMiddle is the middle subtree $m$,
  - mKeyR   is the right key $k_r$,
  - mRight  is the right subtree.
Can you write Python code for it?

class Three(TwoThreeTree):
    def __init__(self, left, keyL, middle, keyR, right):
        TwoThreeTree.__init__(self)
        self.mLeft   = left
        self.mKeyL   = keyL
        self.mMiddle = middle
        self.mKeyR   = keyR
        self.mRight  = right

    def __str__(self):
        return self._make_string(['mLeft', 'mKeyL', 'mMiddle', 'mKeyR', 'mRight'])

    def isThree(self):
        return True


I am working on the file "Python/Chapter-07/2-3-Trees-Visualization.ipynb".
The first task is:
The class Tree is not used in the implementation of 2-3 trees.  It is only used for displaying abstract subtrees in equations.
It is displayed as a triangle containing the string that is stored in the member variable mName.
Can you write Python code for it?


I am working on the file "Python/Chapter-07/2-3-Trees-Visualization.ipynb".
The first task is:
The class Two represents a 2-node of the form $\texttt{Two}(l, k, r)$.  It manages three member variables:
  - mLeft  is the left subtree $l$,
  - mKey   is the key that is stored at this node,
  - mRight is the right subtree $r$.
Can you write Python code for it?


I am working on the file "Python/Chapter-07/2-3-Trees-Visualization.ipynb".
The first task is:
The function $\texttt{toDotList}(\texttt{NodeList})$ takes a list of trees and displays them one by one.
Can you write Python code for it?

def toDotList(NodeList):
    dot = gv.Digraph(node_attr={'shape': 'record', 'style': 'rounded'})
    nodeDict = {}
    for node in NodeList:
        node._collectIDs(nodeDict)
    for n, t in nodeDict.items():
        if t.isNil():
            dot.node(str(n), label='', shape='point')
        elif t.isOne():
            dot.node(str(n), label='', shape='point')
        elif t.isTwo():
            dot.node(str(n), label=str(t.mKey))
        elif t.isThree():
            dot.node(str(n), label=str(t.mKeyL) + '|' + str(t.mKeyR))
        elif t.isFour():
            dot.node(str(n), label=str(t.mKeyL) + '|' + str(t.mKeyM) + '|' + str(t.mKeyR))
        elif t.isTree():
            dot.node(str(n), label=str(t.mName), shape='triangle', style='solid')
        elif t.isMethod():
            dot.node(str(n), label=str(t.mLabel), shape='rectangle', style='dotted')
        else:
            assert False, f'toDotList: Unknown node {str(t)}'
    for n, t in nodeDict.items():
        if t.isOne():
            dot.edge(str(n), str(t.mChild.getID()))
        if t.isTwo():
            dot.edge(str(n), str(t.mLeft .getID()))
            dot.edge(str(n), str(t.mRight.getID()))
        if t.isThree():
            dot.edge(str(n), str(t.mLeft  .getID()))
            dot.edge(str(n), str(t.mMiddle.getID()))
            dot.edge(str(n), str(t.mRight .getID()))
        if t.isFour():
            dot.edge(str(n), str(t.mLeft   .getID()))
            dot.edge(str(n), str(t.mMiddleL.getID()))
            dot.edge(str(n), str(t.mMiddleR.getID()))
            dot.edge(str(n), str(t.mRight  .getID()))
    return dot


I am working on the file "Python/Chapter-07/2-3-Trees-Visualization.ipynb".
The first task is:
The function call $t.\texttt{restore}()$ takes a 2-3-4 tree $t$ that has at most one 4-node. This 4-node has to be a child
of the root.  It returns a 2-3-4 tree that has at most one 4-node.  This 4-node has to be the root node.
Graphically, it is specified as shown below.
Can you write Python code for it?

toDotList([Two(Four(Tree('l1'),'kl',Tree('ml'),'km', Tree('mr'),'kr',Tree('r1')), 'k', Tree('r')),
           Method('.restore()'),
           Three(Two(Tree('l1'),'kl',Tree('ml')), 'km', Two(Tree('mr'),'kr',Tree('r1')), 'k', Tree('r'))])

toDotList([Two(Tree('l'), 'k', Four(Tree('l1'),'kl',Tree('ml'),'km', Tree('mr'),'kr',Tree('r1'))),
           Method('.restore()'),
           Three(Tree('l'), 'k', Two(Tree('l1'),'kl',Tree('ml')), 'km', Two(Tree('mr'),'kr',Tree('r1')))])


I am working on the file "Python/Chapter-07/2-3-Trees-Visualization.ipynb".
The first task is:
The function make_string is a helper function used to shorten the implementation of __str__.
  - obj is the object that is to be rendered as a string
  - attributes is a list of those member variables that are used to produce the string
Can you write Python code for it?


I am working on the file "Python/Chapter-07/2-3-Trees-Visualization.ipynb".
The first task is:
The method $t.\texttt{collectIDs}(d)$ takes a tree $t$ and a dictionary $d$ and updates the dictionary so that the following holds:
$$ d[\texttt{id}] = n \quad \mbox{for every node $n$ in $t$.} $$
Here, $\texttt{id}$ is the unique identifier of the node $n$, i.e. $d$ associates the identifiers with the corresponding nodes.
Can you write Python code for it?


I am working on the file "Python/Chapter-07/2-3-Trees-Visualization.ipynb".
The first task is:
The method $t.\texttt{toDot}()$ takes a 2-3-4 tree $t$ and returns a graph that depicts the tree $t$.
Can you write Python code for it?


I am working on the file "Python/Chapter-07/2-3-Trees-Visualization.ipynb".
The first task is:
This notebook presents 2-3 trees.  We define these trees inductively as follows:
  - $\texttt{Nil}$ is a 2-3 tree that represents the empty set.
  - $\texttt{Two}(l, k, r)$ is a 2-3 tree provided that
      - $l$ is a 2-3 tree,
      - $k$ is a key,
      - $r$ is a 2-3 tree,
      - all keys stored in $l$ are less than k and all keys stored in $r$ are bigger than $k$, that is we have
        $$ l < k < r. $$
      - $l$ and $r$ have the same height.
      A node of the form  $\texttt{Two}(l, k, r)$ is called a 2-node.  Except for the fact
      that there is no value, a 2-node is
      interpreted in the same way as we have interpreted the term $\texttt{Node}(k, v, l, r)$.
  - $\texttt{Three}(l, k_l, m, k_r, r)$ is a 2-3 tree provided
      - $l$, $m$, and $r$ are 2-3 trees,
      - $k_l$ and $k_r$ are keys,
      - $l < k_l < m < k_r < r$,
      - $l$, $m$, and $r$ have the same height.
      A node of the form  $\texttt{Three}(l, k_l, m, k_r, r)$ is called a 3-node.
In order to keep 2-3 trees balanced when inserting new keys we use a fourth constructor of the form
$\texttt{Four}(l,k_1,m_l, k_2, m_r, k_3, r)$.
A term of the form $\texttt{Four}(l,k_1,m_l, k_2, m_r, k_3, r)$ is a 2-3-4 tree iff
  - $l$, $m_l$, $m_r$, and $r$ are 2-3 trees,
  - $k_l$, $k_m$, and $k_r$ are keys,
  - $l < k_l < m_l < k_m < m_r < k_r < r$,
  - $l$, $m_l$, $m_r$, and $r$ all have the same height.
Nodes of this form are called 4-nodes and the key $k_m$ is called the middle key.
Trees containing 2-nodes, 3-node, and 4-nodes are called 2-3-4 trees.
In order to keep 2-3 trees balanced when deleting keys we use a fifth constructor of the form
$\texttt{One}(t)$.
A term of the form $\texttt{One}(t)$ is a 1-2-3 tree iff $t$ is a 2-3 tree.
The class TwoThreeTree is a superclass for constructing the nodes of 2-3-4 trees.  It has one static variable sNodeCount.  This variable is used to equip all nodes with a unique identifier.  This identifier is used to draw the trees using graphviz.
Every node has a uniques id mID that is stored as a...
Can you write Python code for it?

class TwoThreeTree:
    sNodeCount = 0

    def __init__(self):
        TwoThreeTree.sNodeCount += 1
        self.mID = TwoThreeTree.sNodeCount

    def getID(self):
        return self.mID

    def isNil(self):
        return False

    def isOne(self):
        return False

    def isTwo(self):
        return False

    def isThree(self):
        return False

    def isFour(self):
        return False

    def isTree(self):
        return False

    def isMethod(self):
        return False

    def insert(self, k):
        return self._ins(k)._restore()._grow()

    def delete(self, k):
        return self._del(k)._repair()._shrink()

    def _grow(self):
        return self

    def _shrink(self):
        return self


I am working on the file "Python/Chapter-07/AVL-Trees.ipynb".
The first task is:
AVL Trees
This notebook implements
AVL trees.  The set $\mathcal{A}$ of AVL trees is defined inductively:

$\texttt{Nil} \in \mathcal{A}$.
$\texttt{Node}(k,v,l,r) \in \mathcal{A}\quad$  iff
$\texttt{Node}(k,v,l,r) \in \mathcal{B}$,
$l, r \in \mathcal{A}$, and
$|l.\texttt{height}() - r.\texttt{height}()| \leq 1$.

According to this definition, an AVL tree is an ordered binary tree
such that for every node $\texttt{Node}(k,v,l,r)$ in this tree the height of the left subtree $l$ and the right
subtree  $r$ differ at most by one.
The class AVLTree represents the nodes of an AVL tree.  This class has the following member variables:

mKey is the key stored at the root of the tree,
mValue is the values associated with this key,
mLeft is the left subtree,
mRight is the right subtree, and
mHeight is the height.

The constructor __init__ creates the empty tree.
Can you write Python code for it?

class AVLTree:
    def __init__(self):
        self.mKey    = None
        self.mValue  = None
        self.mLeft   = None
        self.mRight  = None
        self.mHeight = 0


I am working on the file "Python/Chapter-07/AVL-Trees.ipynb".
The first task is:
Given an ordered binary tree $t$ and a key $k$, the expression $t.\texttt{find}(k)$ returns the value stored unter the key $k$.
The method find is defined inductively as follows:
  - $\texttt{Nil}.\texttt{find}(k) = \Omega$,
because the empty tree is interpreted as the empty map.

$\texttt{Node}(k, v, l, r).\texttt{find}(k) = v$,
because the node $\texttt{Node}(k,v,l,r)$ stores the assignment $k \mapsto v$.
  - $k_1 < k_2 \rightarrow \texttt{Node}(k_2, v, l, r).\texttt{find}(k_1) = l.\texttt{find}(k_1)$,
because if $k_1$ is less than $k_2$, then any mapping for $k_1$ has to be stored in the left subtree  $l$.
  - $k_1 > k_2 \rightarrow \texttt{Node}(k_2, v, l, r).\texttt{find}(k_1) = r.\texttt{find}(k_1)$,
because if $k_1$ is greater than $k_2$, then any mapping for $k_1$ has to be stored in the right subtree  $r$.
Can you write Python code for it?

def find(self, key):
    if self.isEmpty():
        return
    elif self.mKey == key:
        return self.mValue
    elif key < self.mKey:
        return self.mLeft.find(key)
    else:
        return self.mRight.find(key)

AVLTree.find = find


I am working on the file "Python/Chapter-07/AVL-Trees.ipynb".
The first task is:
Given an ordered binary tree $t$, the expression $t.\texttt{isEmpty}()$ checks whether $t$ is the empty tree.
Can you write Python code for it?

def isEmpty(self):
    return self.mHeight == 0

AVLTree.isEmpty = isEmpty


I am working on the file "Python/Chapter-07/AVL-Trees.ipynb".
The first task is:
Given an ordered binary tree, this function renders the tree graphically using graphviz.
Can you write Python code for it?

def toDot(self):
    AVLTree.sNodeCount = 0 # this is a static variable of the class AVLTree
    dot = gv.Digraph(node_attr={'shape': 'record', 'style': 'rounded'})
    NodeDict = {}
    self._assignIDs(NodeDict)
    for n, t in NodeDict.items():
        if t.mValue != None:
            dot.node(str(n), label='{' + str(t.mKey) + '|' + str(t.mValue) + '}')
        elif t.mKey != None:
            dot.node(str(n), label=str(t.mKey))
        else:
            dot.node(str(n), label='', shape='point')
    for n, t in NodeDict.items():
        if not t.mLeft == None:
            dot.edge(str(n), str(t.mLeft.mID))
        if not t.mRight == None:
            dot.edge(str(n), str(t.mRight.mID))
    return dot

AVLTree.toDot = toDot


I am working on the file "Python/Chapter-07/AVL-Trees.ipynb".
The first task is:
Let's generate an ordered binary tree with random keys.
Can you write Python code for it?

import random as rnd

t = AVLTree()
for k in range(30):
    k = rnd.randrange(100)
    t.insert(k, None)
t.toDot()


I am working on the file "Python/Chapter-07/AVL-Trees.ipynb".
The first task is:
Next, we compute the set of prime numbers $\leq 100$.  Mathematically, this set is given as follows:
$$ \bigl{2, \cdots, 100 \bigr} - \bigl{ i \cdot j \bigm| i, j \in {2, \cdots, 100 }\bigr}$$
Can you write Python code for it?

S = AVLTree()
for k in range(2, 101):
    S.insert(k, None)
for i in range(2, 101):
    for j in range(2, 101):
        S.delete(i * j)
S.toDot()


I am working on the file "Python/Chapter-07/AVL-Trees.ipynb".
The first task is:
The function $\texttt{leanTree}(h, k)$ computes an AVL tree of height $h$ that is as lean as possible.
All key in the tree will be integers that are bigger than $k$.  The definition by induction:
  - $\texttt{leanTree}(0, k) = \texttt{Nil}$,
because there is only one AVL tree of height $0$ and this is the tree $\texttt{Nil}$.

$\texttt{leanTree}(1, k) = \texttt{Node}(k+1,0,\texttt{Nil}, \texttt{Nil})$,
since, if we abstract from the actual keys and values, there is exactly one AVL tree of height $1$.
  - $\texttt{leanTree}(h+1,k).\texttt{maxKey}() = l \rightarrow
 \texttt{leanTree}(h+2,k) = \texttt{Node}\bigl(l+1,\,0,\,\texttt{leanTree}(h+1,k),\,\texttt{leanTree}(h, l+1)\bigr)
$.
Can you write Python code for it?

def leanTree(h, k):
    if h == 0:
        return AVLTree()
    if h == 1:
        return createNode(k + 1, None, AVLTree(), AVLTree())
    left = leanTree(h - 1, k)
    l    = left.maxKey()
    return createNode(l + 1, None, left, leanTree(h - 2, l + 1))

l = leanTree(6, 0)
l.toDot()

for k in range(6):
    l = leanTree(k, 0)
    print(f'Height {k}:')
    display(l.toDot())


I am working on the file "Python/Chapter-07/AVL-Trees.ipynb".
The first task is:
The function $\texttt{restore}(\texttt{self})$ restores the balancing condition of the given binary tree
at the root node and recompute the variable $\texttt{mHeight}$.
The method $\texttt{restore}$ is specified via conditional equations.

$\texttt{Nil}.\texttt{restore}() = \texttt{Nil}$,
because the empty tree already is an  AVL tree.
  - $|l.\texttt{height}() - r.\texttt{height}()| \leq 1 \rightarrow
   \texttt{Node}(k,v,l,r).\texttt{restore}() = \texttt{Node}(k,v,l,r)$.
If the balancing condition is satisfied, then nothing needs to be done.
  - $\begin{array}[t]{cl}
          & l_1.\texttt{height}() = r_1.\texttt{height}() + 2    \
   \wedge & l_1 = \texttt{Node}(k_2,v_2,l_2,r_2)                 \
   \wedge & l_2.\texttt{height}() \geq r_2.\texttt{height}()     \[0.2cm]
   \rightarrow & \texttt{Node}(k_1,v_1,l_1,r_1).\texttt{restore}() =
                 \texttt{Node}\bigl(k_2,v_2,l_2,\texttt{Node}(k_1,v_1,r_2,r_1)\bigr)
   \end{array}
$
  - $\begin{array}[t]{cl}
           & l_1.\texttt{height}() = r_1.\texttt{height}() + 2    \
    \wedge & l_1 = \texttt{Node}(k_2,v_2,l_2,r_2)               \
    \wedge & l_2.\texttt{height}() < r_2.\texttt{height}()     \
    \wedge & r_2 = \texttt{Node}(k_3,v_3,l_3,r_3)               \
    \rightarrow & \texttt{Node}(k_1,v_1,l_1,r_1).\texttt{restore}() =
                  \texttt{Node}\bigl(k_3,v_3,\texttt{Node}(k_2,v_2,l_2,l_3),\texttt{Node}(k_1,v_1,r_3,r_1) \bigr)
    \end{array}
$

$\begin{array}[t]{cl}
              & r_1.\texttt{height}() = l_1.\texttt{height}() + 2    \
       \wedge & r_1 = \texttt{Node}(k_2,v_2,l_2,r_2)               \
       \wedge & r_2.\texttt{height}() \geq l_2.\texttt{height}()     \[0.2cm]
       \rightarrow & \texttt{Node}(k_1,v_1,l_1,r_1).\texttt{restore}() =
                     \texttt{Node}\bigl(k_2,v_2,\texttt{Node}(k_1,v_1,l_1,l_2),r_2\bigr)
       \end{array}
    $

$\begin{array}[t]{cl}
               & r_1.\texttt{height}() = l_1.\texttt{height}() + 2    \
        \wedge & r_1 = \texttt{Node}(k_2,v_2,l_2,r_2)         ...
Can you write Python code for it?

def _restore(self):
    if abs(self.mLeft.mHeight - self.mRight.mHeight) <= 1:
        self._restoreHeight()
        return
    if self.mLeft.mHeight > self.mRight.mHeight:
        k1, v1, l1, r1 = self.mKey, self.mValue, self.mLeft, self.mRight
        k2, v2, l2, r2 = l1.mKey, l1.mValue, l1.mLeft, l1.mRight
        if l2.mHeight >= r2.mHeight:
            self._setValues(k2, v2, l2, createNode(k1, v1, r2, r1))
        else:
            k3, v3, l3, r3 = r2.mKey, r2.mValue, r2.mLeft, r2.mRight
            self._setValues(k3, v3, createNode(k2, v2, l2, l3),
                                    createNode(k1, v1, r3, r1))
    elif self.mRight.mHeight > self.mLeft.mHeight:
        k1, v1, l1, r1 = self.mKey, self.mValue, self.mLeft, self.mRight
        k2, v2, l2, r2 = r1.mKey, r1.mValue, r1.mLeft, r1.mRight
        if r2.mHeight >= l2.mHeight:
            self._setValues(k2, v2, createNode(k1, v1, l1, l2), r2)
        else:
            k3, v3, l3, r3 = l2.mKey, l2.mValue, l2.mLeft, l2.mRight
            self._setValues(k3, v3, createNode(k1, v1, l1, l3),
                                    createNode(k2, v2, r3, r2))
    self._restoreHeight()

AVLTree._restore = _restore


I am working on the file "Python/Chapter-07/AVL-Trees.ipynb".
The first task is:
The function $\texttt{self}.\texttt{_setValues}(k, v, l, r)$ overwrites the member variables of the node $\texttt{self}$ with the given values.
Can you write Python code for it?

def _setValues(self, k, v, l, r):
    self.mKey   = k
    self.mValue = v
    self.mLeft  = l
    self.mRight = r

AVLTree._setValues = _setValues

def _restoreHeight(self):
    self.mHeight = max(self.mLeft.mHeight, self.mRight.mHeight) + 1

AVLTree._restoreHeight = _restoreHeight


I am working on the file "Python/Chapter-07/AVL-Trees.ipynb".
The first task is:
The method  $\texttt{insert}()$ is specified via recursive equations.
  - $\texttt{Nil}.\texttt{insert}(k,v) = \texttt{Node}(k,v, \texttt{Nil}, \texttt{Nil})$,
  - $\texttt{Node}(k, v_2, l, r).\texttt{insert}(k,v_1) = \texttt{Node}(k, v_1, l, r)$,
  - $k_1 < k_2 \rightarrow
          \texttt{Node}(k_2, v_2, l, r).\texttt{insert}(k_1, v_1) =
          \texttt{Node}\bigl(k_2, v_2, l.\texttt{insert}(k_1,v_1), r\bigr).\texttt{restore}()$,
  - $k_1 > k_2 \rightarrow
         \texttt{Node}(k_2, v_2, l, r).\texttt{insert}\bigl(k_1, v_1\bigr) =
         \texttt{Node}\bigl(k_2, v_2, l, r.\texttt{insert}(k_1,v_1)\bigr).\texttt{restore}()$.
The function $\texttt{restore}$ is an auxiliary function that is defined below.  This function restores the balancing condition if it is violated after an insertion.
Can you write Python code for it?

def insert(self, key, value):
    if self.isEmpty():
        self.mKey    = key
        self.mValue  = value
        self.mLeft   = AVLTree()
        self.mRight  = AVLTree()
        self.mHeight = 1
    elif self.mKey == key:
        self.mValue = value
    elif key < self.mKey:
        self.mLeft.insert(key, value)
        self._restore()
    else:
        self.mRight.insert(key, value)
        self._restore()

AVLTree.insert = insert


I am working on the file "Python/Chapter-07/AVL-Trees.ipynb".
The first task is:
The method $\texttt{self}.\texttt{delete}(k)$ removes the key $k$ from the tree $\texttt{self}$.  It is defined as follows:

$\texttt{Nil}.\texttt{delete}(k) = \texttt{Nil}$,
$\texttt{Node}(k,v,\texttt{Nil},r).\texttt{delete}(k) = r$,
$\texttt{Node}(k,v,l,\texttt{Nil}).\texttt{delete}(k) = l$,
$l \not= \texttt{Nil} \,\wedge\, r \not= \texttt{Nil} \,\wedge\,
       \langle r',k_{min}, v_{min} \rangle := r.\texttt{delMin}()  \;\rightarrow\;
      \texttt{Node}(k,v,l,r).\texttt{delete}(k) = \texttt{Node}(k_{min},v_{min},l,r').\texttt{restore}()$
$k_1 < k_2 \rightarrow \texttt{Node}(k_2,v_2,l,r).\texttt{delete}(k_1) =
    \texttt{Node}\bigl(k_2,v_2,l.\texttt{delete}(k_1),r\bigr).\texttt{restore}()$,
$k_1 > k_2 \rightarrow \texttt{Node}(k_2,v_2,l,r).\texttt{delete}(k_1) =
     \texttt{Node}\bigl(k_2,v_2,l,r.\texttt{delete}(k_1)\bigr).\texttt{restore}()$.
Can you write Python code for it?

def delete(self, key):
    if self.isEmpty():
        return
    if key == self.mKey:
        if self.mLeft.isEmpty():
            self._update(self.mRight)
        elif self.mRight.isEmpty():
            self._update(self.mLeft)
        else:
            self.mRight, self.mKey, self.mValue = self.mRight._delMin()
            self._restore()
    elif key < self.mKey:
        self.mLeft.delete(key)
        self._restore()
    else:
        self.mRight.delete(key)
        self._restore()

AVLTree.delete = delete


I am working on the file "Python/Chapter-07/AVL-Trees.ipynb".
The first task is:
This method assigns a unique identifier with each node.  The dictionary NodeDict maps these identifiers to the nodes where they occur.
Can you write Python code for it?

def _assignIDs(self, NodeDict):
    AVLTree.sNodeCount += 1
    self.mID = AVLTree.sNodeCount
    NodeDict[self.mID] = self
    if self.isEmpty():
        return
    self.mLeft ._assignIDs(NodeDict)
    self.mRight._assignIDs(NodeDict)

AVLTree._assignIDs = _assignIDs


I am working on the file "Python/Chapter-07/AVL-Trees.ipynb".
The first task is:
This tree looks more or less balanced.  Lets us try to create a tree by inserting sorted numbers because that resulted in linear complexity for ordered binary trees.
Can you write Python code for it?

t = AVLTree()
for k in range(30):
    t.insert(k, None)
t.toDot()


I am working on the file "Python/Chapter-07/ArrayMap.ipynb".
The first task is:
Lets compute the primes up to $n = 10000$.
Can you write Python code for it?

n = 10000

%%time
S = ArrayMap(n+1)
for i in range(2, n+1):
    S.insert(i, i)
for i in range(2, n // 2 + 1):
    for j in range(i, n+1):
        if i * j > n:
            break
        S.delete(i * j)

for k in range(2, n+1):
    if S.find(k):
        print(k, end=' ')


I am working on the file "Python/Chapter-07/Binary-Tries-Frame.ipynb".
The first task is:
Binary Tries
Can you write Python code for it?


I am working on the file "Python/Chapter-07/Binary-Tries-Frame.ipynb".
The first task is:
Implementing the Method  find
Given a binary trie $b$ and a natural number $n$, the expression
$$ b.\texttt{find}(n) $$
returns the value in $b$ that is associated with the number $n$.  If there is no value associated
with $b$, then the expression evaluates to $\Omega$.  Formally, the value of the expression
$b.\texttt{find}(n)$ is defined by induction on both $b$ and $n$:
  - $\texttt{Nil}.\texttt{find}(n) = \Omega$,
since the empty trie doesn't store any values.

$\texttt{Bin}(v,l,r).\texttt{find}(0) = v$,
because $0$ is interpreted as the empty string $\varepsilon$.
  - $n \not= 0 \rightarrow \texttt{Bin}(v,l,r).\texttt{find}(2\cdot n) = l.\texttt{find}(n)$,
because if a number is represented in binary, then the last bit of every even number is zero
and zero chooses the left subtree.
  - $\texttt{Bin}(v,l,r).\texttt{find}(2 \cdot n + 1) = r.\texttt{find}(n)$,
because if a number is represented in binary, then the last bit of every odd number is 1 and
1 is associated with the right subtree.
Can you write Python code for it?

def find(self, n):
    "your code here"

Nil.find = find
del find

def find(self, n):
    "your code here"

Bin.find = find
del find


I am working on the file "Python/Chapter-07/Binary-Tries-Frame.ipynb".
The first task is:
Let us compute the prime numbers next.
Can you write Python code for it?

Primes = Nil()
for i in range(2, 101):
    Primes = Primes.insert(i, True)
Primes.toDot()

for i in range(2, 51):
    for j in range(i, 100 // i + 1):
        Primes = Primes.delete(i * j)
display(Primes.toDot())
for i in range(2, 101):
    if Primes.find(i):
        print(i, end=' ')


I am working on the file "Python/Chapter-07/Binary-Tries-Frame.ipynb".
The first task is:
The class Bin represents a binary trie of the form $\texttt{Bin}(v,l,r)$.
It has three member variables:
* mValue is the value that is stored at this node.
* mLeft  is the left subtree.
* mRight is the right subtree.
* mDigit is a string that is used by graphviz to display the node.
Can you write Python code for it?

class Bin(BinaryTrie):
    def __init__(self, value, left, right):
        BinaryTrie.__init__(self)
        self.mValue = value
        self.mLeft  = left
        self.mRight = right
        self.mDigit = '' # only used by graphviz

    def __str__(self):
        return _make_string(self, ['mValue', 'mLeft', 'mRight'])


I am working on the file "Python/Chapter-07/Binary-Tries-Frame.ipynb".
The first task is:
The function make_string is a helper function that is used to simplify the implementation of __str__.
  - self is the object that is to be rendered as a string
  - attributes is a list of those member variables that are used to produce the string
Can you write Python code for it?

def _make_string(self, attributes):
        # map the function __str__ to all attributes and join them with a comma
        name = self.__class__.__name__
        return f"{name}({', '.join(map(str, [getattr(self, at) for at in attributes]))})"

BinaryTrie._make_string = _make_string
del _make_string


I am working on the file "Python/Chapter-07/Binary-Tries-Frame.ipynb".
The first task is:
The method $t.\texttt{toDot}()$ takes a binary trie $t$ and returns a graph that depicts the tree $t$.
Can you write Python code for it?

def toDot(self):
    dot = gv.Digraph(node_attr={'shape': 'record', 'style': 'rounded'})
    nodeDict = {}
    self._collectIDs(nodeDict)
    for n, t in nodeDict.items():
        if isinstance(t, Nil):
            dot.node(str(n), label='', shape='point')
        elif isinstance(t, Bin):
            if t.mValue != None:
                dot.node(str(n), label='{' + str(t.mDigit) + '|' + str(t.mValue) + '}')
            else:
                dot.node(str(n), label='{' + str(t.mDigit) + '|' + '}')
        else:
            assert False, f'Unknown node {t}'
    for n, t in nodeDict.items():
        if isinstance(t, Bin):
            dot.edge(str(n), str(t.mLeft .getID()))
            dot.edge(str(n), str(t.mRight.getID()))
    return dot

BinaryTrie.toDot = toDot
del toDot


I am working on the file "Python/Chapter-07/Binary-Tries-Frame.ipynb".
The first task is:
Your equations here!
Can you write Python code for it?

def delete(self, n):
    "your code here"

Nil.delete = delete
del delete

def delete(self, n):
    "your code here"

Bin.delete = delete
del delete


I am working on the file "Python/Chapter-07/HashMap.ipynb".
The first task is:
Given a string $w$ and the size $n$ of the hash table, the function $\texttt{hash_code}(w, n)$ calculates the hash code of $w$.  For a string
$w = c_0c_1\cdots c_{m-1}$ of length $m$, this function is defined as follows:
$$ \texttt{hash_code}(w, n) = \left(\sum\limits_{i=0}^{m-1} \texttt{ord}(c_i) \cdot 128^i\right) \;\texttt{%}\; n  $$
In order to prevent overflows when computing the numbers $128^i$ we can define the partial sum $s_k$ for
$k=0,1,\cdots,m-1$ by induction:
  - $s_{0} = \texttt{ord}(c_{m-1}) \;\texttt{%}\; n$,
  - $s_{k+1} = \bigl(s_k \cdot 128 + \texttt{ord}(c_{k}) \bigr) \;\texttt{%}\; n$.
Then we have
$$ s_{m-1} = \left(\sum\limits_{i=0}^{m-1} \texttt{ord}(c_i) \cdot 128^i\right) \;\texttt{%}\; n. $$
Can you write Python code for it?

def hash_code(w, n):
    m = len(w)
    s = 0
    for k in range(m-1, -1, -1):
        s = (s * 128 + ord(w[k])) % n
    return s


I am working on the file "Python/Chapter-07/HashMap.ipynb".
The first task is:
Hash Tables (Open Hashing)
This notebook provides a simple implementation of a hash table that uses open hashing.
The class ListMap from the notebook ListMap.ipynb implements a map as a linked list.
Can you write Python code for it?


I am working on the file "Python/Chapter-07/HashMap.ipynb".
The first task is:
Hash tables work best if their size is a prime number.  Therefore, the variable Primes stores a list of prime numbers.
These numbers are organized so that Primes[i+1] is roughly twice as big as Primes[i].
Can you write Python code for it?

HashTable.Primes = [ 3, 7, 13, 31, 61, 127, 251, 509, 1021, 2039, 4093,
                     8191, 16381, 32749, 65521, 131071, 262139, 524287,
                     1048573, 2097143, 4194301, 8388593, 16777213,
                     33554393, 67108859, 134217689, 268435399,
                     536870909, 1073741789, 2147483647
                   ]

def find(self, key):
    index = self.mCode(key, self.mSize)
    aList = self.mArray[index]
    return aList.find(key)

HashTable.find = find
del find

def insert(self, key, value):
    if self.mEntries >= self.mSize * self.mAlpha:
        self._rehash()
    index = self.mCode(key, self.mSize)
    aList = self.mArray[index]
    self.mEntries += aList.insert(key, value)

HashTable.insert = insert
del insert

def _rehash(self):
    for p in HashTable.Primes:
        if p * self.mAlpha > self.mEntries:
            prime = p
            break
    newTable = HashTable(prime, self.mCode)
    for aList in self.mArray:
        for k, v in aList:
            newTable.insert(k, v)
    self.mSize  = prime
    self.mArray = newTable.mArray

HashTable._rehash = _rehash
del _rehash

def delete(self, key):
    if 2 * self.mEntries <= self.mSize * self.mAlpha:
        self._rehash()
    index = self.mCode(key, self.mSize)
    aList = self.mArray[index]
    self.mEntries -= aList.delete(key)

HashTable.delete = delete
del delete

def allKeys(self):
    Result = []
    for L in self.mArray:
        for key, _ in L:
            Result.append(key)
    return Result

HashTable.allKeys = allKeys
del allKeys

def __repr__(self):
    result = ''
    for i, aList in enumerate(self.mArray):
        result += f'{i}: {aList}\n'
    return result

HashTable.__repr__ = __repr__
del __repr__

t = HashTable(3)
t.insert('Adrian', 8)
t

t.insert('Benjamin', 24)
t

t.insert('Bereket', 1)
t

t.insert('Christian', 13)
t

t.insert('Christian', 14)
t

t.find('Adrian'), t.find('Christian'), t.find('Benjamin')

t.insert('David', 22)
t

t.insert('Ephraim', 19)
t

t.insert('Erwin',...


I am working on the file "Python/Chapter-07/HashMap.ipynb".
The first task is:
Let us test this function.
Can you write Python code for it?

hash_code('George W. Bush', 6761)

class HashTable:
    def __init__(self, n, code=hash_code):
        self.mSize    = n
        self.mEntries = 0                                        # number of entries
        self.mArray   = [ ListMap() for i in range(self.mSize) ] # array of empty ListMap objects
        self.mAlpha   = 2                                        # load factor
        self.mCode    = code


I am working on the file "Python/Chapter-07/HashMap.ipynb".
The first task is:
The function ord maps characters to their ASCII code. $\mapsto$
Can you write Python code for it?

import string

for c in string.ascii_letters:
    print(f'{c} ↦ {ord(c)}')


I am working on the file "Python/Chapter-07/Heap.ipynb".
The first task is:
$\texttt{Node}(p,v,\texttt{Nil},r).\texttt{remove}() = r$
$\texttt{Node}(p,v,l,\texttt{Nil}).\texttt{remove}() = l$
$l = \texttt{Node}(p_1,v_1,l_1,r_1) \;\wedge\; r = \texttt{Node}(p_2,v_2,l_2,r_2) \;\wedge\; p_1 \leq p_2 \;\rightarrow
     \texttt{Node}(p,v,l,r).\texttt{remove}() =      \texttt{Node}(p_1,v_1,l.\texttt{remove}(),r)$
$l = \texttt{Node}(p_1,v_1,l_1,r_1) \;\wedge\; r = \texttt{Node}(p_2,v_2,l_2,r_2) \;\wedge\; p_1 > p_2 \rightarrow
     \texttt{Node}(p,v,l,r).\texttt{remove}() = \texttt{Node}(p_2,v_2,l,r.\texttt{remove}())$
Can you write Python code for it?

def remove(self):
    p, v, l, r = self._extract()
    if isinstance(l, Nil):
        return r
    if isinstance(r, Nil):
        return l
    p1, v1, l1, r1 = l._extract()
    p2, v2, l2, r2 = r._extract()
    if p1 <= p2:
        return Node(p1, v1, l.remove(), r)
    else:
        return Node(p2, v2, l, r.remove())

Node.remove = remove
del remove