View Source Pythagorean Triples
Mix.install([
{:guesswork, "~> 0.7"},
{:kino, "~> 0.13"}
])
Queries that Calculate Values
import Guesswork.Ast
alias Guesswork.Ast.And
alias Guesswork.Ast.Assign
alias Guesswork.Ast.OneOf
alias Guesswork.Answer.Result
alias Guesswork.Query
Queries don't necisarily need facts to operate (in fact, Guesswork.query/2
will just
use an empty collection), they can use assigned values, and then calculate new values.
The below example is a really simple query that uses Guesswork.Ast.Assign
to assign
values to a
and b
, and then uses is
to calculated a third value based on the first two.
It should be noted that, in most cases, statements are created with functions.
But the is
macro is needed to build a Guesswork.Ast.Is
.
Guesswork.query(
term(And.new([Assign.new(a, 1), Assign.new(b, 2), is(d, fn a, b -> b - a end)])),
10
)
Below is a more complex example, calculating pythagorean triples.
Instead of using set
we use one_of
to assign an enumerable to a variable, so that
the variable can be one of any of the values.
Then we use is
again, but this time to test that our variables really are pythagorean
triples.
Guesswork.query(
term(
And.new([
OneOf.new(a, 1..10),
OneOf.new(b, 1..10),
OneOf.new(c, 1..10),
is(true, fn a, b -> a < b end),
is(0, fn a, b, c -> Integer.pow(c, 2) - Integer.pow(a, 2) - Integer.pow(b, 2) end)
])
),
10
)
But one_of
will support not just finite enumerables, but streams.
So below we calculate the first ten triples for all positive integers.
Its worth noting that here, instead of using just using the query
function,
we create an unresolved query, and then run it.
This allows us to reuse the query below.
query =
Query.new(
term(
And.new([
OneOf.new(a, Stream.iterate(1, &(&1 + 1))),
OneOf.new(b, Stream.iterate(1, &(&1 + 1))),
OneOf.new(c, Stream.iterate(1, &(&1 + 1))),
is(true, fn a, b -> a < b end),
is(0, fn a, b, c -> Integer.pow(c, 2) - Integer.pow(a, 2) - Integer.pow(b, 2) end)
])
)
)
Result.run(query, 10)
Now that we have the unresolved query we can calculate even more, and pull the first 100.
Note that this will take a few seconds.
The process is brute force, so as you request more results, more combinations of a
,
b
, and c
will have to be tested.
Result.run(query, 100)