/// @file behavior.cc /// @author Joshua Petitt /// @author Stefan Schmitt /// @version 1.0 /// @date 2003 /// /// Implements behavior.hh. /// #include "behavior/behavior.hh" #include "state/state.hh" namespace EyeMind { // Explicit instantiation. template Array; // Explicit instantiation. // Not needed since IN_SIGNAL_LIST_SIZE == OUT_SIGNAL_LIST_SIZE //template Array; void SignalLink::Null() { in = NULL; out = NULL; signal = 0; next_signal = 0; excite_on_update = false; } SignalLink::SignalLink() { Null(); generic = true; buffered = false; excite_on_update = false; Ks=1; Bs=0; decay=2; } SignalLink::~SignalLink() { } void SignalLink::Signal(int s) { next_signal = s; updated = true; if (!buffered) Update(); } void SignalLink::Reset() { next_signal = 0; signal = 0; updated = false; } void SignalLink::Decay() { if(decay>0) { signal -= signal/decay + 1; // exponential decay if (signal<0) signal = 0; } } bool SignalLink::Update() { signal += Ks*next_signal; // linear growth updated = false; if ((out != NULL) && excite_on_update) { out->Excite(signal); } return true; } Behavior::Behavior() { threshold = 0; root = false; active = true; excite_lock = false; timebase = 0; feed_signal = 0; } Behavior::~Behavior() { } void Behavior::Timebase(float t) { OSPanicIf(timebase != 0, "Timebase already set"); timebase = t; } void Behavior::Excite(int signal) { if (!active) { DEBUG_PRINT("Not active\n"); return; } if (excite_lock) return; excite_lock=true; if(SumInputSignals() > threshold) { feed_signal = Execute(); FeedAttached(); DecayInputSignals(); } excite_lock=false; } void Behavior::Feed(SignalLink& l) { l.Signal(feed_signal); } void Behavior::FeedAttached() { SignalLink* i = outlinks.Begin(); while (i!=NULL) { Feed(*i); i = ++outlinks; }; } int Behavior::SumInputSignals() { int sum = 0; SignalLink* i = inlinks.Begin(); while (i!=NULL) { sum+=i->Signal(); i = ++inlinks; } return sum; } SignalLink* Behavior::FindMaxInputSignal() { SignalLink* temp = NULL; int max = 0; SignalLink* i = inlinks.Begin(); while (i != NULL) { if(i->Signal() > max) { temp = i; max = i->Signal(); } i = ++inlinks; } if(temp->Signal()) return temp; else return NULL; } SignalLink* Behavior::FindMaxNonGenericInputSignal() { SignalLink* temp = NULL; int max = 0; SignalLink* i = inlinks.Begin(); while (i != NULL) { if(!(i->Generic()) && (i->Signal()>max)) { temp = i; max = i->Signal(); } i = ++inlinks; } if(max) return temp; else return NULL; } unsigned Behavior::SignalRange(SignalLink& l) { int signal = l.Signal(); if ((signal >= (int)EXCITE_LOW_MIN) && (signal <= (int)EXCITE_LOW_MAX)) return EXCITE_RANGE_LOW; if ((signal >= (int)EXCITE_MED_MIN) && (signal <= (int)EXCITE_MED_MAX)) return EXCITE_RANGE_MED; if ((signal >= (int)EXCITE_HI_MIN) && (signal <= (int)EXCITE_HI_MAX)) return EXCITE_RANGE_HI; return EXCITE_RANGE_NONE; } bool Behavior::InSignalRange(SignalLink& l, unsigned range) { bool b = false; int signal = l.Signal(); switch (range) { case EXCITE_RANGE_LOW: if ((signal >= (int)EXCITE_LOW_MIN) && (signal <= (int)EXCITE_LOW_MAX)) b = true; break; case EXCITE_RANGE_MED: if ((signal >= (int)EXCITE_MED_MIN) && (signal <= (int)EXCITE_MED_MAX)) b = true; break; case EXCITE_RANGE_HI : if ((signal >= (int)EXCITE_HI_MIN) && (signal <= (int)EXCITE_HI_MAX)) b = true; break; } return b; } void Behavior::ResetInputSignals() { SignalLink *l = inlinks.Begin(); while(l!=NULL) { l->Reset(); l = ++inlinks; } } void Behavior::DecayInputSignals() { SignalLink *l = inlinks.Begin(); while(l!=NULL) { l->Decay(); l = ++inlinks; } } void Behavior::ResetOutputSignals() { SignalLink *l = outlinks.Begin(); while(l!=NULL) { l->Reset(); l = ++outlinks; } } Behavior& operator>>(SignalLink& l, Behavior& o) { // This operator function is only to be used for generic SignalLinks, // you will have to write your own function for attaching non-generic // SignalLinks to Behaviors. This new function will only take the // one type of non-generic SignalLink as parameter that you declared. // If you try to attach a different type of non-generic SignalLink, // its type is autmatically downcasted to a generic SignalLink, and // this function is called instead. The Generic() property of the // SignalLink is still false, of course. // So this operator function makes the following assumptions: // 1. Non-generic SignalLinks are only used with their specific // Behaviors // 2. If you try something else anyway, it is seen as a mistake, // rather than treating the non-generic SignalLink as a generic one OSPanicIf(!l.Generic(),"Non-generic SignalLink attached as generic"); return SignalLinkOutputToBehavior(l,o); } Behavior& operator<<(SignalLink& l, Behavior& i) { // see comment at operator>>() OSPanicIf(!l.Generic(),"Non-generic SignalLink attached as generic"); return SignalLinkInputToBehavior(l,i); } SignalLink& operator>>(Behavior& n, SignalLink& o) { // see comment at operator>>() OSPanicIf(!o.Generic(),"Non-generic SignalLink attached as generic"); return BehaviorOutputToSignalLink(n,o); } SignalLink& operator<<(Behavior& n, SignalLink& i) { // see comment at operator>>() OSPanicIf(!i.Generic(),"Non-generic SignalLink attached as generic"); return BehaviorInputToSignalLink(n,i); } SignalLink* operator|(Behavior& s, Behavior& t) { return DisconnectBehaviors(s,t); } Behavior& SignalLinkOutputToBehavior(SignalLink& l, Behavior& o) { l.out = &o; // set output of SignalLink o.inlinks + l; // add to inlinks of Behavior return o; // make chaining possible (like stream) } Behavior& SignalLinkInputToBehavior(SignalLink& l, Behavior& i) { l.in = &i; // set input of SignalLink i.outlinks + l; // add to outlinks of Behavior l.excite_on_update = true; return i; // make chaining possible (like stream) } SignalLink& BehaviorOutputToSignalLink(Behavior& n, SignalLink& o) { n.outlinks + o; // add to outlinks of Behavior o.in = &n; // set input of SignalLink o.excite_on_update = true; return o; // make chaining possible (like stream) } SignalLink& BehaviorInputToSignalLink(Behavior& n, SignalLink& i) { n.inlinks + i; // add to inlinks of Behavior i.out = &n; // set output of SignalLink return i; // make chaining possible (like stream) } SignalLink* DisconnectBehaviors(Behavior& s, Behavior& t) { SignalLink* l; // iterate through source output SignalLinks s.outlinks.Begin(); while ((l = s.outlinks++)) if (l->out == &t) break; // check for link to target if (l) // link to target found in source output SignalLinks { l->Null(); t.inlinks-*l; return s.outlinks-*l; } return NULL; } }; // namespace EyeMind