Package fuzz :: Module fnumber
[hide private]
[frames] | no frames]

Source Code for Module fuzz.fnumber

  1  """\ 
  2  Fuzzy number module. Contains basic fuzzy number class definitions. 
  3   
  4  @author: Aaron Mavrinac 
  5  @organization: University of Windsor 
  6  @contact: mavrin1@uwindsor.ca 
  7  @license: LGPL-3 
  8  """ 
  9   
 10  from math import e, sqrt, log 
 11  from numbers import Number 
 12   
 13  from .fset import FuzzySet 
14 15 16 -class RealRange(tuple):
17 """\ 18 Real range class. 19 """
20 - def __new__(cls, arg=(0.0, 0.0)):
21 """\ 22 Instatiation method. Verifies the validity of the range argument 23 before returning the range object. 24 """ 25 if not len(arg) == 2: 26 raise ValueError('range must consist of two values') 27 if not isinstance(arg[0], Number) \ 28 or not isinstance(arg[1], Number): 29 raise TypeError('range values must be numeric') 30 if arg[0] > arg[1]: 31 raise ValueError('range may not have negative size') 32 return tuple.__new__(cls, arg)
33 34 @property
35 - def size(self):
36 """\ 37 Return the size of the range. 38 39 @rtype: C{float} 40 """ 41 return float(self[1] - self[0])
42
43 - def __add__(self, other):
44 """\ 45 Addition operation. 46 47 @param other: The other operand. 48 @type other: L{RealRange} 49 @return: Sum of ranges. 50 @rtype: L{RealRange} 51 """ 52 return RealRange((self[0] + other[0], self[1] + other[1]))
53
54 - def __sub__(self, other):
55 """\ 56 Subtraction operation. 57 58 @param other: The other operand. 59 @type other: L{RealRange} 60 @return: Difference of ranges. 61 @rtype: L{RealRange} 62 """ 63 return RealRange((self[0] - other[1], self[1] - other[0]))
64
65 - def __contains__(self, value):
66 """\ 67 Report whether a given value is within this range. 68 69 @param value: The value. 70 @type value: C{float} 71 @return: True if within the range, false otherwise. 72 @rtype: C{bool} 73 """ 74 return value >= self[0] and value <= self[1]
75
76 - def issubset(self, other):
77 """\ 78 Report whether another range contains this range. 79 80 @param other: The other range. 81 @type other: L{RealRange} 82 @return: True if a subset, false otherwise. 83 @rtype: C{bool} 84 """ 85 if not isinstance(other, RealRange): 86 raise TypeError('argument must be a RealRange') 87 if other[0] <= self[0] and other[1] >= self[1]: 88 return True 89 return False
90
91 - def issuperset(self, other):
92 """\ 93 Report whether this range contains another range. 94 95 @param other: The other range. 96 @type other: L{RealRange} 97 @return: True if a superset, false otherwise. 98 @rtype: C{bool} 99 """ 100 if not isinstance(other, RealRange): 101 raise TypeError('argument must be a RealRange') 102 if self[0] <= other[0] and self[1] >= other[1]: 103 return True 104 return False
105 106 __le__ = issubset 107 __ge__ = issuperset 108
109 - def __lt__(self, other):
110 """\ 111 Report whether another range strictly contains this range. 112 113 @param other: The other range. 114 @type other: L{RealRange} 115 @return: True if a strict subset, false otherwise. 116 @rtype: C{bool} 117 """ 118 return self.issubset(other) and not self == other
119
120 - def __gt__(self, other):
121 """\ 122 Report whether this range strictly contains another range. 123 124 @param other: The other range. 125 @type other: L{RealRange} 126 @return: True if a strict superset, false otherwise. 127 @rtype: C{bool} 128 """ 129 return self.issuperset(other) and not self == other
130
131 132 -class FuzzyNumber(object):
133 """\ 134 Fuzzy number class (abstract base class for all fuzzy numbers). 135 """
136 - def __init__(self):
137 """\ 138 Constructor. Not to be instantiated directly. 139 """ 140 if self.__class__ is FuzzyNumber: 141 raise NotImplementedError('please use one of the subclasses')
142
143 - def __repr__(self):
144 """\ 145 Return the canonical representation of a fuzzy number. 146 147 @return: Canonical representation. 148 @rtype: C{str} 149 """ 150 return '<%s>' % self.__class__.__name__
151
152 - def __str__(self):
153 """\ 154 Return the string representation of a fuzzy number. 155 156 @return: String representation. 157 @rtype: C{str} 158 """ 159 return '%s: kernel %s, support %s' % \ 160 (self.__class__.__name__, str(self.kernel), str(self.support))
161 162 @staticmethod
163 - def _binary_sanity_check(other):
164 """\ 165 Check that the other argument to a binary operation is also a 166 fuzzy number, raising a TypeError otherwise. 167 168 @param other: The other argument. 169 @type other: L{FuzzyNumber} 170 """ 171 if not isinstance(other, FuzzyNumber): 172 raise TypeError('operation only permitted between fuzzy numbers')
173
174 - def mu(self, value):
175 """\ 176 Return the membership level of a value in the universal set domain of 177 the fuzzy number. 178 179 @param value: A value in the universal set. 180 @type value: C{float} 181 """ 182 raise NotImplementedError('mu method must be overridden')
183
184 - def normalize(self):
185 """\ 186 Normalize this fuzzy number, so that its height is equal to 1.0. 187 """ 188 if not self.height == 1.0: 189 raise NotImplementedError('normalize method must be overridden')
190
191 - def to_polygonal(self):
192 """\ 193 Convert this fuzzy number into a polygonal fuzzy number. 194 195 @return: Result polygonal fuzzy number. 196 @rtype: L{PolygonalFuzzyNumber} 197 """ 198 raise NotImplementedError('to_polygonal method must be overridden')
199 200 kernel = None 201 support = None 202 height = None 203
204 - def __or__(self, other):
205 """\ 206 Return the standard fuzzy union of two polygonal fuzzy numbers. 207 208 @param other: The other fuzzy number. 209 @type other: L{FuzzyNumber} 210 @return: The fuzzy union. 211 @rtype: L{FuzzyNumber} 212 """ 213 return self.union(other)
214
215 - def __ior__(self, other):
216 """\ 217 In-place standard fuzzy union. 218 219 @param other: The other fuzzy number. 220 @type other: L{FuzzyNumber} 221 @return: The fuzzy union (self). 222 @rtype: L{FuzzyNumber} 223 """ 224 self = self.union(other) 225 return self
226
227 - def union(self, other):
228 """\ 229 Return the standard fuzzy union of two fuzzy numbers as a new polygonal 230 fuzzy number. 231 232 @param other: The other fuzzy number. 233 @type other: L{FuzzyNumber} 234 @return: The fuzzy union. 235 @rtype: L{PolygonalFuzzyNumber} 236 """ 237 self._binary_sanity_check(other) 238 return self.to_polygonal() | other.to_polygonal()
239
240 - def __and__(self, other):
241 """\ 242 Return the standard fuzzy intersection of two fuzzy numbers. 243 244 @param other: The other fuzzy number. 245 @type other: L{FuzzyNumber} 246 @return: The fuzzy intersection. 247 @rtype: L{FuzzyNumber} 248 """ 249 return self.intersection(other)
250
251 - def __iand__(self, other):
252 """\ 253 In-place standard fuzzy intersection. 254 255 @param other: The other fuzzy number. 256 @type other: L{FuzzyNumber} 257 @return: The fuzzy intersection (self). 258 @rtype: L{FuzzyNumber} 259 """ 260 self = self.intersection(other) 261 return self
262
263 - def intersection(self, other):
264 """\ 265 Return the standard fuzzy intersection of two fuzzy numbers as a new 266 polygonal fuzzy number. 267 268 @param other: The other fuzzy number. 269 @type other: L{FuzzyNumber} 270 @return: The fuzzy union. 271 @rtype: L{PolygonalFuzzyNumber} 272 """ 273 self._binary_sanity_check(other) 274 return self.to_polygonal() & other.to_polygonal()
275
276 277 -class PolygonalFuzzyNumber(FuzzyNumber):
278 """\ 279 Polygonal fuzzy number class. 280 """
281 - def __init__(self, points):
282 """\ 283 Constructor. 284 285 @param points: A set of points from which to generate the polygon. 286 @type points: C{list} of C{tuple} 287 """ 288 if not points[0][1] == 0.0 or not points[-1][1] == 0.0: 289 raise ValueError('points must start and end with mu = 0') 290 for i in range(1, len(points)): 291 if not points[i][0] >= points[i - 1][0]: 292 raise ValueError('points must be in increasing order') 293 self.points = points 294 super(PolygonalFuzzyNumber, self).__init__()
295
296 - def __repr__(self):
297 """\ 298 Return the canonical string representation of this polygonal fuzzy 299 number. 300 301 @return: Canonical string representation. 302 @rtype: C{str} 303 """ 304 return 'PolygonalFuzzyNumber(%s)' % self.points
305
306 - def __eq__(self, other):
307 """\ 308 Return whether this polygonal fuzzy number is equal to another fuzzy 309 number. 310 311 @param other: The other fuzzy number. 312 @type other: L{FuzzyNumber} 313 @return: True if equal. 314 @rtype: C{bool} 315 """ 316 return self.points == other.to_polygonal().points
317
318 - def mu(self, value):
319 """\ 320 Return the membership level of a value in the universal set domain of 321 the fuzzy number. 322 323 @param value: A value in the universal set. 324 @type value: C{float} 325 """ 326 if not True in [value in subrange for subrange in self.support]: 327 return 0.0 328 for i in range(1, len(self.points)): 329 if self.points[i][0] > value: 330 return ((value - self.points[i - 1][0]) / (self.points[i][0] \ 331 - self.points[i - 1][0])) * (self.points[i][1] - \ 332 self.points[i - 1][1]) + self.points[i - 1][1] 333 return 0.0
334 335 @property
336 - def kernel(self):
337 """\ 338 Return the kernel of the fuzzy number (range of values in the 339 universal set where membership degree is equal to one). 340 341 @rtype: C{list} of L{RealRange} 342 """ 343 kernel = [] 344 start = None 345 for i in range(1, len(self.points)): 346 if start is None and self.points[i][1] == 1.0: 347 start = i 348 elif start is not None and self.points[i][1] < 1.0: 349 kernel.append(RealRange((self.points[start][0], 350 self.points[i - 1][0]))) 351 start = None 352 return kernel
353 354 @property
355 - def support(self):
356 """\ 357 Return the support of the fuzzy number (range of values in the 358 universal set where membership degree is nonzero). 359 360 @rtype: C{list} of L{RealRange} 361 """ 362 support = [] 363 start = None 364 for i in range(1, len(self.points)): 365 if start is None and self.points[i][1] > 0.0: 366 start = i - 1 367 elif start is not None and self.points[i][1] == 0.0: 368 support.append(RealRange((self.points[start][0], 369 self.points[i][0]))) 370 start = None 371 return support
372 373 @property
374 - def height(self):
375 """\ 376 Return the height of the fuzzy number (maximum membership degree 377 value). 378 379 @rtype: C{float} 380 """ 381 return max([point[1] for point in self.points])
382 383 @staticmethod
384 - def _line_intersection(p, q, r, s):
385 """\ 386 Return the point of intersection of line segments pq and rs. Helper 387 function for union and intersection. 388 389 @return: The point of intersection. 390 @rtype: C{tuple} of C{float} 391 """ 392 try: 393 ua = ((s[0] - r[0]) * (p[1] - r[1]) - \ 394 (s[1] - r[1]) * (p[0] - r[0])) / \ 395 ((s[1] - r[1]) * (q[0] - p[0]) - \ 396 (s[0] - r[0]) * (q[1] - p[1])) 397 except ZeroDivisionError: 398 return None 399 return(p[0] + ua * (q[0] - p[0]), p[1] + ua * (q[1] - p[1]))
400
401 - def union(self, other):
402 """\ 403 Return the standard fuzzy union of two polygonal fuzzy numbers as a new 404 polygonal fuzzy number. 405 406 @param other: The other fuzzy number. 407 @type other: L{FuzzyNumber} 408 @return: The fuzzy union. 409 @rtype: L{PolygonalFuzzyNumber} 410 """ 411 other = other.to_polygonal() 412 # collect and sort all the existing points 413 points = [[point, i, self] for i, point in enumerate(self.points)] \ 414 + [[point, i, other] for i, point in enumerate(other.points)] 415 points.sort() 416 # take the maximum of duplicates 417 i = 0 418 while True: 419 try: 420 if points[i][0][0] == points[i + 1][0][0]: 421 if points[i][0][1] < points[i + 1][0][1]: 422 del points[i] 423 else: 424 del points[i + 1] 425 continue 426 i += 1 427 except IndexError: 428 break 429 # add intersection points 430 i = 0 431 while True: 432 try: 433 if points[i][2] is not points[i + 1][2]: 434 int = self._line_intersection(points[i][0], 435 points[i][2].points[points[i][1] + 1], points[i + 1][0], 436 points[i + 1][2].points[points[i + 1][1] - 1]) 437 if int and int[1] > 0 and int[0] > points[i][0][0] \ 438 and int[0] < points[i + 1][0][0]: 439 points.insert(i + 1, [int, None, None]) 440 i += 1 441 i += 1 442 except IndexError: 443 break 444 # take the maximum mu value for all points 445 for point in points: 446 point[0] = (point[0][0], max(self.mu(point[0][0]), other.mu(point[0][0]))) 447 # remove redundant points 448 while points[1][0][1] == 0.0: 449 del points[0] 450 while points[-2][0][1] == 0.0: 451 del points[-1] 452 i = 1 453 while True: 454 try: 455 if points[i][0][1] == points[i - 1][0][1] \ 456 and points[i][0][1] == points[i + 1][0][1]: 457 del points[i] 458 continue 459 i += 1 460 except IndexError: 461 break 462 return PolygonalFuzzyNumber([point[0] for point in points])
463
464 - def intersection(self, other):
465 """\ 466 Return the standard fuzzy intersection of two polygonal fuzzy numbers 467 as a new polygonal fuzzy number. 468 469 @param other: The other fuzzy number. 470 @type other: L{FuzzyNumber} 471 @return: The fuzzy intersection. 472 @rtype: L{PolygonalFuzzyNumber} 473 """ 474 other = other.to_polygonal() 475 # collect and sort all the existing points 476 points = [[point, i, self] for i, point in enumerate(self.points)] \ 477 + [[point, i, other] for i, point in enumerate(other.points)] 478 points.sort() 479 # take the minimum of duplicates 480 i = 0 481 while True: 482 try: 483 if points[i][0][0] == points[i + 1][0][0]: 484 if points[i][0][1] > points[i + 1][0][1]: 485 del points[i] 486 else: 487 del points[i + 1] 488 continue 489 i += 1 490 except IndexError: 491 break 492 # add intersection points 493 i = 0 494 while True: 495 try: 496 if points[i][2] is not points[i + 1][2]: 497 int = self._line_intersection(points[i][0], 498 points[i][2].points[points[i][1] + 1], points[i + 1][0], 499 points[i + 1][2].points[points[i + 1][1] - 1]) 500 if int and int[1] > 0 and int[0] > points[i][0][0] \ 501 and int[0] < points[i + 1][0][0]: 502 points.insert(i + 1, [int, None, None]) 503 i += 1 504 i += 1 505 except IndexError: 506 break 507 # take the minimum mu value for all points 508 for point in points: 509 point[0] = (point[0][0], min(self.mu(point[0][0]), other.mu(point[0][0]))) 510 # remove redundant points 511 while points[1][0][1] == 0.0: 512 del points[0] 513 while points[-2][0][1] == 0.0: 514 del points[-1] 515 i = 1 516 while True: 517 try: 518 if points[i][0][1] == points[i - 1][0][1] \ 519 and points[i][0][1] == points[i + 1][0][1]: 520 del points[i] 521 continue 522 i += 1 523 except IndexError: 524 break 525 return PolygonalFuzzyNumber([point[0] for point in points])
526
527 - def normalize(self):
528 """\ 529 Normalize this fuzzy number, so that its height is equal to 1.0. 530 """ 531 self.points = [(point[0], point[1] * (1.0 / self.height)) \ 532 for point in self.points]
533
534 - def to_polygonal(self):
535 """\ 536 Return this polygonal fuzzy number. 537 538 @return: This polygonal fuzzy number. 539 @rtype: L{PolygonalFuzzyNumber} 540 """ 541 return self
542
543 - def to_fuzzy_set(self, samplepoints=None):
544 """\ 545 Convert this polygonal fuzzy number to a discrete fuzzy set at the 546 specified sample points. If no sample points are specified, the 547 vertices of the polygonal fuzzy number will be used. 548 549 @param samplepoints: Set of points at which to sample the number. 550 @type samplepoints: C{set} of C{float} 551 @return: Result fuzzy set. 552 @rtype: L{fset.FuzzySet} 553 """ 554 if samplepoints is None: 555 samplepoints = [point[0] for point in self.points] 556 F = FuzzySet() 557 for point in samplepoints: 558 F.add(point, self.mu(point)) 559 return F
560
561 562 -class TrapezoidalFuzzyNumber(FuzzyNumber):
563 """\ 564 Trapezoidal fuzzy number class. 565 """
566 - def __init__(self, kernel=(0.0, 0.0), support=(0.0, 0.0)):
567 """\ 568 Constructor. 569 570 @param kernel: The kernel of the fuzzy number. 571 @type kernel: C{tuple} 572 @param support: The support of the fuzzy number. 573 @type support: C{tuple} 574 """ 575 if not (isinstance(kernel, tuple) and len(kernel) == 2) \ 576 or not (isinstance(support, tuple) and len(support) == 2): 577 raise TypeError('kernel and support must be 2-tuples') 578 self.kernel = RealRange(kernel) 579 self.support = RealRange(support) 580 if not self.kernel <= self.support: 581 raise ValueError('kernel range must be within support range') 582 self.height = 1.0 583 super(TrapezoidalFuzzyNumber, self).__init__()
584 585 @property
586 - def triangular(self):
587 """\ 588 Report if this is a triangular fuzzy number (kernel has zero size). 589 590 @rtype: C{bool} 591 """ 592 return self.kernel.size == 0
593
594 - def __add__(self, other):
595 """\ 596 Addition operation. 597 598 @param other: The other trapezoidal fuzzy number. 599 @type other: L{TrapezoidalFuzzyNumber} 600 @return: Sum of the trapezoidal fuzzy numbers. 601 @rtype: L{TrapezoidalFuzzyNumber} 602 """ 603 if not isinstance(other, TrapezoidalFuzzyNumber): 604 raise TypeError('operation only permitted between trapezoidal ' 605 'fuzzy numbers') 606 return self.__class__(self.kernel + other.kernel, 607 self.support + other.support)
608
609 - def __sub__(self, other):
610 """\ 611 Subtraction operation. 612 613 @param other: The other trapezoidal fuzzy number. 614 @type other: L{TrapezoidalFuzzyNumber} 615 @return: Difference of the trapezoidal fuzzy numbers. 616 @rtype: L{TrapezoidalFuzzyNumber} 617 """ 618 if not isinstance(other, TrapezoidalFuzzyNumber): 619 raise TypeError('operation only permitted between trapezoidal ' 620 'fuzzy numbers') 621 return self.__class__(self.kernel - other.kernel, 622 self.support - other.support)
623
624 - def mu(self, value):
625 """\ 626 Return the membership level of a value in the universal set domain of 627 the fuzzy number. 628 629 @param value: A value in the universal set. 630 @type value: C{float} 631 """ 632 if value in self.kernel: 633 return 1. 634 elif value > self.support[0] and value < self.kernel[0]: 635 return (value - self.support[0]) / \ 636 (self.kernel[0] - self.support[0]) 637 elif value < self.support[1] and value > self.kernel[1]: 638 return (self.support[1] - value) / \ 639 (self.support[1] - self.kernel[1]) 640 else: 641 return 0.
642
643 - def alpha(self, alpha):
644 """\ 645 Alpha cut function. Returns the interval within the fuzzy number whose 646 membership levels meet or exceed the alpha value. 647 648 @param alpha: The alpha value for the cut in [0, 1]. 649 @type alpha: C{float} 650 @return: The alpha cut interval. 651 @rtype: L{RealRange} 652 """ 653 return RealRange(((self.kernel[0] - self.support[0]) * alpha \ 654 + self.support[0], self.support[1] - \ 655 (self.support[1] - self.kernel[1]) * alpha))
656
657 - def to_polygonal(self):
658 """\ 659 Convert this trapezoidal fuzzy number into a polygonal fuzzy number. 660 661 @return: Result polygonal fuzzy number. 662 @rtype: L{PolygonalFuzzyNumber} 663 """ 664 points = [(self.support[0], 0.0), 665 (self.kernel[0], 1.0), 666 (self.kernel[1], 1.0), 667 (self.support[1], 0.0)] 668 return PolygonalFuzzyNumber(points)
669
670 671 -class TriangularFuzzyNumber(TrapezoidalFuzzyNumber):
672 """\ 673 Triangular fuzzy number class (special case of trapezoidal fuzzy number). 674 """
675 - def __init__(self, kernel=0.0, support=(0.0, 0.0)):
676 """\ 677 Constructor. 678 679 @param kernel: The kernel value of the fuzzy number. 680 @type kernel: C{float} 681 @param support: The support of the fuzzy number. 682 @type support: C{tuple} 683 """ 684 super(TriangularFuzzyNumber, self).__init__(kernel=(kernel, kernel), 685 support=support)
686
687 688 -class GaussianFuzzyNumber(FuzzyNumber):
689 """\ 690 Gaussian fuzzy number class. 691 """
692 - def __init__(self, mean, stddev):
693 """\ 694 Constructor. 695 696 @param mean: The mean (central value) of the Gaussian. 697 @type mean: C{float} 698 @param stddev: The standard deviation of the Gaussian. 699 @type stddev: C{float} 700 """ 701 self.mean = mean 702 self.stddev = stddev 703 self.height = 1.0 704 super(GaussianFuzzyNumber, self).__init__()
705
706 - def __add__(self, other):
707 """\ 708 Addition operation. 709 710 @param other: The other gaussian fuzzy number. 711 @type other: L{GaussianFuzzyNumber} 712 @return: Sum of the gaussian fuzzy numbers. 713 @rtype: L{GaussianFuzzyNumber} 714 """ 715 if not isinstance(other, GaussianFuzzyNumber): 716 raise TypeError('operation only permitted between Gaussian ' 717 'fuzzy numbers') 718 return self.__class__(self.mean + other.mean, 719 self.stddev + other.stddev)
720
721 - def __sub__(self, other):
722 """\ 723 Subtraction operation. 724 725 @param other: The other gaussian fuzzy number. 726 @type other: L{GaussianFuzzyNumber} 727 @return: Difference of the gaussian fuzzy numbers. 728 @rtype: L{GaussianFuzzyNumber} 729 """ 730 if not isinstance(other, GaussianFuzzyNumber): 731 raise TypeError('operation only permitted between Gaussian ' 732 'fuzzy numbers') 733 return self.__class__(self.mean - other.mean, 734 self.stddev + other.stddev)
735
736 - def mu(self, value):
737 """\ 738 Return the membership level of a value in the universal set domain of 739 the fuzzy number. 740 741 @param value: A value in the universal set. 742 @type value: C{float} 743 """ 744 return e ** -((value - self.mean) ** 2 / (2.0 * self.stddev ** 2)) \ 745 if value in self.support else 0.0
746 747 @property
748 - def kernel(self):
749 """\ 750 Return the kernel of the fuzzy number (range of values in the 751 universal set where membership degree is equal to one). 752 753 @rtype: L{RealRange} 754 """ 755 return RealRange((self.mean, self.mean))
756 757 @property
758 - def support(self):
759 """\ 760 Return the support of the fuzzy number (range of values in the 761 universal set where membership degree is nonzero). 762 763 @rtype: L{RealRange} 764 """ 765 return self.alpha(1e-10)
766
767 - def alpha(self, alpha):
768 """\ 769 Alpha cut function. Returns the interval within the fuzzy number whose 770 membership levels meet or exceed the alpha value. 771 772 @param alpha: The alpha value for the cut in [0, 1]. 773 @type alpha: C{float} 774 @return: The alpha cut interval. 775 @rtype: L{RealRange} 776 """ 777 if alpha < 1e-10: 778 alpha = 1e-10 779 edge = sqrt(-2.0 * (self.stddev ** 2) * log(alpha)) 780 return RealRange((self.mean - edge, self.mean + edge))
781
782 - def to_polygonal(self, np=20):
783 """\ 784 Convert this Gaussian fuzzy number into a polygonal fuzzy number 785 (approximate). 786 787 @param np: The number of points to interpolate per side (optional). 788 @type np: C{int} 789 @return: Result polygonal fuzzy number. 790 @rtype: L{PolygonalFuzzyNumber} 791 """ 792 if np < 0: 793 raise ValueError('number of points must be positive') 794 points = [] 795 start, end = self.support 796 increment = (self.mean - start) / float(np + 1) 797 points.append((start, 0.0)) 798 for i in range(1, np + 1): 799 value = start + i * increment 800 points.append((value, self.mu(value))) 801 points.append((self.mean, 1.0)) 802 for i in range(1, np + 1): 803 value = self.mean + i * increment 804 points.append((value, self.mu(value))) 805 points.append((end, 0.0)) 806 return PolygonalFuzzyNumber(points)
807