Previous: , Up: Statistics Storage   [Contents][Index]


3.7 Example of Using the Storage API

When working with an actor, a helpful feature would be the ability to save the state of the actor to a file and restore that state from the file later. This feature is not built in the package, but it can be programmed by a developer manually using Actor and Storage APIs. Example functions that save and load the state of a small actor are available in the file samples/load_save.c in the package distribution and are also given in this section.

The following actor parameters are not saved and loaded by the functions.

The function save_actor_state saves the state of an actor to a specified stream. It returns 0 on success, -1 on soft errors, such as out of memory error, -2 on stream write errors, and -3 if the actor is the large one.

The function load_actor_state loads the state of an actor from a specified stream. Before calling the function, an actor, which state is to be loaded and which handle is passed to the function, must be created by the function qsmm_actor_create. This actor must be a small one, the actor and actor which state was saved to the stream must have the same numbers of signals and supported spur types, the same length of action choice state n-gram, the same ranges of allowed signal identifiers in action choice state n-grams, and the same sets of identifiers of output signals. The function returns 0 on success, -1 on soft errors, -2 on stream read errors, -3 on errors in read data, and -4 on incompatibility between parameters of the actor specified by a handle passed to the function and parameters read from the stream.

#include <assert.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>

#include <qsmm/qsmm.h>


#define ERRRET(code)                                                      \
    do {                                                                  \
        result=(code);                                                    \
        goto Exit;                                                        \
    }                                                                     \
    while (0)


#define LOAD(var)                                                         \
    do {                                                                  \
        if (fread(&var,sizeof(var),1,filep)!=1) ERRRET(-2);               \
    }                                                                     \
    while (0)


#define SAVE(var)                                                         \
    do {                                                                  \
        if (fwrite(&var,sizeof(var),1,filep)!=1) ERRRET(-2);              \
    }                                                                     \
    while (0)


struct param_s {
    int                 err;
    int                 nspur;
    FILE                *filep;
    struct qsmm_cspur_s *cspur_p;  // [nspur]
    struct qsmm_sspur_s *sspur_p;  // [nspur]
};


static int save_acstate(qsmm_storage_t storage,
                        int ngram_sz,
                        const qsmm_sig_t *sig_ngram_p,
                        void *paramp) {
    int ii, spur_type, nspur, result=-1;
    qsmm_sig_t sig_next=QSMM_SIG_INVALID;
    FILE *filep;
    struct param_s *param_p=paramp;
    struct qsmm_state_s state;
    nspur=param_p->nspur;
    filep=param_p->filep;
    SAVE(ngram_sz);
    for (ii=0; ii<ngram_sz; ii++) SAVE(sig_ngram_p[ii]);
    if (qsmm_get_storage_state_stats(storage, ngram_sz, sig_ngram_p,
                                     &state, param_p->sspur_p)<0)
        goto Exit;
    SAVE(state);
    for (spur_type=0; spur_type<nspur; spur_type++)
        SAVE(param_p->sspur_p[spur_type]);
    while (1) {
        struct qsmm_cycle_s cycle;
        if (qsmm_get_storage_cycle_next(storage, ngram_sz,
                                        sig_ngram_p, &sig_next)<0)
            goto Exit;
        SAVE(sig_next);
        if (sig_next==QSMM_SIG_INVALID) break;
        if (qsmm_get_storage_cycle_stats(storage, ngram_sz, sig_ngram_p,
                                         sig_next, &cycle,
                                         param_p->cspur_p)<0)
            goto Exit;
        SAVE(cycle);
        for (spur_type=0; spur_type<nspur; spur_type++)
            SAVE(param_p->cspur_p[spur_type]);
    }
    result=1;

Exit:
    if (result<0) param_p->err=result;
    return result;
}


