Skip to content

Fuzzy sets

Worked examples

Warning zones composes sets; the custom model normalizes finite data.

fuzzyroutines.fuzzysets

Immutable scalar fuzzy sets and explicitly configured algebraic operations.

The modern algebra has no process-wide operator settings. Every complement, intersection, union, and directed difference receives immutable policy values, and binary operations require exactly equal universes before constructing a result.

NegationPolicy dataclass

NegationPolicy(family: str, alpha: MembershipScalar | None = None)

Explicit fuzzy-negation family and its optional fixed-point parameter.

Attributes:

Name Type Description
family str

"standard", "parametric", or "parabolic".

alpha MembershipScalar | None

Fixed point for parametric or parabolic negation; absent for standard negation.

family instance-attribute

family: str

alpha class-attribute instance-attribute

alpha: MembershipScalar | None = None

__post_init__

__post_init__() -> None

Validate the complete negation configuration before evaluation.

Source code in fuzzyroutines/operators.py
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
def __post_init__(self) -> None:
    """Validate the complete negation configuration before evaluation."""

    if self.family == "standard":
        if self.alpha is not None:
            raise InvalidParameterError("standard negation does not accept alpha")

        return

    if self.family == "parametric":
        alpha = _RequireFiniteReal(self.alpha, "alpha")

        if not 0 < alpha < 1:
            raise InvalidParameterError("parametric negation alpha must lie in the open interval (0, 1)")

        object.__setattr__(self, "alpha", alpha)
        return

    if self.family == "parabolic":
        alpha = _RequireFiniteReal(self.alpha, "alpha")

        if not 0.25 <= alpha <= 0.75:
            raise InvalidParameterError("parabolic negation alpha must lie in the closed interval [1/4, 3/4]")

        object.__setattr__(self, "alpha", alpha)
        return

    raise InvalidParameterError(f"unknown negation family: {self.family!r}")

Evaluate

Evaluate(grade: MembershipScalar) -> MembershipScalar

Evaluate the configured negation for one membership grade.

Parameters:

Name Type Description Default
grade MembershipScalar

Finite membership degree in \([0, 1]\).

required

Returns:

Type Description
MembershipScalar

The complemented membership degree under this policy.

Raises:

Type Description
TypeError

If grade is not a real scalar.

ValueError

If grade is non-finite or outside \([0, 1]\).

Source code in fuzzyroutines/operators.py
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
def Evaluate(self, grade: MembershipScalar) -> MembershipScalar:
    """Evaluate the configured negation for one membership grade.

    Args:
        grade: Finite membership degree in $[0, 1]$.

    Returns:
        The complemented membership degree under this policy.

    Raises:
        TypeError: If `grade` is not a real scalar.
        ValueError: If `grade` is non-finite or outside $[0, 1]$.
    """

    grade = _RequireGrade(grade, "grade")

    return _EvaluateNegation(self.family, cast(float | None, self.alpha), grade)

TNormPolicy dataclass

TNormPolicy(family: str)

Explicit t-norm family used by fuzzy-set intersection.

Attributes:

Name Type Description
family str

One of the names in OPERATOR_FAMILIES.

family instance-attribute

family: str

__post_init__

__post_init__() -> None

Reject every family not accepted by ADR-0004.

Source code in fuzzyroutines/operators.py
 99
100
101
102
103
def __post_init__(self) -> None:
    """Reject every family not accepted by ADR-0004."""

    if self.family not in OPERATOR_FAMILIES:
        raise InvalidParameterError(f"unknown t-norm family: {self.family!r}")

Evaluate

Evaluate(leftGrade: MembershipScalar, rightGrade: MembershipScalar) -> MembershipScalar

Evaluate the configured t-norm for two membership grades.

Parameters:

Name Type Description Default
leftGrade MembershipScalar

Left membership degree in \([0, 1]\).

required
rightGrade MembershipScalar

Right membership degree in \([0, 1]\).

required

Returns:

Type Description
MembershipScalar

Conjunction under the configured family.

Raises:

Type Description
TypeError

If an operand is not a real scalar.

ValueError

If an operand is non-finite or outside \([0, 1]\).

