-
Notifications
You must be signed in to change notification settings - Fork 32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Evaluating program against many different sets of facts #161
Comments
You can represent all facts for example in an association list, such as an AVL tree (see In this way, the evaluation is completely thread-safe: Each thread can get passed its own assocation list that it uses to look up such facts. Lookup in AVL trees is O(log(N)) in the number N of facts, and can be made a bit more efficient maybe by using hash-tables if needed. |
One additional comment about how to obtain such trees from strings: For this, it would help to provide the predicate Sample use: ?- read_from_chars("f(a,b).", T). T = f(a,b). Once you have these facts as Prolog terms, you can store them in an AVL tree as mentioned, and look them up there. |
How about creating instances for each A, B, C, ...? https://go.dev/play/p/zWzUth7nWu_L multiple instances with shared/different factspackage main
import (
"fmt"
"github.com/ichiban/prolog"
)
func main() {
names := []string{"a", "b", "c"}
facts := make([]chan string, len(names))
queries := make([]chan string, len(names))
results := make(chan string, 1)
for i, n := range names {
facts[i] = make(chan string, 1)
queries[i] = make(chan string, 1)
go func(name string, fact, query <-chan string) {
p := prolog.New(nil, nil)
if err := p.Exec(`:- set_prolog_flag(unknown, fail).`); err != nil {
panic(err)
}
for {
select {
case f := <-fact:
if err := p.Exec(f); err != nil {
panic(err)
}
case q := <-query:
sol := p.QuerySolution(q)
switch err := sol.Err(); err {
case nil:
results <- name
case prolog.ErrNoSolutions:
break
default:
panic(err)
}
}
}
}(n, facts[i], queries[i])
}
// Shared facts/rules.
for i := range names {
facts[i] <- `
rice.
wasabi.
sushi(X) :- X, rice, wasabi.
`
}
// Individual facts.
facts[0] <- `tuna.`
facts[1] <- `salmon.`
facts[2] <- `egg.`
go func() {
for _, q := range queries {
q <- `sushi(salmon).`
}
}()
fmt.Printf("%s\n", <-results)
} |
As of package main
import (
"bytes"
"errors"
"fmt"
"unicode/utf8"
"github.com/ichiban/prolog"
"github.com/ichiban/prolog/engine"
)
func main() {
p := prolog.New(nil, nil)
p.Register2(engine.NewAtom("read_from_chars"), readFromChars)
var s struct {
T prolog.TermString
}
if err := p.QuerySolution(`read_from_chars("f(a,b).", T).`).Scan(&s); err != nil {
panic(err)
}
fmt.Printf("T = %s\n", s.T)
}
func readFromChars(vm *engine.VM, chars, term engine.Term, k engine.Cont, env *engine.Env) *engine.Promise {
var b bytes.Buffer
iter := engine.ListIterator{List: chars, Env: env}
for iter.Next() {
switch r := iter.Current().(type) {
case engine.Atom:
// Atom is either a rune (r <= utf8.MaxRune) or an ID for the interned string (r > utf8.MaxRune).
if r > utf8.MaxRune {
return engine.Error(errors.New("not a character"))
}
_, _ = b.WriteRune(rune(r))
default:
return engine.Error(errors.New("not a character"))
}
}
if err := iter.Err(); err != nil {
return engine.Error(err)
}
s := engine.NewInputTextStream(&b)
return engine.ReadTerm(vm, s, term, engine.List(), k, env)
}
|
Hello,
I have a situation where I have a base program P with a set of clauses. This base program needs to be evaluated many times for different sets of facts A, B, C, ...
The evaluation of the base program P against each set of facts happens concurrently in different goroutines.
What would be a sensible way to achieve this? Ideally program P would be loaded from file just once, but then evaluated together with sets of facts A, B, C, ...
The sets of facts are defined from go code by string formatting currently.
The text was updated successfully, but these errors were encountered: