View Javadoc
1   /*
2    * Copyright (C) 2021 INRAE AgroClim
3    *
4    * This file is part of Indicators.
5    *
6    * Indicators is free software: you can redistribute it and/or modify
7    * it under the terms of the GNU General Public License as published by
8    * the Free Software Foundation, either version 3 of the License, or
9    * (at your option) any later version.
10   *
11   * Indicators is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14   * GNU General Public License for more details.
15   *
16   * You should have received a copy of the GNU General Public License
17   * along with Indicators. If not, see <http://www.gnu.org/licenses/>.
18   */
19  package fr.inrae.agroclim.indicators.model.function.normalization;
20  
21  import java.util.ArrayList;
22  import java.util.Arrays;
23  import java.util.List;
24  import java.util.StringJoiner;
25  import java.util.stream.Stream;
26  
27  import jakarta.xml.bind.annotation.XmlElement;
28  import jakarta.xml.bind.annotation.XmlRootElement;
29  import lombok.Getter;
30  import lombok.Setter;
31  import lombok.ToString;
32  
33  /**
34   * Normalize with several Linear function applied to intervals.
35   *
36   * Last change $Date$
37   *
38   * @author $Author$
39   * @version $Revision$
40   */
41  @XmlRootElement
42  @ToString
43  public final class MultiLinear extends NormalizationFunction {
44  
45      /**
46       * UUID for Serializable.
47       */
48      private static final long serialVersionUID = 4872847709393688047L;
49  
50      /**
51       * Linear functions on the related intervals.
52       */
53      @Getter
54      @Setter
55      @XmlElement(name = "interval")
56      private List<MultiLinearInterval> intervals = new ArrayList<>();
57  
58      /**
59       * Constructor with no args for Serializable.
60       */
61      public MultiLinear() {
62          // Do nothing
63      }
64  
65      @Override
66      public MultiLinear clone() {
67          final MultiLinear clone = new MultiLinear();
68          if (intervals != null && !intervals.isEmpty()) {
69              clone.setIntervals(new ArrayList<>());
70              intervals.forEach(interval -> clone.getIntervals().add(interval.clone()));
71          }
72          return clone;
73      }
74  
75      @Override
76      public String getFormulaMathML() {
77          final StringJoiner sj = new StringJoiner("\n");
78          sj.add("<mfenced open=\"{\" close=\"\">");
79          sj.add(" <mtable>");
80          final Stream<MultiLinearInterval> stream;
81          if (intervals != null) {
82              stream = intervals.stream();
83          } else {
84              final MultiLinearInterval interval = new MultiLinearInterval();
85              interval.setLinear(new Linear());
86              stream = Arrays.asList(interval).stream();
87          }
88          stream.filter(interval -> interval.getLinear() != null)
89          .forEach(interval -> {
90              sj.add("  <mtr>");
91              sj.add("   <mtd>");
92              sj.add(interval.getLinear().getFormulaMathML());
93              sj.add("   </mtd>");
94              sj.add("   <mtd>");
95              sj.add("     <mn>x</mn><mo>&isin;</mo><mn>[");
96              final Double iMin = interval.getMin();
97              final Double iMax = interval.getMax();
98              if (iMin != null) {
99                  sj.add(iMin.toString());
100             } else {
101                 sj.add("-∞");
102             }
103             sj.add("; ");
104             if (iMax != null) {
105                 sj.add(iMax.toString() + "[;");
106             } else {
107                 sj.add("+∞];");
108             }
109             sj.add("</mn>");
110             sj.add("   </mtd>");
111             sj.add("  </mtr>");
112         });
113         sj.add(" </mtable>");
114         sj.add("</mfenced>");
115         return sj.toString();
116     }
117 
118     @Override
119     public double normalize(final double value) {
120         if (intervals == null || intervals.isEmpty()) {
121             return 0;
122         }
123         for (final MultiLinearInterval interval : intervals) {
124             if (interval.matches(value)) {
125                 return interval.getLinear().normalize(value);
126             }
127         }
128         return 0;
129     }
130 
131 }