#!/usr/bin/env python # -*- coding: utf-8 -*- # Primitive sequence analyzer # written by Fish # https://github.com/kyodaisuu/primseq # # When environmental variable SCRIPT_NAME is set, it runs as a CGI program. # Otherwise it runs as a commandline program. def main(): """Show ordinal of a primitive sequence Determine if it is commandline or CGI. """ import os if os.getenv('SCRIPT_NAME') is None: maincl() else: maincgi() return def maincl(): """Show ordinal of a primitive sequence Invoked from command line. """ # Test some values assert primseq('') == 'Empty sequence' assert primseq('00000') == '5' assert primseq('012') == 'w^w' assert primseq('01012') == 'w^w' # w+w^w is not canonical assert primseq('012123') == 'w^(w^w)' # Another canonical test assert primseq('000111') == 'w^3' # Another canonical test assert primseq('123012') == 'w^w+w^w' # Another canonical test assert primseq('0121212') == 'w^(w+w+w)' assert primseq('01233451234') == 'w^(w^(w^(w^w))+w^(w^w))' assert primseq('0123123') == 'w^(w^w+w^w)' assert primseq('012333') == 'w^(w^(w^3))' assert primseq('01221') == 'w^(w^2+1)' assert primseq('0123122201221') == 'w^(w^w+w^3)+w^(w^2+1)' # Change raw_input to input and it works for Python 3 seq = raw_input('Sequence = ') seq = makelist(seq) assert seq[0].isdigit() seq = standard(seq) assert seq[0] == 0 print(seq) print(primseq(seq)) return def maincgi(): """Show ordinal of a primitive sequence Running as a CGI program. """ import cgi # Comment out for debugging # import cgitb # cgitb.enable() # Write html print(r'''Content-Type: text/html Primitive sequence analyzer

Primitive sequence analyzer 原始数列解析

Primitive sequence:
''') footer = r'''

Primitive sequence analyzer

''' # Get form input f = cgi.FieldStorage() text = f.getfirst('text', '') seq = makelist(text) if len(seq) > 1 and seq[0].isdigit(): try: seq = standard(seq) except Exception: print("

Error in input

") print(footer) return print("\n

Result

") print('

Input: {0}

'.format(text)) print('

Sequence: {0}

'.format(seq)) ord = primseq(seq) ordstr = ord.replace('w', 'ω') ordtex = ord.replace('w', '\omega').replace('(', '{').replace(')', '}') print('

Ordinal: ${0}$

'.format(ordtex)) print( '

Text output: {0}

'.format(ordstr)) else: print('

Input primitive sequence (原始数列) with format of:

') print('') print('より詳しい説明') print(footer) return def makelist(seq): """Make list from string When comma or space is used, they are used as separators""" seq = seq.strip() if ',' in seq: seq = seq.replace(',', ' ') if ' ' in seq: seq = seq.split() seq = list(seq) return seq def primseq(seq): """Convert primitive sequence to ordinal""" # Check input sequence try: if len(seq) == 0: return 'Empty sequence' except Exception: return 'Invalid sequence' for i in seq: try: if int(i) < 0: return 'Number should be positive' except Exception: return 'Invalid number' # Convert to standard sequence seq = standard(seq) right = len(seq)-1 for i in range(right+1)[::-1]: if seq[i] != seq[right]: ord = str(right-i) break if i == 0 and seq[0] == seq[right]: return str(right-i+1) ord = prim(seq[:i+1], seq[i+1], ord) return ord def prim(seq, num, ord): if seq[len(seq)-1] < num: if ord == '1': ord = 'w' else: if '+' in ord or '^' in ord: ord = 'w^('+ord+')' else: ord = 'w^'+ord if len(seq) == 1: return ord ord = prim(seq[:len(seq)-1], seq[len(seq)-1], ord) return ord # A + B for i in range(len(seq))[::-1]: if seq[i] == num: break ord = primseq(seq[i:len(seq)]) + '+' + ord if i == 0: return ord ord = prim(seq[:i], seq[i], ord) return ord def standard(seq): """Convert sequence to standard expression Start from 0: [1,2,3] -> [0,1,2] Increment with 1: [0,2,4] -> [0,1,2]""" st = stand(seq) while len(st) < len(seq): seq = st st = stand(seq) return st def stand(seq): st = [] offset = int(seq[0]) nextoffset = offset prev = 0 for i in range(len(seq)): offset = nextoffset n = int(seq[i])-offset if n < 0: n = 0 nextoffset = int(seq[i]) if n == prev: if i == 0: st.append(0) else: st.append(st[i-1]) if n > prev: st.append(st[i-1] + 1) if n < prev: for j in range(i)[::-1]: if n == int(seq[j])-offset: st.append(st[j]) break if n > int(seq[j])-offset: st.append(st[j]+1) break prev = n # Check canonical # A + B = B when A < B i = len(st)-1 while i > 1: i -= 1 if st[i-1] == st[i]: for j in range(i, len(st)): if st[j] < st[i]: break if st[j] > st[i]: if i == 1: st = st[1:len(st)] else: st = st[:i-1] + st[i:len(st)] break if st[i-1] > st[i]: for j in range(i)[::-1]: if st[j] == st[i]: left = st[j:i] right = st[i:len(st)] # normalize the left part dummy = list(range(left[0])) if dummy + left != list(standard(dummy + left)): return st[:j] + list(standard(dummy + left))[left[0]:]+right found = False equal = True for k in range(len(left)): if len(right) < k+1: continue if left[k] < right[k]: found = True if left[k] > right[k]: equal = False break if equal and found == False and len(left) < len(right) and right[len(left)] > right[0]: found = True if found: if j == 0: return tuple(right) st = st[:j] + right i = j break return tuple(st) if __name__ == '__main__': main()