Fuzzy.h
1 /*
2 
3 MIT License
4 
5 Copyright (c) 2017 FMI Open Development / Markus Peura, first.last@fmi.fi
6 
7 Permission is hereby granted, free of charge, to any person obtaining a copy
8 of this software and associated documentation files (the "Software"), to deal
9 in the Software without restriction, including without limitation the rights
10 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 copies of the Software, and to permit persons to whom the Software is
12 furnished to do so, subject to the following conditions:
13 
14 The above copyright notice and this permission notice shall be included in all
15 copies or substantial portions of the Software.
16 
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 SOFTWARE.
24 
25 */
26 /*
27 Part of Rack development has been done in the BALTRAD projects part-financed
28 by the European Union (European Regional Development Fund and European
29 Neighbourhood Partnership Instrument, Baltic Sea Region Programme 2007-2013)
30 */
31 #ifndef FUZZY_H_
32 #define FUZZY_H_
33 
34 #include <drain/Log.h>
35 #include <cmath>
36 
37 #include "Functor.h"
38 #include "Range.h"
39 
40 
41 // using namespace std;
42 
43 namespace drain
44 {
45 
47 
53 template <class T> //,class T2>
54 class Fuzzifier : public UnaryFunctor
55 {
56 public:
57 
58  inline
59  Fuzzifier(const std::string & name, const std::string & description="", double scale=1.0, double bias=0.0) : UnaryFunctor(name, description, scale, bias),
60  INVERSE(false) {}; // srcMax(1.0),
61 
62  // Auto ok
63  // Fuzzifier(const Fuzzifier<T> & op) : UnaryFunctor(op), INVERSE(op.INVERSE){}
64 
65  virtual
66  inline
67  ~Fuzzifier(){};
68 
70  /*
71  virtual inline
72  void updateBean() const override {
73  updateScale();
74  }
75  */
76 
77  mutable
78  bool INVERSE;
79 
80 protected:
81 
82  inline
83  virtual
84  void updateScale() const {
85 
86  if (!INVERSE){
87  this->scaleFinal = scale;
88  this->biasFinal = bias;
89  }
90  else {
91  this->scaleFinal = -scale;
92  this->biasFinal = bias + scale;
93  }
94  }
95 
96  /*
97  inline
98  void setReferencesAndCopy(const BeanLike & b){
99  setReferences();
100  this->copy(b);
101  this->updateBean();
102  };
103  */
104 
105 private:
106 
107  //virtual
108  //void setReferences() = 0;
109 
110 };
111 
113 
131 template <class T> //,class T2>
132 class FuzzyStep : public Fuzzifier<T> {
133 
134 public:
135 
137 
143  FuzzyStep(T startPos = -1.0, T endPos = 1.0, double scale = 1.0, double bias = 0.0) : Fuzzifier<T>(__FUNCTION__, "Fuzzy step function.", scale, bias), span(1.0) {
144  this->parameters.link("position", this->range.tuple());
145  this->parameters.link("scale", this->scale);
146  this->parameters.link("bias", this->bias);
147  set(startPos, endPos, scale, bias);
148  };
149 
150  FuzzyStep(const FuzzyStep<T> & f) : Fuzzifier<T>(f), span(1.0){
151  this->parameters.copyStruct(f.getParameters(), f, *this);
152  updateBean();
153  }
154 
155  ~FuzzyStep(){};
156 
157  inline
158  void set(double rangeMin, double rangeMax, double scale=1.0, double bias=0.0){
159  this->range.min = rangeMin;
160  this->range.max = rangeMax;
161  this->setScale(scale, bias);
162  this->updateBean();
163  }
164 
165  inline
166  void set(const drain::Range<double> & r, double scale=1.0, double bias=0.0){
167  this->range.set(r);
168  this->setScale(scale, bias);
169  this->updateBean();
170  }
171 
172 
173 
174  virtual
175  inline
176  void updateBean() const override {
177 
178  drain::Logger mout(__FILE__, __FUNCTION__);
179 
180  this->INVERSE = (range.min > range.max);
181 
182  if (!this->INVERSE){
183  finalRange.min = range.min;
184  finalRange.max = range.max;
185  span = range.max - range.min;
186  }
187  else {
188  //cerr << "set INVERSE" << endl;
189  finalRange.min = range.max;
190  finalRange.max = range.min;
191  span = range.min - range.max;
192  }
193 
194  this->updateScale();
195 
196  mout.debug2(this->scaleFinal , ',' , this->biasFinal );
197 
198  }
199 
200  inline
201  virtual
202  double operator()(double x) const {
203 
204  if (x <= finalRange.min)
205  return this->biasFinal;
206  else if (x >= finalRange.max)
207  return this->biasFinal + this->scaleFinal;
208  else
209  return this->biasFinal + this->scaleFinal*(x-finalRange.min) / span; // div by undetectValue not possible, unless start==end
210 
211  }
212 
213  //std::pair<double,double> range;
214  drain::Range<double> range;
215 
216 protected:
217 
218  mutable double span;
219 
220  //
221  mutable
222  drain::Range<double> finalRange;
223  //std::pair<double,double> finalRange;
224 
225 
226 };
227 
229 
239 template <class T> //,class T2>
240 class FuzzyTriangle : public Fuzzifier<T> {
241 
242 public:
243 
244  FuzzyTriangle(double startPos=-1.0, double endPos=+1.0, double peakPos=0.0, double scale = 1.0, T bias = 0) : Fuzzifier<T>(__FUNCTION__, "Fuzzy triangle function.", scale, bias){ // : start(start), peak(peak), end(end), scale(scale), _spanLow(start-peak), _spanHigh(end-peak)
245  this->parameters.link("position", this->range.tuple());
246  this->parameters.link("peakPos", this->peakPos);
247  this->parameters.link("scale", this->scale);
248  this->parameters.link("bias", this->bias);
249 
250  set(startPos, endPos, peakPos, scale, bias);
251 
252  };
253 
254  FuzzyTriangle(drain::Range<double> range, double scale = 1.0, T bias = 0) : Fuzzifier<T>(__FUNCTION__, "Fuzzy triangle function.", scale, bias){ // : start(start), peak(peak), end(end), scale(scale), _spanLow(start-peak), _spanHigh(end-peak)
255  this->parameters.link("position", this->range.tuple());
256  this->parameters.link("peakPos", this->peakPos);
257  this->parameters.link("scale", this->scale);
258  this->parameters.link("bias", this->bias);
259 
260  set(range.min, range.max, (range.min+range.max)/2, scale, bias);
261 
262  }
263 
265  this->parameters.copyStruct(f.getParameters(), f, *this);
266  updateBean();
267  }
268 
269  ~FuzzyTriangle(){};
270 
272  // std::numeric_limits<double>::signaling_NaN()
273  inline
274  void set(double startPos, double endPos, double peakPos=0.0, double scale=1.0, double bias=0.0){ // todo join
275 
276  this->range.set(startPos, endPos);
277 
278  this->peakPos = peakPos;
279  /*
280  if (!std::isnan(peakPos))
281  this->peakPos = peakPos;
282  else
283  this->peakPos = (startPos + endPos) / 2.0;
284  */
285 
286  this->setScale(scale, bias); //
287  this->updateBean();
288  }
289 
290 
291  virtual
292  void updateBean() const override {
293 
294  if (!range.contains(peakPos))
295  peakPos = (range.min + range.max) / 2.0;
296 
297  this->INVERSE = (range.min > range.max);
298 
299  if (!this->INVERSE){
300  span.set(range.min - peakPos, range.max - peakPos);
301  }
302  else {
303  span.set(range.max - peakPos, range.min - peakPos);
304  }
305 
306  this->updateScale();
307 
308  }
309 
310  inline
311  virtual
312  double operator()(double x) const {
313 
314  x = x - peakPos;
315  if (x > span.max)
316  return this->biasFinal;
317  else if (x > 0.0)
318  return this->biasFinal + this->scaleFinal*(1.0 - x/span.max);
319  else if (x > span.min)
320  return this->biasFinal + this->scaleFinal*(1.0 - x/span.min);
321  else // x < spanHi
322  return this->biasFinal;
323 
324  };
325 
328 
330  mutable // adjusted if outside range
331  double peakPos = 0.0;
332 
333 
334 protected:
335 
336  mutable
337  drain::Range<double> span = {-1.0, +1.0};
338 
339 
340 };
341 
342 
343 
345 
362 template <class T>
363 class FuzzyBell : public Fuzzifier<T> {
364 
365 public:
366 
367  FuzzyBell(double location=0.0, double width=1.0, double scale = 1.0, double bias = 0.0) : Fuzzifier<T>(__FUNCTION__, "Fuzzy bell function.", scale, bias), widthInv(1.0) { // location(location), scale(scale), a(1.0/width), INVERSE(a<0.0) {};
368  //setReferences();
369  this->parameters.link("location", this->location = location);
370  this->parameters.link("width", this->width = width);
371  this->parameters.link("scale", this->scale = scale);
372  this->parameters.link("bias", this->bias = bias);
373  //set(location, width, scale, bias);
374  this->updateBean();
375  }
376 
377  FuzzyBell(const FuzzyBell & f) : Fuzzifier<T>(f) {
378  this->parameters.copyStruct(f.getParameters(), f, *this);
379  this->updateBean();
380  }
381 
382  virtual
383  ~FuzzyBell(){};
384 
385  void set(double location = 0.0, double width = 1.0, double scale=1.0, double bias=0.0){
386  this->location = location;
387  this->width = width;
388  this->setScale(scale, bias);
389  this->updateBean();
390  }
391 
392 
393  virtual
394  void updateBean() const override {
395  this->widthInv = 1.0/width;
396  this->INVERSE = (width<0.0);
397  this->updateScale();
398  }
399 
400  inline
401  virtual
402  double operator()(double x) const {
403 
404  x = widthInv * (x - this->location);
405  return this->biasFinal + this->scaleFinal/(1.0 + x*x);
406 
407  };
408 
409  double location;
410  double width;
411 
412 protected:
413 
414  //double scale;
415  mutable
416  double widthInv;
417 
418 
419 };
420 
422 
431 template <class T>
432 class FuzzyBell2 : public Fuzzifier<T> {
433 
434 public:
435 
436  FuzzyBell2(double location=0.0, double width=1.0, double scale = 1.0, double bias = 0.0) : Fuzzifier<T>(__FUNCTION__, "Fuzzy Gaussian-like bell function.", scale, bias) {
437  //setReferences();
438  this->parameters.link("location", this->location = location);
439  this->parameters.link("width", this->width = width);
440  this->parameters.link("scale", this->scale = scale);
441  this->parameters.link("bias", this->bias = bias);
442  updateBean();
443  };
444 
445  FuzzyBell2(const FuzzyBell2 & f) : Fuzzifier<T>(f) {
446  this->parameters.copyStruct(f.getParameters(), f, *this);
447  updateBean();
448  }
449 
450  virtual
451  ~FuzzyBell2(){};
452 
453  //inline
454  void set(double location = 0.0, double width = 1.0, double scale=1.0, double bias=0.0) {
455  this->location = location;
456  this->width = width;
457  this->setScale(scale, bias);
458  updateBean();
459  }
460 
461 
462 
463  inline
464  virtual
465  double operator()(double x) const {
466  x = steepness * (x - location);
467  x = 1.0 + x*x;
468  return this->biasFinal + this->scaleFinal/(x*x); // *x*x*x*x
469 
470  };
471 
472 
473  virtual
474  void updateBean() const override {
475  steepness = sqrt(sqrt(2.0)-1.0)/width;
476  this->INVERSE = (width<0.0);
477  this->updateScale();
478  }
479 
480  double location;
481  double width;
482 
483 protected:
484 
485  mutable
486  double steepness;
487 
488 
489 };
490 
492 
496 template <class T> //,class T2>
497 class FuzzySigmoid : public Fuzzifier<T> {
498 
499 public:
500 
501  FuzzySigmoid(double location=0.0, double width=1.0, double scale=1.0, double bias=0.0) :
502  Fuzzifier<T>(__FUNCTION__, "Fuzzy sign function.", scale, bias), absWidth(0.0) {
503  this->parameters.link("location", this->location = location);
504  this->parameters.link("width", this->width = width);
505  this->parameters.link("scale", this->scale = scale);
506  this->parameters.link("bias", this->bias = bias);
507  this->updateBean();
508  };
509 
510 
511  FuzzySigmoid(const FuzzySigmoid & f) : Fuzzifier<T>(f), absWidth(f.absWidth) {
512  this->parameters.copyStruct(f.getParameters(), f, *this);
513  //this->setReferencesAndCopy(f);
514  //set(location, width, scale, bias);
515  this->updateBean();
516  }
517 
518  ~FuzzySigmoid(){};
519 
520  inline
521  void set(double location=0.0, double width=1.0, double scale=1.0, double bias=0.0){
522  this->location = location;
523  this->width = width;
524  this->setScale(scale, bias); //
525  this->updateBean();
526  }
527 
528 
529  inline
530  virtual
531  double operator()(double x) const {
532  x = x - this->location;
533  if (x > 0.0)
534  return this->biasFinal + this->scaleFinal * x/(absWidth + x);
535  else if (x < 0.0)
536  return this->biasFinal + this->scaleFinal * x/(absWidth - x);
537  else // x==0.0
538  return this->biasFinal;
539  };
540 
541  double location;
542  double width;
543 
544 protected:
545 
546  inline
547  virtual
548  void updateScale() const {
549 
550  this->INVERSE = (width<0.0);
551 
552  if (!this->INVERSE){
553  this->scaleFinal = +this->scale;
554  this->biasFinal = this->bias;
555  this->absWidth = width;
556  }
557  else {
558  this->scaleFinal = -this->scale;
559  this->biasFinal = this->bias;
560  this->absWidth = -width;
561  }
562  }
563 
564  mutable
565  double absWidth;
566 
567 
568 };
569 
571 
575 template <class T>
576 class FuzzyStepsoid : public Fuzzifier<T> {
577 
578 public:
579 
580  FuzzyStepsoid(double location=0.0, double width=1.0, double scale=1.0, double bias=0.0) : Fuzzifier<T>(__FUNCTION__, "Fuzzy step function", scale, bias), widthFinal(1.0) {
581  //this->setReferences();
582  //this->parameters.link("location", this->range.tuple()); consider
583  this->parameters.link("location", this->location = location);
584  this->parameters.link("width", this->width = width);
585  this->parameters.link("scale", this->scale = scale);
586  this->parameters.link("bias", this->bias = bias);
587  this->updateBean();
588  };
589 
590  FuzzyStepsoid(const FuzzyStepsoid & f): Fuzzifier<T>(f), widthFinal(f.widthFinal) {
591  this->parameters.copyStruct(f.getParameters(), f, *this);
592  this->updateBean();
593  }
594 
595  ~FuzzyStepsoid(){};
596 
597  inline
598  void set(double location=0.0, double width=1.0, double scale=1.0, double bias=0.0){
599  this->location = location;
600  this->width = width;
601  this->setScale(scale, bias); //
602  this->updateBean();
603  }
604 
605  virtual
606  void updateBean() const override {
607  this->INVERSE = (width<0.0);
608  this->updateScale();
609  widthFinal = fabs(width);
610  //widthFinal = this->INVERSE ? -width : width; // abs(width) FOR INT!
611  //std::cerr << this->getName() << ' ' << this->getParameters() << '\n';
612  //std::cerr << location << ',' << width << ',' << widthFinal << ',' << (int)this->INVERSE << '\n';
613  }
614 
615  inline
616  virtual
617  double operator()(double x) const {
618  x = x - this->location;
619  if (x > 0.0)
620  return this->biasFinal + this->scaleFinal * x/(widthFinal + x); // was: biasFinal+ ...
621  else if (x < 0.0)
622  return this->biasFinal + this->scaleFinal * x/(widthFinal - x);
623  else // x==0.0
624  return this->biasFinal;
625  };
626 
627  double location;
628  double width;
629 
630 protected:
631 
632  inline
633  virtual
634  void updateScale() const {
635 
636  //const double SCALE = (this->dstMax != 0.0) ? this->dstMax : 1.0;
637 
638  if (!this->INVERSE){
639  this->scaleFinal = +0.5*this->scale; //*SCALE;
640  this->biasFinal = this->bias + 0.5*this->scale; // )*SCALE;
641  }
642  else {
643  this->scaleFinal = -0.5*this->scale; // *SCALE;
644  this->biasFinal = this->bias + 0.5*this->scale; // )*SCALE;
645  }
646 
647  }
648 
649  mutable
650  double widthFinal;
651 
652 };
653 
655 
659 template <class T>
660 class FuzzyTwinPeaks : public Fuzzifier<T> {
661 
662 public:
663 
664  FuzzyTwinPeaks(double location=0.0, double width=1.0, double scale = 1.0, double bias = 0.0) :
665  Fuzzifier<T>(__FUNCTION__, "Fuzzy function of two peaks.", scale, bias) {
667  this->parameters.link("location", this->location = location);
668  this->parameters.link("width", this->width = width);
669  this->parameters.link("scale", this->scale = scale);
670  this->parameters.link("bias", this->bias = bias);
671  this->updateBean();
672  };
673 
674  FuzzyTwinPeaks(const FuzzyTwinPeaks & f) : Fuzzifier<T>(__FUNCTION__, "Fuzzy function of two peaks.") {
675  this->parameters.copyStruct(f.getParameters(), f, *this);
676  this->updateBean();
677  }
678 
679  virtual
680  ~FuzzyTwinPeaks(){};
681 
682  //inline
683  void set(double location = 0.0, double width = 1.0, double scale=1.0, double bias=0.0) {
684  this->location = location;
685  this->width = width;
686  this->setScale(scale, bias);
687  updateBean();
688  }
689 
690  virtual
691  void updateBean() const override {
692  this->INVERSE = (width<0.0);
693  steepness = 1.0/fabs(width);
694  this->updateScale();
695  }
696 
697 
698  virtual inline
699  double operator()(double x) const {
700  x = steepness * (x - location);
701  return this->biasFinal + this->scaleFinal*(x*x)/(1.0 + x*x*x*x);
702  };
703 
704 
705 
706  double location;
707  double width;
708 
709 protected:
710 
711 
712  virtual inline
713  void updateScale() const {
714 
715  if (this->width >= 0.0){
716  this->scaleFinal = +2.0*this->scale;
717  this->biasFinal = this->bias;
718  }
719  else {
720  this->scaleFinal = -2.0*this->scale;
721  this->biasFinal = this->bias;
722  }
723  }
724 
725  mutable
726  double steepness;
727 
728 
729 };
730 
731 
732 } // drain::
733 
734 #endif /* FUZZY_H_*/
735 
736 // Drain
double scale
Relative scale, typically 1. Optional.
Definition: Functor.h:99
double scaleFinal
Scaling factor after encodings of src and dst images are known.
Definition: Functor.h:106
double bias
"Relative" bias, typically 0. Optional.
Definition: Functor.h:102
virtual void updateBean() const override
Called after setParameters()
Definition: Functor.h:65
double biasFinal
Scaling factor after encodings of src and dst images are known.
Definition: Functor.h:110
A base class for fuzzy functions; also an unary functor.
Definition: Fuzzy.h:55
bool INVERSE
Updates internal variables. Should be called after modifying public members.
Definition: Fuzzy.h:67
A smooth symmetric peak function that resembles the Gaussian bell curve. Diminishes quicker than Fuzz...
Definition: Fuzzy.h:432
virtual void updateBean() const override
Called after setParameters()
Definition: Fuzzy.h:474
A smooth symmetric peak function that resembles the Gaussian bell curve.
Definition: Fuzzy.h:363
virtual void updateBean() const override
Called after setParameters()
Definition: Fuzzy.h:394
A smooth step function, by default from -1.0 to +1.0.
Definition: Fuzzy.h:497
A basic, linear transition from 0 to scale between (start) and (end) .
Definition: Fuzzy.h:132
virtual void updateBean() const override
Called after setParameters()
Definition: Fuzzy.h:176
FuzzyStep(T startPos=-1.0, T endPos=1.0, double scale=1.0, double bias=0.0)
Constructor.
Definition: Fuzzy.h:143
A smooth step function between 0.0 and 1.0. Increasing (decreasing) with positive (negative) width....
Definition: Fuzzy.h:576
virtual void updateBean() const override
Called after setParameters()
Definition: Fuzzy.h:606
A basic triangular peak function with linear around the peak.
Definition: Fuzzy.h:240
double peakPos
Peak position.
Definition: Fuzzy.h:331
virtual void updateBean() const override
Called after setParameters()
Definition: Fuzzy.h:292
void set(double startPos, double endPos, double peakPos=0.0, double scale=1.0, double bias=0.0)
Sets the parameters of the membership function.
Definition: Fuzzy.h:274
drain::Range< double > range
Start and end position.
Definition: Fuzzy.h:324
A function taking shape of two peaks, with a zero in the middle .
Definition: Fuzzy.h:660
virtual void updateBean() const override
Called after setParameters()
Definition: Fuzzy.h:691
FuzzyTwinPeaks(double location=0.0, double width=1.0, double scale=1.0, double bias=0.0)
Definition: Fuzzy.h:664
LogSourc e is the means for a function or any program segment to "connect" to a Log.
Definition: Log.h:308
Logger & debug2(const TT &... args)
Debug information.
Definition: Log.h:686
void copyStruct(const ReferenceMap &m, const T &src, T &dst, extLinkPolicy policy=RESERVE)
Experimental. Copies references and values of a structure to another.
Definition: ReferenceMap.h:399
Definition: DataSelector.cpp:1277
Definition: Functor.h:116