induction & recursion discrete mathematics and its applications baojian hua [email protected]

27
Induction & Recursion Discrete Mathematics and Its Applications Baojian Hua [email protected]

Upload: ezra-hudson

Post on 31-Dec-2015

226 views

Category:

Documents


1 download

TRANSCRIPT

Induction & Recursion

Discrete Mathematics andIts Applications

Baojian [email protected]

Our Goal How to write data types (math.) via

inductive definitions? How to turn inductive definitions

into data structures? How to write algorithms operated

on these data structures? How to argue the correctness of

the algorithms?

Dead-simple Example: nat// Data types:

1. A zero, or

2. a number follow another nat.

// Rewrite into inductive definition form:

nat -> Zero

-> Succ nat

// Q: how to turn this into data structures?

Tagged Union in C// Rewrite into inductive definition form:nat -> Zero -> Succ nat

typedef natStruct *nat;struct natStruct { enum natKind {Zero, Succ} kind; union {

nat n; } u;};

u

kind

Interface#ifndef NAT_H#define NAT_H

typedef natStruct *nat;struct natStruct { enum natKind {Zero, Succ} kind; union {

nat n; } u;};

Interface Continuednat newNatZero ();nat newNatSucc (nat n);nat natAdd (nat n1, nat n2);int natToInt (nat n);

#endif

Generate natnat newNatZero (){ nat t = (nat)malloc (sizeof (*t)); t->kind = Zero; return t;}

nat newNatSucc (nat n){ nat t = (nat)malloc (sizeof (*t)); t->kind = Succ; t->u.n = n; return t;}

u

kind

nat -> Zero -> Succ nat

Example: 33: Succ(Succ(Succ(Zero)));

three = newNatSucc( newNatSucc( newNatSucc( newNatZero())));

u

kind

u

kind

u

kind

u

kindthree

Example: 33: Succ(Succ(Succ(Zero)));

three = newNatSucc( newNatSucc( newNatSucc( newNatZero())));

u

Zero

u

Succ

u

Succ

u

Succthree

Additionn1 n2 = { n2, if n1==Zero;⊕ { Succ (m n2), if n1==Succ(m).⊕

nat natAdd (nat n1, nat n2){ switch (n1->kind) { case Zero: return n2; case Succ: return newNatSucc (natAdd (n1->u.n, n2)); default: error (…); } return NULL;}

u

kind

toInttoInt(n) = { 0, if n==Zero; { 1+toInt(m), if n1==Succ(m).

int natToInt (nat n){ switch (n->kind) { case Zero: return 0; case Succ: return 1+(natToInt(n->u.n)); default: error (…); } return -1;}

u

kind

Linked List// Data types:

1. An empty list, or

2. a node, followed by another list.

// Rewrite into inductive definition form:

list -> Empty

-> Cons T, list

// Q: how to turn this into data structures?

Tagged Union in C// Rewrite into inductive definition form:list -> Empty -> Cons (T, list)typedef listStruct *list;struct listStruct { enum listKind {Empty, Cons} kind; union {

struct { void *data; list next; } node; } u;};

u

kind

Interface#ifndef LIST_H#define LIST_H

typedef listStruct *list;struct listStruct { enum listKind {Empty, Cons} kind; union {

struct { void *data; list next; } node; } u;};

Interface Continuedlist newListEmpty ();list newListCons (void *data, list next);int length (list l);list insertHead (list l, void *data);list insertTail (list l, void *data);

#endif

Generate a Listlist newListEmpty (){ list t = (list)malloc (sizeof (*t)); t->kind = Empty; return t;}list newListCons (void *data, list l){ list t = (list)malloc (sizeof (*t)); t->kind = Cons; t->u.node.data = data; t->u.node.next = l; return t;}

u

kind

list -> Empty -> Cons (T, list)

Lengthlength(l) = { 0, if l==Empty; { 1+length(m), if l==Cons (T, m)

int length (list l){ switch (l->kind) { case Empty: return 0; case Cons: return 1 + length(l->u.node.next); default: error (…); } return -1;}

u

kind

Insert at Headf(d, l) = Cons (d, l)

list insertHead (void *d, list l){ return newListCons (d, l);} u

kind

Insert at Tailf(d, l) = { Cons (d, l), if l==Empty; { Cons (x, f(d, m)), if l==Cons(x, m).list insertTail (void *d, list l){ switch (l->kind) { case Empty: return newListCons (d, l); case Cons: return newListCons (l->u.node.data, insertTail (d, l->u.node.next)); default: error (…); } return NULL;}

u

kind

How can you argue this is correct?

How does it Work?

u

Empty

3

Cons

6

Cons

4

Conslist

insert 9 at tail

u

Empty

9

Cons

3

Cons

6

ConsnewList

4

Cons

Persistent Data Structures Data structures never change once

created you may want to compare the list here with

the ones we discussed in Lab #1 Good for many purpose

reason the correctness of the code local debugging important in emerging fields such as

concurrent programming or multi-core

Functional Programming Stemming from mathematics

Church and Turing, etc. Programming (and the resulting code) just

behaves like writing mathematical functions persistent data structures h recursive functions

An important programming idioms I personally love it more than procedural, OO,

generic, etc. Stepping into industry

Such as F# from M…S…

Summary

Inductive Def’ == Persistent DSDeduction == RecursionMath Proof == Program

Correctness

Local Class Hierarchyabstract class List<X> {}

class ListEmpty<X> extends List<X> {}

class ListCons<X> extends List<X>{ X data; List<X> next;

ListCons (X data, List<X>next) {…}}

Ugly Castclass Match<X>{ public int size (List<X> l) { if (l instanceof ListEmpty<X>) return 0; else if (l instanceof ListCons<X>) …; else …; }}// Or the visitor pattern

In C++template <typename X>class List{public: virtual void foo()=0;};

template <typename X>class ListEmpty: public List<X> {public: void foo (){};};

In C++template <typename X>class ListCons: public List<X>{public: X data; List<X> next;

ListCons(X adata, List<X> anext) :data(adata), next(anext) {}; void foo () {};}