imp/sandbox/cmd/cycsub.py
2025-06-24 16:42:17 +10:00

60 lines
2 KiB
Python

from sys import stdout
from noether.cli.style import *
from noether.cli.prompt import *
from noether.lib.structs import Result
from noether.lib.util import digits
from noether.lib.groups import cyclic_subgrp
from noether.lib.primes import totient, is_prime
class cycsub(Prompt):
DEFAULT_PROMPT = style('[n]: ', Color.BLUE)
def __init__(self, ignore_zero: bool = True) -> None:
super().__init__()
self.ignore_zero = ignore_zero
def _parse(self, command: str) -> int:
try:
return Result.succeed(int(command))
except ValueError:
return Result.fail('Not an integer.')
def _exec(self, n: int) -> None:
phi = totient(n)
lpadding = digits(n)
rpadding = digits(phi)
if is_prime(n, phi=n):
Cursor.save()
Cursor.move_y(-1, reset=False)
Cursor.set_x(len(self.DEFAULT_PROMPT) + lpadding + 1)
stdout.write(style('[PRIME]', Color.MAGENTA, Effect.BOLD))
Cursor.restore()
stdout.flush()
# keeps track of all primitive roots
# (note that there will be exactly totient(phi) of them)
proots = []
for g in range(n):
G, order, periodic = cyclic_subgrp(g, n, ignore_zero=self.ignore_zero)
primitive = (order == phi) # primitive root
lpad = ' ' * (lpadding - digits(a))
rpad = ' ' * (rpadding - digits(order))
color_g = Color.RED
style_G = []
style_order = []
if primitive:
color_g = Color.GREEN
style_G = [Color.GREEN, Effect.BOLD]
style_order = [Color.YELLOW, Effect.BOLD]
proots.append(g)
elif gcd(g, n) == 1:
color_g = Color.Yellow
line = style(f'{lpad}{g}', color_g, Effect.BOLD) + \
'-> ' + \
style(f'{order}{rpad} ', *style_order) + \
'| ' + \
style(str(G), *style_G)
print(line, flush=True)