1
0
forked from GitHub/gf-core

random generation always produces something if possible

This commit is contained in:
Krasimir Angelov
2023-03-16 17:22:42 +01:00
parent de5f027bde
commit 6c3a4f5dcd
6 changed files with 123 additions and 110 deletions

View File

@@ -8,6 +8,7 @@
#include <functional> #include <functional>
#include <queue> #include <queue>
#include <map> #include <map>
#include <set>
#include "pgf.h" #include "pgf.h"

View File

@@ -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;
} }

View File

@@ -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

View File

@@ -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

View File

@@ -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);

View File

@@ -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 $