Source code in fuzzyroutines/operators.py
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
def Evaluate(self, leftGrade: MembershipScalar, rightGrade: MembershipScalar) -> MembershipScalar:
    """Evaluate the configured t-norm for two membership grades.

    Args:
        leftGrade: Left membership degree in $[0, 1]$.
        rightGrade: Right membership degree in $[0, 1]$.

    Returns:
        Conjunction under the configured family.

    Raises:
        TypeError: If an operand is not a real scalar.
        ValueError: If an operand is non-finite or outside $[0, 1]$.
    """

    leftGrade = _RequireGrade(leftGrade, "leftGrade")
    rightGrade = _RequireGrade(rightGrade, "rightGrade")

    return _EvaluateTNorm(self.family, leftGrade, rightGrade)

SNormPolicy dataclass

SNormPolicy(family: str)

Explicit s-norm family used by fuzzy-set union.

Attributes:

Name Type Description
family str

One of the names in OPERATOR_FAMILIES.

family instance-attribute

family: str

__post_init__

__post_init__() -> None

Reject every family not accepted by ADR-0004.

Source code in fuzzyroutines/operators.py
136
137
138
139
140
def __post_init__(self) -> None:
    """Reject every family not accepted by ADR-0004."""

    if self.family not in OPERATOR_FAMILIES:
        raise InvalidParameterError(f"unknown s-norm family: {self.family!r}")

Evaluate

Evaluate(leftGrade: MembershipScalar, rightGrade: MembershipScalar) -> MembershipScalar

Evaluate the configured s-norm for two membership grades.

Parameters:

Name Type Description Default
leftGrade MembershipScalar

Left membership degree in \([0, 1]\).

required
rightGrade MembershipScalar

Right membership degree in \([0, 1]\).

required

Returns:

Type Description
MembershipScalar

Disjunction under the configured family.

Raises:

Type Description
TypeError

If an operand is not a real scalar.

ValueError

If an operand is non-finite or outside \([0, 1]\).

Source code in fuzzyroutines/operators.py
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
def Evaluate(self, leftGrade: MembershipScalar, rightGrade: MembershipScalar) -> MembershipScalar:
    """Evaluate the configured s-norm for two membership grades.

    Args:
        leftGrade: Left membership degree in $[0, 1]$.
        rightGrade: Right membership degree in $[0, 1]$.

    Returns:
        Disjunction under the configured family.

    Raises:
        TypeError: If an operand is not a real scalar.
        ValueError: If an operand is non-finite or outside $[0, 1]$.
    """

    leftGrade = _RequireGrade(leftGrade, "leftGrade")
    rightGrade = _RequireGrade(rightGrade, "rightGrade")

    return _EvaluateSNorm(self.family, leftGrade, rightGrade)

ScalarFuzzySet dataclass

ScalarFuzzySet(universe: ContinuousUniverse | DiscreteUniverse, membershipFunction: MembershipCallable)

Immutable scalar fuzzy-set definition over one explicit universe.

Attributes:

Name Type Description
universe ContinuousUniverse | DiscreteUniverse

Continuous or discrete scalar coordinate contract.

membershipFunction MembershipCallable

Callable evaluated after universe membership is validated; its result must be a finite degree in \([0, 1]\). MembershipCallable describes the structural contract without requiring inheritance. Construction checks callability only, not signatures or results.

universe instance-attribute

membershipFunction instance-attribute

membershipFunction: MembershipCallable

__post_init__

__post_init__() -> None

Require a supported universe and an evaluable membership function.

Source code in fuzzyroutines/fuzzysets.py
61
62
63
64
65
66
67
68
def __post_init__(self) -> None:
    """Require a supported universe and an evaluable membership function."""

    if not isinstance(self.universe, (ContinuousUniverse, DiscreteUniverse)):
        raise InvalidParameterTypeError("universe must be a ContinuousUniverse or DiscreteUniverse")

    if not callable(self.membershipFunction):
        raise InvalidParameterTypeError("membershipFunction must be callable")

Membership

Membership(coordinate: MembershipScalar) -> MembershipScalar

Return the validated membership grade for a universe coordinate.

Parameters:

Name Type Description Default
coordinate MembershipScalar

Finite scalar coordinate belonging to universe.

required

Returns:

Type Description
MembershipScalar

Membership degree in \([0, 1]\).

Raises:

Type Description
TypeError

If the coordinate or returned grade is not a real scalar.

ValueError

If the coordinate is outside the universe or the callable returns a non-finite or out-of-range grade.

