diff --git a/res/.keep b/res/.keep new file mode 100644 index 0000000..e69de29 diff --git a/res/icons/scallop-logo-transp-128.png b/res/icons/scallop-logo-transp-128.png new file mode 100644 index 0000000..456127e Binary files /dev/null and b/res/icons/scallop-logo-transp-128.png differ diff --git a/res/icons/scallop-logo-ws-512.png b/res/icons/scallop-logo-ws-512.png new file mode 100644 index 0000000..1406f9c Binary files /dev/null and b/res/icons/scallop-logo-ws-512.png differ diff --git a/res/notes/design/grammar.md b/res/notes/design/grammar.md new file mode 100644 index 0000000..2475488 --- /dev/null +++ b/res/notes/design/grammar.md @@ -0,0 +1,85 @@ +# Grammar + +``` +SCALLOP_PROGRAM ::= ITEM* + +ITEM ::= TYPE_DECL + | RELATION_DECL + | CONST_DECL + | QUERY_DECL + +TYPE ::= u8 | u16 | u32 | u64 | u128 | usize + | i8 | i16 | i32 | i64 | i128 | isize + | f32 | f64 | char | bool + | String + | CUSTOM_TYPE_NAME + +TYPE_DECL ::= type CUSTOM_TYPE_NAME = TYPE + | type CUSTOM_TYPE_NAME <: TYPE + | type ENUM_TYPE_NAME = VARIANT1 [= VAL1] | VARIANT2 [= VAL2] | ... + | type RELATION_NAME(TYPE*) + | type RELATION_NAME(VAR1: TYPE1, VAR2: TYPE2, ...) + +CONST_DECL ::= const CONSTANT_NAME : TYPE = CONSTANT + | const CONSTANT_NAME1 [: TYPE1] = CONSTANT1, CONSTANT_NAME2 [: TYPE2] = CONSTANT2, ... + +RELATION_DECL ::= FACT_DECL + | FACTS_SET_DECL + | RULE_DECL + +CONSTANT ::= true | false | NUMBER_LITERAL | STRING_LITERAL + +CONST_TUPLE ::= CONSTANT | (CONSTANT1, CONSTANT2, ...) + +FOREIGN_FN ::= hash | string_length | string_concat | substring | abs + +BIN_OP ::= + | - | * | / | % | == | != | <= | < | >= | > | && | || | ^ + +UNARY_OP ::= ! | - + +CONST_EXPR ::= CONSTANT + | CONST_EXPR BIN_OP CONST_EXPR | UNARY_OP CONST_EXPR + | $ FOREIGN_FN(CONST_EXPR*) + | if CONST_EXPR then CONST_EXPR else CONST_EXPR + | ( CONST_EXPR ) + +TAG ::= true | false | NUMBER_LITERAL // true/false is for boolean tags; NUMBER_LITERAL is used for probabilities + +FACT_DECL ::= rel RELATION_NAME(CONST_EXPR*) // Untagged fact + | rel TAG :: RELATION_NAME(CONST_EXPR*) // Tagged fact + +FACTS_SET_DECL ::= rel RELATION_NAME = {CONST_TUPLE1, CONST_TUPLE2, ...} // Untagged tuples + | rel RELATION_NAME = {TAG1 :: CONST_TUPLE1, TAG2 :: CONST_TUPLE2, ...} // Tagged tuples + | rel RELATION_NAME = {TAG1 :: CONST_TUPLE1; TAG2 :: CONST_TUPLE2; ...} // Tagged tuples forming annotated disjunction + +EXPR ::= VARIABLE | CONSTANT + | EXPR BIN_OP EXPR | UNARY_OP EXPR + | $ FOREIGN_FN(EXPR*) + | if EXPR then EXPR else EXPR + | ( EXPR ) + +ATOM ::= RELATION_NAME(EXPR*) + +RULE_DECL ::= rel ATOM :- FORMULA | rel ATOM = FORMULA // Normal rule + | rel TAG :: ATOM :- FORMULA | rel TAG :: ATOM = FORMULA // Tagged rule + +FORMULA ::= ATOM + | not ATOM | ~ ATOM // negation + | FORMULA1, FORMULA2, ... | FORMULA and FORMULA | FORMULA /\ FORMULA // conjunction + | FORMULA or FORMULA | FORMULA \/ FORMULA // disjunction + | FORMULA implies FORMULA | FORMULA => FORMULA // implies + | CONSTRAINT | AGGREGATION + | ( FORMULA ) + +CONSTRAINT ::= EXPR // When expression returns a boolean value + +AGGREGATOR ::= count | sum | prod | min | max | exists | forall | unique + +AGGREGATION ::= VAR* = AGGREGATOR(VAR* : FORMULA) // Normal aggregation + | VAR* = AGGREGATOR(VAR* : FORMULA where VAR* : FORMULA) // Aggregation with group-by condition + | VAR* = AGGREGATOR[VAR*](VAR* : FORMULA) // Aggregation with arg (only applied to AGGREGATOR = min or max) + | VAR* = AGGREGATOR[VAR*](VAR* : FORMULA where VAR* : FORMULA) // Aggregation with arg and group-by condition (only applied to AGGREGATOR = min or max) + +QUERY_DECL ::= query RELATION_NAME + | query ATOM +``` diff --git a/res/notes/design/group_by.md b/res/notes/design/group_by.md new file mode 100644 index 0000000..f0d6678 --- /dev/null +++ b/res/notes/design/group_by.md @@ -0,0 +1,53 @@ +# Design of Group By + +## Examples + +### Example 1 + +The following count does not have a group by variable + +``` scl +rel num_cars(n) :- n = count(o: is_a(o, "car")) +``` + +### Example 2 + +The following count does have a group by variable `c`. +The body of the rule `is_a(o, "car"), color(o, c)` bounds two variables: `o` and `c`. +We want the variables that occur in the head that is not "to-aggregate" or "argument" values. + +``` scl +rel num_cars_of_color(c, n) :- n = count(o: is_a(o, "car"), color(o, c)) +``` + +### Example 3 + +The following count does have a group by variable `c`, note that `s` is not a group-by variable: + +``` scl +rel num_cars_of_color(c, n) :- n = count(o: is_a(o, "car"), color(o, c), shape(o, s)) +``` + +Although we have `shape(o, s)`, but we are not storing `s` in the head. +Therefore we do not treat `s` as a group-by variable. + +### Example 4 + +``` scl +rel num_cars_of_color(c, n) :- n = count(o: is_a(o, "car"), color(o, c) where c: all_colors(c)) +``` + +body_bounded_vars: o, c +group_by_bounded_vars: c +group_by_vars: c + +### Example 5 + +``` scl +rel eval_yn(e, b) :- b = exists(o: eval_obj(f, o) where e: exists_expr(e, f)) +``` + +body_bounded_vars: f, o +group_by_bounded_vars: e, f +group_by_vars: e +to_agg_vars: o