Для контекста, я работаю над C ++ искусственной системой , включающей агентов, контролируемых рекуррентными нейронными сетями, но детали не важны.нужно разделить две иерархии объектов на «мозг» и «тело» моих агентов.Я хочу разнообразные типы мозга и телосложения, которые могут быть связаны друг с другом во время выполнения.Я должен сделать это, чтобы избежать комбинаторного взрыва, вызванного мультипликативным перечислением отдельных проблем как тело работает и как мозг работает .
Например, существует много топологий и стилей рекуррентной нейронной сети с различными функциями передачи и соглашениями ввода / вывода.Однако эти детали не зависят от того, как работает тело агента, если сенсорные входы могут быть закодированы в нейронную активность, а затем декодированы в действия.
Вот простая иерархия классов, которая иллюстрирует проблему и одно потенциальное решение:
// Classes we are going to declare
class Image2D; // fake
class Angle2D; // fake
class Brain;
class Body;
class BodyWithEyes;
class BrainWithVisualCortex;
// Brain and Body base classes know about their parallels
class Brain
{
public:
Body* base_body;
Body* body() { return base_body; }
virtual Brain* copy() { return 0; } // fake
// ...etc
};
class Body
{
public:
Brain* base_brain;
Brain* brain() { return base_brain; }
virtual Body* reproduce() { return 0; } // fake
// ...etc
};
// Now introduce two strongly coupled derived classes, with overloaded access
// methods to each-other that return the parallel derived type
class BrainWithVisualCortex : public Brain
{
public:
BodyWithEyes* body();
virtual void look_for_snakes();
virtual Angle2D* where_to_look_next() { return 0; } // fake
};
class BodyWithEyes : public Body
{
public:
BrainWithVisualCortex* brain();
virtual void swivel_eyeballs();
virtual Image2D* get_image() { return 0; } // fake
};
// Member functions of these derived classes
void BrainWithVisualCortex::look_for_snakes()
{
Image2D* image = body()->get_image();
// ... find snakes and respond
}
void BodyWithEyes::swivel_eyeballs()
{
Angle2D* next = brain()->where_to_look_next();
// ... move muscles to achieve the brain's desired gaze
}
// Sugar to allow derived parallel classes to refer to each-other
BodyWithEyes* BrainWithVisualCortex::body()
{ return dynamic_cast<BodyWithEyes*>(base_body); }
BrainWithVisualCortex* BodyWithEyes::brain()
{ return dynamic_cast<BrainWithVisualCortex*>(base_brain); }
// pretty vacuous test
int main()
{
BodyWithEyes* body = new BodyWithEyes;
BrainWithVisualCortex* brain = new BrainWithVisualCortex;
body->base_brain = brain;
brain->base_body = body;
brain->look_for_snakes();
body->swivel_eyeballs();
}
Проблема этого подхода в том, что он неуклюж и не особенно безопасен для типов.Преимущество состоит в том, что функции-члены body () и brain () предоставляют немного сахара для производных классов, чтобы обращаться к своим партнерам.
Кто-нибудь знает лучший способ достижения этой тесной связи между «параллельными» иерархиями классов?Эта модель встречается достаточно часто, чтобы оправдать общеизвестное общее решение?Изучение обычных источников не выявило каких-либо устоявшихся закономерностей, соответствующих этой проблеме.
Любая помощь приветствуется!