···11+#!/usr/bin/env bash
22+set -e
33+if [[ ! -d "/home/diego/omnium-gatherum/C++/inve" ]]; then
44+ echo "Cannot find source directory; Did you move it?"
55+ echo "(Looking for "/home/diego/omnium-gatherum/C++/inve")"
66+ echo 'Cannot force reload with this script - use "direnv reload" manually and then try again'
77+ exit 1
88+fi
99+1010+# rebuild the cache forcefully
1111+_nix_direnv_force_reload=1 direnv exec "/home/diego/omnium-gatherum/C++/inve" true
1212+1313+# Update the mtime for .envrc.
1414+# This will cause direnv to reload again - but without re-building.
1515+touch "/home/diego/omnium-gatherum/C++/inve/.envrc"
1616+1717+# Also update the timestamp of whatever profile_rc we have.
1818+# This makes sure that we know we are up to date.
1919+touch -r "/home/diego/omnium-gatherum/C++/inve/.envrc" "/home/diego/omnium-gatherum/C++/inve/.direnv"/*.rc
···11+#include "external.hpp"
22+#include "lib/prelude.hpp"
33+44+// Code taken from: https://stackoverflow.com/a/4424496
55+fn power(I32 a, I32 n, I32 mod) noexcept -> I64 {
66+ I64 power = I64(a);
77+ I64 result = I64(1);
88+99+ while (n) {
1010+ if (n & 1)
1111+ result = (result * power) % mod;
1212+ power = (power * power) % mod;
1313+ n >>= 1;
1414+ }
1515+ return result;
1616+}
1717+1818+fn witness(I32 a, I32 n) noexcept -> Bool {
1919+ I32 t, u, i;
2020+ I64 prev, curr;
2121+2222+ u = n / 2;
2323+ t = 1;
2424+ while (!(u & 1)) {
2525+ u /= 2;
2626+ ++t;
2727+ }
2828+2929+ prev = power(a, u, n);
3030+ // [[assume(i <= t)]];
3131+ for (i = 1; i <= t; ++i) {
3232+ curr = (prev * prev) % n;
3333+ if (curr == 1 && prev != 1 && prev != n - 1)
3434+ return true;
3535+ prev = curr;
3636+ }
3737+3838+ if (curr != 1)
3939+ return true;
4040+ return false;
4141+}
+46
src/external.hpp
···11+#pragma once
22+#include "lib/prelude.hpp"
33+44+fn power(I32 a, I32 n, I32 mod) noexcept -> I64;
55+66+fn witness(I32 a, I32 n) noexcept -> Bool;
77+88+/* WARNING: Algorithm deterministic only for numbers < 4,759,123,141 (unsigned
99+ * int's max is 4294967296) if n < 1,373,653, it is enough to test a = 2 and 3.
1010+ * if n < 9,080,191, it is enough to test a = 31 and 73.
1111+ * if n < 4,759,123,141, it is enough to test a = 2, 7, and 61.
1212+ * if n < 2,152,302,898,747, it is enough to test a = 2, 3, 5, 7, and 11.
1313+ * if n < 3,474,749,660,383, it is enough to test a = 2, 3, 5, 7, 11, and 13.
1414+ * if n < 341,550,071,728,321, it is enough to test a = 2, 3, 5, 7, 11, 13,
1515+ * and 17.
1616+ */
1717+fn inline is_prime(Int number) noexcept -> Bool {
1818+ if ((!(number & 1) && number != 2) || number < 2 ||
1919+ (number % 3 == 0 && number != 3))
2020+ return false;
2121+2222+ if (number < 1373653) {
2323+ for (Int k = 1; 36 * k * k - 12 * k < number; ++k)
2424+ if (number % (6 * k + 1) == 0 ||
2525+ (number % 6 * k - 1) == 0)
2626+ return false;
2727+2828+ return true;
2929+ }
3030+3131+ if (number < 9080191) {
3232+ if (witness(31, number))
3333+ return false;
3434+ if (witness(73, number))
3535+ return false;
3636+ return true;
3737+ }
3838+3939+ if (witness(2, number))
4040+ return false;
4141+ if (witness(7, number))
4242+ return false;
4343+ if (witness(61, number))
4444+ return false;
4545+ return true;
4646+}
+29
src/lib/lib.cpp
···11+#include "lib.hpp"
22+#include "prelude.hpp"
33+#include <cmath>
44+#include <ranges>
55+66+fn is_primitive_root(UInt p, Int a) noexcept -> Bool {
77+ return (UInt(std::pow(a, (p - 1) / 2)) % p) == p - 1;
88+}
99+1010+fn primitive_roots(UInt p) noexcept -> Vec<UInt> {
1111+ Vec<UInt> out;
1212+ out.reserve(Size(p));
1313+ for (auto i : vi::iota(1, Int(p))) {
1414+ if (is_primitive_root(p, i))
1515+ out.push_back(i);
1616+ }
1717+ return out;
1818+}
1919+2020+fn seq(UInt p, UInt a) noexcept -> Vec<UInt> {
2121+ Vec<UInt> out;
2222+ out.reserve(Size(p));
2323+ for (UInt i = 1, e = a; e != 1; ++i) {
2424+ e = UInt(std::pow(a, i)) % p;
2525+ out.push_back(e);
2626+ }
2727+ return out;
2828+}
2929+
+8
src/lib/lib.hpp
···11+#pragma once
22+#include "prelude.hpp"
33+44+fn is_primitive_root(UInt p, Int a) noexcept -> Bool;
55+66+fn primitive_roots(UInt p) noexcept -> Vec<UInt>;
77+88+fn seq(UInt p, UInt a) noexcept -> Vec<UInt>;
+16
src/lib/prelude.hpp
···11+#pragma once
22+#include <cstdint>
33+#include <vector>
44+#define fn [[nodiscard, gnu::const]] auto
55+66+template <class T> using Vec = std::vector<T>;
77+using Bool = bool;
88+using Int = int;
99+using UInt = unsigned int;
1010+using Size = std::size_t;
1111+// namespace ra = std::ranges;
1212+namespace vi = std::ranges::views;
1313+using U64 = std::uint64_t;
1414+using U32 = std::uint32_t;
1515+using I32 = std::int32_t;
1616+typedef std::int64_t I64;
+23
src/main.cpp
···11+#include "external.hpp"
22+#include "lib/lib.hpp"
33+#include "test/test.hpp"
44+#include <iostream>
55+#include <ranges>
66+77+fn main() noexcept -> int {
88+ "2 is a primitive root of 11"_test = is_primitive_root(11, 2);
99+ for (auto p : vi::iota(2, 20) | vi::filter(is_prime)) {
1010+ auto space = "";
1111+ std::cout << p << ": [";
1212+ for (auto const& i : primitive_roots(UInt(p))) {
1313+ std::cout << space << i;
1414+ space = " ";
1515+ }
1616+ std::cout << "]" << std::endl;
1717+ }
1818+ for (auto e : seq(11, 2)) {
1919+ std::cout << e << std::endl;
2020+ }
2121+2222+ return 0;
2323+}