"""Command line version of the explorer (like the old sph.pl). Usage: python3 -m sphexplorer [-v verbosity] [-t type] [-f file] [-c standard|bourbaki|gap] [-h] python3 -m sphexplorer --roots TYPE RANK [--labels gap|1,2,...] python3 -m sphexplorer --unipotent TYPE RANK python3 -m sphexplorer --examples """ import argparse import re import sys from . import spherical from .examples import getExamples from .rootsystem import showAll from .web import processLine, unipotentLambdas, InputError, parse_lambda HELP = """ Unitarity tester for Classical Groups. Given a list lambda of real numbers of length n (in standard coordinates) compute if X(lambda) is unitary, and give some other information about it. This implements an algorithm due to Dan Barbasch. When run from the command line, enter type (A,B,C,D) and lambda at the prompt. Allowable numbers in lambda: of the form 1, -1.34, or 7/8. You can optionally specify the type as an option with -t. To read in a file of lambda's use -f; you must specify the type with -t. Usage: python3 -m sphexplorer [-v verbosity] [-t type] [-f file] [-c standard|bourbaki|gap] [-h] -h: This help. -t: Set type (A,B,C,D) -f: Read in lambda's from file. -c: Coordinates of lambda: standard (default), or fundamental weight coordinates with the Bourbaki or Gap labelling (-w is short for -c bourbaki). -v: Set amount of output (0, 1 or 2). --roots TYPE RANK [--labels gap|p1,...,pn] Root system data (types A-G, F*, G*). --unipotent TYPE RANK Test all unipotent parameters. --examples Run the built-in examples. In types B, C, D negative signs in lambda are ignored (after acting by the Weyl group all coordinates may be taken positive). In type A every coordinate must occur in a plus-minus pair; if all entries are non-negative, the negatives are adjoined. In type D(odd) lambda must have a 0 entry. Format of the file: Each line must contain a string of numbers separated by commas or spaces. Everything after a # is ignored, as are all characters except numbers, '.', '/', commas and spaces (so minus signs are dropped). Examples: (1/2,1/2,0) {.5, .5, 0} points={{1/2, .5, 0}}, Default is -v 2 in command line mode, -v 1 in file mode (-f). -------------------------------------------------------------- How to read the results. Orbit O: partition giving the nilpotent orbit associated to lambda. Centralizer Z: Reductive part of the centralizer of O, on the dual side. Each row of the table with M,O,h,nu corresponds to a factor of M. Then O is the part of O corresponding to M. We write lambda=h+nu, where h is determined by O, and nu is central. The h,nu columns in the table give the coordinates of h,nu for the given factor of M. The row/mult/Z table has one row for each factor of Z. Each such factor corresponds to a row length, which has a given multiplicity. These are the first two terms in the first column. The third term is the corresponding component of Z. The unitary column shows if the test for unitarity passes or not on this term (+/-). The final column shows nu for this component; the test passes for this row if this parameter is in the 0-complementary series for the given factor of Z. """ DEFAULT_LAMBDA = "2 2 1 1 1 1 0" def _run(type, items, coordinates): out = [] try: r = spherical.process(type, items, coordinates, out) except (ValueError, ZeroDivisionError) as err: sys.stdout.write("Error: %s\n" % err) return sys.stdout.write("".join(out)) if r is not None and r.result == "stop": sys.stdout.write(r.message) def interactive(type, coordinates): while True: if not type: sys.stdout.write("Enter type (A,B,C,D), or q to quit:") sys.stdout.write("\ntype: [%s] " % (type or "")) sys.stdout.flush() line = sys.stdin.readline() if not line: return lam_in_type = re.sub(r"[^0-9\.,/ \-]", "", line).strip() new_type = re.sub(r"[^A-Dq]", "", line.upper().replace("Q", "q")) if new_type == "q" or line.strip().lower() in ("q", "quit"): return new_type = new_type[:1] if re.search(r"[0-9]", lam_in_type): lam = lam_in_type else: if not (new_type or type): continue if not type: sys.stdout.write("Enter string of real numbers (separated " "by spaces or commas) for lambda\n") sys.stdout.write("lambda: ") sys.stdout.flush() lam = sys.stdin.readline().strip() if lam.lower() == "q": return type = new_type or type if not type: continue lam = lam or DEFAULT_LAMBDA try: items = parse_lambda(lam) except InputError as err: sys.stdout.write(re.sub(r"<[^>]+>|&[a-z]+;", "", str(err)) + "\n") continue _run(type, items, coordinates) def main(argv=None): ap = argparse.ArgumentParser(add_help=False) ap.add_argument("-h", "--help", action="store_true") ap.add_argument("-t", dest="type") ap.add_argument("-f", dest="file") ap.add_argument("-v", dest="verbose", type=int) ap.add_argument("-c", dest="coordinates", default="standard", choices=["standard", "bourbaki", "gap"]) ap.add_argument("-w", action="store_true") ap.add_argument("--roots", nargs=2, metavar=("TYPE", "RANK")) ap.add_argument("--labels", default="") ap.add_argument("--unipotent", nargs=2, metavar=("TYPE", "RANK")) ap.add_argument("--examples", action="store_true") args = ap.parse_args(argv) if args.help: sys.stdout.write(HELP) return coordinates = "bourbaki" if args.w else args.coordinates if args.type: args.type = args.type.upper() if args.roots: type, rank = args.roots[0].upper(), int(args.roots[1]) labels = args.labels if labels and labels.lower() != "gap": labels = [int(x) for x in re.split(r"[,\s]+", labels) if x] sys.stdout.write("".join(showAll(type, rank, labels)) + "\n") return if args.unipotent: spherical.verbose = 1 if args.verbose is None else args.verbose type, rank = args.unipotent[0].upper(), int(args.unipotent[1]) for lam in unipotentLambdas(type, rank): _run(type, lam, "") return if args.examples: spherical.verbose = 2 if args.verbose is None else args.verbose types, lambdas, titles, comments = getExamples() for n in sorted(titles): sys.stdout.write("\n%s\n%s\n" % (titles[n], re.sub( r"<[^>]+>", "", comments[n]))) _run(types[n], list(lambdas[n]), "standard") return if args.file: if not args.type: sys.stdout.write("In file mode you must specify a type with -t\n") return spherical.verbose = 1 if args.verbose is None else args.verbose with open(args.file) as fh: for line in fh: try: items = processLine(args.type, line, coordinates) except InputError as err: sys.stdout.write("Error: %s\n" % re.sub( r"<[^>]+>|&[a-z]+;", "", str(err))) continue if items is None: continue if spherical.verbose > 2: sys.stdout.write("lambda from file:%s\n" % ",".join(items)) _run(args.type, items, coordinates) return spherical.verbose = 2 if args.verbose is None else args.verbose try: interactive(args.type, coordinates) except KeyboardInterrupt: sys.stdout.write("\n") if __name__ == "__main__": main()