Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2002-2024 German Aerospace Center (DLR) and others.
4 : // This program and the accompanying materials are made available under the
5 : // terms of the Eclipse Public License 2.0 which is available at
6 : // https://www.eclipse.org/legal/epl-2.0/
7 : // This Source Code may also be made available under the following Secondary
8 : // Licenses when the conditions for such availability set forth in the Eclipse
9 : // Public License 2.0 are satisfied: GNU General Public License, version 2
10 : // or later which is available at
11 : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 : /****************************************************************************/
14 : /// @file CharacteristicMap.h
15 : /// @author Kevin Badalian (badalian_k@mmp.rwth-aachen.de)
16 : /// @date 2021-02
17 : ///
18 : // Characteristic map for vehicle type parameters as needed by the MMPEVEM model
19 : // Teaching and Research Area Mechatronics in Mobile Propulsion (MMP), RWTH Aachen
20 : /****************************************************************************/
21 :
22 :
23 : /******************************************************************************
24 : * ============================= Example Usage ============================== *
25 : ******************************************************************************
26 : * *
27 : * Assume a function f which maps from R^2 to R^1 according to... *
28 : * *
29 : * | 0 | 1 | 2 | 3 | 4 -> x_1 *
30 : * ----|------------------------ *
31 : * -1 | 1 | 3 | 1 | -2 | *
32 : * 1 | 1 | -2 | -3 | 7 | 5 *
33 : * 3 | -2 | -1 | 0 | 1 | 3 *
34 : * 5 | | 0 | 8 | 4 | 4 *
35 : * *
36 : * | *
37 : * v *
38 : * x_2 *
39 : * *
40 : * ... so that, for example, f(3, 1) = 7. Note that f is not defined at *
41 : * (4, -1) and (0, 5). There are two ways to create a CharacteristicMap *
42 : * object for this function. *
43 : * 1) Using the standard constructor: *
44 : * // Axes *
45 : * std::vector<std::vector<double>> axes; *
46 : * axes.push_back(std::vector<double>{0, 1, 2, 3, 4}); // Axis 1 *
47 : * axes.push_back(std::vector<double>{-1, 1, 3, 5}); // Axis 2 *
48 : * // Flattened row-major map entries *
49 : * std::vector<double> flattenedMap{1, 3, 1, -2, std::nan(""), *
50 : * 1, -2, -3, 7, 5, -2, -1, 0, 1, 3, std::nan(""), 0, 8, 4, 4}; *
51 : * *
52 : * CharacteristicMap map1(2, // Mapping from R^2... *
53 : * 1, // ... to R^1 *
54 : * axes, *
55 : * flattenedMap); *
56 : * *
57 : * 2) Using a string-encoding of the map: *
58 : * CharacteristicMap map2("2,1|0,1,2,3,4;-1,1,3,5|1,3,1,-2,nan," *
59 : * "1,-2,-3,7,5,-2,-1,0,1,3,nan,0,8,4,4"); *
60 : * *
61 : * See below for an in-depth explanation of the format. *
62 : * *
63 : * *
64 : * To evaluate the map at, for instance, p = (2.2, 2), one must call: *
65 : * std::vector<double> res = map1.eval(std::vector<double>{2.2, 2}, // p *
66 : * 1e-3); // eps *
67 : * if(std::isnan(res[0])) *
68 : * std::cout << "[WARNING] Couldn't evaluate the map." << std::endl; *
69 : * else *
70 : * std::cout << "res = " << res[0] << std::endl; *
71 : * *
72 : * The epsilon value is used for numerical reasons and decides how much a *
73 : * point must deviate from its nearest neighbor before linear interpolation *
74 : * is applied or when a point is considered outside of the map. The default *
75 : * is 1e-6. *
76 : * *
77 : * *
78 : * The string-encoding of a CharacteristicMap that maps from R^m to R^n is *
79 : * formally defined as *
80 : * "m,n|A_1[1],A_1[2],...,A_1[l1];A_2[1],A_2[2],...,A_2[l2];...;\ *
81 : * A_m[1],A_m[2],...,A_m[lm]|\ *
82 : * M_flat[1],M_flat[2],...,M_flat[l1*l2*...*lm]" *
83 : * where A_i[j] denotes the j-th value of the i-th axis (which has li values *
84 : * total) and M_flat[i] stands for the i-th entry in the row-major flattened *
85 : * map. To be more specific, given a map M, its flattened version is *
86 : * computed as follows (using pseudo code): *
87 : * M_flat = "" *
88 : * for i_m in {1,2,...,lm}: // Last axis *
89 : * ... *
90 : * for i_2 in {1,2,...,l2}: // Second axis *
91 : * for i_1 in {1,2,...,l1}: // First axis (i.e. row axis) *
92 : * for d in {1,2,...,n}: // Image dimensions *
93 : * M_flat += M[i_1,i_2,...,i_m][d] + "," *
94 : * removeTrailingComma(M_flat) *
95 : * *
96 : ******************************************************************************/
97 : #pragma once
98 :
99 : #include <vector>
100 : #include <string>
101 :
102 :
103 : /**
104 : * \class CharacteristicMap
105 : * \brief The purpose of this class is to store a characteristic map (German:
106 : * Kennfeld) of arbitrary dimensions and to provide functions in order to
107 : * evaluate/interpolate points in it.
108 : */
109 319509 : class CharacteristicMap {
110 : private:
111 : /// Dimension of the map's domain
112 : int domainDim;
113 :
114 : /// Image dimension of the map
115 : int imageDim;
116 :
117 : /// Vector containing the values along each domain axis in ascending order
118 : std::vector<std::vector<double>> axes;
119 :
120 : /// Flattened map entries
121 : std::vector<double> flattenedMap;
122 :
123 : /// Stride for each domain dimension in the flattened map
124 : std::vector<int> strides;
125 :
126 : /**
127 : * \brief Determine the stride for each map dimension in the flattened map.
128 : */
129 : void determineStrides();
130 :
131 : /**
132 : * \brief Compute the index of a map entry in the flattened map.
133 : *
134 : * \param[in] ref_idxs Non-flattened map indices
135 : * \returns Flattened map index
136 : * \throws std::runtime_error
137 : */
138 : int calcFlatIdx(const std::vector<int>& ref_idxs) const;
139 :
140 : /**
141 : * \brief Determine the indices of the nearest neighbor of a point in the map.
142 : *
143 : * A point has no such neighbor if it lies outside of the range of an axis
144 : * with respect to some epsilon.
145 : * \param[in] ref_p A point
146 : * \param[out] ref_idxs A vector into which the indices shall be written
147 : * \param[in] eps An epsilon value
148 : * \returns 0 if a nearest neighbor could be found, else -1
149 : * \throws std::runtime_error
150 : */
151 : int findNearestNeighborIdxs(const std::vector<double>& ref_p,
152 : std::vector<int>& ref_idxs, double eps = 1e-6) const;
153 :
154 : /**
155 : * \brief Access a map entry using its indices.
156 : *
157 : * \param[in] ref_idxs A vector containing indices
158 : * \returns A vector containing the image values of the map at the specified
159 : * location
160 : * \throws std::runtime_error
161 : */
162 : std::vector<double> at(const std::vector<int>& ref_idxs) const;
163 :
164 :
165 :
166 : public:
167 : /**
168 : * \brief Constructor
169 : *
170 : * \param[in] domainDim The map's domain dimension
171 : * \param[in] imageDim The map's image dimension
172 : * \param[in] ref_axes A vector of vectors containing the entries of their
173 : * respective axes in ascending order
174 : * \param[in] ref_flattenedMap The row-major flattened entries of the map
175 : * (i.e. the map is flattened along its first axis)
176 : * \throws std::runtime_error
177 : */
178 : CharacteristicMap(int domainDim, int imageDim,
179 : const std::vector<std::vector<double>>& ref_axes,
180 : const std::vector<double>& ref_flattenedMap);
181 :
182 : /**
183 : * \brief Constructor
184 : *
185 : * \param[in] ref_mapString A string representation of a characteristic map
186 : * (cf. example at the top of the file)
187 : * throws std::runtime_error
188 : */
189 : CharacteristicMap(const std::string& ref_mapString);
190 :
191 : /**
192 : * \brief Encode the map as a string.
193 : *
194 : * \returns A string representation of the characteristic map (cf. example at
195 : * the top of the file)
196 : */
197 : std::string toString() const;
198 :
199 : /**
200 : * \brief Get the dimension of the map's domain.
201 : *
202 : * \returns The domain's dimension
203 : */
204 : int getDomainDim() const;
205 :
206 : /**
207 : * \brief Get the image dimension of the map.
208 : *
209 : * \returns The image dimension of the characteristic map
210 : */
211 : int getImageDim() const;
212 :
213 : /**
214 : * \brief Evaluate a point in the map using linear interpolation.
215 : *
216 : * Please note that the result may contain NaNs. That happens when...
217 : * a) ... the point in question has no nearest neighbor (that is, it lies
218 : * outside of the domain). In that case, all entries of the vector are set
219 : * to NaN.
220 : * b) ... an image value of the nearest neighbor is NaN. Then, the result is
221 : * also NaN in that image dimension.
222 : * c) ... evaluation would require interpolating with a support point which is
223 : * NaN in an image dimension. The corresponding result entry is set to NaN
224 : * in that case.
225 : * \param[in] ref_p A point
226 : * \param[in] eps An epsilon value
227 : * \returns The (interpolated) image values of the map at the specified point
228 : * \throws std::runtime_error
229 : */
230 : std::vector<double> eval(const std::vector<double>& ref_p,
231 : double eps = 1e-6) const;
232 : };
|