@@ -222,7 +222,7 @@ void MinimalRationalInterpolation::AddSolutionSample(double omega, const Complex
222222 z.push_back (omega);
223223}
224224
225- std::vector<double > MinimalRationalInterpolation::FindMaxError (int N) const
225+ std::vector<double > MinimalRationalInterpolation::FindMaxError (std:: size_t N) const
226226{
227227 // Return an estimate for argmax_z ||u(z) - V y(z)|| as argmin_z |Q(z)| with Q(z) =
228228 // sum_i q_z / (z - z_i) (denominator of the barycentric interpolation of u). The roots of
@@ -279,36 +279,40 @@ std::vector<double> MinimalRationalInterpolation::FindMaxError(int N) const
279279 // }
280280
281281 // Fall back to sampling Q on discrete points if no roots exist in [start, end].
282- if (std::abs (z_star[0 ]) == 0.0 )
282+ // TODO: currently we always us this. Consider other optimization above again.
283+
284+ // We could use priority queue here to keep the N lowest values. However, we don't use
285+ // std::priority_queue class since we want to have access to the vector and also binary
286+ // tree structure of heap class as rebalancing is excessive overhead for tiny size N.
287+ using q_t = std::pair<std::complex <double >, double >;
288+ std::vector<q_t > queue{};
289+ queue.reserve (N);
290+
291+ const std::size_t nr_sample = 1.0e6 ; // must be >= N
292+ const auto delta = (end - start) / nr_sample;
293+ for (double z_sample = start; z_sample <= end; z_sample += delta)
283294 {
284- const auto delta = (end - start) / 1.0e6 ;
285- std::vector<double > Q_star (N, mfem::infinity ());
286- while (start <= end)
295+ const double Q_sample = std::abs ((q.array () / (z_map.array () - z_sample)).sum ());
296+
297+ bool partial_full = (queue.size () < N);
298+ if (partial_full || Q_sample < queue.back ().second )
287299 {
288- const double Q = std::abs ((q.array () / (z_map.array () - start)).sum ());
289- for (int i = 0 ; i < N; i++)
300+ auto it_loc = std::upper_bound (queue.begin (), queue.end (), Q_sample,
301+ [](double q, const q_t &p2) { return q < p2.second ; });
302+ queue.insert (it_loc, std::make_pair (z_sample, Q_sample));
303+ if (!partial_full)
290304 {
291- if (Q < Q_star[i])
292- {
293- for (int j = N - 1 ; j > i; j--)
294- {
295- z_star[j] = z_star[j - 1 ];
296- Q_star[j] = Q_star[j - 1 ];
297- }
298- z_star[i] = start;
299- Q_star[i] = Q;
300- break ;
301- }
305+ queue.pop_back ();
302306 }
303- start += delta;
304307 }
305- MFEM_VERIFY (
306- N == 0 || std::abs (z_star[0 ]) > 0.0 ,
307- fmt::format (" Could not locate a maximum error in the range [{}, {}]!" , start, end));
308308 }
309+ MFEM_VERIFY (queue.size () == N,
310+ fmt::format (" Internal failure: queue should be size should be N={} (got {})" ,
311+ N, queue.size ()));
312+
309313 std::vector<double > vals (z_star.size ());
310- std::transform (z_star .begin (), z_star .end (), vals.begin (),
311- [](std:: complex < double > z ) { return std:: real (z ); });
314+ std::transform (queue .begin (), queue .end (), vals.begin (),
315+ [](const q_t &p ) { return p. first . real (); });
312316 return vals;
313317}
314318
0 commit comments