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


3.8 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 is not a built-in feature, but a developer can program it using the Actor and Storage APIs. Example functions actor_save and actor_load for saving and loading the state of a small actor are available in the file samples/load_save.c in the package distribution. This section includes them too.

The function actor_save saves the following information for a small actor:

  1. The mode of behavior: adaptive or random.
  2. The number of signals.
  3. The number of spur types.
  4. The length of a signal list encoding an action choice state.
  5. The index of a spur type for the automatic spur.
  6. Discrete time.
  7. Continuous time.
  8. The number of output signals emitted per one unit of discrete time passed.
  9. The nominal number of output signals.
  10. Actor temperature.
  11. The ranges of signals in a list encoding an action choice state. For every range, the function saves the following information:
    1. Minimum allowed signal identifier.
    2. Maximum allowed signal identifier.
  12. Spur type parameters. For every spur type, the function saves the following information:
    1. Spur value.
    2. Spur weight.
    3. The way of spur perception: normal or inverse.
    4. The type of time for computing spur increment velocity: discrete or continuous.
  13. Output signal weights. For every output signal, the function saves the following information:
    1. Signal identifier.
    2. Signal weight.
  14. The content of the buffer for an n-gram of signals from the event history.
  15. Information on action choice states held in statistics storage. For every action choice state, the callback function wr_acstate saves the following information:
    1. Signal list encoding the action choice state.
    2. The condition of the action choice state itself.
    3. The condition of every spur type for the action choice state.
    4. Cycle type statistics. For every cycle type, the callback function wr_acstate saves the following information:
      1. Cycle direction.
      2. Statistics on the cycle type itself.
      3. Statistics on every spur type for the cycle type.

The functions actor_save and actor_load do not save and load the following parameters:

  1. The type of a function returning the relative probability of an output signal. The function qsmm_get_actor_relprob_type queries that type. The function qsmm_set_actor_relprob_type sets that type.
  2. A helper function for computing the relative probability of an output signal. The function qsmm_get_actor_relprob_helper retrieves the helper function. The function qsmm_set_actor_relprob_helper sets the helper function.
  3. The content of the internal array holding the relative probabilities of output signals. The function qsmm_get_actor_choice_sig_prob returns a pointer to the array. The function qsmm_actor_choice_sig_prob_release releases the pointer after accessing the array. The function qsmm_get_actor_choice_sig_prob_vec returns a read-only view of that array as an ordinary or sparse vector.
  4. The content of the pool of probabilities lists in normal form. The function qsmm_actor_profile_add adds a probabilities list to the pool.
  5. The content of the pool of permutations of output signals. The functions qsmm_actor_profile_add and qsmm_actor_permut_add add a permutation of output signals to the pool.
  6. Preloaded probability profiles assigned to action choice states. The function qsmm_get_actor_ngram_profile queries a preloaded probability profile assigned to an action choice state. The function qsmm_set_actor_ngram_profile assigns a preloaded probability profile to an action choice state.
  7. Last discrete cycle period. The function qsmm_get_actor_discrete_cycle_period_last returns this cycle period.
  8. Mean discrete cycle period. The function qsmm_get_actor_discrete_cycle_period_mean returns this cycle period.
  9. Storage redirection functions if used. The functions qsmm_get_storage_state_stats_redir, qsmm_get_storage_cycle_stats_redir, qsmm_get_storage_cycle_next_redir, and qsmm_get_storage_cycle_update_hook retrieve those storage redirection functions. The functions qsmm_set_storage_state_stats_redir, qsmm_set_storage_cycle_stats_redir, qsmm_set_storage_cycle_next_redir, and qsmm_set_storage_cycle_update_hook set those storage redirection functions.

The function actor_save saves the state of a small actor to a file. That function returns 0 on success or prints an error message to stderr and returns -1 on failure.

The function actor_load loads the state of an existing small actor from a file. The existing actor must have the following parameters set equal to parameters contained in the file:

  1. The number of signals.
  2. The number of spur types.
  3. The length of a signal list encoding an action choice state.
  4. The ranges of signals in a list encoding an action choice state.
  5. The set of identifiers of output signals.

The function actor_load adds information on action choice states read from a file to storage. That function does not clear existing information on action choice states in the storage. The function returns 0 on success or prints an error message to stderr and returns -1 on failure.

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

#include <qsmm/qsmm.h>