int save_actor_state(qsmm_actor_t actor, FILE *filep) {
    char is_random=qsmm_get_actor_random(actor)?1:0;
    int ii, rc, spur_type, result=-1, nsig=qsmm_get_actor_nsig(actor),
        nspur=qsmm_get_actor_nspur(actor),
        ngram_sz=qsmm_get_actor_ngram_sz(actor),
        auto_spur_type=qsmm_get_actor_auto_spur_type(actor);
    long tmd=qsmm_get_actor_discrete_time(actor);
    double tmc=qsmm_get_actor_continuous_time(actor),
        naction_per_evt=qsmm_get_actor_naction_per_evt(actor),
        nsig_ctrl=qsmm_get_actor_nsig_ctrl(actor),
        ktemperature=qsmm_get_actor_ktemperature(actor);
    qsmm_sig_t sig_next, *sig_ngram_p=qsmm_get_actor_sig_ngram(actor);
    struct param_s param;
    const struct qsmm_pair_sig_s *range_sig_p=qsmm_get_actor_range_sig(actor);
    memset(&param,0,sizeof(param));
    if (qsmm_get_actor_large_model(actor)) ERRRET(-3);
    if (auto_spur_type==QSMM_ERR_NOTFOUND) auto_spur_type=-1;
    SAVE(is_random);
    SAVE(nsig);
    SAVE(nspur);
    SAVE(ngram_sz);
    SAVE(auto_spur_type);
    SAVE(tmd);
    SAVE(tmc);
    SAVE(naction_per_evt);
    SAVE(nsig_ctrl);
    SAVE(ktemperature);
    for (ii=0; ii<ngram_sz; ii++) {
        const struct qsmm_pair_sig_s *pair_p=range_sig_p+ii;
        SAVE(pair_p->first);
        SAVE(pair_p->second);
    }
    for (spur_type=0; spur_type<nspur; spur_type++) {
        double spur=0, spur_weight=0;
        enum qsmm_spur_perception_e spur_perception=QSMM_SPUR_PERCEPTION_NORMAL;
        enum qsmm_time_e spur_time=QSMM_TIME_CONTINUOUS;
        rc=qsmm_get_actor_spur(actor,spur_type,&spur);
        assert(rc>=0);
        SAVE(spur);
        rc=qsmm_get_actor_spur_weight(actor,spur_type,&spur_weight);
        assert(rc>=0);
        SAVE(spur_weight);
        rc=qsmm_get_actor_spur_perception(actor, spur_type,
                                          &spur_perception);
        assert(rc>=0);
        SAVE(spur_perception);
        rc=qsmm_get_actor_spur_time(actor,spur_type,&spur_time);
        assert(rc>=0);
        SAVE(spur_time);
    }
    for (sig_next=0; sig_next<nsig; sig_next++) {
        double weight_sig=0;
        rc=qsmm_get_actor_sig_weight(actor,sig_next,&weight_sig);
        if (rc==QSMM_ERR_INVAL) continue;
        assert(rc>=0);
        SAVE(sig_next);
        SAVE(weight_sig);
    }
    sig_next=QSMM_SIG_INVALID;
    SAVE(sig_next);
    for (ii=0; ii<ngram_sz; ii++) SAVE(sig_ngram_p[ii]);
    param.nspur=nspur;
    param.filep=filep;
    if (!(param.cspur_p=malloc(sizeof(*param.cspur_p)*nspur)) ||
        !(param.sspur_p=malloc(sizeof(*param.sspur_p)*nspur)))
        goto Exit;
    if (qsmm_storage_enum_states(qsmm_get_actor_storage(actor), 0, 0,
                                 &save_acstate, &param)<0) {
        if (param.err<0) ERRRET(param.err);
        goto Exit;
    }
    ii=0;
    SAVE(ii);
    result=0;

Exit:
    if (param.sspur_p) free(param.sspur_p);
    if (param.cspur_p) free(param.cspur_p);
    return result;
}


