diff --git a/src/gboml/ast/__init__.py b/src/gboml/ast/__init__.py index 391efbe5008caf59b7dc24f69331167a83379460..be4da11911fda64d808d7a09d793473f7633fa02 100644 --- a/src/gboml/ast/__init__.py +++ b/src/gboml/ast/__init__.py @@ -7,7 +7,8 @@ __all__ = [ "HyperEdge", "NodeDefinition", "NodeImport", "HyperEdgeDefinition", "HyperEdgeImport", "ExpressionOp", "GBOMLGraph", "ImplicitLoop", "RValue", "RValueWithGen", "GeneratedRValue", "Range", "MultiLoop", "DictEntry", "Dictionary", "NodeGenerator", "HyperEdgeGenerator", - "DefinitionType", "FunctionDefinition", "ConstantDefinition", "ExpressionDefinition" + "DefinitionType", "FunctionDefinition", "ConstantDefinition", "ExpressionDefinition", + "CtrActivation", "ObjActivation", "ActivationType", "Activation" ] from gboml.ast.arrays import * @@ -25,3 +26,4 @@ from gboml.ast.objectives import * from gboml.ast.path import * from gboml.ast.rvalue import * from gboml.ast.variables import * +from gboml.ast.activation import * \ No newline at end of file diff --git a/src/gboml/ast/activation.py b/src/gboml/ast/activation.py new file mode 100644 index 0000000000000000000000000000000000000000..690b1fd07a1d6f6def84a2daadfc5b8115fa082e --- /dev/null +++ b/src/gboml/ast/activation.py @@ -0,0 +1,18 @@ +from dataclasses import dataclass +from enum import Enum +from typing import Optional + +from gboml.ast.base import GBOMLObject +from gboml.ast.expressions import BoolExpression + + +class ActivationType(Enum): + activate = "activate" + deactivate = "deactivate" + + +@dataclass +class Activation(GBOMLObject): + type: ActivationType + what: list[str] + condition: Optional[BoolExpression] \ No newline at end of file diff --git a/src/gboml/ast/constraints.py b/src/gboml/ast/constraints.py index 17cc19c3dcb86f79e019099f6a412ca7fdf796ae..42038b5e90c4a36d28a0acd32294766762745a02 100644 --- a/src/gboml/ast/constraints.py +++ b/src/gboml/ast/constraints.py @@ -2,6 +2,7 @@ from dataclasses import dataclass, field from enum import Enum from typing import Optional +from gboml.ast.activation import Activation from gboml.ast.arrays import Array from gboml.ast.base import GBOMLObject from gboml.ast.expression_operators import Operator @@ -34,3 +35,8 @@ class SOSConstraint(Constraint): content: Array loop: Optional[Loop] = None tags: list[str] = field(default_factory=list) + + +@dataclass +class CtrActivation(Activation): + pass diff --git a/src/gboml/ast/hyperedges.py b/src/gboml/ast/hyperedges.py index ddd209717cd161e25007ee77f7956a84e4993978..f6fdeb73e2f0a0d930890590925e8ee552edc3f2 100644 --- a/src/gboml/ast/hyperedges.py +++ b/src/gboml/ast/hyperedges.py @@ -2,7 +2,7 @@ from dataclasses import dataclass, field from gboml.ast import Loop from gboml.ast.base import GBOMLObject -from gboml.ast.constraints import Constraint +from gboml.ast.constraints import Constraint, CtrActivation from gboml.ast.path import VarOrParam from gboml.ast.variables import Definition @@ -17,6 +17,7 @@ class HyperEdgeDefinition(HyperEdge): name: str parameters: list[Definition] = field(default_factory=list) constraints: list[Constraint] = field(default_factory=list) + activations: list[CtrActivation] = field(default_factory=list) tags: list[str] = field(default_factory=list) @@ -26,6 +27,7 @@ class HyperEdgeGenerator(HyperEdge): loop: Loop parameters: list[Definition] = field(default_factory=list) constraints: list[Constraint] = field(default_factory=list) + activations: list[CtrActivation] = field(default_factory=list) tags: list[str] = field(default_factory=list) diff --git a/src/gboml/ast/nodes.py b/src/gboml/ast/nodes.py index 2b452b35e05bfcd596b562cd5a1cfa4cfb3427f8..25dbef1db3652c7532e3317a8af6a66db77e8696 100644 --- a/src/gboml/ast/nodes.py +++ b/src/gboml/ast/nodes.py @@ -1,6 +1,6 @@ from dataclasses import dataclass, field -from gboml.ast import Loop +from gboml.ast import Loop, Activation from gboml.ast.base import GBOMLObject from gboml.ast.constraints import Constraint from gboml.ast.path import VarOrParam @@ -23,6 +23,7 @@ class NodeDefinition(Node): variables: list[VariableDefinition] = field(default_factory=list) constraints: list[Constraint] = field(default_factory=list) objectives: list[Objective] = field(default_factory=list) + activations: list[Activation] = field(default_factory=list) tags: list[str] = field(default_factory=list) @@ -36,6 +37,7 @@ class NodeGenerator(Node): variables: list[VariableDefinition] = field(default_factory=list) constraints: list[Constraint] = field(default_factory=list) objectives: list[Objective] = field(default_factory=list) + activations: list[Activation] = field(default_factory=list) tags: list[str] = field(default_factory=list) diff --git a/src/gboml/ast/objectives.py b/src/gboml/ast/objectives.py index c78f5ee12b61262b3a07c66debb4b062a74fd2da..458decd69b57f60ced67a9b0dc3e29e6eadcb957 100644 --- a/src/gboml/ast/objectives.py +++ b/src/gboml/ast/objectives.py @@ -2,6 +2,7 @@ from dataclasses import dataclass, field from enum import Enum from typing import Optional +from gboml.ast.activation import Activation from gboml.ast.base import GBOMLObject from gboml.ast.expressions import Expression from gboml.ast.loops import Loop @@ -19,3 +20,7 @@ class Objective(GBOMLObject): expression: Expression loop: Optional[Loop] = None tags: list[str] = field(default_factory=list) + +@dataclass +class ObjActivation(Activation): + pass \ No newline at end of file diff --git a/src/gboml/gboml.lark b/src/gboml/gboml.lark index d37f0e6a95e461ac178ccb12ee13c0b0913ca52a..361c1f10609b23dce6ac0f4d2aa32998321587cc 100644 --- a/src/gboml/gboml.lark +++ b/src/gboml/gboml.lark @@ -40,8 +40,10 @@ _node_content: parameters_block program_block variables_block constraints_block parameters_block: (_block_repeat_or_pass{_opt_param_header,definition})? _opt_param_header: "#PARAMETERS"? variables_block: _block_repeat_or_pass{"#VARIABLES",variable_definition} -constraints_block: (_block_repeat_or_pass{"#CONSTRAINTS",constraint})? -objectives_block: (_block_repeat_or_pass{"#OBJECTIVES",objective})? +constraints_block: (_block_repeat_or_pass{"#CONSTRAINTS",_constraint_block_c})? +_constraint_block_c: constraint | ctr_activate | ctr_deactivate +objectives_block: (_block_repeat_or_pass{"#OBJECTIVES",_objective_block_c})? +_objective_block_c: objective | obj_activate | obj_deactivate node_import: "#NODE" ID "=" "import" var_or_param "from" STRING node_redefs node_redefs: ("with" redefinition*) | ";" @@ -117,6 +119,16 @@ _maybe_unary_minus: value | unary_minus unary_minus: "-" value ?value: function | var_or_param | INT | FLOAT | ("(" expression ")") +// ACTIVATE/DEACTIVATE +_activate.1: "activate" separated_list{_activation_id, ","} ["if" bool_expression] ";" +_deactivate.1: "deactivate" separated_list{_activation_id, ","} ["if" bool_expression] ";" +_activation_id: ID | TAG +ctr_activate: _activate +ctr_deactivate: _deactivate +obj_activate: _activate +obj_deactivate: _deactivate + + // FUNCTIONS function: ID "(" separated_maybe_empty_list{generated_rvalue, ","} ")" diff --git a/src/gboml/parsing.py b/src/gboml/parsing.py index 5709e5d7f48e9016215a8b67e19342f901eb3169..c37a3413adc8582f502671c42a5a9d764e77ef31 100644 --- a/src/gboml/parsing.py +++ b/src/gboml/parsing.py @@ -89,7 +89,11 @@ def _lark_to_gboml(tree: Tree, filename: Optional[str] = None) -> GBOMLGraph: "range": Range, "dict_entry": DictEntry, "array": Array, - "dict": Dictionary + "dict": Dictionary, + "ctr_activate": lambda *x, meta: CtrActivation(ActivationType.activate, *x, meta=meta), + "ctr_deactivate": lambda *x, meta: CtrActivation(ActivationType.deactivate, *x, meta=meta), + "obj_activate": lambda *x, meta: ObjActivation(ActivationType.activate, *x, meta=meta), + "obj_deactivate": lambda *x, meta: ObjActivation(ActivationType.deactivate, *x, meta=meta) } def __default__(self, data, children, _): @@ -122,33 +126,38 @@ def _lark_to_gboml(tree: Tree, filename: Optional[str] = None) -> GBOMLGraph: return self.NodesAndHyperEdges([x for x in childrens if isinstance(x, Node)], [x for x in childrens if isinstance(x, HyperEdge)]) def hyperedge_definition(self, meta: Meta, name: VarOrParam, loop: Optional[Loop], tags: list[str], - param_block: list[Definition] = None, constraint_block: list[Constraint] = None): + param_block: list[Definition] = None, + constraint_block: list[Constraint | CtrActivation] = None): if constraint_block is None: constraint_block = [] + activations = [x for x in constraint_block if isinstance(x, CtrActivation)] + constraint_block = [x for x in constraint_block if isinstance(x, Constraint)] if param_block is None: param_block = [] if loop is None: if len(name.path) != 1 or len(name.path[0].indices) != 0: raise Exception(f"Invalid name for node: {name}") - return HyperEdgeDefinition(name.path[0].name, param_block, constraint_block, tags, meta=meta) + return HyperEdgeDefinition(name.path[0].name, param_block, constraint_block, + activations, tags, meta=meta) else: - return HyperEdgeGenerator(name, loop, param_block, constraint_block, tags, meta=meta) + return HyperEdgeGenerator(name, loop, param_block, constraint_block, + activations, tags, meta=meta) def node_definition(self, meta: Meta, name: VarOrParam, loop: Optional[Loop], tags: list[str], param_block: list[Definition] = None, subprogram_block: NodesAndHyperEdges = None, - variable_block: list[VariableDefinition] = None, constraint_block: list[Constraint] = None, - objectives_block: list[Objective] = None): - if objectives_block is None: - objectives_block = [] - if constraint_block is None: - constraint_block = [] - if variable_block is None: - variable_block = [] - if param_block is None: - param_block = [] - if subprogram_block is None: - subprogram_block = self.NodesAndHyperEdges([], []) + variable_block: list[VariableDefinition] = None, + constraint_block: list[Constraint | CtrActivation] = None, + objectives_block: list[Objective | ObjActivation] = None): + objectives_block = objectives_block or [] + constraint_block = constraint_block or [] + variable_block = variable_block or [] + param_block = param_block or [] + subprogram_block = subprogram_block or self.NodesAndHyperEdges([], []) + + activations: list[Activation] = [x for x in constraint_block if isinstance(x, CtrActivation)] + [x for x in objectives_block if isinstance(x, ObjActivation)] + constraint_block = [x for x in constraint_block if isinstance(x, Constraint)] + objectives_block = [x for x in objectives_block if isinstance(x, Objective)] if loop is None: if len(name.path) != 1 or len(name.path[0].indices) != 0: @@ -157,13 +166,13 @@ def _lark_to_gboml(tree: Tree, filename: Optional[str] = None) -> GBOMLGraph: param_block, subprogram_block.nodes, subprogram_block.hyperedges, variable_block, constraint_block, - objectives_block, tags, meta=meta) + objectives_block, activations, tags, meta=meta) else: return NodeGenerator(name, loop, param_block, subprogram_block.nodes, subprogram_block.hyperedges, variable_block, constraint_block, - objectives_block, tags, meta=meta) + objectives_block, activations, tags, meta=meta) def node_import(self, meta: Meta, name: str, imported_name: VarOrParam, imported_from: str, redef: list[ScopeChange | Definition]): return NodeImport(name, imported_name, imported_from,