Source code in fuzzyroutines/fuzzysets.py
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
def Membership(self, coordinate: MembershipScalar) -> MembershipScalar:
    """Return the validated membership grade for a universe coordinate.

    Args:
        coordinate: Finite scalar coordinate belonging to `universe`.

    Returns:
        Membership degree in $[0, 1]$.

    Raises:
        TypeError: If the coordinate or returned grade is not a real
            scalar.
        ValueError: If the coordinate is outside the universe or the
            callable returns a non-finite or out-of-range grade.
    """

    if not self.universe.Contains(coordinate):
        raise InvalidDomainError("coordinate must belong to the fuzzy set universe")

    return _RequireGrade(self.membershipFunction(coordinate), "membership grade")

Height

Height(fuzzySet: ScalarFuzzySet) -> MembershipScalar

Return the exact supremum of membership grades when it is provable.

A discrete universe is evaluated exhaustively. A continuous universe requires internally preserved exact evidence, a modern analytical MembershipFunction, or a registered historical MFunction evaluator supported by DeriveProperties. The function never promotes a finite sample maximum to an exact height.

Parameters:

Name Type Description Default
fuzzySet ScalarFuzzySet

Scalar fuzzy set whose exact height is requested.

required

Returns:

Type Description
MembershipScalar

Exact supremum of the membership grades.

Raises:

Type Description
TypeError

If fuzzySet is not a scalar fuzzy set.

ValueError

If an exact continuous height is unavailable.

Source code in fuzzyroutines/fuzzysets.py
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
def Height(fuzzySet: ScalarFuzzySet) -> MembershipScalar:
    """Return the exact supremum of membership grades when it is provable.

    A discrete universe is evaluated exhaustively.  A continuous universe
    requires internally preserved exact evidence, a modern analytical
    [MembershipFunction][fuzzyroutines.membership.MembershipFunction], or a
    registered historical [MFunction][fuzzyroutines.FuzzyRoutines.MFunction]
    evaluator supported by
    [DeriveProperties][fuzzyroutines.properties.DeriveProperties].
    The function never promotes a finite sample maximum to an exact height.

    Args:
        fuzzySet: Scalar fuzzy set whose exact height is requested.

    Returns:
        Exact supremum of the membership grades.

    Raises:
        TypeError: If `fuzzySet` is not a scalar fuzzy set.
        ValueError: If an exact continuous height is unavailable.
    """

    if not isinstance(fuzzySet, ScalarFuzzySet):
        raise InvalidParameterTypeError("fuzzySet must be a ScalarFuzzySet")

    membershipFunction = fuzzySet.membershipFunction

    if isinstance(membershipFunction, _NormalizedDiscreteMembership):
        if fuzzySet.universe == membershipFunction.universe:
            return 1.0

    elif isinstance(membershipFunction, _NormalizedContinuousMembership):
        if fuzzySet.universe == membershipFunction.universe:
            return 1.0

        if isinstance(fuzzySet.universe, ContinuousUniverse):
            return _NormalizedContinuousHeight(membershipFunction, fuzzySet.universe)

    if isinstance(fuzzySet.universe, DiscreteUniverse):
        return max(_DiscreteGrades(fuzzySet))

    analyticalSource = _RequireContinuousAnalyticalSource(fuzzySet)

    from fuzzyroutines.properties import DeriveProperties

    return DeriveProperties(analyticalSource, fuzzySet.universe).height

IsNormal

IsNormal(fuzzySet: ScalarFuzzySet, tolerance: MembershipScalar = 1e-12) -> bool

Return whether the exact fuzzy-set height equals one within tolerance.

Parameters:

Name Type Description Default
fuzzySet ScalarFuzzySet

Scalar fuzzy set with a provable exact height.

required
tolerance MembershipScalar

Non-negative absolute comparison tolerance.

1e-12

Returns:

Type Description
bool

Whether the exact height is within tolerance of one.

Raises:

Type Description
TypeError

If fuzzySet is not a scalar fuzzy set or tolerance is not a real scalar.

ValueError

If tolerance is negative or exact height is unavailable.