int load_actor_state(qsmm_actor_t actor, FILE *filep) {
    char is_random=0;
    int ii, rc, spur_type, ngram_allo=1, nsig=0, nspur=0, ngram_sz=0,
        result=-1, auto_spur_type=-1;
    long tmd=0;
    double tmc0, tmc=0, naction_per_evt=0, nsig_ctrl=0, ktemperature=0;
    qsmm_sig_t sig_next, *sig_ngram_p, *sig_ngram_storage_p=0;
    const struct qsmm_pair_sig_s *range_sig_p;
    qsmm_storage_t storage;
    struct qsmm_cspur_s *cspur_p=0;
    struct qsmm_sspur_s *sspur_p=0;
    if (qsmm_get_actor_large_model(actor)) ERRRET(-4);
    LOAD(is_random);
    LOAD(nsig);
    LOAD(nspur);
    LOAD(ngram_sz);
    LOAD(auto_spur_type);
    LOAD(tmd);
    LOAD(tmc);
    LOAD(naction_per_evt);
    LOAD(nsig_ctrl);
    LOAD(ktemperature);
    if (nsig!=qsmm_get_actor_nsig(actor)) ERRRET(-4);
    if (nspur!=qsmm_get_actor_nspur(actor)) ERRRET(-4);
    if (ngram_sz!=qsmm_get_actor_ngram_sz(actor)) ERRRET(-4);
    if (auto_spur_type<-1 || auto_spur_type>=nspur) ERRRET(-3);
    qsmm_set_actor_random(actor,is_random);
    rc=qsmm_set_actor_auto_spur_type(actor,auto_spur_type);
    assert(rc>=0);
    qsmm_set_actor_discrete_time(actor,tmd);
    if (!isfinite(tmc) || tmc<0) ERRRET(-3);
    tmc0=qsmm_get_actor_continuous_time(actor);
    rc=qsmm_actor_time_delta(actor,tmc-tmc0);
    assert(rc>=0);
    if (!isfinite(naction_per_evt) ||
        naction_per_evt<=0 || naction_per_evt>1)
        ERRRET(-3);
    rc=qsmm_set_actor_naction_per_evt(actor,naction_per_evt);
    assert(rc>=0);
    if (!isfinite(nsig_ctrl) || nsig_ctrl<2) ERRRET(-3);
    rc=qsmm_set_actor_nsig_ctrl(actor,nsig_ctrl);
    assert(rc>=0);
    if (!isfinite(ktemperature) || ktemperature<=0) ERRRET(-3);
    rc=qsmm_set_actor_ktemperature(actor,ktemperature);
    assert(rc>=0);
    range_sig_p=qsmm_get_actor_range_sig(actor);
    for (ii=0; ii<ngram_sz; ii++) {
        struct qsmm_pair_sig_s range;
        const struct qsmm_pair_sig_s *pair_p=range_sig_p+ii;
        LOAD(range.first);
        LOAD(range.second);
        if (range.first!=pair_p->first) ERRRET(-4);
        if (range.second!=pair_p->second) ERRRET(-4);
    }
    for (spur_type=0; spur_type<nspur; spur_type++) {
        double spur=0, spur0=0, spur_weight=0;
        enum qsmm_spur_perception_e spur_perception=QSMM_SPUR_PERCEPTION_NORMAL;
        enum qsmm_time_e spur_time=QSMM_TIME_CONTINUOUS;
        LOAD(spur);
        if (!isfinite(spur)) ERRRET(-3);
        rc=qsmm_get_actor_spur(actor,spur_type,&spur0);
        assert(rc>=0);
        rc=qsmm_actor_spur_delta(actor,spur_type,spur-spur0);
        assert(rc>=0);
        LOAD(spur_weight);
        if (!isfinite(spur_weight)) ERRRET(-3);
        rc=qsmm_set_actor_spur_weight(actor,spur_type,spur_weight);
        assert(rc>=0);
        LOAD(spur_perception);
        rc=qsmm_set_actor_spur_perception(actor,spur_type,spur_perception);
        assert(rc>=0);
        LOAD(spur_time);
        rc=qsmm_set_actor_spur_time(actor,spur_type,spur_time);
        assert(rc>=0);
    }
    while (1) {
        double weight_sig=0;
        LOAD(sig_next);
        if (sig_next==QSMM_SIG_INVALID) break;
        LOAD(weight_sig);
        if (!isfinite(weight_sig) || weight_sig<0) ERRRET(-3);
        rc=qsmm_set_actor_sig_weight(actor,sig_next,weight_sig);
        if (rc==QSMM_ERR_INVAL) ERRRET(-4);
        assert(rc>=0);
    }
    sig_ngram_p=qsmm_get_actor_sig_ngram(actor);
    for (ii=0; ii<ngram_sz; ii++) {
        LOAD(sig_next);
        if (sig_next>=nsig) ERRRET(-3);
        sig_ngram_p[ii]=sig_next;
    }
    if (!(sig_ngram_storage_p=
          malloc(ngram_allo*sizeof(*sig_ngram_storage_p))) ||
        !(cspur_p=malloc(nspur*sizeof(*cspur_p))) ||
        !(sspur_p=malloc(nspur*sizeof(*sspur_p))))
        goto Exit;
    storage=qsmm_get_actor_storage(actor);
    while (1) {
        int ngram_storage_sz=0;
        struct qsmm_state_s state;
        LOAD(ngram_storage_sz);
        if (ngram_storage_sz<1) break;
        if (ngram_allo<ngram_storage_sz) {
            qsmm_sig_t *sig_new_p=
                realloc(sig_ngram_storage_p,
                        ngram_storage_sz*sizeof(*sig_ngram_storage_p));
            if (!sig_new_p) goto Exit;
            sig_ngram_storage_p=sig_new_p;
            ngram_allo=ngram_storage_sz;
        }
        for (ii=0; ii<ngram_storage_sz; ii++)
            LOAD(sig_ngram_storage_p[ii]);
        LOAD(state);
        for (spur_type=0; spur_type<nspur; spur_type++)
            LOAD(sspur_p[spur_type]);
        if (qsmm_set_storage_state_stats(storage, ngram_storage_sz,
                                         sig_ngram_storage_p,
                                         &state, sspur_p)<0)
            goto Exit;
        while (1) {
            struct qsmm_cycle_s cycle;
            LOAD(sig_next);
            if (sig_next==QSMM_SIG_INVALID) break;
            LOAD(cycle);
            for (spur_type=0; spur_type<nspur; spur_type++)
                LOAD(cspur_p[spur_type]);
            if (qsmm_set_storage_cycle_stats(storage, ngram_storage_sz,
                                             sig_ngram_storage_p,
                                             sig_next, &cycle, cspur_p)<0)
                goto Exit;
        }
    }
    result=0;

Exit:
    if (sspur_p) free(sspur_p);
    if (cspur_p) free(cspur_p);
    if (sig_ngram_storage_p) free(sig_ngram_storage_p);
    return result;
}

Previous: , Up: Statistics Storage   [Contents][Index]