ACTS
Experiment-independent tracking
Loading...
Searching...
No Matches
quadratic_equation.hpp
1// This file is part of the ACTS project.
2//
3// Copyright (C) 2016 CERN for the benefit of the ACTS project
4//
5// This Source Code Form is subject to the terms of the Mozilla Public
6// License, v. 2.0. If a copy of the MPL was not distributed with this
7// file, You can obtain one at https://mozilla.org/MPL/2.0/.
8
9#pragma once
10
11// Project include(s)
12#include "detray/definitions/algebra.hpp"
13#include "detray/definitions/containers.hpp"
14#include "detray/definitions/detail/qualifiers.hpp"
15#include "detray/definitions/math.hpp"
16#include "detray/utils/invalid_values.hpp"
17
18// System include(s)
19#include <limits>
20
21namespace detray::detail {
22
23template <concepts::scalar scalar_t, typename = void>
25
31template <concepts::scalar scalar_t>
32 requires std::is_arithmetic_v<scalar_t>
33class quadratic_equation<scalar_t> {
34 public:
35 quadratic_equation() = delete;
36
43 DETRAY_HOST_DEVICE
45 const scalar_t a, const scalar_t b, const scalar_t c,
46 const scalar_t tolerance = std::numeric_limits<scalar_t>::epsilon()) {
47 // linear case
48 if (math::fabs(a) <= tolerance) {
49 if (math::fabs(b) <= tolerance) {
50 m_solutions = 0;
51 } else {
52 m_solutions = 1;
53 m_values[0] = -c / b;
54 }
55 } else {
56 const scalar_t discriminant{b * b - 4.f * a * c};
57 // If there is more than one solution, then a != 0 and q != 0
58 if (discriminant > tolerance) {
59 m_solutions = 2;
60 const scalar_t q{-0.5f *
61 (b + math::copysign(math::sqrt(discriminant), b))};
62 m_values = {q / a, c / q};
63 // Sort the two solutions
64 if (m_values[0] > m_values[1]) {
65 m_values = {m_values[1], m_values[0]};
66 }
67 }
68 // Only one solution and a != 0
69 else if (discriminant >= 0.f) {
70 m_solutions = 1;
71 m_values[0] = -0.5f * b / a;
72 }
73 // discriminant < 0 is not allowed, since all solutions should be
74 // real
75 }
76 }
77
81 constexpr int solutions() const { return m_solutions; }
83 constexpr scalar_t smaller() const { return m_values[0]; }
85 constexpr scalar_t larger() const { return m_values[1]; }
87
88 private:
90 int m_solutions{0};
92 darray<scalar_t, 2> m_values{detail::invalid_value<scalar_t>(),
93 detail::invalid_value<scalar_t>()};
94};
95
101template <concepts::scalar scalar_t>
102 requires(!std::is_arithmetic_v<scalar_t>)
104 public:
105 quadratic_equation() = delete;
106
112 DETRAY_HOST_DEVICE
113 constexpr quadratic_equation(const scalar_t &a, const scalar_t &b,
114 const scalar_t &c,
115 const scalar_t &tolerance = 1e-6f) {
116 // Linear case
117 auto one_sol = (math::fabs(a) <= tolerance);
118 m_solutions(one_sol) = 1.f;
119 m_values[0] = -c / b;
120
121 // Early exit
122 if (detray::detail::all_of(one_sol)) {
123 return;
124 }
125
126 const scalar_t discriminant = b * b - (4.f * a) * c;
127
128 const auto two_sol = (discriminant > tolerance);
129 one_sol = !two_sol && (discriminant >= 0.f);
130
131 // If there is more than one solution, then a != 0 and q != 0
132 if (detray::detail::any_of(two_sol)) {
133 m_solutions = 2.f;
134 m_solutions.setZeroInverted(two_sol);
135
136 const scalar_t q =
137 -0.5f * (b + math::copysign(math::sqrt(discriminant), b));
138
139 scalar_t first = q / a;
140 scalar_t second = c / q;
141 first.setZeroInverted(two_sol);
142 second.setZeroInverted(two_sol);
143
144 // Sort the solutions
145 const auto do_swap = (second < first);
146 if (detray::detail::all_of(do_swap)) {
147 m_values = {second, first};
148 } else if (detray::detail::none_of(do_swap)) {
149 m_values = {first, second};
150 } else {
151 const auto tmp = second;
152 second(do_swap) = first;
153 first(do_swap) = tmp;
154 m_values = {first, second};
155 }
156 }
157
158 // Only one solution and a != 0
159 if (detray::detail::any_of(one_sol)) {
160 scalar_t sol = 1.f;
161 scalar_t result = -0.5f * b / a;
162 sol.setZeroInverted(one_sol);
163 result.setZeroInverted(one_sol);
164
165 m_solutions += sol;
166 m_values[0] += result;
167 }
168 // discriminant < 0 is not allowed, since all solutions should
169 // be real
170 }
171
175 constexpr const auto &solutions() const { return m_solutions; }
177 constexpr const scalar_t &smaller() const { return m_values[0]; }
179 constexpr const scalar_t &larger() const { return m_values[1]; }
181
182 private:
185 scalar_t m_solutions = 0.f;
187 darray<scalar_t, 2> m_values{static_cast<scalar_t>(0.f),
188 static_cast<scalar_t>(0.f)};
189};
190
191template <typename S>
192quadratic_equation(const S a, const S &b, const S &c, const S &tolerance)
193 -> quadratic_equation<S>;
194
195} // namespace detray::detail
constexpr scalar_t smaller() const
Definition quadratic_equation.hpp:83
constexpr scalar_t larger() const
Definition quadratic_equation.hpp:85
constexpr const scalar_t & larger() const
Definition quadratic_equation.hpp:179
constexpr const scalar_t & smaller() const
Definition quadratic_equation.hpp:177
constexpr quadratic_equation(const scalar_t &a, const scalar_t &b, const scalar_t &c, const scalar_t &tolerance=1e-6f)
Solve the equation a*x^2 + b*x + c = 0 for SIMD coefficients.
Definition quadratic_equation.hpp:113
constexpr int solutions() const
Getters for the solution(s).
Definition quadratic_equation.hpp:81
constexpr const auto & solutions() const
Getters for the solution(s).
Definition quadratic_equation.hpp:175
constexpr quadratic_equation(const scalar_t a, const scalar_t b, const scalar_t c, const scalar_t tolerance=std::numeric_limits< scalar_t >::epsilon())
Solve the equation a*x^2 + b*x + c = 0 for arithmetic coefficients.
Definition quadratic_equation.hpp:44
Definition quadratic_equation.hpp:24
std::array< value_t, kDIM > darray
Fixed-size array container.
Definition containers.hpp:30