Rules
hgp_lib.rules.rules.Rule
Bases: ABC
Abstract base class for logical rule nodes used in rule trees.
Each Rule represents either:
- An operator: a logical operation combining subrules (e.g., And, Or), or
- A literal: a literal condition (e.g., Literal(value=5, negated=True)).
Rules can be nested to form complex logical expressions. The tree can be traversed, copied, or evaluated against data.
Attributes:
| Name | Type | Description |
|---|---|---|
subrules |
Optional[List[Rule]]
|
The list of child rules, for operators, or |
parent |
Optional[Rule]
|
A reference to the parent rule in the tree (if any). Default: |
value |
Optional[int]
|
The value held by this rule (e.g., for literals). Should be |
negated |
bool
|
Whether this rule or literal is logically negated (e.g., |
copy_subrules |
bool
|
Whether to deep copy the subrules (valid only for operators). If False, the subrules are moved.
Default: |
Notes
__slots__are used for performance optimization to reduce memory overhead.- No runtime validation is performed for speed; incorrect usage may cause undefined behavior.
Examples:
>>> from hgp_lib.rules import And, Or, Literal
>>> rule = And([
... Literal(value=0),
... Or([Literal(value=1, negated=True), Literal(value=2)]),
... Literal(value=3)
... ])
>>> rule
And(0, Or(~1, 2), 3)
Source code in hgp_lib\rules\rules.py
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 | |
flatten()
Iteratively flattens the rule subtree into a single list of all Rule nodes using a queue.
Returns:
| Type | Description |
|---|---|
|
List[Rule]: A flat list containing |
Examples:
>>> from hgp_lib.rules import And, Or, Literal
>>> rule = And([
... Literal(value=0),
... Or([Literal(value=1, negated=True), Or([Literal(value=2), Literal(value=4)])]),
... Literal(value=3)
... ])
>>> rule.flatten()
[And(0, Or(~1, Or(2, 4)), 3), 0, Or(~1, Or(2, 4)), 3, ~1, Or(2, 4), 2, 4]
Source code in hgp_lib\rules\rules.py
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | |
__len__()
Returns the total number of nodes in this rule subtree, including the current rule and all its descendants.
Returns:
| Name | Type | Description |
|---|---|---|
int |
int
|
The total number of |
Examples:
>>> from hgp_lib.rules import And, Or, Literal
>>> len(Literal(value=1))
1
>>> len(Or([Literal(value=2), Literal(value=3)]))
3
>>> len(And([Literal(value=1), Or([Literal(value=2), Literal(value=3)])]))
5
Source code in hgp_lib\rules\rules.py
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | |
to_str(feature_names=None, indent=-1)
Returns a human-readable string representation of this rule and replaces the literal values with the feature names if available.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
feature_names
|
Dict[int, str] | None
|
The feature names that can be used to replace literal values when
provided. Default: |
None
|
indent
|
int
|
The indentation level when printing the rules. If |
-1
|
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
A string representation such as |
Examples:
>>> from hgp_lib.rules import And, Literal
>>> str(And([Literal(value=1), Literal(value=2)]))
'And(1, 2)'
>>> str(And([Literal(value=1), Literal(value=2)], negated=True))
'~And(1, 2)'
>>> And([Literal(value=1), Literal(value=2)], negated=True).to_str({1: "good", 2:"nice"})
'~And(good, nice)'
Source code in hgp_lib\rules\rules.py
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 | |
copy(parent=None)
Creates a deep copy of this rule and its entire subtree, optionally assigning a new parent.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
parent
|
Optional[Rule]
|
The parent rule for the new copy. If omitted, retains the current parent. Default: |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
Rule |
Rule
|
A new instance of the same rule type, with all subrules recursively copied. |
Examples:
>>> from hgp_lib.rules import And, Literal
>>> a = And([Literal(value=1), Literal(value=2)])
>>> b = a.copy()
>>> a is b
False
>>> a.subrules[0] is b.subrules[0]
False
>>> all([(x.value is None and y.value is None) or (x.value == y.value) for x, y in zip(a.flatten(), b.flatten())])
True
Source code in hgp_lib\rules\rules.py
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 | |
evaluate(data)
abstractmethod
Abstract method to evaluate this rule against the given data, in a vectorized manner.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
ndarray
|
The input data. Must be a 2D ndarray, with instances on rows and features on columns. |
required |
Returns:
| Type | Description |
|---|---|
ndarray
|
np.ndarray: The boolean result of evaluating this rule vectorized across all instances. |
Notes
Concrete subclasses (And, Or, Literal, etc.) must implement this.
Source code in hgp_lib\rules\rules.py
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 | |
apply_feature_mapping(feature_mapping)
Applies a feature mapping to this rule and all its subrules in-place.
This method remaps feature indices used in literals according to the provided mapping dictionary. It is used in hierarchical GP when child populations operate on a subset of features (feature bagging) and need to be translated back to the parent's feature space during crossover.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
feature_mapping
|
Dict[int, int]
|
A dictionary mapping old feature indices to new feature indices.
For literals, |
required |
Returns:
| Name | Type | Description |
|---|---|---|
None |
This method modifies the rule in-place. |
Raises:
| Type | Description |
|---|---|
KeyError
|
If |
Examples:
>>> from hgp_lib.rules import And, Literal
>>> rule = And([Literal(value=0), Literal(value=1)])
>>> rule.apply_feature_mapping({0: 5, 1: 10})
>>> str(rule)
'And(5, 10)'
Source code in hgp_lib\rules\rules.py
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 | |
hgp_lib.rules.literals.Literal
Bases: Rule
Represents a single literal condition in a rule tree.
A Literal corresponds to a single feature (column) in the input data.
It may optionally be negated, in which case its logical value is inverted.
Attributes:
| Name | Type | Description |
|---|---|---|
subrules |
Optional[List[Rule]]
|
The list of child rules, for operators, or |
parent |
Optional[Rule]
|
A reference to the parent rule in the tree (if any). Default: |
value |
int
|
The column index of the feature this literal refers to in |
negated |
bool
|
Whether the literal is negated (logical NOT). |
Examples:
>>> import numpy as np
>>> data = np.array([[True, False, True], [False, True, False]])
>>> literal = Literal(value=0)
>>> literal.evaluate(data)
array([ True, False])
>>> negated_literal = Literal(value=1, negated=True)
>>> negated_literal.evaluate(data)
array([ True, False])
>>> str(Literal(value=2))
'2'
>>> str(Literal(value=2, negated=True))
'~2'
Source code in hgp_lib\rules\literals.py
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | |
evaluate(data)
Evaluates this literal on the given data array, based on the self.value feature.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
ndarray
|
Input data passed to subrules. Must be a 2D ndarray, with instances on rows and features on columns. Not checked at runtime for performance reasons. |
required |
Returns:
| Type | Description |
|---|---|
|
np.ndarray: The boolean result of evaluating this rule vectorized across all instances. |
Examples:
>>> import numpy as np
>>> data = np.array([[True, False], [False, True]])
>>> Literal(value=0).evaluate(data)
array([ True, False])
>>> Literal(value=1, negated=True).evaluate(data)
array([ True, False])
Source code in hgp_lib\rules\literals.py
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | |
to_str(feature_names=None, indent=-1)
Returns a human-readable string representation of the literal. The literal can be replaced with the feature name if provided.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
feature_names
|
Dict[int, str] | None
|
The feature names that can be used to replace literal values when
provided. Default: |
None
|
indent
|
int
|
Not used. Default: |
-1
|
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
The literal as a string, prefixed with |
Examples:
>>> str(Literal(value=0))
'0'
>>> str(Literal(value=0, negated=True))
'~0'
>>> Literal(value=0, negated=True).to_str({0: "bad"})
'~bad'
Source code in hgp_lib\rules\literals.py
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | |
hgp_lib.rules.operators.And
Bases: Rule
Logical conjunction (AND) operator node for rule trees. It evaluates to True only if every subrule evaluates to
True.
Attributes:
| Name | Type | Description |
|---|---|---|
subrules |
List[Rule]
|
A list of child rules combined with logical AND. Must be a list longer than 1 element. Not checked at
runtime for performance reasons. Default: |
parent |
Optional[Rule]
|
A reference to the parent rule, if part of a larger tree. Default: |
value |
None
|
Always |
negated |
bool
|
Whether the entire conjunction is logically negated ( |
Examples:
>>> from hgp_lib.rules.operators import And, Or
>>> from hgp_lib.rules import Literal
>>> rule = And([
... Literal(value=0),
... Or([Literal(value=1, negated=True), Literal(value=2)]),
... Literal(value=3)
... ])
>>> rule
And(0, Or(~1, 2), 3)
Source code in hgp_lib\rules\operators.py
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | |
evaluate(data)
All subrules are recursively evaluated, and their results are combined using logical conjunction. The final
result is optionally negated if self.negated is True.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
ndarray
|
Input data passed to subrules. Must be a 2D ndarray, with instances on rows and features on columns. Not checked at runtime for performance reasons. |
required |
Returns:
| Type | Description |
|---|---|
ndarray
|
np.ndarray: The boolean result of evaluating this rule vectorized across all instances. |
Examples:
>>> from hgp_lib.rules.operators import And
>>> from hgp_lib.rules import Literal
>>> import numpy as np
>>> data = np.array([
... [True, False],
... [False, False],
... [False, False]
... ])
>>> rule = And([Literal(value=0), Literal(value=1, negated=True)])
>>> rule.evaluate(data)
array([ True, False, False])
Notes
This implementation does as few operations as possible, at the expense of more memory usage.
Source code in hgp_lib\rules\operators.py
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | |
hgp_lib.rules.operators.Or
Bases: Rule
Logical disjunction (OR) operator node for rule trees. It evaluates to True if any subrule evaluates to True.
Attributes:
| Name | Type | Description |
|---|---|---|
subrules |
List[Rule]
|
A list of child rules combined with logical AND. Must be a list longer than 1 element. Not checked at
runtime for performance reasons. Default: |
parent |
Optional[Rule]
|
A reference to the parent rule, if part of a larger tree. Default: |
value |
None
|
Always |
negated |
bool
|
Whether the entire conjunction is logically negated ( |
Examples:
>>> from hgp_lib.rules.operators import And
>>> from hgp_lib.rules import Literal
>>> rule = Or([Literal(value=0), Literal(value=1, negated=True)])
>>> rule
Or(0, ~1)
Source code in hgp_lib\rules\operators.py
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | |
evaluate(data)
All subrules are recursively evaluated, and their results are combined using logical disjunction. The final
result is optionally negated if self.negated is True.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
ndarray
|
Input data passed to subrules. Must be a 2D ndarray, with instances on rows and features on columns. Not checked at runtime for performance reasons. |
required |
Returns:
| Type | Description |
|---|---|
ndarray
|
np.ndarray: The boolean result of evaluating this rule vectorized across all instances. |
Examples:
>>> from hgp_lib.rules.operators import And
>>> from hgp_lib.rules import Literal
>>> import numpy as np
>>> data = np.array([
... [True, False, True],
... [False, False, True]
... ])
>>> rule = Or([Literal(value=0), Literal(value=1)])
>>> rule.evaluate(data)
array([ True, False])
Notes
This implementation does as few operations as possible, at the expense of more memory usage.
Source code in hgp_lib\rules\operators.py
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | |