61a lecture 13
play

61A Lecture 13 {'Dem': 0} Wednesday, September 28 2 Limitations - PDF document

Dictionaries 61A Lecture 13 {'Dem': 0} Wednesday, September 28 2 Limitations on Dictionaries Implementing Dictionaries def make_dict(): """Return a functional implementation of a dictionary.""" Dictionaries are


  1. Dictionaries 61A Lecture 13 {'Dem': 0} Wednesday, September 28 2 Limitations on Dictionaries Implementing Dictionaries def make_dict(): """Return a functional implementation of a dictionary.""" Dictionaries are unordered collections of key-value pairs. records = [] def getitem(key): Dictionaries do have two restrictions: for k, v in records: if k == key: return v • A key of a dictionary cannot be an object of a mutable def setitem(key, value): Question: Do we need a built-in type. nonlocal statement here? for item in records: if item[0] == key: item[1] = value • Two keys cannot be equal . There can be at most one value for return a given key. records.append([key, value]) def dispatch(message, key=None, value=None): if message == 'getitem': This first restriction is tied to Python's underlying return getitem(key) implementation of dictionaries. elif message == 'setitem': setitem(key, value) elif message == 'keys': return tuple(k for k, _ in records) The second restriction is an intentional consequence of the elif message == 'values': dictionary abstraction. return tuple(v for _, v in records) Demo return dispatch 3 4 Message Passing Dispatch Dictionaries An approach to organizing the relationship among different Enumerating different messages in a conditional statement pieces of a program isn't very convenient: ! Equality tests are repetitive Different objects pass messages to each other ! We can't add new messages without writing new code • What is your fourth element? A dispatch dictionary has messages as keys and functions (or • Change your third element to this new value. (please) data objects) as values. Dictionaries handle the message look-up logic; we concentrate Encapsulates the behavior of all on implementing useful behavior. operations on a piece of data within one function that responds to different messages. Important historical interest: the Demo message passing approach strongly influenced object-oriented programming (next lecture). In Javascript, all objects are just dictionaries 5 6

  2. Example: Constraint Programming A Constraint Network for Temperature Conversion a + b = c Combination idea: All intermediate quantities have values too. p * v = n * k * t a = c - b u 9 * c = 5 * (f - 32) u v b = c - a Both sides equal: 9 * celsius = 5 * ( fahrenheit - 32) they must be the same quantity Algebraic equations are declarative . They describe how This quantity This quantity different quantities relate to one another. relates directly relates directly to celsius to fahrenheit Python functions are procedural . They describe how to compute a particular result from a particular set of inputs. Constraint programming: v a a a celsius u ! We define the relationship between quantities * c c * + c fahrenheit ! We provide values for the "known" quantities b b b w x y ! The system computes values for the "unknown" quantities 5 32 9 Challenge : We want a general means of combination. 7 8 Anatomy of a Constraint Constructing a Constraint Network def make_converter(celsius, fahrenheit): """Make a temperature conversion network.""" a celsius Constraints compute u u, v, w, x, y = [make_connector() for _ in range(5)] * c values for "unknown" multiplier(celsius, w, u) w b connectors Blue names are multiplier(v, x, u) "connectors" adder(v, y, fahrenheit) constant(w, 9) Boxes are constant(x, 5) "constraints" constant(y, 32) v • Connectors represent quantities that have values. a a a celsius u * c c * + c fahrenheit � • Constraints spread information among connectors. b b b w x y • A constraint can receive two messages from its connectors: 5 32 9 � ! ' new_val ' indicates that some connector that is connected � to the constraint has a new value. celsius = make_connector('Celsius') ! ' forget ' indicates that some connector that is connected fahrenheit = make_connector('Fahrenheit') to the constraint has forgotten its value. Demo make_converter(celsius, fahrenheit) 9 10 The Messages of a Connector Implementing an Adder Constraint def adder_constraint(a, b, c): """The constraint that a + b = c. connector = make_connector('Celsius') >>> a, b, c = [make_connector(name) for name in ('a', 'b', 'c')] >>> constraint = adder_constraint(a, b, c) connector[ 'set_val' ](source, value) indicates that the >>> a['set_val']('user', 2) a = 2 source is requesting the connector to set its current >>> b['set_val']('user', 3) value to value. b = 3 c = 5 """ connector[ 'has_val' ]() returns whether the connector """ def new_value(): def new_value(): � already has a value. av, bv, cv = [connector['has_val']() for connector in (a, b, c)] # We will implement this function momentarily! a['set_val'](constraint, c['val'] � b['val']) connector[ 'val' ] is the current value of the connector. def forget_value(): � � for connector in (a, b, c): connector['forget'](constraint) � connector[ 'forget' ](source) tells the connector that the � source is requesting it to forget its value. constraint = {'new_val': new_value, 'forget': forget_value} for connector in (a, b, c): connector[ 'connect' ](source) tells the connector to connector['connect'](constraint) participate in a new constraint, the source. return constraint 11 12

  3. � � � � � � � � � Generalizing to a Multiplication Constraint Implementing a Connector def make_connector(name=None): Connectors Relations """ """A connector between constraints. informant = None constraints = [] def make_ternary_constraint(a, b, c, ab, ca, cb): constraints = [] def set_value(source, value): def set_value(source, value): """The constraint that ab(a,b)=c and ca(c,a)=b and cb(c,b)=a.""" nonlocal informant def new_value(): val = connector['val'] av, bv, cv = [connector['has_val']() for connector in (a, b, c)] if val is None: av, bv, cv = [connector['has_val']() for connector in (a, b, c)] if av and bv: informant, connector['val'] = source, value if av and bv: if name is not None: c['set_val'](constraint, ab(a['val'], b['val'])) print(name, '=', value) c['set_val'](constraint, ab(a['val'], b['val'])) elif av and cv: inform_all_except(source, 'new_val', constraints) elif av and cv: else : b['set_val'](constraint, ac(c['val'], a['val'])) if val != value: print('Contradiction detected:', val, 'vs', value) print('Contradiction detected:', val, 'vs', value) elif bv and cv: def forget_value(source): a['set_val'](constraint, cb(c['val'], b['val'])) def forget_value(source): nonlocal informant def forget_value(): if informant == source: informant, connector['val'] = None, None from operator import add, sub, mul, truediv if name is not None: print(name, 'is forgotten') def adder(a, b, c): inform_all_except(source, 'forget', constraints) """The constraint that a + b = c.""" inform_all_except(source, 'forget', constraints) connector = {'val': None, return make_ternary_constraint(a, b, c, add, sub, sub) connector = {'val': None, 'set_val': set_value, 'forget': forget_value, def multiplier(a, b, c): 'has_val': lambda : connector['val'] is not None, """The constraint that a * b = c.""" 'connect': lambda source: constraints.append(source)} return make_ternary_constraint(a, b, c, mul, truediv, truediv) return connector 13 14

Recommend


More recommend