6. Compile And Run

50
Compile and Run. No change. Good!

Transcript of 6. Compile And Run

Page 1: 6. Compile And Run

Compile and Run.

No change.

Good!

Page 2: 6. Compile And Run

Don’t think of an elephant! (ii) The TActivation class

Page 3: 6. Compile And Run

How to implement the sigmoid?B3=IF(A3<=0.5,A3,1.0-A3)

Page 4: 6. Compile And Run

How do we build an architecture

that’s easy and simple to change?

Welcome to the world of Design Patterns.

Page 5: 6. Compile And Run

Class Structure Tactivation = class private current_state, level, increment: real; Signals_Received: real; procedure Recompute_Level; Strategy Pattern public Constructor Create; Function Get_Level:real; Function Get_CurrentState:real; Function Get_Increment: real; Procedure Reset_Increment; Procedure increase (step: real);

Procedure DeployChange; Procedure decay; Strategy Pattern end;

Bureaucratic stuff

Page 6: 6. Compile And Run
Page 7: 6. Compile And Run
Page 8: 6. Compile And Run
Page 9: 6. Compile And Run

So OUR own code for “activation.increase” should be a Strategy Pattern

1. All instances of the class can call “increase” (even if they don’t implement the method)

2. We minimize duplicate code

3. We can CHANGE behavior at RUNTIME!If a global signal (pain, pleasure, attention, boredom) is received, then we can immediately change behavior, if needed.

Page 10: 6. Compile And Run

Advantages of a strategy pattern

• If, one day, we find the right psychological curve, we do not need to change the code at the activation class (we just add a new algorithm as a subclass of the strategy)

• The algorithm can change at runtime, if needed (imagine that hedonic or attentional feedback signals should change behavior)

Page 11: 6. Compile And Run

Tactivation = classprivatecurrent_state, level, increment: real;Signals_Received: real;procedure Recompute_Level; STRATEGY PATTERN publicConstructor Create;procedure increase (step: real);Function Get_Level:real;function Get_CurrentState:real;function Get_Increment: real;Procedure Reset_Increment;Procedure DeployChange;procedure Decay; STRATEGY PATTERN

end;

Page 12: 6. Compile And Run

How do we change a method to a strategy pattern?

1. Create an interface that defines the strategic operation

Page 13: 6. Compile And Run

1. Create an interface that defines the strategic operation

IRecompute_Activation = Interface function Recompute_ Activation (Current_state: Real):Real;

end;

Now we can start coding multiple ways to Recompute Activation levels!

Page 14: 6. Compile And Run

How do we change a method to a strategy pattern?

1. Create an interface that defines the strategic operation

2. Implement the interface with classes that represent each strategy

Page 15: 6. Compile And Run

2. Implement the interface with classes that represent each strategy

Subclass the strategy. Copy/Paste the previous method code (in the sigmoid case), without deleting the original.======================TRecompute_Activation_Sigmoid = Class (TInterfacedObject, IRecompute_Activation)

function Recompute_Activation(Current_state: Real):Real;end;

function TRecompute_Activation_Sigmoid.Recompute_Activation(Current_State:Real):real;var pyramid, sum, t:real; counter: integer;begin

Sum:=0;for counter:= 0 to floor (Current_State*max_Steps) dobegint:= counter/max_steps;If(t<=0.5) then Pyramid:=t else pyramid :=1-t; Sum:=(4*(1/max_steps)* Pyramid) + Sum; end; Result:= Sum;

end; ======================TRecompute_Activation_equals_state = Class (TInterfacedObject, IRecompute_Activation)

function Recompute_Activation(Current_state: Real):Real;end;

function TRecompute_Activation_equals_State. Recompute_Activation (Current_State:Real) :real;begin

Result:= Current_State;end;

Page 16: 6. Compile And Run

How do we change a method to a strategy pattern?

1. Create an interface that defines the strategic operation

2. Implement the interface with classes that represent each strategy

3. Refactor the code to select and to use an instance of the right strategic class

Page 17: 6. Compile And Run

3. Refactor the code to select and to use an instance of the right strategic class

(3.1) First we need to include the strategy pattern object, named activation_strategy, then compile and run. No change. Good.

Activation_Strategy: IActivation_Strategy;

Page 18: 6. Compile And Run

(3.2) Now on to include methods to set_activation_sigmoid, or set_activation_linear; hence we include in the TActivation Class:

Procedure set_activation_sigmoid; Procedure set_activation_linear;

...and the respective methods on the Activation class which call the constructor of the desired strategy:

Procedure Tactivation.set_activation_sigmoid;begin Activation_Strategy:= TRecompute_Activation_Sigmoid.create;end;

Procedure Tactivation.set_activation_linear;begin Activation_Strategy:= TRecompute_Activation_Linear.create;end;

Page 19: 6. Compile And Run

Compile and run.

Nothing changed in functionality.

Good.

Page 20: 6. Compile And Run

(3.3) Kill the previous code, by commenting out the method and its declaration. Compile... and it doesn't run anymore! Great, because the compiler will point out to you all the previous calls made to the method, so just substitute them for your strategy. In our example, we substitute calls to…

Recompute_Level

…to the new function:Level:=Activation_Strategy.Recompute_Activation (Current_State)

Compile and run, and functionality should be restored!

Page 21: 6. Compile And Run

(3.4) Now, test whether or not the whole strategy is working by changing the pattern at runtime. In my case this means including the following piece of code in the end of the DeployChange method:

if Level>0.5 then set_activation_linear;

Compile and run. Now marvel at the runtime behavioral change!

Page 22: 6. Compile And Run

