libsemigroups  v3.6.0
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 // We use SFINAE here so that <Constant> is only implicitly converted to
69 // <T> when <T> satisfies a strict set of conditions. This is necessary as
70 // some incorrect implicit conversions were happening in the Python
71 // bindings.
72 template <typename T,
73 typename
74 = std::enable_if_t<!std::is_enum_v<T> && std::is_integral_v<T>
75 && (std::is_signed_v<T>
76 || std::is_same_v<TMaxOrMin, Max>),
77 T>>
78 constexpr operator T() const noexcept {
79 return TMaxOrMin().template operator()<T>() + TOffset;
80 }
81 };
82 } // namespace detail
83
85 // Constant values
87
94
99 using Undefined = detail::Constant<0, detail::Max>;
100
105 using PositiveInfinity = detail::Constant<-1, detail::Max>;
106
111 using LimitMax = detail::Constant<-2, detail::Max>;
112
117 using NegativeInfinity = detail::Constant<0, detail::Min>;
118
126 extern Undefined const UNDEFINED;
127
138
147 extern LimitMax const LIMIT_MAX;
148
158
160 // Operators for all constants
162
163 // Note that for some reason Catch requires that the comparison functions are
164 // in the namespace detail.
165
166#ifndef LIBSEMIGROUPS_PARSED_BY_DOXYGEN
167 namespace detail {
168
169 // operator==
170 // No SFINAE required, since the functions delegated to don't exist.
171 template <int64_t R, typename S, typename T>
172 constexpr bool operator==(Constant<R, S> const& lhs,
173 T const& rhs) noexcept {
174 return lhs.operator T() == rhs;
175 }
176
177 template <int64_t R, typename S, typename T>
178 constexpr bool operator==(T const& lhs,
179 Constant<R, S> const& rhs) noexcept {
180 return rhs.operator T() == lhs;
181 }
182
183 template <int64_t R1, typename S1, int64_t R2, typename S2>
184 constexpr bool operator==(Constant<R1, S1> const&,
185 Constant<R2, S2> const&) noexcept {
186 return std::is_same_v<S1, S2> && R1 == R2;
187 }
188
189 // operator!=
190 // No SFINAE required, since the functions delegated to don't exist.
191 template <int64_t R, typename S, typename T>
192 constexpr bool operator!=(Constant<R, S> const& lhs,
193 T const& rhs) noexcept {
194 return !(lhs == rhs);
195 }
196
197 template <int64_t R, typename S, typename T>
198 constexpr bool operator!=(T const& lhs,
199 Constant<R, S> const& rhs) noexcept {
200 return !(lhs == rhs);
201 }
202
203 template <int64_t R1, typename S1, int64_t R2, typename S2>
204 constexpr bool operator!=(Constant<R1, S1> const& lhs,
205 Constant<R2, S2> const& rhs) noexcept {
206 return !(lhs == rhs);
207 }
208
209 // operator>
210 // No SFINAE required, since the functions delegated to don't exist.
211 template <int64_t R, typename S, typename T>
212 constexpr bool operator>(Constant<R, S> const& lhs, T const& rhs) noexcept {
213 return rhs < lhs;
214 }
215
216 template <int64_t R, typename S, typename T>
217 constexpr bool operator>(T const& lhs, Constant<R, S> const& rhs) noexcept {
218 return rhs < lhs;
219 }
220
221 template <int64_t R, typename S>
222 constexpr bool operator>(Constant<R, S> const&,
223 Constant<R, S> const&) noexcept {
224 return false;
225 }
226
227 template <int64_t R, typename S>
228 constexpr bool operator<(Constant<R, S> const&,
229 Constant<R, S> const&) noexcept {
230 return false;
231 }
232 // No further operator< for Constant and Constant unless given explicitly
233
235 // Operators for specific constants
237
238 // PositiveInfinity is not less than any integral value, or
239 // NegativeInfinity.
240 template <typename T, typename SFINAE = bool>
241 constexpr auto operator<(PositiveInfinity const&, T const&) noexcept
242 -> std::enable_if_t<std::is_integral_v<T>
243 || std::is_same_v<NegativeInfinity, T>,
244 SFINAE> {
245 return false;
246 }
247
248 // Every integral value, and negative infinity, is less than
249 // PositiveInfinity.
250 template <typename T, typename SFINAE = bool>
251 constexpr auto operator<(T const&, PositiveInfinity const&) noexcept
252 -> std::enable_if_t<std::is_integral_v<T>
253 || std::is_same_v<NegativeInfinity, T>,
254 SFINAE> {
255 return true;
256 }
257
258 // NegativeInfinity is less than every integral value.
259 template <typename T, typename SFINAE = bool>
260 constexpr auto operator<(NegativeInfinity const&, T const&) noexcept
261 -> std::enable_if_t<std::is_integral_v<T>, SFINAE> {
262 return true;
263 }
264
265 // No integral value is less than NegativeInfinity.
266 template <typename T, typename SFINAE = bool>
267 constexpr auto operator<(T const&, NegativeInfinity const&) noexcept
268 -> std::enable_if_t<std::is_integral_v<T>, SFINAE> {
269 return false;
270 }
271
272 // LimitMax is compared by implicit conversion with any integral value.
273 template <typename T, typename SFINAE = bool>
274 constexpr auto operator<(LimitMax const& lhs, T const& rhs) noexcept
275 -> std::enable_if_t<std::is_integral_v<T>, SFINAE> {
276 return lhs.operator T() < rhs;
277 }
278
279 // LimitMax is compared by implicit conversion with any integral value.
280 template <typename T, typename SFINAE = bool>
281 constexpr auto operator<(T const& lhs, LimitMax const& rhs) noexcept
282 -> std::enable_if_t<std::is_integral_v<T>, SFINAE> {
283 return lhs < rhs.operator T();
284 }
285
286 template <typename T, typename SFINAE = T>
287 constexpr auto operator-(LimitMax const& lhs, T const& rhs) noexcept
288 -> std::enable_if_t<std::is_integral_v<T>, SFINAE> {
289 return lhs.operator T() - rhs;
290 }
291
292 template <typename T, typename SFINAE = T>
293 constexpr auto operator-(T const& lhs, LimitMax const& rhs) noexcept
294 -> std::enable_if_t<std::is_integral_v<T>, SFINAE> {
295 return lhs - rhs.operator T();
296 }
297
298 // operator>= and operator<= for PositiveInfinity
299 // PositiveInfinity is always greater than or equal to any integral.
300 template <typename T, typename SFINAE = bool>
301 constexpr auto operator>=(PositiveInfinity const&, T const&) noexcept
302 -> std::enable_if_t<std::is_integral_v<T>
303 || std::is_same_v<NegativeInfinity, T>,
304 SFINAE> {
305 return true;
306 }
307
308 // PositiveInfinity is equal to itself.
309 constexpr bool operator>=(PositiveInfinity const&,
310 PositiveInfinity const&) noexcept {
311 return true;
312 }
313
314 // PositiveInfinity is never less than or equal to any integral.
315 template <typename T, typename SFINAE = bool>
316 constexpr auto operator>=(T const&, PositiveInfinity const&) noexcept
317 -> std::enable_if_t<std::is_integral_v<T>
318 || std::is_same_v<NegativeInfinity, T>,
319 SFINAE> {
320 return false;
321 }
322
323 // An integral is never greater than or equal to PositiveInfinity.
324 template <typename T, typename SFINAE = bool>
325 constexpr auto operator<=(PositiveInfinity const&, T const&) noexcept
326 -> std::enable_if_t<std::is_integral_v<T>
327 || std::is_same_v<NegativeInfinity, T>,
328 SFINAE> {
329 return false;
330 }
331
332 // PositiveInfinity is equal to itself.
333 constexpr bool operator<=(PositiveInfinity const&,
334 PositiveInfinity const&) noexcept {
335 return true;
336 }
337
338 // PositiveInfinity is always greater than or equal to any integral.
339 template <typename T, typename SFINAE = bool>
340 constexpr auto operator<=(T const&, PositiveInfinity const&) noexcept
341 -> std::enable_if_t<std::is_integral_v<T>
342 || std::is_same_v<NegativeInfinity, T>,
343 SFINAE> {
344 return true;
345 }
346
347 // operator>= and operator<= for NegativeInfinity
348 // NegativeInfinity is never greater than or equal to any integral value.
349 template <typename T, typename SFINAE = bool>
350 constexpr auto operator>=(NegativeInfinity const&, T const&) noexcept
351 -> std::enable_if_t<std::is_integral_v<T>, SFINAE> {
352 return false;
353 }
354
355 // NegativeInfinity is equal to itself.
356 constexpr bool operator>=(NegativeInfinity const&,
357 NegativeInfinity const&) noexcept {
358 return true;
359 }
360
361 // NegativeInfinity is always less than any integral value.
362 template <typename T, typename SFINAE = bool>
363 constexpr auto operator>=(T const&, NegativeInfinity const&) noexcept
364 -> std::enable_if_t<std::is_integral_v<T>, SFINAE> {
365 return true;
366 }
367
368 // NegativeInfinity is always less than or equal to any integral.
369 template <typename T, typename SFINAE = bool>
370 constexpr auto operator<=(NegativeInfinity const&, T const&) noexcept
371 -> std::enable_if_t<std::is_integral_v<T>, SFINAE> {
372 return true;
373 }
374
375 // NegativeInfinity is equal to itself.
376 constexpr bool operator<=(NegativeInfinity const&,
377 NegativeInfinity const&) noexcept {
378 return true;
379 }
380
381 // An integral value is never leass than or equal to NegativeInfinity.
382 template <typename T, typename SFINAE = bool>
383 constexpr auto operator<=(T const&, NegativeInfinity const&) noexcept
384 -> std::enable_if_t<std::is_integral_v<T>, SFINAE> {
385 return false;
386 }
387
388 // operator>= and operator<= for LimitMax
389 // LimitMax is always greater than or equal to any integral value.
390 template <typename T, typename SFINAE = bool>
391 constexpr auto operator>=(LimitMax const&, T const&) noexcept
392 -> std::enable_if_t<std::is_integral_v<T>, SFINAE> {
393 return true;
394 }
395
396 // LimitMax CAN be compared to itself.
397 constexpr bool operator>=(LimitMax const&, LimitMax const&) noexcept {
398 return true;
399 }
400
401 // LimitMax is never less than or equal to an integral value.
402 template <typename T, typename SFINAE = bool>
403 constexpr auto operator>=(T const&, LimitMax const&) noexcept
404 -> std::enable_if_t<std::is_integral_v<T>, SFINAE> {
405 return false;
406 }
407
408 // LimitMax is never less than or equal to an integral value.
409 template <typename T, typename SFINAE = bool>
410 constexpr auto operator<=(LimitMax const&, T const&) noexcept
411 -> std::enable_if_t<std::is_integral_v<T>, SFINAE> {
412 return false;
413 }
414
415 // LimitMax is equal to itself.
416 constexpr bool operator<=(LimitMax const&, LimitMax const&) noexcept {
417 return true;
418 }
419
420 // LimitMax is always greater than or equal to any integral value.
421 template <typename T, typename SFINAE = bool>
422 constexpr auto operator<=(T const&, LimitMax const&) noexcept
423 -> std::enable_if_t<std::is_integral_v<T>, SFINAE> {
424 return true;
425 }
426
427 // operator>= and operator<= for Undefined
428 // Undefined can be compared to itself.
429 constexpr bool operator<=(Undefined const&, Undefined const&) noexcept {
430 return true;
431 }
432
433 // Undefined is always equal to itself.
434 constexpr bool operator>=(Undefined const&, Undefined const&) noexcept {
435 return true;
436 }
437 } // namespace detail
438#endif // LIBSEMIGROUPS_PARSED_BY_DOXYGEN
439} // namespace libsemigroups
440#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:99
NegativeInfinity const NEGATIVE_INFINITY
Value for negative infinity.
detail::Constant<-1, detail::Max > PositiveInfinity
Type for positive infinity.
Definition constants.hpp:105
Undefined const UNDEFINED
Value for something undefined.
detail::Constant< 0, detail::Min > NegativeInfinity
Type for negative infinity.
Definition constants.hpp:117
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:111
bool operator==(Presentation< Word > const &lhop, Presentation< Word > const &rhop)
Compare for equality.
Definition presentation.hpp:3378
T max(T... args)
T min(T... args)
Namespace for everything in the libsemigroups library.
Definition action.hpp:44