core.base
Core abstractions for single-element fuzzy-number implementations.
This module defines FuzznumStrategy, the primary abstract base
class that concrete fuzzy-number types (mtype) must inherit from.
It provides attribute declaration/validation, change callbacks, per-instance
operation caching and a uniform operation dispatch helper that integrates
with the operation registry.
Notes
Implementations of specific fuzzy types live under
axisfuzzy/fuzztype/.See examples in
axisfuzzy/fuzztype/qrofs/qrofn.pyandaxisfuzzy/fuzztype/qrohfs/qrohfn.pyfor concrete usages.
- class axisfuzzy.core.base.FuzznumStrategy(q=None)[source]
Bases:
ABCAbstract base for a single-element fuzzy-number strategy.
The strategy represents the data and behavior of a single fuzzy number. Subclasses declare data attributes (via annotations or class-level defaults) and implement the presentation and operation-specific logic. Key responsibilities include:
Enforce a “declared attribute” contract: assignments to attributes not declared in the subclass raise
AttributeError(strict mode).Provide attribute validators, transformers and change callbacks.
Offer an operation dispatcher with caching via
execute_operation().Collect declared attributes at class creation via
__init_subclass__.
- Parameters:
q (int, optional) – q-rung parameter used by many fuzzy types. If
Nonethe library default (fromaxisfuzzy.config.get_config()) is used.
- mtype
Registered fuzzy-number type identifier for the concrete strategy class.
- Type:
str
- q
Effective q-rung for the instance.
- Type:
int or None
Notes
Subclasses should call
super().__init__()in their__init__.Use
add_attribute_validator(),add_attribute_transformer()andadd_change_callback()inside subclass initialization to register type-specific rules or reactive behavior.The default
qvalidator enforces an integer in [1, 100]; subclasses may override or refine this by registering a custom validator.
- Raises:
AttributeError – When assigning to an undeclared attribute (strict mode).
ValueError – If a validator rejects a new attribute value.
RuntimeError – If a registered change callback raises an unexpected error.
Examples
Minimal subclass pattern and validators. The following examples mirror patterns used in the repository:
# Example (simple numeric attributes) class MyStrategy(FuzznumStrategy): mtype = 'mytype' a: float = 0.0 b: float = 1.0 def __init__(self, q=None): super().__init__(q=q) # ensure a and b are in [0, 1] self.add_attribute_validator('a', lambda v: isinstance(v, (int, float)) and 0.0 <= v <= 1.0) self.add_attribute_validator('b', lambda v: isinstance(v, (int, float)) and 0.0 <= v <= 1.0) def report(self) -> str: return f"a={self.a}, b={self.b}" def str(self) -> str: return f"<{self.a},{self.b}>"
Concrete examples from the codebase:
q-rung orthopair fuzzy number (QROFN): see
axisfuzzy.fuzztype.qrofs.qrofnwhere membership attributesmdandnmdare registered with validators and change callbacks that enforce the q-rung constraint \(\mu^q + \nu^q \leq 1\)q-rung hesitant fuzzy number (QROHFN): see
axisfuzzy.fuzztype.qrohfs.qrohfnwhich demonstrates usage of attribute transformers to coerce inputs into numpy arrays and validators that check elementwise ranges and shapes.
Implementation hints
Use transformers to normalise inputs (e.g., convert lists -> np.ndarray) before validation and storage.
Register change callbacks when inter-dependent attributes must trigger cross-checks (e.g., enforcing md/nmd constraints whenever either changes).
Prefer registering validators/transformers in
__init__so that they are instance-local and do not unintentionally share state across instances.
See also
axisfuzzy.fuzztype.qrofs.qrofn.QROFNStrategy,axisfuzzy.fuzztype.qrohfs.qrohfn.QROHFNStrategy- add_attribute_transformer(attr_name, transformer)[source]
Register a transformer for an attribute value.
Transformers receive the candidate value (after validators pass) and must return the value that will be stored on the instance. Typical uses are type coercion, normalization or conversion (e.g. list -> ndarray).
- Parameters:
attr_name (str) – Attribute name to transform.
transformer (Callable[[Any], Any]) – Callable that takes the incoming value and returns the transformed value to be stored.
- Raises:
TypeError – If
transformeris not callable.- Return type:
None
Notes
Transformers run after validators and before the value is written.
If a transformer raises an exception, the assignment fails.
Register transformers during
__init__to keep them instance-local.
Examples
# coerce lists to numpy arrays for attribute 'md' self.add_attribute_transformer('md', lambda v: None if v is None else np.asarray(v, dtype=float))
- add_attribute_validator(attr_name, validator)[source]
Register a validator for a specific attribute.
Validators are primarily used to ensure that attribute values meet specific conditions or constraints when they are set. The validator is called whenever the attribute is set via
__setattr__. If the validator returnsFalsethe assignment is rejected and aValueErroris raised.- Parameters:
attr_name (str) – Name of the attribute to validate. Should be one of the names returned by
get_declared_attributes()or an instance attribute.validator (Callable[[Any], bool]) – Callable that accepts the candidate value and returns
Trueif the value is acceptable,Falseotherwise.
- Raises:
TypeError – If
validatoris not callable.- Return type:
None
Notes
Validators are stored per-instance (registered inside
__init__of the concrete strategy). Registering a validator replaces any previously registered validator for the same attribute.Validators are executed before transformers.
Examples
# inside a strategy __init__: self.add_attribute_validator('md', lambda v: v is None or 0.0 <= float(v) <= 1.0)
- add_change_callback(attr_name, callback)[source]
Register a post-assignment change callback for an attribute.
The callback is invoked after the attribute value has been successfully assigned. Its signature must be
(attr_name, old_value, new_value). Callbacks may raiseValueErrorto reject an assignment, or any other exception which will be wrapped asRuntimeErrorby__setattr__.- Parameters:
attr_name (str) – Attribute name to monitor.
callback (Callable[[str, Any, Any], None]) – Callable invoked after assignment; may perform cross-attribute checks or trigger side-effects.
- Raises:
TypeError – If
callbackis not callable.- Return type:
None
Notes
Callbacks are executed after validators and transformers and after the value has been stored on the instance.
If multiple callbacks for the same attribute are needed, wrap them in a small dispatcher function or register a single callback that calls others.
Examples
def on_md_change(name, old, new): # enforce relationship with other attribute(s) if new is not None and self.nmd is not None and self.q is not None: if new**self.q + self.nmd**self.q > 1.0: raise ValueError("q-rung constraint violated") self.add_change_callback('md', on_md_change)
- execute_operation(op_name, operand)[source]
Dispatch and execute a named operation for this strategy instance.
This method is the per-instance entry point to the operation subsystem. It resolves the appropriate
OperationMixinimplementation from the global operation registry, builds a t-norm configuration, performs caching, and finally calls the concrete operation implementation.- Parameters:
op_name (str) – Operation identifier (for example:
'add','complement','gt'). Seeget_available_operations()for supported names.operand (FuzznumStrategy or int or float or None) – Second operand for binary/comparison operations, scalar for unary-with-operand operations, or
Nonefor pure unary ops.
- Returns:
Operation-specific result. Concrete operations define the returned dictionary structure (commonly includes keys like
'value'or component arrays).- Return type:
dict
- Raises:
NotImplementedError – If no operation implementation is registered for this instance’s
mtypeand the requestedop_name.TypeError – If the provided
operandhas an incompatible type for the requested operation (e.g. scalar where a strategy was expected).ValueError – If
op_nameis unknown or preprocessing fails.
Notes
Results are cached per-instance when a stable cache key can be created.
The t-norm configuration used is obtained from the global operation registry; this method wraps the concrete operation call with timing and caching logic.
Examples
# binary operation with another strategy instance res = my_strategy.execute_operation('add', other_strategy) print(res) # operation-defined dict # unary complement res = my_strategy.execute_operation('complement', None)
- get_available_operations()[source]
Gets the names of all operations supported by the current fuzzy number type.
This method queries the global operation registry to determine which operations are registered and available for the mtype of this FuzznumStrategy instance.
- Returns:
A list of strings, where each string is the name of an operation supported by this fuzzy number type.
- Return type:
List[str]
Examples
ops = s.get_available_operations() # ['add', 'complement', 'gt', ...]
- get_declared_attributes()[source]
Retrieves a copy of the list of declared attribute names for this strategy.
This method provides introspection capabilities, allowing external code to discover which attributes are explicitly defined as data members of a FuzznumStrategy instance or its subclasses, in their definition order.
- Returns:
Copy of the declared attributes list, preserving definition order.
- Return type:
List[str]
Examples
attrs = instance.get_declared_attributes() # e.g. ['md', 'nmd']
-
mtype:
str= 'qrofn'
-
q:
Optional[int] = 1
- abstractmethod report()[source]
Produce a detailed textual report of the fuzzy number.
- Returns:
Multi-line detailed representation.
- Return type:
str
Notes
Must be implemented by concrete strategies.
- abstractmethod str()[source]
Produce a concise string representation.
- Returns:
Short one-line representation.
- Return type:
str
Notes
Subclasses may override; default can delegate to report.
- validate_all_attributes()[source]
Validates all attributes of the FuzznumStrategy instance.
This method runs both the centralized _validate() hook (for inter-attribute constraints) and any per-attribute validators registered via
add_attribute_validator(). It collects failures rather than raising immediately to provide a consolidated report.- Returns:
A dictionary with two keys: -
is_valid(bool): True if all checks passed. -errors(List[str]): Human-readable error messages for failures.- Return type:
dict
Notes
Use this method in tests or validation pipelines to obtain a full diagnostic report without raising exceptions.
For strict enforcement, call
_validate()directly and let it raise exceptions on serious violations.
Examples
report = s.validate_all_attributes() if not report['is_valid']: print('\n'.join(report['errors']))