(3.5) Finally, clean the code. Delete the (commented out) method calls and method implementation (and declaration).

Compile and run.

Works like a charm.

Congratulate yourself now.

Page 23: 6. Compile And Run

Now we have activation functionality.

It is easy to change, no matter what happens.

We can change behavior during runtime.

We can change the code very easily.

Page 24: 6. Compile And Run

Time to move on, to more

sophisticated

functionality

Page 25: 6. Compile And Run

Let’s do the semantic network,

the slipnet.

But, let’s do it

right.(Which means slowly and carefully)

Page 26: 6. Compile And Run

Copycat’s slipnet

Page 27: 6. Compile And Run

Let’s do classes for nodes and for links

But first, notice that there is an asymmetry between associations:

• "Polar bear" primes "white" to a higher extent than "white" primes "polar bear".

• "Niels Böhr" primes "physics" to a higher extent than "physics" primes "Niels Böhr".

• "Monica Lewinsky" primes "impeachment" to a higher extent than "impeachment" primes "Monica Lewinsky".

• 222 primes 2 to a higher extent than 2 primes 222 (if it does, actually).

Page 28: 6. Compile And Run

My favorite example comes from the research in concepts showing that people tend to think that numbers such as 22846221 are "more even" than numbers such as 13. It's crazy but natural; those numbers prime "even-ness" much more than 13 can ever aspire to.

This is a psychological fact, full of evidence for it.

Page 29: 6. Compile And Run

Here's a coupling problem. Consider a class TLINK, which should, of course, link two nodes, providing an association or connotation between them. It should obviously have something like:

TLINK.Create_Link (Node1, Node2, Link_Type, Link_Distance, etc.)

Page 30: 6. Compile And Run

TLINK.Create_Link (Node1, Node2, Link_Type, Link_Distance, etc.)

We have a coupling problem!

This class uses the class of Nodes, right? Ok. Now, the Nodes Class also uses this (Link) one, because, when spreading activation, one needs to know at least the link_distance.

So we end up with the following situation:

Class A (Links) needs objects from Class B (Nodes) & Class B (Nodes) needs info from Class A

(Link_Distances) in order to function.

Page 31: 6. Compile And Run

Rewriting… if spread_activation belongs to NODES…

…then NODES have to look at the distances involved in LINKS,

&

The method also has to change the activation of another NODE (that is a property of the LINK)!

(NODELINKNODE)&

We cannot include new LINKS at runtime!

Page 32: 6. Compile And Run

OR…if spread_activation belongs to LINKS…

…then LINKS have to look at the activation involved in N1,

&

The method also has to change the activation of N2! (LINK reads NODE1 and writes in NODE2)

&

We cannot include new LINKS at runtime!

Page 33: 6. Compile And Run

NODES

ActivationDataData…

MethodMethodMethod…

LINKS

DistanceDataData…

MethodMethodMethod…

The classes become strongly coupled.It will be very hard to change them in 2010.

Practically impossible to include new links at runtime.

Page 34: 6. Compile And Run

Welcome to the observer pattern!

Can you imagine calling a method without knowing which method from which object you are calling?

Page 35: 6. Compile And Run
Page 36: 6. Compile And Run
Page 37: 6. Compile And Run

How could we include a new display if they have all been hardcoded?

By changing this code? That would be bad! We don’t want to change code.

What if we want to include a new display during runtime?

Page 38: 6. Compile And Run
Page 39: 6. Compile And Run
Page 40: 6. Compile And Run
Page 41: 6. Compile And Run
Page 42: 6. Compile And Run
Page 43: 6. Compile And Run
Page 44: 6. Compile And Run
Page 45: 6. Compile And Run
Page 46: 6. Compile And Run

So here's what the design looks like:

Node= subject/publisher

Links=observers

Nodes propagate activation as subjects/publishers. Nodes do NOT care who is receiving their messages. (Even a codelet might be interested in receiving a NODE message).

Links observe the Nodes they have interest in (whenever they do); they can opt-in or opt-out during runtime.

Page 47: 6. Compile And Run

So here's what the design looks like:

TActivationObserverClass = Class (TInterfacedObject, IObserverActivation){Observer Interface here}procedure Update(Received_Activation: Tactivation); virtual;abstract;

end;

Tnode = class (TInterfacedObject, ISubjectActivation)privateassociations: tlist;previous_level: real;publicactivation: Tactivation;constructor create;{Observable (Subject) interface here}procedure RegisterObserver(const Observer: TObject);procedure UnRegisterObserver(const Observer: TObject);procedure Notify (Sent_Activation: TActivation);

end;

TLink = Class (TActivationObserverClass)link_drag: real;Dest_Node: TNode;constructor create (destination: TNode; drag: real);{Observer Interface here}procedure Update (Received_Activation: Tactivation); override;

end;

Node= subject/publisher

Links=observers

Page 48: 6. Compile And Run

NODES implement:procedure RegisterObserver(const Observer: TObject);

{adds the Observer to a list}

procedure UnRegisterObserver(const Observer: TObject);{Withdraws the observer from the list}

procedure Notify (Sent_Activation: TActivation);for x:=1 to Num_Observers do observer[x].update(Param);

Page 49: 6. Compile And Run

Links implement:

Link.update (Param)

{deals with the new parameter}

Page 50: 6. Compile And Run

So here's what the design looks like:

Node= subject/publisher

Links=observers

Nodes propagate activation as subjects/publishers. Nodes do NOT care who is receiving their messages. (Even a codelet might be interested in receiving a NODE message).

Links observe the Nodes they have interest in (whenever they do); they can opt-in or opt-out during runtime.