forked from GitHub/gf-core
random generation always produces something if possible
This commit is contained in:
@@ -8,6 +8,7 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
#include "pgf.h"
|
#include "pgf.h"
|
||||||
|
|
||||||
|
|||||||
@@ -173,42 +173,49 @@ again: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
PgfExpr expr = 0;
|
PgfExpr expr = 0;
|
||||||
PgfExpr var_expr = 0;
|
std::set<ref<PgfAbsFun>> excluded;
|
||||||
|
|
||||||
int index = 0;
|
prob_t save_prob = prob;
|
||||||
Scope *sc = scope;
|
prob_t total_prob = 1;
|
||||||
auto tmp = m;
|
for (;;) {
|
||||||
while (sc != NULL) {
|
prob = save_prob;
|
||||||
m = sc->m;
|
|
||||||
PgfVarGenerator v_gen(this, index, cat, n_exprs, exprs);
|
int index = 0;
|
||||||
expr = m->match_type(&v_gen, sc->type);
|
Scope *sc = scope;
|
||||||
if (expr != 0) {
|
auto tmp = m;
|
||||||
if (rand() < VAR_PROB) {
|
while (sc != NULL) {
|
||||||
prob += -log(VAR_PROB);
|
m = sc->m;
|
||||||
break;
|
PgfVarGenerator v_gen(this, index, cat, n_exprs, exprs);
|
||||||
} else {
|
expr = m->match_type(&v_gen, sc->type);
|
||||||
prob += -log(1-VAR_PROB);
|
if (expr != 0) {
|
||||||
if (var_expr != 0)
|
if (rand() < VAR_PROB) {
|
||||||
u->free_ref(var_expr);
|
prob += -log(VAR_PROB);
|
||||||
var_expr = expr;
|
break;
|
||||||
expr = 0;
|
} else {
|
||||||
|
prob += -log(1-VAR_PROB);
|
||||||
|
u->free_ref(expr);
|
||||||
|
expr = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
sc = sc->next;
|
||||||
|
index++;
|
||||||
}
|
}
|
||||||
sc = sc->next;
|
m = tmp;
|
||||||
index++;
|
|
||||||
}
|
if (expr != 0)
|
||||||
m = tmp;
|
break;
|
||||||
|
|
||||||
if (expr == 0) {
|
|
||||||
if (strcmp(cat->text, "Int") == 0) {
|
if (strcmp(cat->text, "Int") == 0) {
|
||||||
uintmax_t value = 999;
|
uintmax_t value = 999;
|
||||||
PgfLiteral lint = u->lint(1,&value);
|
PgfLiteral lint = u->lint(1,&value);
|
||||||
expr = u->elit(lint);
|
expr = u->elit(lint);
|
||||||
u->free_ref(lint);
|
u->free_ref(lint);
|
||||||
|
break;
|
||||||
} else if (strcmp(cat->text, "Float") == 0) {
|
} else if (strcmp(cat->text, "Float") == 0) {
|
||||||
PgfLiteral lflt = u->lflt(3.14);
|
PgfLiteral lflt = u->lflt(3.14);
|
||||||
expr = u->elit(lflt);
|
expr = u->elit(lflt);
|
||||||
u->free_ref(lflt);
|
u->free_ref(lflt);
|
||||||
|
break;
|
||||||
} else if (strcmp(cat->text, "String") == 0) {
|
} else if (strcmp(cat->text, "String") == 0) {
|
||||||
PgfText *value = (PgfText *) alloca(sizeof(PgfText)+4);
|
PgfText *value = (PgfText *) alloca(sizeof(PgfText)+4);
|
||||||
value->size = 3;
|
value->size = 3;
|
||||||
@@ -217,25 +224,26 @@ again: {
|
|||||||
PgfLiteral lstr = u->lstr(value);
|
PgfLiteral lstr = u->lstr(value);
|
||||||
expr = u->elit(lstr);
|
expr = u->elit(lstr);
|
||||||
u->free_ref(lstr);
|
u->free_ref(lstr);
|
||||||
|
break;
|
||||||
} else {
|
} else {
|
||||||
prob_t rand_value = rand();
|
prob_t rand_value = rand() * total_prob;
|
||||||
|
|
||||||
ref<PgfAbsFun> fun = probspace_random(pgf->abstract.funs_by_cat, cat, rand_value);
|
ref<PgfAbsFun> fun =
|
||||||
|
probspace_random(pgf->abstract.funs_by_cat, cat, rand_value, excluded);
|
||||||
|
if (fun == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (!function_has_lins(&fun->name))
|
if (!function_has_lins(&fun->name)) {
|
||||||
fun = 0;
|
excluded.insert(fun);
|
||||||
|
total_prob -= exp(-fun->prob);
|
||||||
if (fun == 0) {
|
if (total_prob < 0) // possible because of rounding
|
||||||
if (var_expr != 0) {
|
total_prob = 0;
|
||||||
prob += -log(VAR_PROB/(1-VAR_PROB));
|
|
||||||
expr = var_expr;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (depth > 0 || fun->type->hypos->len > 0) {
|
ref<Vector<PgfHypo>> hypos = fun->type->hypos;
|
||||||
|
if (depth > ((hypos->len > 0) ? 1 : 0)) {
|
||||||
prob += fun->prob;
|
prob += fun->prob;
|
||||||
expr = u->efun(&fun->name);
|
expr = u->efun(&fun->name);
|
||||||
|
|
||||||
ref<Vector<PgfHypo>> hypos = fun->type->hypos;
|
|
||||||
PgfTypeHypo *t_hypos = (PgfTypeHypo *)
|
PgfTypeHypo *t_hypos = (PgfTypeHypo *)
|
||||||
alloca(hypos->len * sizeof(PgfTypeHypo));
|
alloca(hypos->len * sizeof(PgfTypeHypo));
|
||||||
for (size_t i = 0; i < hypos->len; i++) {
|
for (size_t i = 0; i < hypos->len; i++) {
|
||||||
@@ -248,19 +256,25 @@ again: {
|
|||||||
expr = descend(expr, hypos->len, t_hypos);
|
expr = descend(expr, hypos->len, t_hypos);
|
||||||
this->m = tmp;
|
this->m = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (expr != 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
excluded.insert(fun);
|
||||||
|
total_prob -= exp(-fun->prob);
|
||||||
|
if (total_prob < 0) // possible because of rounding
|
||||||
|
total_prob = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (expr != 0) {
|
while (scope != entry_scope) {
|
||||||
while (scope != entry_scope) {
|
PgfExpr abs_expr = u->eabs(scope->bind_type, &scope->var, expr);
|
||||||
PgfExpr abs_expr = u->eabs(scope->bind_type, &scope->var, expr);
|
u->free_ref(expr);
|
||||||
u->free_ref(expr);
|
expr = abs_expr;
|
||||||
expr = abs_expr;
|
Scope *next = scope->next;
|
||||||
Scope *next = scope->next;
|
free(scope);
|
||||||
free(scope);
|
scope = next;
|
||||||
scope = next;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return expr;
|
return expr;
|
||||||
@@ -269,9 +283,10 @@ again: {
|
|||||||
PgfExpr PgfRandomGenerator::descend(PgfExpr expr,
|
PgfExpr PgfRandomGenerator::descend(PgfExpr expr,
|
||||||
size_t n_hypos, PgfTypeHypo *hypos)
|
size_t n_hypos, PgfTypeHypo *hypos)
|
||||||
{
|
{
|
||||||
depth--;
|
|
||||||
for (size_t i = 0; i < n_hypos; i++) {
|
for (size_t i = 0; i < n_hypos; i++) {
|
||||||
|
depth--;
|
||||||
PgfExpr arg = m->match_type(this, hypos[i].type);
|
PgfExpr arg = m->match_type(this, hypos[i].type);
|
||||||
|
depth++;
|
||||||
if (arg == 0) {
|
if (arg == 0) {
|
||||||
u->free_ref(expr);
|
u->free_ref(expr);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -287,7 +302,6 @@ PgfExpr PgfRandomGenerator::descend(PgfExpr expr,
|
|||||||
u->free_ref(expr);
|
u->free_ref(expr);
|
||||||
expr = app;
|
expr = app;
|
||||||
}
|
}
|
||||||
depth++;
|
|
||||||
|
|
||||||
return expr;
|
return expr;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1205,18 +1205,14 @@ PgfExpr pgf_generate_random(PgfDB *db, PgfRevision revision,
|
|||||||
|
|
||||||
ref<PgfPGF> pgf = db->revision2pgf(revision);
|
ref<PgfPGF> pgf = db->revision2pgf(revision);
|
||||||
|
|
||||||
// Generation may fail for certain random choices, but succeed
|
PgfRandomGenerator gen(pgf, depth, seed, m, u);
|
||||||
// for others. We try 10 time to increase the chance of succeess.
|
for (size_t i = 0; i < n_concr_revisions; i++) {
|
||||||
for (size_t i = 0; i < 10; i++) {
|
gen.addConcr(db->revision2concr(concr_revisions[i]));
|
||||||
PgfRandomGenerator gen(pgf, depth, seed, m, u);
|
}
|
||||||
for (size_t i = 0; i < n_concr_revisions; i++) {
|
PgfExpr expr = m->match_type(&gen, type);
|
||||||
gen.addConcr(db->revision2concr(concr_revisions[i]));
|
if (expr != 0) {
|
||||||
}
|
*prob = gen.getProb();
|
||||||
PgfExpr expr = m->match_type(&gen, type);
|
return expr;
|
||||||
if (expr != 0) {
|
|
||||||
*prob = gen.getProb();
|
|
||||||
return expr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} PGF_API_END
|
} PGF_API_END
|
||||||
|
|
||||||
@@ -1237,18 +1233,14 @@ PgfExpr pgf_generate_random_from
|
|||||||
|
|
||||||
ref<PgfPGF> pgf = db->revision2pgf(revision);
|
ref<PgfPGF> pgf = db->revision2pgf(revision);
|
||||||
|
|
||||||
// Generation may fail for certain random choices, but succeed
|
PgfRandomGenerator gen(pgf, depth, seed, m, u);
|
||||||
// for others. We try 10 time to increase the chance of succeess.
|
for (size_t i = 0; i < n_concr_revisions; i++) {
|
||||||
for (size_t i = 0; i < 10; i++) {
|
gen.addConcr(db->revision2concr(concr_revisions[i]));
|
||||||
PgfRandomGenerator gen(pgf, depth, seed, m, u);
|
}
|
||||||
for (size_t i = 0; i < n_concr_revisions; i++) {
|
PgfExpr new_expr = m->match_expr(&gen, expr);
|
||||||
gen.addConcr(db->revision2concr(concr_revisions[i]));
|
if (new_expr != 0) {
|
||||||
}
|
*prob = gen.getProb();
|
||||||
PgfExpr new_expr = m->match_expr(&gen, expr);
|
return new_expr;
|
||||||
if (new_expr != 0) {
|
|
||||||
*prob = gen.getProb();
|
|
||||||
return new_expr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} PGF_API_END
|
} PGF_API_END
|
||||||
|
|
||||||
|
|||||||
@@ -204,50 +204,51 @@ void probspace_iter(PgfProbspace space, PgfText *cat,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct PGF_INTERNAL RSState {
|
||||||
|
const std::set<ref<PgfAbsFun>> &excluded;
|
||||||
|
prob_t rand;
|
||||||
|
ref<PgfAbsFun> result;
|
||||||
|
};
|
||||||
|
|
||||||
static
|
static
|
||||||
ref<PgfAbsFun> probspace_random(PgfProbspace space,
|
bool probspace_random(PgfProbspace space, PgfText *cat,
|
||||||
PgfText *cat, prob_t *rand,
|
RSState *st)
|
||||||
bool is_last)
|
|
||||||
{
|
{
|
||||||
if (space == 0)
|
if (space == 0)
|
||||||
return 0;
|
return false;
|
||||||
|
|
||||||
int cmp = textcmp(cat,&(*space->value.cat));
|
int cmp = textcmp(cat,&(*space->value.cat));
|
||||||
if (cmp < 0) {
|
if (cmp < 0) {
|
||||||
return probspace_random(space->left, cat, rand, true);
|
return probspace_random(space->left, cat, st);
|
||||||
} else if (cmp > 0) {
|
} else if (cmp > 0) {
|
||||||
return probspace_random(space->right, cat, rand, true);
|
return probspace_random(space->right, cat, st);
|
||||||
} else {
|
} else {
|
||||||
ref<PgfAbsFun> fun;
|
if (probspace_random(space->left, cat, st))
|
||||||
|
return true;
|
||||||
fun = probspace_random(space->left, cat, rand, false);
|
|
||||||
if (fun != 0)
|
|
||||||
return fun;
|
|
||||||
|
|
||||||
bool is_res = space->value.is_result();
|
bool is_res = space->value.is_result();
|
||||||
if (is_res) {
|
if (is_res && !st->excluded.count(space->value.fun)) {
|
||||||
*rand -= exp(-space->value.fun->prob);
|
st->rand -= exp(-space->value.fun->prob);
|
||||||
if (*rand <= 0)
|
st->result = space->value.fun;
|
||||||
return space->value.fun;
|
if (st->rand <= 0)
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
fun = probspace_random(space->right, cat, rand, is_last);
|
if (probspace_random(space->right, cat, st))
|
||||||
if (fun != 0)
|
return true;
|
||||||
return fun;
|
|
||||||
if (is_last && is_res) {
|
|
||||||
// necessary due to floating point rounding
|
|
||||||
return space->value.fun;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
PGF_INTERNAL
|
PGF_INTERNAL
|
||||||
ref<PgfAbsFun> probspace_random(PgfProbspace space,
|
ref<PgfAbsFun> probspace_random(PgfProbspace space,
|
||||||
PgfText *cat, prob_t rand)
|
PgfText *cat, prob_t rand,
|
||||||
|
const std::set<ref<PgfAbsFun>> &excluded)
|
||||||
{
|
{
|
||||||
return probspace_random(space,cat,&rand,true);
|
RSState st = {excluded, rand, 0};
|
||||||
|
probspace_random(space,cat,&st);
|
||||||
|
return st.result;
|
||||||
}
|
}
|
||||||
|
|
||||||
PGF_INTERNAL
|
PGF_INTERNAL
|
||||||
|
|||||||
@@ -73,7 +73,8 @@ void probspace_iter(PgfProbspace space, PgfText *cat,
|
|||||||
* the given category */
|
* the given category */
|
||||||
PGF_INTERNAL_DECL
|
PGF_INTERNAL_DECL
|
||||||
ref<PgfAbsFun> probspace_random(PgfProbspace space,
|
ref<PgfAbsFun> probspace_random(PgfProbspace space,
|
||||||
PgfText *cat, prob_t rand);
|
PgfText *cat, prob_t rand,
|
||||||
|
const std::set<ref<PgfAbsFun>> &excluded);
|
||||||
|
|
||||||
PGF_INTERNAL_DECL
|
PGF_INTERNAL_DECL
|
||||||
void probspace_release(PgfProbspace space);
|
void probspace_release(PgfProbspace space);
|
||||||
|
|||||||
@@ -1005,14 +1005,16 @@ generateAllDepth :: PGF -> Type -> Int -> [(Expr,Float)]
|
|||||||
generateAllDepth p ty dp = generateAllExt p ty dp []
|
generateAllDepth p ty dp = generateAllExt p ty dp []
|
||||||
|
|
||||||
generateAllExt :: PGF -> Type -> Int -> [Concr] -> [(Expr,Float)]
|
generateAllExt :: PGF -> Type -> Int -> [Concr] -> [(Expr,Float)]
|
||||||
generateAllExt p ty dp cs =
|
generateAllExt p ty dp cs
|
||||||
unsafePerformIO $
|
| dp <= 0 = []
|
||||||
bracket (newStablePtr ty) freeStablePtr $ \c_ty ->
|
| otherwise =
|
||||||
withForeignPtr (a_revision p) $ \a_revision ->
|
unsafePerformIO $
|
||||||
withPgfConcrs cs $ \c_db c_revisions n_revisions ->
|
bracket (newStablePtr ty) freeStablePtr $ \c_ty ->
|
||||||
mask_ $ do
|
withForeignPtr (a_revision p) $ \a_revision ->
|
||||||
c_enum <- withPgfExn "generateAllExt" (pgf_generate_all (a_db p) a_revision c_revisions n_revisions c_ty (fromIntegral dp) marshaller unmarshaller)
|
withPgfConcrs cs $ \c_db c_revisions n_revisions ->
|
||||||
enumerateExprs (a_db p) c_enum
|
mask_ $ do
|
||||||
|
c_enum <- withPgfExn "generateAllExt" (pgf_generate_all (a_db p) a_revision c_revisions n_revisions c_ty (fromIntegral dp) marshaller unmarshaller)
|
||||||
|
enumerateExprs (a_db p) c_enum
|
||||||
|
|
||||||
generateAllFrom :: PGF -> Expr -> [(Expr,Float)]
|
generateAllFrom :: PGF -> Expr -> [(Expr,Float)]
|
||||||
generateAllFrom p ty = generateAllFromExt p ty maxBound []
|
generateAllFrom p ty = generateAllFromExt p ty maxBound []
|
||||||
@@ -1033,9 +1035,10 @@ generateRandomDepth :: RandomGen g => g -> PGF -> Type -> Int -> [(Expr,Float)]
|
|||||||
generateRandomDepth g p ty dp = generateRandomExt g p ty dp []
|
generateRandomDepth g p ty dp = generateRandomExt g p ty dp []
|
||||||
|
|
||||||
generateRandomExt :: RandomGen g => g -> PGF -> Type -> Int -> [Concr] -> [(Expr,Float)]
|
generateRandomExt :: RandomGen g => g -> PGF -> Type -> Int -> [Concr] -> [(Expr,Float)]
|
||||||
generateRandomExt g p ty dp cs =
|
generateRandomExt g p ty dp cs
|
||||||
let (seed,_) = random g
|
| dp <= 0 = []
|
||||||
in generate seed
|
| otherwise = let (seed,_) = random g
|
||||||
|
in generate seed
|
||||||
where
|
where
|
||||||
generate seed =
|
generate seed =
|
||||||
unsafePerformIO $
|
unsafePerformIO $
|
||||||
@@ -1062,9 +1065,10 @@ generateRandomFromDepth :: RandomGen g => g -> PGF -> Expr -> Int -> [(Expr,Floa
|
|||||||
generateRandomFromDepth g p e dp = generateRandomFromExt g p e dp []
|
generateRandomFromDepth g p e dp = generateRandomFromExt g p e dp []
|
||||||
|
|
||||||
generateRandomFromExt :: RandomGen g => g -> PGF -> Expr -> Int -> [Concr] -> [(Expr,Float)]
|
generateRandomFromExt :: RandomGen g => g -> PGF -> Expr -> Int -> [Concr] -> [(Expr,Float)]
|
||||||
generateRandomFromExt g p e dp cs =
|
generateRandomFromExt g p e dp cs
|
||||||
let (seed,_) = random g
|
| dp <= 0 = []
|
||||||
in generate seed
|
| otherwise = let (seed,_) = random g
|
||||||
|
in generate seed
|
||||||
where
|
where
|
||||||
generate seed =
|
generate seed =
|
||||||
unsafePerformIO $
|
unsafePerformIO $
|
||||||
|
|||||||
Reference in New Issue
Block a user