s-arash / ascent Goto Github PK
View Code? Open in Web Editor NEWlogic programming in Rust
License: MIT License
logic programming in Rust
License: MIT License
Looks like parallel Ascent has been merged to the main branch. It would be great to have this feature available in a release on crates.io!
While a bump to >= v2.x would obviously be preferable I'd like to suggest bumping it at least to the highest v1.x version available for the time being.
Deleting Cargo.lock
and running cargo minimal-versions check --workspace --all-features --ignore-private -v
(crates.io) reveals that ascent_macro
is using APIs from syn
and itertools
that are not available in their versions specified in Cargo.toml
$ cargo minimal-versions check --workspace --all-features --ignore-private -v
(base)
info: modifying from <SNIP>/ascent/Cargo.toml
info: modifying from <SNIP>/ascent_base/Cargo.toml
info: modifying from <SNIP>/ascent_macro/Cargo.toml
info: running `rustup run nightly cargo update -Z minimal-versions`
warning: virtual workspace defaulting to `resolver = "1"` despite one or more workspace members being on edition 2021 which implies `resolver = "2"`
note: to keep the current resolver, specify `workspace.resolver = "1"` in the workspace root's manifest
note: to use the edition 2021 resolver, specify `workspace.resolver = "2"` in the workspace root's manifest
note: for more details see https://doc.rust-lang.org/cargo/reference/resolver.html#resolver-versions
Updating crates.io index
info: running `~/.rustup/toolchains/stable-x86_64-apple-darwin/bin/cargo hack check --workspace --all-features`
info: running `cargo check --all-features` on ascent (1/3)
warning: virtual workspace defaulting to `resolver = "1"` despite one or more workspace members being on edition 2021 which implies `resolver = "2"`
note: to keep the current resolver, specify `workspace.resolver = "1"` in the workspace root's manifest
note: to use the edition 2021 resolver, specify `workspace.resolver = "2"` in the workspace root's manifest
note: for more details see https://doc.rust-lang.org/cargo/reference/resolver.html#resolver-versions
Blocking waiting for file lock on package cache
Blocking waiting for file lock on package cache
Blocking waiting for file lock on package cache
Compiling crossbeam-utils v0.8.7
Compiling proc-macro2 v1.0.52
Compiling memoffset v0.6.1
Checking lazy_static v1.4.0
Compiling unicode-ident v1.0.0
Compiling libc v0.2.95
Checking scopeguard v1.1.0
Compiling crossbeam-epoch v0.9.5
Compiling syn v1.0.0
Compiling unicode-xid v0.2.0
Compiling ahash v0.8.4
Compiling indexmap v1.6.2
Compiling paste v1.0.0
Checking either v1.0.0
Checking zerocopy v0.7.3
Compiling hashbrown v0.9.1
Checking smallvec v1.6.1
Checking allocator-api2 v0.2.9
Compiling fixedbitset v0.4.0
Compiling heck v0.4.0
Compiling itertools v0.10.0
Checking lock_api v0.4.10
Checking instant v0.1.0
Checking segvec v0.1.0
Checking sync-unsafe-cell v0.1.0
Compiling ascent_base v0.5.0 (<SNIP>/ascent_base)
Checking crossbeam-channel v0.5.0
Compiling petgraph v0.6.0
Checking crossbeam-deque v0.8.1
Checking num_cpus v1.2.0
Checking parking_lot_core v0.9.8
Checking rayon-core v1.11.0
Compiling quote v1.0.26
Checking rayon v1.7.0
Compiling proc-macro-error-attr v1.0.4
Checking hashbrown v0.14.0
Checking dashmap v5.5.0
Compiling proc-macro-error v1.0.4
Compiling derive-syn-parse v0.1.5
Compiling duplicate v0.4.0
error[E0599]: no method named `get_ident` found for struct `syn::Path` in the current scope
--> ~/.cargo/registry/src/index.crates.io-6f17d22bba15001f/derive-syn-parse-0.1.5/src/fields.rs:192:26
|
192 | let name = attr.path.get_ident()?.to_string();
| ^^^^^^^^^ help: there is a method with a similar name: `is_ident`
error[E0599]: no method named `get_ident` found for struct `syn::Path` in the current scope
--> ~/.cargo/registry/src/index.crates.io-6f17d22bba15001f/derive-syn-parse-0.1.5/src/variants.rs:154:26
|
154 | let name = attr.path.get_ident()?.to_string();
| ^^^^^^^^^ help: there is a method with a similar name: `is_ident`
For more information about this error, try `rustc --explain E0599`.
error: could not compile `derive-syn-parse` (lib) due to 2 previous errors
warning: build failed, waiting for other jobs to finish...
error: process didn't exit successfully: `~/.rustup/toolchains/stable-x86_64-apple-darwin/bin/cargo check --all-features --manifest-path ascent/Cargo.toml` (exit status: 101)
info: restoring <SNIP>/ascent/Cargo.toml
info: restoring <SNIP>/ascent_base/Cargo.toml
info: restoring <SNIP>/ascent_macro/Cargo.toml
error: process didn't exit successfully: `~/.rustup/toolchains/stable-x86_64-apple-darwin/bin/cargo hack check --workspace --all-features` (exit status: 1)
Bumping syn
and itertools
from …
[dependencies]
syn = { version = "1.0", features = [
"derive",
"full",
"extra-traits",
"visit-mut",
] }
itertools = "0.10"
# ...
… to …
[dependencies]
syn = { version = "1.0.109", features = [
"derive",
"full",
"extra-traits",
"visit-mut",
] }
itertools = "0.12"
# ...
fixes it.
$ cargo minimal-versions check --workspace --all-features --ignore-private -v (base)
info: modifying from <SNIP>/ascent/ascent/Cargo.toml
info: modifying from <SNIP>/ascent/ascent_base/Cargo.toml
info: modifying from <SNIP>/ascent/ascent_macro/Cargo.toml
info: running `rustup run nightly cargo update -Z minimal-versions`
warning: virtual workspace defaulting to `resolver = "1"` despite one or more workspace members being on edition 2021 which implies `resolver = "2"`
note: to keep the current resolver, specify `workspace.resolver = "1"` in the workspace root's manifest
note: to use the edition 2021 resolver, specify `workspace.resolver = "2"` in the workspace root's manifest
note: for more details see https://doc.rust-lang.org/cargo/reference/resolver.html#resolver-versions
Updating crates.io index
info: running `~/.rustup/toolchains/stable-x86_64-apple-darwin/bin/cargo hack check --workspace --all-features`
info: running `cargo check --all-features` on ascent (1/3)
warning: virtual workspace defaulting to `resolver = "1"` despite one or more workspace members being on edition 2021 which implies `resolver = "2"`
note: to keep the current resolver, specify `workspace.resolver = "1"` in the workspace root's manifest
note: to use the edition 2021 resolver, specify `workspace.resolver = "2"` in the workspace root's manifest
note: for more details see https://doc.rust-lang.org/cargo/reference/resolver.html#resolver-versions
Blocking waiting for file lock on package cache
Blocking waiting for file lock on package cache
Blocking waiting for file lock on package cache
Finished dev [unoptimized + debuginfo] target(s) in 0.68s
info: running `cargo check --all-features` on ascent_base (2/3)
warning: virtual workspace defaulting to `resolver = "1"` despite one or more workspace members being on edition 2021 which implies `resolver = "2"`
note: to keep the current resolver, specify `workspace.resolver = "1"` in the workspace root's manifest
note: to use the edition 2021 resolver, specify `workspace.resolver = "2"` in the workspace root's manifest
note: for more details see https://doc.rust-lang.org/cargo/reference/resolver.html#resolver-versions
Finished dev [unoptimized + debuginfo] target(s) in 0.02s
info: running `cargo check --all-features` on ascent_macro (3/3)
warning: virtual workspace defaulting to `resolver = "1"` despite one or more workspace members being on edition 2021 which implies `resolver = "2"`
note: to keep the current resolver, specify `workspace.resolver = "1"` in the workspace root's manifest
note: to use the edition 2021 resolver, specify `workspace.resolver = "2"` in the workspace root's manifest
note: for more details see https://doc.rust-lang.org/cargo/reference/resolver.html#resolver-versions
Finished dev [unoptimized + debuginfo] target(s) in 0.05s
info: restoring <SNIP>/ascent/ascent/Cargo.toml
info: restoring <SNIP>/ascent/ascent_base/Cargo.toml
info: restoring <SNIP>/ascent/ascent_macro/Cargo.toml
For generic programs ascent currently requires something along the following:
ascent! {
pub struct AscentProgram<T: Clone + Eq + Hash>;
relation dummy(T);
// ...
}
or
ascent! {
pub struct AscentProgram<T> where T: Clone + Eq + Hash;
relation dummy(T);
// ...
}
which then generates code that looks something like this:
pub struct AscentProgram<T>
where
T: Clone + Eq + Hash,
{
pub dummy: Vec<(T,), Global>,
// ...
}
impl<T> AscentProgram<T>
where
T: Clone + Eq + Hash,
{
pub fn run(&mut self){
// ...
}
// ...
}
// ...
This unfortunately tends to lead to problems with rather nasty effects one one's code and is thus generally considered an anti-pattern.
As such the official Rust API guidelines has a chapter on the topic (it talks specifically about derived trait bounds, but the viral breaking change effect is not limited to derived traits):
Data structures do not duplicate derived trait bounds
Generic data structures should not use trait bounds that can be derived or do not otherwise add semantic value. […]
// Prefer this: #[derive(Clone, Debug, PartialEq)] struct Good<T> { /* ... */ } // Over this: #[derive(Clone, Debug, PartialEq)] struct Bad<T: Clone + Debug + PartialEq> { /* ... */ }Generally speaking, adding a trait bound to a data structure is a breaking change because every consumer of that structure will need to start satisfying the additional bound. […]
There is a grey area around other non-derivable trait bounds that are not strictly required by the structure definition, like Read or Write. They may communicate the intended behavior of the type better in its definition but also limits future extensibility. Including semantically useful trait bounds on data structures is still less problematic than including derivable traits as bounds. […]
In short the problem is that trait bounds attached to a type's declaration spread virally (i.e. they require your surrounding code to now also be bounded by these traits), while those only attached to a type's implementation generally don't.
As such the generated code should preferably look like this instead:
pub struct AscentProgram<T>
// notice the lack of a where clause here!
{
pub dummy: Vec<(T,), Global>,
// ...
}
impl<T> AscentProgram<T>
where
T: Clone + Eq + Hash,
{
pub fn run(&mut self){
// ...
}
// ...
}
// ...
This change should have no affect on ascent itself, but make integrating it much more pleasant and less intrusive.
The project's current code formatting suffers from a couple of issues, affect:
tl;dr: For the sake of making contributions hassle-free it would arguably be preferable to revert to Rust's default format (as applied by rustfmt
without a custom rustfmt.toml
file) and used by >90% of Rust projects.
It uses a non-standard format
The Rust project recommends using the default formatting configuration to ease collaboration.
It provides a custom rustfmt.toml
file but doesn't actually use it
While the project provides a rustfmt.toml
file
./rustfmt.toml
# https://github.com/rust-lang/rustfmt/blob/master/Configurations.md
tab_spaces = 3
fn_call_width = 120
chain_width = 120
max_width = 120
fn_single_line = true
Running cargo fmt
results in 30+ reformatted files, which should not happen if the code had previously been formatted with it.
As such it is currently impossible to have rustfmt
/cargo fmt
apply the same formatting as used by the project. And anybody opening a PR on the project gets a nasty surprise when they notice that their IDE auto-formatted the code (as is usually desirable) and now the semantic changes are lost in thousands of formatting changes (as it just happened to me, again).
The rustfmt.toml
file requires nightly
and is also invalid
Further more running cargo fmt
results in a bunch of warnings:
$ cargo fmt
Warning: can't set `fn_single_line = true`, unstable features are only available in nightly channel.
Warning: can't set `fn_single_line = true`, unstable features are only available in nightly channel.
`fn_call_width` cannot have a value that exceeds `max_width`. `fn_call_width` will be set to the same value as `max_width`
`chain_width` cannot have a value that exceeds `max_width`. `chain_width` will be set to the same value as `max_width`
Warning: can't set `fn_single_line = true`, unstable features are only available in nightly channel.
`fn_call_width` cannot have a value that exceeds `max_width`. `fn_call_width` will be set to the same value as `max_width`
`chain_width` cannot have a value that exceeds `max_width`. `chain_width` will be set to the same value as `max_width`
`fn_call_width` cannot have a value that exceeds `max_width`. `fn_call_width` will be set to the same value as `max_width`
`chain_width` cannot have a value that exceeds `max_width`. `chain_width` will be set to the same value as `max_width`
`fn_call_width` cannot have a value that exceeds `max_width`. `fn_call_width` will be set to the same value as `max_width`
`chain_width` cannot have a value that exceeds `max_width`. `chain_width` will be set to the same value as `max_width`
`fn_call_width` cannot have a value that exceeds `max_width`. `fn_call_width` will be set to the same value as `max_width`
`chain_width` cannot have a value that exceeds `max_width`. `chain_width` will be set to the same value as `max_width`
The project mixes CRLF and LF
In the following program, the relation stop2
is a copy of stop
.
And then obstruct
is derived from stop
the same way as obstruct2
is from stop2
.
Therefore one would expect that the two relations have the same output, but instead the following happens:
1: [(1, 0, 2)]
2: []
But stop(1,2)
is not part of the final result, (even though it is implied by roll(1,6), block(2)
, because it undergoes lattice merge with stop(1,4)
implied by roll(1,6), block(4)
.
Yet it appears stop(1,2)
is still used in deriving obstruct, even though its value isn't final yet.
use ascent::ascent_run;
fn main() {
let prog = ascent_run! {
relation block(i64) = vec![(2,),(4,)];
relation roll(usize,i64) = vec![(0,3),(1,6)];
lattice stop(usize,i64);
stop(id,x) <--roll(id,x_start), block(x), if x < x_start;
relation stop2(usize,i64);
stop2(id,x) <-- stop(id,x);
relation obstruct(usize,usize,i64);
obstruct(id,id1,x2) <-- stop(id,x2), stop(id1,x2), if id1 < id;
relation obstruct2(usize,usize,i64);
obstruct2(id,id1,x2) <-- stop2(id,x2), stop2(id1,x2), if id1 < id;
};
println!(
"1: {:?}\n2: {:?}",
prog.obstruct,
prog.obstruct2,
);
}
Hi guys,
Consider the following program:
use ascent::ascent;
ascent!{
relation a__(i32, i32);
relation c__(i32, i32, i32);
relation e__(i32);
relation h__(i32, i32, i32);
e__(a) <-- a__(b, a);
h__(e, e, e) <-- a__(d, e), c__(e, f, e), e__(e);
}
fn main() {
let mut prog = AscentProgram::default();
prog.a__ = vec![(88,5), (37,24), (11,91)];
prog.c__ = vec![(32,83,88), (2,8,5)];
prog.e__ = vec![(44,), (83,)];
prog.h__ = vec![(38,88,18), (76,18,65), (86,73,91), (98,26,91), (76,10,14)];
prog.run();
println!("{:?}", prog.h__);
}
If I run the program, I get the following for the relation h__
:
[(38, 88, 18), (76, 18, 65), (86, 73, 91), (98, 26, 91), (76, 10, 14), (5, 5, 5)]
Now, if I add a subgoal c__(e, a, e)
in the rule for h__
to get the following new program:
use ascent::ascent;
ascent!{
relation a__(i32, i32);
relation c__(i32, i32, i32);
relation e__(i32);
relation h__(i32, i32, i32);
e__(a) <-- a__(b, a);
h__(e, e, e) <-- a__(d, e), c__(e, f, e), e__(e), c__(e, a, e);
}
fn main() {
let mut prog = AscentProgram::default();
prog.a__ = vec![(88,5), (37,24), (11,91)];
prog.c__ = vec![(32,83,88), (2,8,5)];
prog.e__ = vec![(44,), (83,)];
prog.h__ = vec![(38,88,18), (76,18,65), (86,73,91), (98,26,91), (76,10,14)];
prog.run();
println!("{:?}", prog.h__);
}
The result for h__
changes and I get:
[(38, 88, 18), (76, 18, 65), (86, 73, 91), (98, 26, 91), (76, 10, 14)]
Adding the subgoal c__(e, a, e)
should not change the result for relation h__
.
The tuple (5, 5, 5)
disappears for the second program which should not have appeared for the first program in the first place.
My Cargo.toml
file:
[package]
name = "ascent_project"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
ascent = "0.2"
Please let me know if you cannot reproduce this or if I am doing anything wrong.
ascent_base::util::update
is unsound, because the value will be left in an inconsistent state if the update function panics.
The crate replace_with
provides a safe way to implement this idiom.
This is a wonderful project and deserves to be an industry standard. Please provide an explicit license.
The README.MD file hints at macros being useful for scaffolding head/body items …
It may be useful to define macros that expand to either body items or head items. Ascent allows you to do this.
… which the MACROS.MD then provides further examples for and gives the following motivation …
Macros can be defined inside Ascent programs to avoid having to repeat code.
As somebody accustomed to Rust's native macro the above would make one assume that —just like in Rust itself— ascent's macros could be used in effectively every position in the code. In reality however it seems that ascent's macros are limited to clause position.
As such this works:
ascent! {
// Facts:
relation unique(isize);
// Macros:
macro shared($x: expr) {
shared(Rc::new($x))
}
// Rules:
relation shared(Rc<isize>);
shared!(*x) <-- unique(x);
}
This however doesn't:
ascent! {
// Facts:
relation unique(isize);
// Macros:
macro rc($x: expr) {
Rc::new($x)
}
// Rules:
relation shared(Rc<isize>);
shared(rc!(*x)) <-- unique(x);
// ^^
// error: cannot find macro `rc` in this scope
}
This is rather surprising and unexpected.
As such I would expect the above to either be accepted or at least provide a more useful error message than the current "cannot find macro …
in this scope".
I've browsed a bit through the available docs, but couldn't find whether this is possible.
So this is a question / maybe feature request.
Is there some way of composing multiple sets of predicates? Ideally you'd be able to multiple blocks of interdependent ascent code spread over multiple files.
Hi @s-arash,
I think something broke upon your latest commit.
Now the instructions in Using Ascent does not work anymore.
I get:
$ cargo run
Updating crates.io index
Compiling ascent_base v0.2.1
Compiling hashbrown v0.12.1
error: type parameters must be declared prior to const parameters
--> /home/taylorswift/.cargo/registry/src/github.com-1ecc6299db9ec823/ascent_base-0.2.1/src/lattice/product.rs:102:23
|
102 | impl <const N: usize, T: PartialOrd> PartialOrd for Product<[T; N]> {
| -----------------^------------- help: reorder the parameters: lifetimes, then types, then consts: `<T: PartialOrd, const N: usize>`
error: type parameters must be declared prior to const parameters
--> /home/taylorswift/.cargo/registry/src/github.com-1ecc6299db9ec823/ascent_base-0.2.1/src/lattice/product.rs:134:23
|
134 | impl <const N: usize, T: Lattice> Lattice for Product<[T; N]> {
| -----------------^---------- help: reorder the parameters: lifetimes, then types, then consts: `<T: Lattice, const N: usize>`
error: type parameters must be declared prior to const parameters
--> /home/taylorswift/.cargo/registry/src/github.com-1ecc6299db9ec823/ascent_base-0.2.1/src/lattice/product.rs:150:23
|
150 | impl <const N: usize, T: BoundedLattice> BoundedLattice for Product<[T; N]> {
| -----------------^----------------- help: reorder the parameters: lifetimes, then types, then consts: `<T: BoundedLattice, const N: usize>`
error: type parameters must be declared prior to const parameters
--> /home/taylorswift/.cargo/registry/src/github.com-1ecc6299db9ec823/ascent_base-0.2.1/src/lattice/bounded_set.rs:11:43
|
11 | pub struct BoundedSet<const BOUND: usize, T: PartialEq + Eq + Hash + Ord>(Option<Set<T>>);
| ---------------------^------------------------------ help: reorder the parameters: lifetimes, then types, then consts: `<T: PartialEq + Eq + Hash + Ord, const BOUND: usize>`
error: type parameters must be declared prior to const parameters
--> /home/taylorswift/.cargo/registry/src/github.com-1ecc6299db9ec823/ascent_base-0.2.1/src/lattice/bounded_set.rs:10:10
|
10 | #[derive(Clone, PartialEq, Eq, Hash)]
| ^^^^^ help: reorder the parameters: lifetimes, then types, then consts: `<T: ::core::clone::Clone + PartialEq + Eq + Hash + Ord, const BOUND: usize>`
error: type parameters must be declared prior to const parameters
--> /home/taylorswift/.cargo/registry/src/github.com-1ecc6299db9ec823/ascent_base-0.2.1/src/lattice/bounded_set.rs:10:17
|
10 | #[derive(Clone, PartialEq, Eq, Hash)]
| ^^^^^^^^^ help: reorder the parameters: lifetimes, then types, then consts: `<T: ::core::cmp::PartialEq + PartialEq + Eq + Hash + Ord, const BOUND: usize>`
error: type parameters must be declared prior to const parameters
--> /home/taylorswift/.cargo/registry/src/github.com-1ecc6299db9ec823/ascent_base-0.2.1/src/lattice/bounded_set.rs:10:28
|
10 | #[derive(Clone, PartialEq, Eq, Hash)]
| ^^ help: reorder the parameters: lifetimes, then types, then consts: `<T: ::core::cmp::Eq + PartialEq + Eq + Hash + Ord, const BOUND: usize>`
error: type parameters must be declared prior to const parameters
--> /home/taylorswift/.cargo/registry/src/github.com-1ecc6299db9ec823/ascent_base-0.2.1/src/lattice/bounded_set.rs:10:32
|
10 | #[derive(Clone, PartialEq, Eq, Hash)]
| ^^^^ help: reorder the parameters: lifetimes, then types, then consts: `<T: ::core::hash::Hash + PartialEq + Eq + Hash + Ord, const BOUND: usize>`
error: type parameters must be declared prior to const parameters
--> /home/taylorswift/.cargo/registry/src/github.com-1ecc6299db9ec823/ascent_base-0.2.1/src/lattice/bounded_set.rs:14:26
|
14 | impl<const BOUND: usize, T: PartialEq + Eq + Hash + Ord> Default for BoundedSet<BOUND, T> {
| ---------------------^------------------------------ help: reorder the parameters: lifetimes, then types, then consts: `<T: PartialEq + Eq + Hash + Ord, const BOUND: usize>`
error: type parameters must be declared prior to const parameters
--> /home/taylorswift/.cargo/registry/src/github.com-1ecc6299db9ec823/ascent_base-0.2.1/src/lattice/bounded_set.rs:18:26
|
18 | impl<const BOUND: usize, T: PartialEq + Eq + Hash + Ord> BoundedSet<BOUND, T> {
| ---------------------^------------------------------ help: reorder the parameters: lifetimes, then types, then consts: `<T: PartialEq + Eq + Hash + Ord, const BOUND: usize>`
error: type parameters must be declared prior to const parameters
--> /home/taylorswift/.cargo/registry/src/github.com-1ecc6299db9ec823/ascent_base-0.2.1/src/lattice/bounded_set.rs:60:26
|
60 | impl<const BOUND: usize, T: PartialEq + Eq + Hash + Ord> PartialOrd for BoundedSet<BOUND, T> {
| ---------------------^------------------------------ help: reorder the parameters: lifetimes, then types, then consts: `<T: PartialEq + Eq + Hash + Ord, const BOUND: usize>`
error: type parameters must be declared prior to const parameters
--> /home/taylorswift/.cargo/registry/src/github.com-1ecc6299db9ec823/ascent_base-0.2.1/src/lattice/bounded_set.rs:74:26
|
74 | impl<const BOUND: usize, T: PartialEq + Eq + Hash + Ord> Lattice for BoundedSet<BOUND, T> {
| ---------------------^------------------------------ help: reorder the parameters: lifetimes, then types, then consts: `<T: PartialEq + Eq + Hash + Ord, const BOUND: usize>`
error: type parameters must be declared prior to const parameters
--> /home/taylorswift/.cargo/registry/src/github.com-1ecc6299db9ec823/ascent_base-0.2.1/src/lattice/bounded_set.rs:103:26
|
103 | impl<const BOUND: usize, T: PartialEq + Eq + Hash + Ord> BoundedLattice for BoundedSet<BOUND, T> {
| ---------------------^------------------------------ help: reorder the parameters: lifetimes, then types, then consts: `<T: PartialEq + Eq + Hash + Ord, const BOUND: usize>`
error: could not compile `ascent_base` due to 13 previous errors
warning: build failed, waiting for other jobs to finish...
error: build failed
When i change ascent = "0.2"
in Cargo.toml
to a previous commit, e.g.
ascent = {git = "https://github.com/s-arash/ascent", rev="da6078289bbf87bcc843d5cd3f079a08a232051c"}
Then everything works fine.
Are you already aware of this problem or am I doing something wrong?
Hi Arash--my apologies for writing you here, I did not know where else to look. We are trying to find your current email address (VLDB Slog resubmission). If you can please email me ([email protected]) so we can make an account for you, I would appreciate it.
When using non-pub
types in ascent macros the generated code emits a "private type …
in public interface (error E0446)" warning that will turn into an error in future versions of Rust.
To reproduce compile this code:
fn main() {
#[derive(Hash, Eq, PartialEq, Clone)]
struct PrivateType;
#[allow(clippy::all)]
let _ = ascent::ascent_run! {
// struct Program;
relation dummy(PrivateType);
};
}
warning: private type `PrivateType` in public interface (error E0446)
--> src/main.rs:6:13
|
6 | let _ = ascent::ascent_run! {
| _____________^
7 | | // struct Program;
8 | |
9 | | relation dummy(PrivateType);
10 | | };
| |_____^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #34537 <https://github.com/rust-lang/rust/issues/34537>
= note: `#[warn(private_in_public)]` on by default
= note: this warning originates in the macro `ascent::ascent_run` (in Nightly builds, run with -Z macro-backtrace for more info)
Un-commenting the // struct Program;
silences the warning.
I'm not sure if there's a good solution for this (which doesn't get in the way of scenarios for public types), but it might be a good idea to add a note in the docs for this, since the fix might not be obvious immediately?
The very minimal use of std::time
in Ascent unfortunately panics on WASM.
Possible fixes include either a feature flag to gate use of std::time
(this is only slightly complicated by run_timeout
), or using an alternative library which provides a WASM-safe implementation such as https://github.com/sebcrozet/instant.
Just a thought. If you would prefer a PR for one or the other of these options, let me know. Thanks!
Hi! Thank you for writing this library. It is awesome.
I've run into something weird which is probably not even an issue with ascent– crates.io
shows mimalloc
as a dependency of ascent, even though it doesn't appear in any of the Cargo.toml
files in the workspace: https://crates.io/crates/ascent/0.2.0/dependencies
Any ideas?
If I understand correctly, ascent is't a 'differential datalog'-style implementation, but is optimized for batch processing.
The API does however allow .run() to be called multiple times, so users will eventually do it.
I did a little experiment:
use std::time::Instant;
use ascent::ascent;
fn main() {
ascent!{
#![measure_rule_times]
relation x(u64,u64);
relation y(u64,u64);
y(i,n) <-- x(i,n), x(i,n+100);
x(i,n+200) <-- y(i,n), if *n < 400000;
}
let mut prog = AscentProgram::default();
fn time(prog: &mut AscentProgram, title: &str) {
let start = Instant::now();
prog.run();
println!("{:?} {:?}", prog.x.len(), prog.y.len());
println!("{}", prog.scc_times_summary());
println!("{}: {:?}",title, start.elapsed());
}
prog.x = vec![(0, 1,), (0, 101,)];
time(&mut prog, "Initial run");
prog.x.push((1,1,));
time(&mut prog,"Add of non-consequential fact");
prog.x.push((1,101,));
time(&mut prog,"Add of consequential fact");
let mut prog = AscentProgram::default();
prog.x = vec![(0, 1,), (0, 101,), (1,1,), (1,101)];
time(&mut prog,"Full rerun");
}
The output is:
4002 4001
scc 0 time: 1.436391002s
some of rule times: 1.42136186s
rule x <-- y_indices_none_delta, if ⋯
time: 4.024887ms
rule y <-- x_indices_none_delta, x_indices_0_1_total+delta
time: 2.227919ms
rule y <-- x_indices_none_total, x_indices_0_1_delta
time: 1.415109054s
-----------------------------------------
Initial run: 1.436422348s
4003 4001
scc 0 time: 1.443135223s
some of rule times: 1.42810157s
rule x <-- y_indices_none_delta, if ⋯
time: 5.573965ms
rule y <-- x_indices_none_delta, x_indices_0_1_total+delta
time: 7.418424ms
rule y <-- x_indices_none_total, x_indices_0_1_delta
time: 1.415109181s
-----------------------------------------
Add of non-consequential fact: 9.375828ms
8004 8002
scc 0 time: 11.459918911s
some of rule times: 11.423892339s
rule x <-- y_indices_none_delta, if ⋯
time: 12.857089ms
rule y <-- x_indices_none_delta, x_indices_0_1_total+delta
time: 17.993869ms
rule y <-- x_indices_none_total, x_indices_0_1_delta
time: 11.393041381s
-----------------------------------------
Add of consequential fact: 10.019436059s
8004 8002
scc 0 time: 3.073175727s
some of rule times: 3.047507618s
rule x <-- y_indices_none_delta, if ⋯
time: 7.811237ms
rule y <-- x_indices_none_delta, x_indices_0_1_total+delta
time: 4.606486ms
rule y <-- x_indices_none_total, x_indices_0_1_delta
time: 3.035089895s
-----------------------------------------
Full rerun: 3.073211278s
It seems to me that:
While (as I expected), removing facts from relations isn't supported.
ascent!{
struct A;
relation x(u64);
relation y(u64);
y(n) <-- x(n);
}
let mut prog = A::default();
prog.x = vec![(1,), (2,)];
prog.run();
println!("{:?}", prog.y);
prog.x = vec![(1,)];
prog.run();
println!("{:?}", prog.y)
produces
[(1,), (2,)]
[(1,), (2,)]
My question is, would it be possible to either:
Crepe is another Rust-macro-embedded Datalog-like eDSL. It would be nice to point to it from the README as an alternative, or even better, to provide a short comparison between the two projects.
syn
has undergone a major version bump. Since it's a slow package to compile, it'd be nice to have just one version of it in my dependency tree.
Is there any way I can make the ascent embedded program dynamically generated?
Would there be an internal function that might help, even if not part of the user-facing API?
Thanks!
Hello!
Could you point me where in this repository's code do you compute the optimal solution to the input program's MISP, as described in Subotič et al's "Automatic Index Selection for Large-Scale Datalog Computation"?
From what I understood, HIR transforms each program's rule to a relational form, and then MIR...maps it to primitive searches?
The following fails in 0.5.0:
assert_eq!(ascent_run! {
lattice a(i64) = vec![(0,),(1,)];
}.a, vec![(1,)]);
Presumably because the lattice joins are not executed on the incoming vector, as it is seen as 'input'
I think it would make sense to generate an intermediate input relation, so the lattice's rules are upheld.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.