Source code in fuzzyroutines/fuzzysets.py
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
def IsNormal(fuzzySet: ScalarFuzzySet, tolerance: MembershipScalar = 1e-12) -> bool:
    """Return whether the exact fuzzy-set height equals one within tolerance.

    Args:
        fuzzySet: Scalar fuzzy set with a provable exact height.
        tolerance: Non-negative absolute comparison tolerance.

    Returns:
        Whether the exact height is within `tolerance` of one.

    Raises:
        TypeError: If `fuzzySet` is not a scalar fuzzy set or `tolerance` is
            not a real scalar.
        ValueError: If `tolerance` is negative or exact height is unavailable.
    """

    tolerance = _RequireFiniteReal(tolerance, "tolerance")

    if tolerance < 0:
        raise InvalidParameterError("tolerance must be non-negative")

    return math.isclose(Height(fuzzySet), 1.0, rel_tol=0.0, abs_tol=tolerance)

Normalize

Normalize(fuzzySet: ScalarFuzzySet) -> ScalarFuzzySet

Return a new height-one fuzzy set without mutating the source set.

Normalization is the pointwise quotient \(\mu_A(x) / \mathrm{height}(A)\). It is undefined for height zero and unavailable when an exact continuous height cannot be proved under the current analytical contracts.

Parameters:

Name Type Description Default
fuzzySet ScalarFuzzySet

Scalar fuzzy set with a provable nonzero exact height.

required

Returns:

Type Description
ScalarFuzzySet

A new scalar fuzzy set whose exact height is one.

Raises:

Type Description
TypeError

If fuzzySet is not a scalar fuzzy set.

ValueError

If exact height is unavailable or equals zero.

Source code in fuzzyroutines/fuzzysets.py
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
def Normalize(fuzzySet: ScalarFuzzySet) -> ScalarFuzzySet:
    r"""Return a new height-one fuzzy set without mutating the source set.

    Normalization is the pointwise quotient
    $\mu_A(x) / \mathrm{height}(A)$. It is
    undefined for height zero and unavailable when an exact continuous height
    cannot be proved under the current analytical contracts.

    Args:
        fuzzySet: Scalar fuzzy set with a provable nonzero exact height.

    Returns:
        A new scalar fuzzy set whose exact height is one.

    Raises:
        TypeError: If `fuzzySet` is not a scalar fuzzy set.
        ValueError: If exact height is unavailable or equals zero.
    """

    if not isinstance(fuzzySet, ScalarFuzzySet):
        raise InvalidParameterTypeError("fuzzySet must be a ScalarFuzzySet")

    height: MembershipScalar
    normalizedMembership: MembershipCallable

    if isinstance(fuzzySet.universe, DiscreteUniverse):
        sourceGrades = _DiscreteGrades(fuzzySet)
        height = max(sourceGrades)

        if height == 0:
            raise UndefinedResultError("cannot normalize a zero-height fuzzy set")

        normalizedGrades = tuple(grade / height for grade in sourceGrades)
        # max(grades / height) is exactly one at the coordinate that attained
        # the finite discrete maximum; no sampled supremum claim is involved.
        normalizedMembership = _NormalizedDiscreteMembership(
            fuzzySet.universe,
            normalizedGrades,
        )

    else:
        if isinstance(fuzzySet.membershipFunction, _NormalizedContinuousMembership):
            if fuzzySet.universe == fuzzySet.membershipFunction.universe:
                return ScalarFuzzySet(fuzzySet.universe, fuzzySet.membershipFunction)

            familyIdentifier = fuzzySet.membershipFunction.familyIdentifier
            parameters = fuzzySet.membershipFunction.parameters

            from fuzzyroutines.properties import DeriveProperties

            frozenSource = _AnalyticalSource(familyIdentifier.title(), parameters)
            height = DeriveProperties(frozenSource, fuzzySet.universe).height
            _RequireGrade(
                height / cast(float, fuzzySet.membershipFunction.sourceHeight),
                "normalized height",
            )

            if height == 0:
                raise UndefinedResultError("cannot normalize a zero-height fuzzy set")

            normalizedMembership = _NormalizedContinuousMembership(
                fuzzySet.universe,
                familyIdentifier,
                parameters,
                height,
            )
            return ScalarFuzzySet(fuzzySet.universe, normalizedMembership)

        analyticalSource = _RequireContinuousAnalyticalSource(fuzzySet)

        familyIdentifier = analyticalSource.name.lower()
        parameters = tuple(sorted(analyticalSource.parameters.items()))

        from fuzzyroutines.properties import DeriveProperties

        frozenSource = _AnalyticalSource(familyIdentifier.title(), parameters)
        height = DeriveProperties(frozenSource, fuzzySet.universe).height

        if height == 0:
            raise UndefinedResultError("cannot normalize a zero-height fuzzy set")

        normalizedMembership = _NormalizedContinuousMembership(
            fuzzySet.universe,
            familyIdentifier,
            parameters,
            height,
        )

    return ScalarFuzzySet(fuzzySet.universe, normalizedMembership)