#define ERREXIT(fmt, ...)                                                 \
    do {                                                                  \
        fprintf(stderr,"%s: " fmt "\n", prg_name, ## __VA_ARGS__);        \
        goto Exit;                                                        \
    }                                                                     \
    while (0)


#define ERRFILE(fmt, ...) ERREXIT("%s: " fmt, fln, ## __VA_ARGS__);


#define CHK_FAIL(func, ...)                                               \
    do {                                                                  \
        const int rc=func(__VA_ARGS__);                                   \
        if (rc<0) ERREXIT(#func ": %s", qsmm_err_str(rc));                \
    }                                                                     \
    while (0)


#define READ(var)                                                         \
    do {                                                                  \
        if (fread(&(var),sizeof(var),1,filep)!=1) ERRFILE("read error");  \
    }                                                                     \
    while (0)


#define WRITE(var)                                                        \
    do {                                                                  \
        if (fwrite(&(var),sizeof(var),1,filep)!=1)                        \
            ERRFILE("write error");                                       \
    }                                                                     \
    while (0)


struct wr_acstate_param_s {

    const char *prg_name;  // program name
    const char *fln;       // output stream file name;

    FILE       *filep;     // output stream
};


// Write the condition of an enumerated action choice state and
// statistics on its cycle types to a stream.
// Returns: 1 = success;
//         -1 = failure.

static int
wr_acstate(
    qsmm_storage_t storage,
    int ngram_sz,
    const qsmm_sig_t *sig_ngram_p,
    void *paramp
) {
    int spur_type, result=-1;
    struct wr_acstate_param_s *const param_p=paramp;
    const char *const prg_name=param_p->prg_name, *const fln=param_p->fln;
    FILE *const filep=param_p->filep;
    WRITE(ngram_sz);
    for (int ii=0; ii<ngram_sz; ii++) WRITE(sig_ngram_p[ii]);
    const int nspur=qsmm_get_storage_nspur(storage);
    {
        struct qsmm_state_s state;
        struct qsmm_sspur_s sspur[nspur];
        CHK_FAIL(qsmm_get_storage_state_stats, storage,
                 ngram_sz, sig_ngram_p, &state, sspur);
        WRITE(state);
        for (spur_type=0; spur_type<nspur; spur_type++)
            WRITE(sspur[spur_type]);
    }
    qsmm_sig_t sig=QSMM_SIG_INVALID;
    while (1) {
        CHK_FAIL(qsmm_get_storage_cycle_next, storage,
                 ngram_sz, sig_ngram_p, &sig);
        WRITE(sig);
        if (sig==QSMM_SIG_INVALID) break;
        struct qsmm_cycle_s cycle;
        struct qsmm_cspur_s cspur[nspur];
        CHK_FAIL(qsmm_get_storage_cycle_stats, storage,
                 ngram_sz, sig_ngram_p, sig, &cycle, cspur);
        WRITE(cycle);
        for (spur_type=0; spur_type<nspur; spur_type++)
            WRITE(cspur[spur_type]);
    }
    result=1;

Exit:
    return result;
}


// Save the state of a small actor to a file.
// Returns: 0 = success;
//         -1 = failure.

int
actor_save(
    const char *prg_name,
    const char *fln,
    qsmm_actor_t actor
) {
    int ii, result=-1;
    FILE *filep=0;
    if (qsmm_get_actor_large_model(actor))
        ERREXIT("saving the state of a large actor not supported");
    if (!(filep=fopen(fln,"w")))
        ERRFILE("failed to open the file for writing");
    const char is_random=!!qsmm_get_actor_random(actor);
    WRITE(is_random);
    const int nsig=qsmm_get_actor_nsig(actor);
    WRITE(nsig);
    const int nspur=qsmm_get_actor_nspur(actor);
    WRITE(nspur);
    const int ngram_sz=qsmm_get_actor_ngram_sz(actor);
    WRITE(ngram_sz);
    int auto_spur_type=qsmm_get_actor_auto_spur_type(actor);
    if (auto_spur_type==QSMM_ERR_NOTFOUND) auto_spur_type=-1;
    WRITE(auto_spur_type);
    const long tmd=qsmm_get_actor_discrete_time(actor);
    WRITE(tmd);
    const double tmc=qsmm_get_actor_continuous_time(actor);
    WRITE(tmc);
    const double naction_per_evt=qsmm_get_actor_naction_per_evt(actor);
    WRITE(naction_per_evt);
    const double nsig_ctrl=qsmm_get_actor_nsig_ctrl(actor);
    WRITE(nsig_ctrl);
    const double ktemperature=qsmm_get_actor_ktemperature(actor);
    WRITE(ktemperature);
    const struct qsmm_pair_sig_s *const range_sig_p=qsmm_get_actor_range_sig(actor);
    for (ii=0; ii<ngram_sz; ii++) {
        const struct qsmm_pair_sig_s *const pair_p=range_sig_p+ii;
        WRITE(pair_p->first);
        WRITE(pair_p->second);
    }
    for (int spur_type=0; spur_type<nspur; spur_type++) {
        double spur_val=0, spur_weight=0;
        CHK_FAIL(qsmm_get_actor_spur,actor,spur_type,&spur_val);
        WRITE(spur_val);
        CHK_FAIL(qsmm_get_actor_spur_weight,actor,spur_type,&spur_weight);
        WRITE(spur_weight);
        enum qsmm_spur_perception_e spur_perception=QSMM_SPUR_PERCEPTION_NORMAL;
        CHK_FAIL(qsmm_get_actor_spur_perception, actor,
                 spur_type, &spur_perception);
        WRITE(spur_perception);
        enum qsmm_time_e spur_time=QSMM_TIME_CONTINUOUS;
        CHK_FAIL(qsmm_get_actor_spur_time,actor,spur_type,&spur_time);
        WRITE(spur_time);
    }
    qsmm_sig_t sig_next;
    for (sig_next=0; sig_next<nsig; sig_next++) {
        double weight_sig=0;
        const int rc=qsmm_get_actor_sig_weight(actor,sig_next,&weight_sig);
        if (rc<0) {
            if (rc==QSMM_ERR_INVAL) continue;
            ERREXIT("qsmm_get_actor_sig_weight: %s",qsmm_err_str(rc));
        }
        WRITE(sig_next);
        WRITE(weight_sig);
    }
    sig_next=QSMM_SIG_INVALID;
    WRITE(sig_next);
    const qsmm_sig_t *const sig_ngram_p=qsmm_get_actor_sig_ngram(actor);
    for (ii=0; ii<ngram_sz; ii++) WRITE(sig_ngram_p[ii]);
    struct wr_acstate_param_s wr_acstate_param;
    memset(&wr_acstate_param,0,sizeof(wr_acstate_param));
    wr_acstate_param.prg_name=prg_name;
    wr_acstate_param.fln=fln;
    wr_acstate_param.filep=filep;
    CHK_FAIL(qsmm_storage_enum_states, qsmm_get_actor_storage(actor),
             0, 0, &wr_acstate, &wr_acstate_param);
    ii=0;
    WRITE(ii);
    result=0;

Exit:
    if (filep) fclose(filep);
    return result;
}


// Load the state of a small actor from a file.
// Returns: 0 = success;
//         -1 = failure.
// WARNING: possible loss of atomicity: on failure, the state of the actor
//          may be partially updated.

int
actor_load(
    const char *prg_name,
    const char *fln,
    qsmm_actor_t actor
) {
    int ii, spur_type, result=-1;
    FILE *filep=0;
    if (qsmm_get_actor_large_model(actor))
        ERREXIT("loading the state of a large actor not supported");
    if (!(filep=fopen(fln,"r"))) ERRFILE("failed to open the file");
    char is_random=0;
    READ(is_random);
    int nsig_stream=0, nspur_stream=0, ngram_sz_stream=0,
        auto_spur_type=-1;
    READ(nsig_stream);
    const int nsig_actor=qsmm_get_actor_nsig(actor);
    if (nsig_stream!=nsig_actor)
        ERREXIT(
               "number of signals does not match: %d (file) != %d (actor)",
                nsig_stream, nsig_actor);
    READ(nspur_stream);
    const int nspur_actor=qsmm_get_actor_nspur(actor);
    if (nspur_stream!=nspur_actor)
        ERREXIT(
            "number of spur types does not match: %d (file) != %d (actor)",
                nspur_stream, nspur_actor);
    READ(ngram_sz_stream);
    const int ngram_sz_actor=qsmm_get_actor_ngram_sz(actor);
    if (ngram_sz_stream!=ngram_sz_actor)
        ERREXIT("n-gram length does not match: %d (file) != %d (actor)",
                ngram_sz_stream, ngram_sz_actor);
    READ(auto_spur_type);
    long tmd=0;
    READ(tmd);
    double tmc=0, naction_per_evt=0, nsig_ctrl=0, ktemperature=0; 
    READ(tmc);
    if (!isfinite(tmc) || tmc<0)
        ERREXIT("invalid continuous time (%g)",tmc);
    READ(naction_per_evt);
    READ(nsig_ctrl);
    READ(ktemperature);
    const struct qsmm_pair_sig_s *pair_p,
        *const range_sig_p=qsmm_get_actor_range_sig(actor);
    for (ii=0; ii<ngram_sz_stream; ii++) {
        struct qsmm_pair_sig_s range;
        READ(range.first);
        READ(range.second);
        pair_p=range_sig_p+ii;
        if (range.first!=pair_p->first)
            ERREXIT("range %d: minimum allowed signal does not match: %"
                    QSMM_FMT_PRI_SIG " (file) != %" QSMM_FMT_PRI_SIG
                    " (actor)", ii, range.first, pair_p->first);
        if (range.second!=pair_p->second)
            ERREXIT("range %d: maximum allowed signal does not match: %"
                    QSMM_FMT_PRI_SIG " (file) != %" QSMM_FMT_PRI_SIG
                    " (actor)", ii, range.second, pair_p->second);
    }
    qsmm_set_actor_random(actor,is_random);
    CHK_FAIL(qsmm_set_actor_auto_spur_type,actor,auto_spur_type);
    qsmm_set_actor_discrete_time(actor,tmd);
    CHK_FAIL(qsmm_actor_time_delta, actor,
             tmc-qsmm_get_actor_continuous_time(actor));
    CHK_FAIL(qsmm_set_actor_naction_per_evt,actor,naction_per_evt);
    CHK_FAIL(qsmm_set_actor_nsig_ctrl,actor,nsig_ctrl);
    CHK_FAIL(qsmm_set_actor_ktemperature,actor,ktemperature);
    for (spur_type=0; spur_type<nspur_stream; 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;
        READ(spur);
        if (!isfinite(spur))
            ERREXIT("spur type %d: invalid spur value (%g)",
                    spur_type, spur);
        CHK_FAIL(qsmm_get_actor_spur,actor,spur_type,&spur0);
        CHK_FAIL(qsmm_actor_spur_delta,actor,spur_type,spur-spur0);
        READ(spur_weight);
        CHK_FAIL(qsmm_set_actor_spur_weight,actor,spur_type,spur_weight);
        READ(spur_perception);
        if (spur_perception!=QSMM_SPUR_PERCEPTION_NORMAL &&
            spur_perception!=QSMM_SPUR_PERCEPTION_INVERSE)
            ERREXIT("spur type %d: invalid spur perception (%d)",
                    spur_type, spur_perception);
        CHK_FAIL(qsmm_set_actor_spur_perception, actor,
                 spur_type, spur_perception);
        READ(spur_time);
        if (spur_time!=QSMM_TIME_DISCRETE &&
            spur_time!=QSMM_TIME_CONTINUOUS)
            ERREXIT("spur type %d: invalid spur time (%d)",
                    spur_type, spur_time);
        CHK_FAIL(qsmm_set_actor_spur_time,actor,spur_type,spur_time);
    }
    qsmm_sig_t sig;
    while (1) {
        READ(sig);
        if (sig==QSMM_SIG_INVALID) break;
        double weight_sig=0;
        READ(weight_sig);
        CHK_FAIL(qsmm_set_actor_sig_weight,actor,sig,weight_sig);
    }
    qsmm_sig_t *const sig_ngram_p=qsmm_get_actor_sig_ngram(actor);
    for (ii=0; ii<ngram_sz_stream; ii++) {
        READ(sig);
        pair_p=range_sig_p+ii;
        if (sig<pair_p->first)
            ERREXIT("n-gram signal #%d (%" QSMM_FMT_PRI_SIG
                    ") is less than the minimum allowed signal (%"
                    QSMM_FMT_PRI_SIG ")", ii, sig, pair_p->first);
        if (sig>pair_p->second)
            ERREXIT("n-gram signal #%d (%" QSMM_FMT_PRI_SIG
                    ") is greater than the maximum allowed signal (%"
                    QSMM_FMT_PRI_SIG ")", ii, sig, pair_p->second);
        sig_ngram_p[ii]=sig;
    }
    const qsmm_storage_t storage=qsmm_get_actor_storage(actor);
    while (1) {
        int ngram_storage_sz=0;
        struct qsmm_state_s state;
        READ(ngram_storage_sz);
        if (ngram_storage_sz<1) break;
        if (ngram_storage_sz!=ngram_sz_actor)
            ERREXIT(
                   "n-gram length does not match: %d (file) != %d (actor)",
                    ngram_storage_sz, ngram_sz_actor);
        qsmm_sig_t sig_ngram_storage[ngram_storage_sz];
        for (ii=0; ii<ngram_storage_sz; ii++) READ(sig_ngram_storage[ii]);
        READ(state);
        struct qsmm_sspur_s sspur[nspur_stream];
        for (spur_type=0; spur_type<nspur_stream; spur_type++)
            READ(sspur[spur_type]);
        CHK_FAIL(qsmm_set_storage_state_stats, storage,
                 ngram_storage_sz, sig_ngram_storage, &state, sspur);
        while (1) {
            struct qsmm_cycle_s cycle;
            READ(sig);
            if (sig==QSMM_SIG_INVALID) break;
            READ(cycle);
            struct qsmm_cspur_s cspur[nspur_stream];
            for (spur_type=0; spur_type<nspur_stream; spur_type++)
                READ(cspur[spur_type]);
            CHK_FAIL(qsmm_set_storage_cycle_stats, storage,
                     ngram_storage_sz, sig_ngram_storage,
                     sig, &cycle, cspur);
        }
    }
    result=0;

Exit:
    if (filep) fclose(filep);
    return result;
}

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