mirror of
https://github.com/GrammaticalFramework/gf-core.git
synced 2026-05-08 10:42:50 -06:00
added random generation
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
#include <fcntl.h>
|
||||
#include <math.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#ifdef _WIN32
|
||||
#include <sys\stat.h>
|
||||
#endif
|
||||
@@ -14,6 +15,7 @@
|
||||
#include "parser.h"
|
||||
#include "graphviz.h"
|
||||
#include "aligner.h"
|
||||
#include "generator.h"
|
||||
|
||||
static void
|
||||
pgf_exn_clear(PgfExn* err)
|
||||
@@ -1190,6 +1192,61 @@ void pgf_check_type(PgfDB *db, PgfRevision revision,
|
||||
} PGF_API_END
|
||||
}
|
||||
|
||||
PGF_API
|
||||
PgfExpr pgf_generate_random(PgfDB *db, PgfRevision revision,
|
||||
PgfType type, size_t depth,
|
||||
uint64_t *seed, prob_t *prob,
|
||||
PgfMarshaller *m, PgfUnmarshaller *u,
|
||||
PgfExn *err)
|
||||
{
|
||||
PGF_API_BEGIN {
|
||||
DB_scope scope(db, READER_SCOPE);
|
||||
|
||||
ref<PgfPGF> pgf = db->revision2pgf(revision);
|
||||
|
||||
// Generation may fail for certain random choices, but succeed
|
||||
// for others. We try 10 time to increase the chance of succeess.
|
||||
for (size_t i = 0; i < 10; i++) {
|
||||
PgfRandomGenerator gen(pgf, depth, seed, m, u);
|
||||
PgfExpr expr = m->match_type(&gen, type);
|
||||
if (expr != 0) {
|
||||
*prob = gen.getProb();
|
||||
return expr;
|
||||
}
|
||||
}
|
||||
} PGF_API_END
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
PGF_API
|
||||
PgfExpr pgf_generate_random_from
|
||||
(PgfDB *db, PgfRevision revision,
|
||||
PgfExpr expr, size_t depth,
|
||||
uint64_t *seed, prob_t *prob,
|
||||
PgfMarshaller *m, PgfUnmarshaller *u,
|
||||
PgfExn *err)
|
||||
{
|
||||
PGF_API_BEGIN {
|
||||
DB_scope scope(db, READER_SCOPE);
|
||||
|
||||
ref<PgfPGF> pgf = db->revision2pgf(revision);
|
||||
|
||||
// Generation may fail for certain random choices, but succeed
|
||||
// for others. We try 10 time to increase the chance of succeess.
|
||||
for (size_t i = 0; i < 10; i++) {
|
||||
PgfRandomGenerator gen(pgf, depth, seed, m, u);
|
||||
PgfExpr new_expr = m->match_expr(&gen, expr);
|
||||
if (new_expr != 0) {
|
||||
*prob = gen.getProb();
|
||||
return new_expr;
|
||||
}
|
||||
}
|
||||
} PGF_API_END
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
PGF_API
|
||||
PgfRevision pgf_start_transaction(PgfDB *db, PgfExn *err)
|
||||
{
|
||||
|
||||
@@ -509,6 +509,21 @@ void pgf_check_type(PgfDB *db, PgfRevision revision,
|
||||
PgfMarshaller *m, PgfUnmarshaller *u,
|
||||
PgfExn *err);
|
||||
|
||||
PGF_API_DECL
|
||||
PgfExpr pgf_generate_random(PgfDB *db, PgfRevision revision,
|
||||
PgfType type, size_t depth,
|
||||
uint64_t *seed, prob_t *prob,
|
||||
PgfMarshaller *m, PgfUnmarshaller *u,
|
||||
PgfExn *err);
|
||||
|
||||
PGF_API_DECL
|
||||
PgfExpr pgf_generate_random_from
|
||||
(PgfDB *db, PgfRevision revision,
|
||||
PgfExpr expr, size_t depth,
|
||||
uint64_t *seed, prob_t *prob,
|
||||
PgfMarshaller *m, PgfUnmarshaller *u,
|
||||
PgfExn *err);
|
||||
|
||||
PGF_API_DECL
|
||||
PgfRevision pgf_start_transaction(PgfDB *db, PgfExn *err);
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "data.h"
|
||||
#include "math.h"
|
||||
|
||||
static
|
||||
int entry_cmp(PgfProbspaceEntry *entry1, PgfProbspaceEntry *entry2)
|
||||
@@ -199,6 +200,52 @@ void probspace_iter(PgfProbspace space, PgfText *cat,
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
ref<PgfAbsFun> probspace_random(PgfProbspace space,
|
||||
PgfText *cat, prob_t *rand,
|
||||
bool is_last)
|
||||
{
|
||||
if (space == 0)
|
||||
return 0;
|
||||
|
||||
int cmp = textcmp(cat,&(*space->value.cat));
|
||||
if (cmp < 0) {
|
||||
return probspace_random(space->left, cat, rand, true);
|
||||
} else if (cmp > 0) {
|
||||
return probspace_random(space->right, cat, rand, true);
|
||||
} else {
|
||||
ref<PgfAbsFun> fun;
|
||||
|
||||
fun = probspace_random(space->left, cat, rand, false);
|
||||
if (fun != 0)
|
||||
return fun;
|
||||
|
||||
bool is_res = (space->value.cat == ref<PgfText>::from_ptr(&space->value.fun->type->name));
|
||||
if (is_res) {
|
||||
*rand -= exp(-space->value.fun->prob);
|
||||
if (*rand <= 0)
|
||||
return space->value.fun;
|
||||
}
|
||||
|
||||
fun = probspace_random(space->right, cat, rand, is_last);
|
||||
if (fun != 0)
|
||||
return fun;
|
||||
if (is_last && is_res) {
|
||||
// necessary due to floating point rounding
|
||||
return space->value.fun;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
PGF_INTERNAL
|
||||
ref<PgfAbsFun> probspace_random(PgfProbspace space,
|
||||
PgfText *cat, prob_t rand)
|
||||
{
|
||||
return probspace_random(space,cat,&rand,true);
|
||||
}
|
||||
|
||||
PGF_INTERNAL
|
||||
void probspace_release(PgfProbspace space)
|
||||
{
|
||||
|
||||
@@ -67,6 +67,12 @@ PGF_INTERNAL_DECL
|
||||
void probspace_iter(PgfProbspace space, PgfText *cat,
|
||||
PgfItor* itor, bool all, PgfExn *err);
|
||||
|
||||
/* Given a random number from 0 to 1, select a random function from
|
||||
* the given category */
|
||||
PGF_INTERNAL_DECL
|
||||
ref<PgfAbsFun> probspace_random(PgfProbspace space,
|
||||
PgfText *cat, prob_t rand);
|
||||
|
||||
PGF_INTERNAL_DECL
|
||||
void probspace_release(PgfProbspace space);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user