/* model.h — the world model with EMERGENT relations.
*
* The model always tracks the two marginals P(class|ext), P(class|dir) and the
* joint counts. But a *relation* over a specific pair (ext,dir) only "exists" if
* that pair carries information beyond its parts — measured by the divergence of
* its joint distribution from the factored marginals (an MI/interaction score).
*
* rel_gain(f0,f1) = KL( P_joint(class|f0,f1) || P_marginal(class|f0,f1) ) [nats]
* rel_emerged(f0,f1)= seen(f0,f1) >= MINOBS && rel_gain >= MI_THRESH
*
* Prediction uses the joint iff the relation has emerged, else the marginals.
* So relations precipitate from data (Linas's connectors forming themselves),
* rather than being hard-wired as "always ext x dir". */
#ifndef BASAL_MODEL_H
#define BASAL_MODEL_H
#include "sensor.h"
typedef struct {
double alpha;
int nf0, nf1;
long *m0, *s0; /* marginal ext */
long *m1, *s1; /* marginal dir */
long *j, *sj; /* joint */
} Rel;
void rel_init(Rel *r, int nf0, int nf1, double alpha);
void rel_free(Rel *r);
void rel_update(Rel *r, int f0, int f1, int klass);
void pred_ext (const Rel *r, int f0, double out[NUM_CLASSES]);
void pred_dir (const Rel *r, int f1, double out[NUM_CLASSES]);
void pred_marg(const Rel *r, int f0, int f1, double out[NUM_CLASSES]); /* no relation */
void pred_rel (const Rel *r, int f0, int f1, double out[NUM_CLASSES]); /* gated by emergence */
double rel_gain (const Rel *r, int f0, int f1); /* MI-type score, nats */
int rel_emerged(const Rel *r, int f0, int f1); /* has the relation formed? */
int argmax(const double p[NUM_CLASSES]);
double infogain_pair(const Rel *r, int f0, int f1);
long pair_seen(const Rel *r, int f0, int f1);
#endif