Complement

Complement(fuzzySet: ScalarFuzzySet, negationPolicy: NegationPolicy) -> ScalarFuzzySet

Return a new fuzzy set using one explicit approved negation policy.

Parameters:

Name Type Description Default
fuzzySet ScalarFuzzySet

Source scalar fuzzy set.

required
negationPolicy NegationPolicy

Explicit complement semantics.

required

Returns:

Type Description
ScalarFuzzySet

A lazy immutable set over the unchanged universe.

Raises:

Type Description
TypeError

If either argument has the wrong contract type.

Source code in fuzzyroutines/fuzzysets.py
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
def Complement(fuzzySet: ScalarFuzzySet, negationPolicy: NegationPolicy) -> ScalarFuzzySet:
    """Return a new fuzzy set using one explicit approved negation policy.

    Args:
        fuzzySet: Source scalar fuzzy set.
        negationPolicy: Explicit complement semantics.

    Returns:
        A lazy immutable set over the unchanged universe.

    Raises:
        TypeError: If either argument has the wrong contract type.
    """

    if not isinstance(fuzzySet, ScalarFuzzySet):
        raise InvalidParameterTypeError("fuzzySet must be a ScalarFuzzySet")

    if not isinstance(negationPolicy, NegationPolicy):
        raise InvalidParameterTypeError("negationPolicy must be a NegationPolicy")

    def ComplementMembership(coordinate: MembershipScalar) -> MembershipScalar:
        """Evaluate the source set before applying the configured negation."""

        return negationPolicy.Evaluate(fuzzySet.Membership(coordinate))

    return ScalarFuzzySet(fuzzySet.universe, ComplementMembership)

Intersection

Intersection(leftSet: ScalarFuzzySet, rightSet: ScalarFuzzySet, tNormPolicy: TNormPolicy) -> ScalarFuzzySet

Return a fuzzy-set intersection under one explicit t-norm family.

Parameters:

Name Type Description Default
leftSet ScalarFuzzySet

Left scalar fuzzy set.

required
rightSet ScalarFuzzySet

Right scalar fuzzy set over exactly the same universe.

required
tNormPolicy TNormPolicy

Explicit conjunction semantics.

required

Returns:

Type Description
ScalarFuzzySet

A lazy immutable intersection over the shared universe.

Raises:

Type Description
TypeError

If an argument has the wrong contract type.

ValueError

If the operand universes differ.

Source code in fuzzyroutines/fuzzysets.py
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
def Intersection(
    leftSet: ScalarFuzzySet,
    rightSet: ScalarFuzzySet,
    tNormPolicy: TNormPolicy,
) -> ScalarFuzzySet:
    """Return a fuzzy-set intersection under one explicit t-norm family.

    Args:
        leftSet: Left scalar fuzzy set.
        rightSet: Right scalar fuzzy set over exactly the same universe.
        tNormPolicy: Explicit conjunction semantics.

    Returns:
        A lazy immutable intersection over the shared universe.

    Raises:
        TypeError: If an argument has the wrong contract type.
        ValueError: If the operand universes differ.
    """

    leftSet, rightSet = _RequireCompatibleSets(leftSet, rightSet)

    if not isinstance(tNormPolicy, TNormPolicy):
        raise InvalidParameterTypeError("tNormPolicy must be a TNormPolicy")

    def IntersectionMembership(coordinate: MembershipScalar) -> MembershipScalar:
        """Evaluate both operands before applying the configured t-norm."""

        return tNormPolicy.Evaluate(
            leftSet.Membership(coordinate),
            rightSet.Membership(coordinate),
        )

    return ScalarFuzzySet(leftSet.universe, IntersectionMembership)

Union

Union(leftSet: ScalarFuzzySet, rightSet: ScalarFuzzySet, sNormPolicy: SNormPolicy) -> ScalarFuzzySet

Return a fuzzy-set union under one explicit s-norm family.

Parameters:

