world champion chess player garry...world champion chess player garry kasparov was defeated by...

51

Upload: others

Post on 16-Apr-2020

49 views

Category:

Documents


0 download

TRANSCRIPT

World Champion chess player Garry Kasparov was defeated by IBM’s Deep Blue chess-playing computer in a six-game match in May, 1997. The match received enormous media coverage, much of which emphasized the notion that Kasparov was defending humanity’s honor. http://www.computerhistory.org/chess/stl-431e1a07b22e1/

Games

Minimax for 2-player games

Minimax is a standard AI strategy for 2-player games that arealternating: players take turnsdeterministic: each move has a well-defined outcome (there is no randomness)perfect-information: each player knows the complete state of the game (there is no hidden informationzero-sum: if I win you lose, and vice versa — what’s good for me is bad for you (but draws are allowed)

Example: Nim

• Start with 15 pebbles• To make a move you pick up 1, 2, or 3 pebbles• Whoever picks up the last pebble loses• e.g.,

1. You pick up 3 (12 left)2. I pick up 3 (9 left)3. You pick up 2 (7 left)4. I pick up 2 (5 left)5. You pick up 1 (4 left)6. I pick up 3 (1 left)7. You pick 1 (0 left)8. I win!

Example: Nim

Nim actually has a winning strategy for the player going first!Consider Nim with 5 pebbles.If it’s your turn and there are 5 pebbles left then you lose:

if you take 1, I take 3, and there is 1 left;if you take 2, I take 2;if you take 3 I take 1.

Similarly: 9…5, 13...9, etc.The pattern:

if it’s your turn and pebbles mod 4 ≅ 1 then I have a winning strategy: choose always to leave the number of pebbles congruent to 1 mod 4.

Example: Nim

Nim is special: a quick calculation tells who will win.For a game like chess (or Kalaha!) you can’t tell (in constant time) just by looking at a board who will win.So, we must use computation to search possible future states.Build a game tree where nodes are states and edges are moves.Each row is labeled with the player whose turn it is.

Example: Nim

Starting with 3 pebbles:3

0 1 2

0 0 1

0

Maxie

Minnie

Maxie

Minnie

Example: Nim

Next assign each node a value, saying who wins.

Maxie wins if the value is 1.Minnie wins if the value is -1.

First label the leaves.

3

0 1 2

0 0 1

0

Maxie

Minnie

Maxie

Minnie

-1

1 1

-1

Example: Nim

Then propagate the labels up the tree.

If it’s Maxie’s turn the value is the maximum of the children (because Maxie will choose the maximising move).If it’s Minnie’s it is the minimum.

First level.

3

0 1 2

0 0 1

0

Maxie

Minnie

Maxie

Minnie

-1

1 1

-1

-1

Example: Nim

Next level.

For example, on the rightmost subtree if there are two pebbles left then Minnie should take 1, leaving 1, rather than 2, leaving 0.

3

0 1 2

0 0 1

0

Maxie

Minnie

Maxie

Minnie

-1

1 1

-1

-1

1 -1

Example: Nim

Next level.

Maxie should take 2, leaving 1, rather than taking 3 or 1.

3

0 1 2

0 0 1

0

Maxie

Minnie

Maxie

Minnie

-1

1 1

-1

-1

1 -1

1

Minimax algorithm

Minimax computes the value of a game state assuming both players will play optimally.It does not account for things like

“that chess board is confusing, so it will be easy to make a mistake”For a game with a bigger search space than this we can’t draw out the whole tree!Instead, a heuristic must approximate the value of the board.Nim has a perfect heuristic: number of pebbles congruent to 1 mod 4.

Minimax algorithm

The overall algorithm is:1. explore the game tree up to a certain depth2. use the heuristic to approximate the value when the depth is

reached.For chess, a given heuristic would include which pieces are left, where they are positioned, etc.

GameTree.hs

[live coding]

Abstract Data TypesChapter 16 of Thompson

Information Hiding

Abstract data types (ADTs) allow information hiding on types.They hide the representation (or model) behind an abstract set of operations.Separates:• data type definition from

representation• function declaration from

implementation

Application

Specification

Implementation

Interface

User

Implementor

Information Hiding

Consider modeling a computer’s Random Access Memory (RAM), which stores values in memory variables.We might model RAM in different ways:

[(Integer,Var)] -- a list of integer/variable pairs(Var -> Integer) -- a function from vars to integers

Regardless of the model, operations to obtain an initial store and access/update variables have well-defined specifications:

initial :: Storeread :: Store -> Var -> Integerwrite :: Store -> Var -> Integer -> Store

Information Hiding

The operation signatures specify the interface, upon which users and implementers agree, allowing them to work independently.But we want to isolate users from the model:• allows evolution of the model without affecting users• prevents manipulating the model in unintended ways

e.g., prevent list operations on list model, composition on function model

Example: Signature

Modules support information hiding by exposing only operations in the signature of the module header:

module Store ( Store,

initial, -- Storevalue, -- Store -> Var -> Integerupdate -- Store -> Var -> Integer -> Store

) where

Example: Implementation I

data Store = Store [ (Integer,Var) ]initial :: Storeinitial = Store []value :: Store -> Var -> Integervalue (Store []) v = 0value (Store ((n,w):s)) v| v==w = n| otherwise = value (Store s) v

update :: Store -> Var -> Integer -> Storeupdate (Store s) v n = Store ((n,v):s)

Example: Implementation II

data Store = Store (Var -> Integer)initial :: Store initial = Store (\v -> 0)value :: Store -> Var -> Integervalue (Store s) v = s vupdate :: Store -> Var -> Integer -> Storeupdate (Store s) v n

= Store (\w -> if v==w then n else s w)

Example: Implementations I and II

Note that in both implementations storing more than once to the same variable will result in adding the new value to the store, but not removing the old one!• Implementation I prepends to the list• Implementation II constructs a new function as a conditional

expression with the old function as the condition’s “else” part

Queues: First-In First-Out (FIFO)

module Queue( Queue,

emptyQ, -- Queue aisEmptyQ, -- Queue a -> BooladdQ, -- a -> Queue a -> Queue aremQ -- Queue a -> ( a , Queue a )

) where

Queues: Implementation I

newtype Queue a = Queue [a]emptyQ :: Queue aemptyQ = Queue []isEmptyQ :: Queue a -> BoolisEmptyQ (Queue []) = TrueisEmptyQ _ = FalseaddQ :: a -> Queue a -> Queue aaddQ x (Queue xs) = Queue (xs++[x])remQ :: Queue a -> ( a , Queue a )remQ q@(Queue xs)

| not (isEmptyQ q) = (head xs , Queue (tail xs))| otherwise = error "remQ"

Queues: Implementation II

addQ x (Queue xs) = Queue (x:xs)remQ q@(Queue xs)

| not (isEmptyQ q) = (last xs , Queue (init xs))| otherwise = error "remQ"

Queues: a two-list queue

Remove from left.Add to right.Only case of empty queue on left is expensive: reverse right list to left list.

Queues: Implementation III

data Queue a = Queue [a] [a]emptyQ :: Queue aemptyQ = Queue [] []isEmptyQ :: Queue a -> BoolisEmptyQ (Queue [] []) = TrueisEmptyQ _ = FalseaddQ :: a -> Queue a -> Queue aaddQ x (Queue xs ys) = Queue xs (x:ys)remQ :: Queue a -> ( a , Queue a )remQ (Queue (x:xs) ys) = (x , Queue xs ys)remQ (Queue [] ys@(z:zs)) = remQ (Queue (reverse ys) [])remQ (Queue [] []) = error "remQ"

Designing ADTs to solve problems

1. Identify and name the types in the system.2. Informally describe them.3. Write the signature of each ADT.What belongs in the signature? What doesn’t?• Create an instance• Discriminate instances• Get state from an instance• Transform an instance• Combine instances• Collapse instances

Tree module

module Tree (Tree,nil, -- Tree aisNil, -- Tree a -> Bool isNode, -- Tree a -> BoolleftSub, -- Tree a -> Tree a rightSub, -- Tree a -> Tree a treeVal, -- Tree a -> ainsTree, -- Ord a => a -> Tree a -> Tree a delete, -- Ord a => a -> Tree a -> Tree aminTree, -- Ord a => Tree a -> Maybe a

) where

ADT signatures should be minimal

Omit operations that can be defined in terms of other operations, so independent of implementation:

size :: Tree a -> Integersize t

| isNil t = 0| otherwise

= 1 + size (leftSub t) + size (rightSub t)

Search Trees

A binary search tree is a binary tree whose elements are ordered.Recall:

data Tree a = Nil | Node a (Tree a) (Tree a)A tree (Node val t1 t2) is ordered if:• all values in t1 are smaller than val,• all values in t2 are larger than val, and• the trees t1 and t2 are also orderedwhere the tree Nil is trivially ordered.We can use an ADT to enforce order, by making sure implementations of operations in the interface preserve order.

Search Trees: Signaturemodule Tree (Tree,nil, -- Tree aisNil, -- Tree a -> Bool isNode, -- Tree a -> BoolleftSub, -- Tree a -> Tree a rightSub, -- Tree a -> Tree a treeVal, -- Tree a -> ainsTree, -- Ord a => a -> Tree a -> Tree a delete, -- Ord a => a -> Tree a -> Tree aminTree, -- Ord a => Tree a -> Maybe aelemT -- Ord a => a -> Tree a -> Bool) where

Search Trees: Insertion

2 9

73

3

7

2 9

7

2 9

3

insTree val (Node v t1 t2)| v==val = Node v t1 t2| val > v = Node v t1 (insTree val t2)| val < v = Node v (insTree val t1) t2

Search Trees: Deletion7

2 9

8

2 9

8

2 9

8 2 9

8

delete val (Node v t1 t2)| val < v = Node v (delete val t1) t2| val > v = Node v t1 (delete val t2)| isNil t2 = t1| isNil t1 = t2| otherwise = join t1 t2

join t1 t2 = Node mini t1 newt

where(Just mini) = minTree t2newt = delete mini t2

“Set Theory”

Sets

Lists impose order, and allow multiplicity.[Joe, Sue, Ben] [Ben, Sue, Joe][Joe, Sue, Sue, Ben] [Joe, Sue, Ben, Sue]

Whereas, there is only one set containing these people:{Ben, Joe, Sue}

So, an implementation of the Set ADT must ensure uniqueness of elements.

Sets

Example implementation:an ordered list of elements without repetition

[Set.hs]

Relations

A binary relation is a relationship among elements of a set.e.g., parents and children in a familyisParent = {(Ben, Sue), (Ben,Leo), (Sue, Joe)}

In general:type Relation a = Set (a,a)

So, all set operations are available on Relation values.

Relations

The image of an element: all elements related to a given elemente.g., all of Ben’s childrenimage isParent Ben = {Sue, Leo}

The image of a set of elements: all elements related to a set of elements: the union of the images (sets) of each of the elements:

unionSet {s1, … , sn} = s1 ∪ … ∪ sn = s1 `union` … `union` sne.g., addChildren: take image of a set of people under isParent and add

Relations: defining isAncestor

The transitive closure of the isParent relation.First, consider grandparent starting from parents:

e.g., (Ben,Sue), (Sue, Joe)isGrandParent = isParent `compose` isParent

e.g., {(Ben,Joe)}Set product is used by compose to pair elements of a first set with elements of a second set.

e.g., setProduct {Ben,Suzie} {Sue,Joe} = {(Ben,Sue),(Ben,Joe),(Suzie,Sue),(Suzie,Joe)}

Relations: transitive closure and limits

A relation rel is transitive if for all (a,b) and (b,c) in rel, then (a,c) is also in rel.The transitive closure of a relation rel is the smallest relation extending rel that is transitive: repeat compose until nothing more is added.To do this, we can use limit f x to give the limit of the sequence:

x, f x, f (f x), f (f (f x)), … , fn xwhich is the value the sequence settles to if it exists, computed by taking the first element in the sequence whose successor is equal to the element itself:

fn x = fn+1 x

Relations: example

Given {(Ben,Sue), (Sue,Joe)}addChildren {Joe,Ben} = {Joe,Sue,Ben}limit addChildren {Ben}

?? {Ben}=={Ben,Sue} ➝ False➝ limit addChildren {Ben,Sue}

?? {Ben,Sue}=={Ben,Joe,Sue} ➝ False➝ limit addChildren {Ben,Joe,Sue}

?? {Ben,Joe,Sue}=={Ben,Joe,Sue} ➝ True➝ {Ben,Joe,Sue}

Graphs

Another way of thinking of relations is as directed graphs:e.g., graph1 = {(1,2),(1,3),(3,2),(3,4),(4,2),(2,4)}

Here, transitive closure represents paths of reachability in the graph:e.g., the transitive closure contains (1,4), but not (2,1)

1 2

3 4

Graphs: strongly connected components

Nodes connected by a path to all other nodes in the component:e.g., the components of graph1 are {1}, {3}, {2,4}

1 2

3 4

Computing strongly connected components

• First form the relation that links points in the same componentThere is a path from x to y and vice versa if both (x,y) and (y,x) are in the closure:

connect :: Ord a => Relation a -> Relation aconnect rel = clos `inter` solc

whereclos = tClosure relsolc = inverse clos

where inverse swaps all pairs in the relation:inverse = mapSet swap

whereswap (x,y) = (y,x)

Computing strongly connected components

• Next form the components (or equivalance classes) generated by this relation

Start with the nodes (e.g., {{1},{2},{3},{4}}) and close over them using the relation:

classes :: Ord a => Relation a -> Set (Set a)classes rel

= limit (addImages rel) startwherestart = mapSet sing (eles rel)