6. Compile And Run

Post on 11-May-2015

775 views 2 download

Tags:

Transcript of 6. Compile And Run

Compile and Run.

No change.

Good!

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

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

How do we build an architecture

that’s easy and simple to change?

Welcome to the world of Design Patterns.

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

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.

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)

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;

How do we change a method to a strategy pattern?

1. Create an interface that defines the strategic operation

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!

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

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;

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

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;

(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;

Compile and run.

Nothing changed in functionality.

Good.

(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!

(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!

(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.

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.

Time to move on, to more

sophisticated

functionality

Let’s do the semantic network,

the slipnet.

But, let’s do it

right.(Which means slowly and carefully)

Copycat’s slipnet

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).

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.

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.)

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.

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!

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!

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.

Welcome to the observer pattern!

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

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?

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.

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

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);

Links implement:

Link.update (Param)

{deals with the new parameter}

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.