Name Type Description Default
leftSet ScalarFuzzySet

Left scalar fuzzy set.

required
rightSet ScalarFuzzySet

Right scalar fuzzy set over exactly the same universe.

required
sNormPolicy SNormPolicy

Explicit disjunction semantics.

required

Returns:

Type Description
ScalarFuzzySet

A lazy immutable union over the shared universe.

Raises:

Type Description
TypeError

If an argument has the wrong contract type.

ValueError

If the operand universes differ.

Source code in fuzzyroutines/fuzzysets.py
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
def Union(leftSet: ScalarFuzzySet, rightSet: ScalarFuzzySet, sNormPolicy: SNormPolicy) -> ScalarFuzzySet:
    """Return a fuzzy-set union under one explicit s-norm family.

    Args:
        leftSet: Left scalar fuzzy set.
        rightSet: Right scalar fuzzy set over exactly the same universe.
        sNormPolicy: Explicit disjunction semantics.

    Returns:
        A lazy immutable union over the shared universe.

    Raises:
        TypeError: If an argument has the wrong contract type.
        ValueError: If the operand universes differ.
    """

    leftSet, rightSet = _RequireCompatibleSets(leftSet, rightSet)

    if not isinstance(sNormPolicy, SNormPolicy):
        raise InvalidParameterTypeError("sNormPolicy must be an SNormPolicy")

    def UnionMembership(coordinate: MembershipScalar) -> MembershipScalar:
        """Evaluate both operands before applying the configured s-norm."""

        return sNormPolicy.Evaluate(
            leftSet.Membership(coordinate),
            rightSet.Membership(coordinate),
        )

    return ScalarFuzzySet(leftSet.universe, UnionMembership)

Difference

Difference(leftSet: ScalarFuzzySet, rightSet: ScalarFuzzySet, tNormPolicy: TNormPolicy, negationPolicy: NegationPolicy) -> ScalarFuzzySet

Return the directed fuzzy-set difference under explicit policies.

The membership definition is \(T(\mu_A(x), N(\mu_B(x)))\).

Parameters:

Name Type Description Default
leftSet ScalarFuzzySet

Minuend scalar fuzzy set \(A\).

required
rightSet ScalarFuzzySet

Subtrahend scalar fuzzy set \(B\) over the same universe.

required
tNormPolicy TNormPolicy

Explicit conjunction semantics \(T\).

required
negationPolicy NegationPolicy

Explicit complement semantics \(N\).

required

Returns:

Type Description
ScalarFuzzySet

A lazy immutable directed difference over the shared universe.

Raises:

Type Description
TypeError

If an argument has the wrong contract type.

ValueError

If the operand universes differ.

Source code in fuzzyroutines/fuzzysets.py
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
def Difference(
    leftSet: ScalarFuzzySet,
    rightSet: ScalarFuzzySet,
    tNormPolicy: TNormPolicy,
    negationPolicy: NegationPolicy,
) -> ScalarFuzzySet:
    r"""Return the directed fuzzy-set difference under explicit policies.

    The membership definition is $T(\mu_A(x), N(\mu_B(x)))$.

    Args:
        leftSet: Minuend scalar fuzzy set $A$.
        rightSet: Subtrahend scalar fuzzy set $B$ over the same universe.
        tNormPolicy: Explicit conjunction semantics $T$.
        negationPolicy: Explicit complement semantics $N$.

    Returns:
        A lazy immutable directed difference over the shared universe.

    Raises:
        TypeError: If an argument has the wrong contract type.
        ValueError: If the operand universes differ.
    """

    leftSet, rightSet = _RequireCompatibleSets(leftSet, rightSet)

    if not isinstance(tNormPolicy, TNormPolicy):
        raise InvalidParameterTypeError("tNormPolicy must be a TNormPolicy")

    if not isinstance(negationPolicy, NegationPolicy):
        raise InvalidParameterTypeError("negationPolicy must be a NegationPolicy")

    def DifferenceMembership(coordinate: MembershipScalar) -> MembershipScalar:
        r"""Evaluate $T(\mu_A(x), N(\mu_B(x)))$ without an implicit policy."""

        return tNormPolicy.Evaluate(
            leftSet.Membership(coordinate),
            negationPolicy.Evaluate(rightSet.Membership(coordinate)),
        )

    return ScalarFuzzySet(leftSet.universe, DifferenceMembership)