libsemigroups  v3.5.5
C++ library for semigroups and monoids
Loading...
Searching...
No Matches
constants.hpp
1//
2// libsemigroups - C++ library for semigroups and monoids
3// Copyright (C) 2019-2026 James D. Mitchell
4//
5// This program is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// This program is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with this program. If not, see <http://www.gnu.org/licenses/>.
17//
18//
19// This file contains functionality for various constant values used in
20// libsemigroups.
21
22// TODO(later)
23// 1. NegativeInfinity could be comparable with unsigned integers (always <).
24// 2. specialisation of operator<< for ostringstream for better printing. I
25// couldn't immediately get this to work.
26
27#ifndef LIBSEMIGROUPS_CONSTANTS_HPP_
28#define LIBSEMIGROUPS_CONSTANTS_HPP_
29
30#include <cinttypes> // for int64_t
31#include <limits> // for numeric_limits
32#include <type_traits> // for is_integral
33
34namespace libsemigroups {
35 namespace detail {
36
37 struct Min {
38 template <typename T>
39 constexpr T operator()() const noexcept {
40 static_assert(std::is_integral_v<T>,
41 "can only call Min with an integral type");
43 }
44 };
45
46 struct Max {
47 template <typename T>
48 constexpr T operator()() const noexcept {
49 static_assert(std::is_integral_v<T>,
50 "can only call Max with an integral type");
52 }
53 };
54
55 template <int64_t TOffset, typename TMaxOrMin>
56 struct Constant {
57 static_assert(std::is_same_v<TMaxOrMin, Max>
58 || std::is_same_v<TMaxOrMin, Min>,
59 "template parameter TMaxOrMin must be Max or Min");
60
61 Constant() = default;
62 Constant(Constant const&) = default;
63 Constant(Constant&&) = default;
64 Constant& operator=(Constant const&) = default;
65 Constant& operator=(Constant&&) = default;
66 ~Constant() = default;
67
68 template <typename T, typename = std::enable_if_t<!std::is_enum_v<T>, T>>
69 constexpr operator T() const noexcept {
70 static_assert(
71 std::is_integral_v<T>
72 && (std::is_signed_v<T> || std::is_same_v<TMaxOrMin, Max>),
73 "the template parameter T must be an integral type, and either "
74 "unsigned or the template parameter TMaxOrMin must be Max.");
75 return TMaxOrMin().template operator()<T>() + TOffset;
76 }
77 };
78 } // namespace detail
79
81 // Constant values
83
90
95 using Undefined = detail::Constant<0, detail::Max>;
96
101 using PositiveInfinity = detail::Constant<-1, detail::Max>;
102
107 using LimitMax = detail::Constant<-2, detail::Max>;
108
113 using NegativeInfinity = detail::Constant<0, detail::Min>;
114
122 extern Undefined const UNDEFINED;
123
134
143 extern LimitMax const LIMIT_MAX;
144
154
156 // Operators for all constants
158
159 // Note that for some reason Catch requires that the comparison functions are
160 // in the namespace detail.
161
162#ifndef LIBSEMIGROUPS_PARSED_BY_DOXYGEN
163 namespace detail {
164
165 // operator==
166 // No SFINAE required, since the functions delegated to don't exist.
167 template <int64_t R, typename S, typename T>
168 constexpr bool operator==(Constant<R, S> const& lhs,
169 T const& rhs) noexcept {
170 return lhs.operator T() == rhs;
171 }
172
173 template <int64_t R, typename S, typename T>
174 constexpr bool operator==(T const& lhs,
175 Constant<R, S> const& rhs) noexcept {
176 return rhs.operator T() == lhs;
177 }
178
179 template <int64_t R1, typename S1, int64_t R2, typename S2>
180 constexpr bool operator==(Constant<R1, S1> const&,
181 Constant<R2, S2> const&) noexcept {
182 return std::is_same_v<S1, S2> && R1 == R2;
183 }
184
185 // operator!=
186 // No SFINAE required, since the functions delegated to don't exist.
187 template <int64_t R, typename S, typename T>
188 constexpr bool operator!=(Constant<R, S> const& lhs,
189 T const& rhs) noexcept {
190 return !(lhs == rhs);
191 }
192
193 template <int64_t R, typename S, typename T>
194 constexpr bool operator!=(T const& lhs,
195 Constant<R, S> const& rhs) noexcept {
196 return !(lhs == rhs);
197 }
198
199 template <int64_t R1, typename S1, int64_t R2, typename S2>
200 constexpr bool operator!=(Constant<R1, S1> const& lhs,
201 Constant<R2, S2> const& rhs) noexcept {
202 return !(lhs == rhs);
203 }
204
205 // operator>
206 // No SFINAE required, since the functions delegated to don't exist.
207 template <int64_t R, typename S, typename T>
208 constexpr bool operator>(Constant<R, S> const& lhs, T const& rhs) noexcept {
209 return rhs < lhs;
210 }
211
212 template <int64_t R, typename S, typename T>
213 constexpr bool operator>(T const& lhs, Constant<R, S> const& rhs) noexcept {
214 return rhs < lhs;
215 }
216
217 template <int64_t R, typename S>
218 constexpr bool operator>(Constant<R, S> const&,
219 Constant<R, S> const&) noexcept {
220 return false;
221 }
222
223 template <int64_t R, typename S>
224 constexpr bool operator<(Constant<R, S> const&,
225 Constant<R, S> const&) noexcept {
226 return false;
227 }
228 // No further operator< for Constant and Constant unless given explicitly
229
231 // Operators for specific constants
233
234 // PositiveInfinity is not less than any integral value, or
235 // NegativeInfinity.
236 template <typename T, typename SFINAE = bool>
237 constexpr auto operator<(PositiveInfinity const&, T const&) noexcept
238 -> std::enable_if_t<std::is_integral_v<T>
239 || std::is_same_v<NegativeInfinity, T>,
240 SFINAE> {
241 return false;
242 }
243
244 // Every integral value, and negative infinity, is less than
245 // PositiveInfinity.
246 template <typename T, typename SFINAE = bool>
247 constexpr auto operator<(T const&, PositiveInfinity const&) noexcept
248 -> std::enable_if_t<std::is_integral_v<T>
249 || std::is_same_v<NegativeInfinity, T>,
250 SFINAE> {
251 return true;
252 }
253
254 // NegativeInfinity is less than every integral value.
255 template <typename T, typename SFINAE = bool>
256 constexpr auto operator<(NegativeInfinity const&, T const&) noexcept
257 -> std::enable_if_t<std::is_integral_v<T>, SFINAE> {
258 return true;
259 }
260
261 // No integral value is less than NegativeInfinity.
262 template <typename T, typename SFINAE = bool>
263 constexpr auto operator<(T const&, NegativeInfinity const&) noexcept
264 -> std::enable_if_t<std::is_integral_v<T>, SFINAE> {
265 return false;
266 }
267
268 // LimitMax is compared by implicit conversion with any integral value.
269 template <typename T, typename SFINAE = bool>
270 constexpr auto operator<(LimitMax const& lhs, T const& rhs) noexcept
271 -> std::enable_if_t<std::is_integral_v<T>, SFINAE> {
272 return lhs.operator T() < rhs;
273 }
274
275 // LimitMax is compared by implicit conversion with any integral value.
276 template <typename T, typename SFINAE = bool>
277 constexpr auto operator<(T const& lhs, LimitMax const& rhs) noexcept
278 -> std::enable_if_t<std::is_integral_v<T>, SFINAE> {
279 return lhs < rhs.operator T();
280 }
281
282 template <typename T, typename SFINAE = T>
283 constexpr auto operator-(LimitMax const& lhs, T const& rhs) noexcept
284 -> std::enable_if_t<std::is_integral_v<T>, SFINAE> {
285 return lhs.operator T() - rhs;
286 }
287
288 template <typename T, typename SFINAE = T>
289 constexpr auto operator-(T const& lhs, LimitMax const& rhs) noexcept
290 -> std::enable_if_t<std::is_integral_v<T>, SFINAE> {
291 return lhs - rhs.operator T();
292 }
293
294 // operator>= and operator<= for PositiveInfinity
295 // PositiveInfinity is always greater than or equal to any integral.
296 template <typename T, typename SFINAE = bool>
297 constexpr auto operator>=(PositiveInfinity const&, T const&) noexcept
298 -> std::enable_if_t<std::is_integral_v<T>
299 || std::is_same_v<NegativeInfinity, T>,
300 SFINAE> {
301 return true;
302 }
303
304 // PositiveInfinity is equal to itself.
305 constexpr bool operator>=(PositiveInfinity const&,
306 PositiveInfinity const&) noexcept {
307 return true;
308 }
309
310 // PositiveInfinity is never less than or equal to any integral.
311 template <typename T, typename SFINAE = bool>
312 constexpr auto operator>=(T const&, PositiveInfinity const&) noexcept
313 -> std::enable_if_t<std::is_integral_v<T>
314 || std::is_same_v<NegativeInfinity, T>,
315 SFINAE> {
316 return false;
317 }
318
319 // An integral is never greater than or equal to PositiveInfinity.
320 template <typename T, typename SFINAE = bool>
321 constexpr auto operator<=(PositiveInfinity const&, T const&) noexcept
322 -> std::enable_if_t<std::is_integral_v<T>
323 || std::is_same_v<NegativeInfinity, T>,
324 SFINAE> {
325 return false;
326 }
327
328 // PositiveInfinity is equal to itself.
329 constexpr bool operator<=(PositiveInfinity const&,
330 PositiveInfinity const&) noexcept {
331 return true;
332 }
333
334 // PositiveInfinity is always greater than or equal to any integral.
335 template <typename T, typename SFINAE = bool>
336 constexpr auto operator<=(T const&, PositiveInfinity const&) noexcept
337 -> std::enable_if_t<std::is_integral_v<T>
338 || std::is_same_v<NegativeInfinity, T>,
339 SFINAE> {
340 return true;
341 }
342
343 // operator>= and operator<= for NegativeInfinity
344 // NegativeInfinity is never greater than or equal to any integral value.
345 template <typename T, typename SFINAE = bool>
346 constexpr auto operator>=(NegativeInfinity const&, T const&) noexcept
347 -> std::enable_if_t<std::is_integral_v<T>, SFINAE> {
348 return false;
349 }
350
351 // NegativeInfinity is equal to itself.
352 constexpr bool operator>=(NegativeInfinity const&,
353 NegativeInfinity const&) noexcept {
354 return true;
355 }
356
357 // NegativeInfinity is always less than any integral value.
358 template <typename T, typename SFINAE = bool>
359 constexpr auto operator>=(T const&, NegativeInfinity const&) noexcept
360 -> std::enable_if_t<std::is_integral_v<T>, SFINAE> {
361 return true;
362 }
363
364 // NegativeInfinity is always less than or equal to any integral.
365 template <typename T, typename SFINAE = bool>
366 constexpr auto operator<=(NegativeInfinity const&, T const&) noexcept
367 -> std::enable_if_t<std::is_integral_v<T>, SFINAE> {
368 return true;
369 }
370
371 // NegativeInfinity is equal to itself.
372 constexpr bool operator<=(NegativeInfinity const&,
373 NegativeInfinity const&) noexcept {
374 return true;
375 }
376
377 // An integral value is never leass than or equal to NegativeInfinity.
378 template <typename T, typename SFINAE = bool>
379 constexpr auto operator<=(T const&, NegativeInfinity const&) noexcept
380 -> std::enable_if_t<std::is_integral_v<T>, SFINAE> {
381 return false;
382 }
383
384 // operator>= and operator<= for LimitMax
385 // LimitMax is always greater than or equal to any integral value.
386 template <typename T, typename SFINAE = bool>
387 constexpr auto operator>=(LimitMax const&, T const&) noexcept
388 -> std::enable_if_t<std::is_integral_v<T>, SFINAE> {
389 return true;
390 }
391
392 // LimitMax CAN be compared to itself.
393 constexpr bool operator>=(LimitMax const&, LimitMax const&) noexcept {
394 return true;
395 }
396
397 // LimitMax is never less than or equal to an integral value.
398 template <typename T, typename SFINAE = bool>
399 constexpr auto operator>=(T const&, LimitMax const&) noexcept
400 -> std::enable_if_t<std::is_integral_v<T>, SFINAE> {
401 return false;
402 }
403
404 // LimitMax is never less than or equal to an integral value.
405 template <typename T, typename SFINAE = bool>
406 constexpr auto operator<=(LimitMax const&, T const&) noexcept
407 -> std::enable_if_t<std::is_integral_v<T>, SFINAE> {
408 return false;
409 }
410
411 // LimitMax is equal to itself.
412 constexpr bool operator<=(LimitMax const&, LimitMax const&) noexcept {
413 return true;
414 }
415
416 // LimitMax is always greater than or equal to any integral value.
417 template <typename T, typename SFINAE = bool>
418 constexpr auto operator<=(T const&, LimitMax const&) noexcept
419 -> std::enable_if_t<std::is_integral_v<T>, SFINAE> {
420 return true;
421 }
422
423 // operator>= and operator<= for Undefined
424 // Undefined can be compared to itself.
425 constexpr bool operator<=(Undefined const&, Undefined const&) noexcept {
426 return true;
427 }
428
429 // Undefined is always equal to itself.
430 constexpr bool operator>=(Undefined const&, Undefined const&) noexcept {
431 return true;
432 }
433 } // namespace detail
434#endif // LIBSEMIGROUPS_PARSED_BY_DOXYGEN
435} // namespace libsemigroups
436#endif // LIBSEMIGROUPS_CONSTANTS_HPP_
bool operator<=(Bipartition const &x, Bipartition const &y)
Compare bipartitions.
Definition bipart.hpp:1737
bool operator>=(Bipartition const &x, Bipartition const &y)
Compare bipartitions.
Definition bipart.hpp:1759
bool operator>(Bipartition const &x, Bipartition const &y)
Compare bipartitions.
Definition bipart.hpp:1748
bool operator!=(Bipartition const &x, Bipartition const &y)
Check bipartitions for inequality.
Definition bipart.hpp:1727
detail::Constant< 0, detail::Max > Undefined
Type for undefined values.
Definition constants.hpp:95
NegativeInfinity const NEGATIVE_INFINITY
Value for negative infinity.
detail::Constant<-1, detail::Max > PositiveInfinity
Type for positive infinity.
Definition constants.hpp:101
Undefined const UNDEFINED
Value for something undefined.
detail::Constant< 0, detail::Min > NegativeInfinity
Type for negative infinity.
Definition constants.hpp:113
PositiveInfinity const POSITIVE_INFINITY
Value for positive infinity.
LimitMax const LIMIT_MAX
Value for the maximum of something.
detail::Constant<-2, detail::Max > LimitMax
Type for the maximum value of something.
Definition constants.hpp:107
bool operator==(Presentation< Word > const &lhop, Presentation< Word > const &rhop)
Compare for equality.
Definition presentation.hpp:2893
T max(T... args)
T min(T... args)
Namespace for everything in the libsemigroups library.
Definition action.hpp:44