Cistercian numerals

Cistercian numerals were used across Europe by Cistercian monks during the Late Medieval Period as an alternative to Roman numerals. They were used to represent base 10 integers from '''0''' to '''9999'''.

;How they work
All Cistercian numerals begin with a vertical line segment, which by itself represents the number '''0'''. Then, glyphs representing the digits '''1''' through '''9''' are optionally added to the four quadrants surrounding the vertical line segment. These glyphs are drawn with vertical and horizontal symmetry about the initial line segment. Each quadrant corresponds to a digit place in the number:

:* The '''upper-right''' quadrant represents the '''ones''' place.
:* The '''upper-left''' quadrant represents the '''tens''' place.
:* The '''lower-right''' quadrant represents the '''hundreds''' place.
:* The '''lower-left''' quadrant represents the '''thousands''' place.

Please consult the following image for examples of Cistercian numerals showing each glyph: [https://upload.wikimedia.org/wikipedia/commons/6/67/Cistercian_digits_%28vertical%29.svg]

;Task

:* Write a function/procedure/routine to display any given Cistercian numeral. This could be done by drawing to the display, creating an image, or even as text (as long as it is a reasonable facsimile).

:* Use the routine to show the following Cistercian numerals:

::* 0
::* 1
::* 20
::* 300
::* 4000
::* 5555
::* 6789
::* And a number of your choice!

;Notes
Due to the inability to upload images to Rosetta Code as of this task's creation, showing output here on this page is not required. However, it is welcomed -- especially for text output.

;See also

:* '''Numberphile - The Forgotten Number System'''
:* '''dcode.fr - Online Cistercian numeral converter'''

Solution:
# -*- coding: utf-8 -*-
"""
Some UTF-8 chars used:

‾	8254	203E	‾	OVERLINE
┃	9475	2503	 	BOX DRAWINGS HEAVY VERTICAL
╱	9585	2571	 	BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT
╲	9586	2572	 	BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT
◸	9720	25F8	 	UPPER LEFT TRIANGLE
◹	9721	25F9	 	UPPER RIGHT TRIANGLE
◺	9722	25FA	 	LOWER LEFT TRIANGLE
◻	9723	25FB	 	WHITE MEDIUM SQUARE
◿	9727	25FF	 	LOWER RIGHT TRIANGLE

"""

#%% digit sections

def _init():
    "digit sections for forming numbers"
    digi_bits = """
#0  1   2  3  4  5  6   7   8   9
#
 .  ‾   _  ╲  ╱  ◸  .|  ‾|  _|  ◻
#
 .  ‾   _  ╱  ╲  ◹  |.  |‾  |_  ◻
#
 .  _  ‾   ╱  ╲  ◺  .|  _|  ‾|  ◻
#
 .  _  ‾   ╲  ╱  ◿  |.  |_  |‾  ◻

""".strip()

    lines = [[d.replace('.', ' ') for d in ln.strip().split()]
             for ln in digi_bits.strip().split('\n')
             if '#' not in ln]
    formats = '<2 >2 <2 >2'.split()
    digits = [[f"{dig:{f}}" for dig in line]
              for f, line in zip(formats, lines)]

    return digits

_digits = _init()

#%% int to 3-line strings
def _to_digits(n):
    assert 0 <= n < 10_000 and int(n) == n

    return [int(digit) for digit in f"{int(n):04}"][::-1]

def num_to_lines(n):
    global _digits
    d = _to_digits(n)
    lines = [
        ''.join((_digits[1][d[1]], '┃',  _digits[0][d[0]])),
        ''.join((_digits[0][   0], '┃',  _digits[0][   0])),
        ''.join((_digits[3][d[3]], '┃',  _digits[2][d[2]])),
        ]

    return lines

def cjoin(c1, c2, spaces='   '):
    return [spaces.join(by_row) for by_row in zip(c1, c2)]

#%% main
if __name__ == '__main__':
    #n = 6666
    #print(f"Arabic {n} to Cistercian:\n")
    #print('\n'.join(num_to_lines(n)))

    for pow10 in range(4):
        step = 10 ** pow10
        print(f'\nArabic {step}-to-{9*step} by {step} in Cistercian:\n')
        lines = num_to_lines(step)
        for n in range(step*2, step*10, step):
            lines = cjoin(lines, num_to_lines(n))
        print('\n'.join(lines))

    numbers = [0, 5555, 6789, 6666]
    print(f'\nArabic {str(numbers)[1:-1]} in Cistercian:\n')
    lines = num_to_lines(numbers[0])
    for n in numbers[1:]:
        lines = cjoin(lines, num_to_lines(n))
    print('\n'.join(lines))


Closures/Value capture

Create a list of ten functions, in the simplest manner possible   (anonymous functions are encouraged),   such that the function at index   '' i ''    (you may choose to start    '' i ''    from either    '''0'''    or    '''1'''),     when run, should return the square of the index,   that is,    '' i '' 2.

Display the result of running any but the last function, to demonstrate that the function indeed remembers its value.

;Goal:
Demonstrate how to create a series of independent closures based on the same template but maintain separate copies of the variable closed over.

In imperative languages, one would generally use a loop with a mutable counter variable.

For each function to maintain the correct number, it has to capture the ''value'' of the variable at the time it was created, rather than just a reference to the variable, which would have a different value by the time the function was run.

See also: [[Multiple distinct objects]]

Solution:
funcs = []
for i in range(10):
    funcs.append((lambda i: lambda: i * i)(i))
print funcs[3]() # prints 9


Colorful numbers

A '''colorful number''' is a non-negative base 10 integer where the product of every sub group of consecutive digits is unique.

;E.G.

24753 is a colorful number. 2, 4, 7, 5, 3, (2x4)8, (4x7)28, (7x5)35, (5x3)15, (2x4x7)56, (4x7x5)140, (7x5x3)105, (2x4x7x5)280, (4x7x5x3)420, (2x4x7x5x3)840

Every product is unique.

2346 is '''not''' a colorful number. 2, 3, 4, '''6''', (2x3)'''6''', (3x4)12, (4x6)24, (2x3x4)48, (3x4x6)72, (2x3x4x6)144

The product '''6''' is repeated.

Single digit numbers '''are''' considered to be colorful. A colorful number larger than 9 cannot contain a repeated digit, the digit 0 or the digit 1. As a consequence, there is a firm upper limit for colorful numbers; no colorful number can have more than 8 digits.

;Task

* Write a routine (subroutine, function, procedure, whatever it may be called in your language) to test if a number is a colorful number or not.
* Use that routine to find all of the colorful numbers less than 100.
* Use that routine to find the largest possible colorful number.

;Stretch

* Find and display the count of colorful numbers in each order of magnitude.
* Find and show the total count of '''all''' colorful numbers.

''Colorful numbers have no real number theory application. They are more a recreational math puzzle than a useful tool.''

Solution:
from math import prod

largest = [0]

def iscolorful(n):
    if 0 <= n < 10:
        return True
    dig = [int(c) for c in str(n)]
    if 1 in dig or 0 in dig or len(dig) > len(set(dig)):
        return False
    products = list(set(dig))
    for i in range(len(dig)):
        for j in range(i+2, len(dig)+1):
            p = prod(dig[i:j])
            if p in products:
                return False
            products.append(p)

    largest[0] = max(n, largest[0])
    return True

print('Colorful numbers for 1:25, 26:50, 51:75, and 76:100:')
for i in range(1, 101, 25):
    for j in range(25):
        if iscolorful(i + j):
            print(f'{i + j: 5,}', end='')
    print()

csum = 0
for i in range(8):
    j = 0 if i == 0 else 10**i
    k = 10**(i+1) - 1
    n = sum(iscolorful(x) for x in range(j, k+1))
    csum += n
    print(f'The count of colorful numbers between {j} and {k} is {n}.')

print(f'The largest possible colorful number is {largest[0]}.')
print(f'The total number of colorful numbers is {csum}.')


Colour bars/Display

Display a series of vertical color bars across the width of the display.

The color bars should either use:
:::*   the system palette,   or
:::*   the sequence of colors:
::::::*   black
::::::*   red
::::::*   green
::::::*   blue
::::::*   magenta
::::::*   cyan
::::::*   yellow
::::::*   white

Solution:
#!/usr/bin/env python
#vertical coloured stripes in window in Python 2.7.1

from livewires import *

horiz=640; vert=480
begin_graphics(width=horiz,height=vert,title="v_stripes",background=Colour.black)
NameColors=["black","red","green","dark_blue","purple","blue","yellow","white"]
stepik=horiz/len(NameColors)

for index,each in enumerate(NameColors):
	ExcStrng="set_colour(Colour."+each+")"
	exec ExcStrng
	box(index*stepik,0,(index+1)*stepik,vert,filled=1)

while keys_pressed() != ['x']: # press x key to terminate program
	pass

end_graphics()


Colour pinstripe/Printer

The task is to create 1 point wide colour vertical pinstripes with a sufficient number of pinstripes to span the entire width of the colour graphics printer. The pinstripes should alternate between each individual cartridge ink and ink pair and black and white pinstripes should be included. A typical pinstripe sequence woud be black, red, green, blue, magenta, cyan, yellow, white.

After the first inch of printing, we switch to a wider 2 pixel wide vertical pinstripe pattern. and to 3 point wide vertical for the next inch, and then 4 point wide, etc. This trend continues for the entire length of the page (or for 12 inches of run length in the case of a printer using continuous roll stationery). After printing the test pattern the page is ejected (or the test pattern is rolled clear of the printer enclosure, in the case of continuous roll printers).

Note that it is an acceptable solution to use the smallest marks that the language provides, rather than working at native printer resolution, where this is not achievable from within the language.

Optionally, on systems where the printer resolution cannot be determined, it is permissible to prompt the user for printer resolution, and to calculate point size based on user input, enabling fractional point sizes to be used.

Solution:
from turtle import *
from PIL import Image
import time
import subprocess

"""

Only works on Windows. Assumes that you have Ghostscript
installed and in your path.

https://www.ghostscript.com/download/gsdnld.html

Hard coded to 100 pixels per inch.

"""

colors = ["black", "red", "green", "blue", "magenta", "cyan", "yellow", "white"]

screen = getscreen()

# width and height in pixels
# aspect ratio for 11 by 8.5 paper

inch_width = 11.0
inch_height = 8.5

pixels_per_inch = 100

pix_width = int(inch_width*pixels_per_inch)
pix_height = int(inch_height*pixels_per_inch)

screen.setup (width=pix_width, height=pix_height, startx=0, starty=0)

screen.screensize(pix_width,pix_height)

# center is 0,0

# get coordinates of the edges

left_edge = -screen.window_width()//2

right_edge = screen.window_width()//2

bottom_edge = -screen.window_height()//2

top_edge = screen.window_height()//2

# draw quickly

screen.delay(0)
screen.tracer(5)

for inch in range(int(inch_width)-1):
    line_width = inch + 1
    pensize(line_width)
    colornum = 0

    min_x = left_edge + (inch * pixels_per_inch)
    max_x = left_edge + ((inch+1) * pixels_per_inch)

    for y in range(bottom_edge,top_edge,line_width):
        penup()
        pencolor(colors[colornum])
        colornum = (colornum + 1) % len(colors)
        setposition(min_x,y)
        pendown()
        setposition(max_x,y)

screen.getcanvas().postscript(file="striped.eps")

# convert to jpeg
# won't work without Ghostscript.

im = Image.open("striped.eps")
im.save("striped.jpg")

# Got idea from http://rosettacode.org/wiki/Colour_pinstripe/Printer#Go

subprocess.run(["mspaint", "/pt", "striped.jpg"])


Comma quibbling

Comma quibbling is a task originally set by Eric Lippert in his blog.

;Task:

Write a function to generate a string output which is the concatenation of input words from a list/sequence where:
# An input of no words produces the output string of just the two brace characters "{}".
# An input of just one word, e.g. ["ABC"], produces the output string of the word inside the two braces, e.g. "{ABC}".
# An input of two words, e.g. ["ABC", "DEF"], produces the output string of the two words inside the two braces with the words separated by the string " and ", e.g. "{ABC and DEF}".
# An input of three or more words, e.g. ["ABC", "DEF", "G", "H"], produces the output string of all but the last word separated by ", " with the last word separated by " and " and all within braces; e.g. "{ABC, DEF, G and H}".

Test your function with the following series of inputs showing your output here on this page:
* []                       # (No input words).
* ["ABC"]
* ["ABC", "DEF"]
* ["ABC", "DEF", "G", "H"]

Note: Assume words are non-empty strings of uppercase characters for this task.

Solution:
>>> def strcat(sequence):
    return '{%s}' % ', '.join(sequence)[::-1].replace(',', 'dna ', 1)[::-1]

>>> for seq in ([], ["ABC"], ["ABC", "DEF"], ["ABC", "DEF", "G", "H"]):
    print('Input: %-24r -> Output: %r' % (seq, strcat(seq)))

Input: []                       -> Output: '{}'
Input: ['ABC']                  -> Output: '{ABC}'
Input: ['ABC', 'DEF']           -> Output: '{ABC and DEF}'
Input: ['ABC', 'DEF', 'G', 'H'] -> Output: '{ABC, DEF, G and H}'
>>>


Command-line arguments

{{selection|Short Circuit|Console Program Basics}} Retrieve the list of command-line arguments given to the program. For programs that only print the arguments when run directly, see [[Scripted main]].
See also [[Program name]].

For parsing command line arguments intelligently, see [[Parsing command-line arguments]].

Example command line:

 myprogram -c "alpha beta" -h "gamma"

Solution:
import sys
program_name = sys.argv[0]
arguments = sys.argv[1:]
count = len(arguments)


Compare a list of strings

Given a   list   of arbitrarily many strings, show how to:

*   test if they are all lexically '''equal'''
*   test if every string is lexically '''less than''' the one after it  ''(i.e. whether the list is in strict ascending order)''

Each of those two tests should result in a single true or false value, which could be used as the condition of an    if    statement or similar.

If the input list has less than two elements, the tests should always return true.

There is ''no'' need to provide a complete program and output.

Assume that the strings are already stored in an array/list/sequence/tuple variable (whatever is most idiomatic) with the name   strings,   and just show the expressions for performing those two tests on it (plus of course any includes and custom functions etc. that it needs),   with as little distractions as possible.

Try to write your solution in a way that does not modify the original list,   but if it does then please add a note to make that clear to readers.

If you need further guidance/clarification,   see [[#Perl]] and [[#Python]] for solutions that use implicit short-circuiting loops,   and [[#Raku]] for a solution that gets away with simply using a built-in language feature.

Solution:
from operator import (eq, lt)

xs = ["alpha", "beta", "gamma", "delta", "epsilon", "zeta",
      "eta", "theta", "iota", "kappa", "lambda", "mu"]

ys = ["alpha", "beta", "gamma", "delta", "epsilon", "zeta",
      "eta", "theta", "iota", "kappa", "lambda", "mu"]

az = sorted(xs)

print (
    all(map(eq, xs, ys)),

    all(map(lt, xs, xs[1:])),

    all(map(lt, az, az[1:]))
)


Compiler/AST interpreter

The C and Python versions can be considered reference implementations.

;Related Tasks

* Lexical Analyzer task
* Syntax Analyzer task
* Code Generator task
* Virtual Machine Interpreter task

__TOC__

Solution:
from __future__ import print_function
import sys, shlex, operator

nd_Ident, nd_String, nd_Integer, nd_Sequence, nd_If, nd_Prtc, nd_Prts, nd_Prti, nd_While, \
nd_Assign, nd_Negate, nd_Not, nd_Mul, nd_Div, nd_Mod, nd_Add, nd_Sub, nd_Lss, nd_Leq,     \
nd_Gtr, nd_Geq, nd_Eql, nd_Neq, nd_And, nd_Or = range(25)

all_syms = {
    "Identifier"  : nd_Ident,    "String"      : nd_String,
    "Integer"     : nd_Integer,  "Sequence"    : nd_Sequence,
    "If"          : nd_If,       "Prtc"        : nd_Prtc,
    "Prts"        : nd_Prts,     "Prti"        : nd_Prti,
    "While"       : nd_While,    "Assign"      : nd_Assign,
    "Negate"      : nd_Negate,   "Not"         : nd_Not,
    "Multiply"    : nd_Mul,      "Divide"      : nd_Div,
    "Mod"         : nd_Mod,      "Add"         : nd_Add,
    "Subtract"    : nd_Sub,      "Less"        : nd_Lss,
    "LessEqual"   : nd_Leq,      "Greater"     : nd_Gtr,
    "GreaterEqual": nd_Geq,      "Equal"       : nd_Eql,
    "NotEqual"    : nd_Neq,      "And"         : nd_And,
    "Or"          : nd_Or}

input_file  = None
globals     = {}

#*** show error and exit
def error(msg):
    print("%s" % (msg))
    exit(1)

class Node:
    def __init__(self, node_type, left = None, right = None, value = None):
        self.node_type  = node_type
        self.left  = left
        self.right = right
        self.value = value

#***
def make_node(oper, left, right = None):
    return Node(oper, left, right)

#***
def make_leaf(oper, n):
    return Node(oper, value = n)

#***
def fetch_var(var_name):
    n = globals.get(var_name, None)
    if n == None:
        globals[var_name] = n = 0
    return n

#***
def interp(x):
    global globals

    if x == None: return None
    elif x.node_type == nd_Integer: return int(x.value)
    elif x.node_type == nd_Ident:   return fetch_var(x.value)
    elif x.node_type == nd_String:  return x.value

    elif x.node_type == nd_Assign:
                    globals[x.left.value] = interp(x.right)
                    return None
    elif x.node_type == nd_Add:     return interp(x.left) +   interp(x.right)
    elif x.node_type == nd_Sub:     return interp(x.left) -   interp(x.right)
    elif x.node_type == nd_Mul:     return interp(x.left) *   interp(x.right)
    # use C like division semantics
    # another way: abs(x) / abs(y) * cmp(x, 0) * cmp(y, 0)
    elif x.node_type == nd_Div:     return int(float(interp(x.left)) / interp(x.right))
    elif x.node_type == nd_Mod:     return int(float(interp(x.left)) % interp(x.right))
    elif x.node_type == nd_Lss:     return interp(x.left) <   interp(x.right)
    elif x.node_type == nd_Gtr:     return interp(x.left) >   interp(x.right)
    elif x.node_type == nd_Leq:     return interp(x.left) <=  interp(x.right)
    elif x.node_type == nd_Geq:     return interp(x.left) >=  interp(x.right)
    elif x.node_type == nd_Eql:     return interp(x.left) ==  interp(x.right)
    elif x.node_type == nd_Neq:     return interp(x.left) !=  interp(x.right)
    elif x.node_type == nd_And:     return interp(x.left) and interp(x.right)
    elif x.node_type == nd_Or:      return interp(x.left) or  interp(x.right)
    elif x.node_type == nd_Negate:  return -interp(x.left)
    elif x.node_type == nd_Not:     return not interp(x.left)

    elif x.node_type ==  nd_If:
                    if (interp(x.left)):
                        interp(x.right.left)
                    else:
                        interp(x.right.right)
                    return None

    elif x.node_type == nd_While:
                    while (interp(x.left)):
                        interp(x.right)
                    return None

    elif x.node_type == nd_Prtc:
                    print("%c" % (interp(x.left)), end='')
                    return None

    elif x.node_type == nd_Prti:
                    print("%d" % (interp(x.left)), end='')
                    return None

    elif x.node_type == nd_Prts:
                    print(interp(x.left), end='')
                    return None

    elif x.node_type == nd_Sequence:
                    interp(x.left)
                    interp(x.right)
                    return None
    else:
        error("error in code generator - found %d, expecting operator" % (x.node_type))

def str_trans(srce):
    dest = ""
    i = 0
    srce = srce[1:-1]
    while i < len(srce):
        if srce[i] == '\\' and i + 1 < len(srce):
            if srce[i + 1] == 'n':
                dest += '\n'
                i += 2
            elif srce[i + 1] == '\\':
                dest += '\\'
                i += 2
        else:
            dest += srce[i]
            i += 1

    return dest

def load_ast():
    line = input_file.readline()
    line_list = shlex.split(line, False, False)

    text = line_list[0]

    value = None
    if len(line_list) > 1:
        value = line_list[1]
        if value.isdigit():
            value = int(value)

    if text == ";":
        return None
    node_type = all_syms[text]
    if value != None:
        if node_type == nd_String:
            value = str_trans(value)

        return make_leaf(node_type, value)
    left = load_ast()
    right = load_ast()
    return make_node(node_type, left, right)

#*** main driver
input_file = sys.stdin
if len(sys.argv) > 1:
    try:
        input_file = open(sys.argv[1], "r", 4096)
    except IOError as e:
        error(0, 0, "Can't open %s" % sys.argv[1])

n = load_ast()
interp(n)


Compiler/code generator

The C and Python versions can be considered reference implementations.

;Related Tasks

* Lexical Analyzer task
* Syntax Analyzer task
* Virtual Machine Interpreter task
* AST Interpreter task

__TOC__

Solution:
from __future__ import print_function
import sys, struct, shlex, operator

nd_Ident, nd_String, nd_Integer, nd_Sequence, nd_If, nd_Prtc, nd_Prts, nd_Prti, nd_While, \
nd_Assign, nd_Negate, nd_Not, nd_Mul, nd_Div, nd_Mod, nd_Add, nd_Sub, nd_Lss, nd_Leq,     \
nd_Gtr, nd_Geq, nd_Eql, nd_Neq, nd_And, nd_Or = range(25)

all_syms = {
    "Identifier"  : nd_Ident,    "String"      : nd_String,
    "Integer"     : nd_Integer,  "Sequence"    : nd_Sequence,
    "If"          : nd_If,       "Prtc"        : nd_Prtc,
    "Prts"        : nd_Prts,     "Prti"        : nd_Prti,
    "While"       : nd_While,    "Assign"      : nd_Assign,
    "Negate"      : nd_Negate,   "Not"         : nd_Not,
    "Multiply"    : nd_Mul,      "Divide"      : nd_Div,
    "Mod"         : nd_Mod,      "Add"         : nd_Add,
    "Subtract"    : nd_Sub,      "Less"        : nd_Lss,
    "LessEqual"   : nd_Leq,      "Greater"     : nd_Gtr,
    "GreaterEqual": nd_Geq,      "Equal"       : nd_Eql,
    "NotEqual"    : nd_Neq,      "And"         : nd_And,
    "Or"          : nd_Or}

FETCH, STORE, PUSH, ADD, SUB, MUL, DIV, MOD, LT, GT, LE, GE, EQ, NE, AND, OR, NEG, NOT, \
JMP, JZ, PRTC, PRTS, PRTI, HALT = range(24)

operators = {nd_Lss: LT, nd_Gtr: GT, nd_Leq: LE, nd_Geq: GE, nd_Eql: EQ, nd_Neq: NE,
    nd_And: AND, nd_Or: OR, nd_Sub: SUB, nd_Add: ADD, nd_Div: DIV, nd_Mul: MUL, nd_Mod: MOD}

unary_operators = {nd_Negate: NEG, nd_Not: NOT}

input_file  = None
code        = bytearray()
string_pool = {}
globals     = {}
string_n    = 0
globals_n   = 0
word_size   = 4

#*** show error and exit
def error(msg):
    print("%s" % (msg))
    exit(1)

def int_to_bytes(val):
    return struct.pack("<i", val)

def bytes_to_int(bstr):
    return struct.unpack("<i", bstr)

class Node:
    def __init__(self, node_type, left = None, right = None, value = None):
        self.node_type  = node_type
        self.left  = left
        self.right = right
        self.value = value

#***
def make_node(oper, left, right = None):
    return Node(oper, left, right)

#***
def make_leaf(oper, n):
    return Node(oper, value = n)

#***
def emit_byte(x):
    code.append(x)

#***
def emit_word(x):
    s = int_to_bytes(x)
    for x in s:
        code.append(x)

def emit_word_at(at, n):
    code[at:at+word_size] = int_to_bytes(n)

def hole():
    t = len(code)
    emit_word(0)
    return t

#***
def fetch_var_offset(name):
    global globals_n

    n = globals.get(name, None)
    if n == None:
        globals[name] = globals_n
        n = globals_n
        globals_n += 1
    return n

#***
def fetch_string_offset(the_string):
    global string_n

    n = string_pool.get(the_string, None)
    if n == None:
        string_pool[the_string] = string_n
        n = string_n
        string_n += 1
    return n

#***
def code_gen(x):
    if x == None: return
    elif x.node_type == nd_Ident:
        emit_byte(FETCH)
        n = fetch_var_offset(x.value)
        emit_word(n)
    elif x.node_type == nd_Integer:
        emit_byte(PUSH)
        emit_word(x.value)
    elif x.node_type == nd_String:
        emit_byte(PUSH)
        n = fetch_string_offset(x.value)
        emit_word(n)
    elif x.node_type == nd_Assign:
        n = fetch_var_offset(x.left.value)
        code_gen(x.right)
        emit_byte(STORE)
        emit_word(n)
    elif x.node_type == nd_If:
        code_gen(x.left)              # expr
        emit_byte(JZ)                 # if false, jump
        p1 = hole()                   # make room for jump dest
        code_gen(x.right.left)        # if true statements
        if (x.right.right != None):
            emit_byte(JMP)            # jump over else statements
            p2 = hole()
        emit_word_at(p1, len(code) - p1)
        if (x.right.right != None):
            code_gen(x.right.right)   # else statements
            emit_word_at(p2, len(code) - p2)
    elif x.node_type == nd_While:
        p1 = len(code)
        code_gen(x.left)
        emit_byte(JZ)
        p2 = hole()
        code_gen(x.right)
        emit_byte(JMP)                       # jump back to the top
        emit_word(p1 - len(code))
        emit_word_at(p2, len(code) - p2)
    elif x.node_type == nd_Sequence:
        code_gen(x.left)
        code_gen(x.right)
    elif x.node_type == nd_Prtc:
        code_gen(x.left)
        emit_byte(PRTC)
    elif x.node_type == nd_Prti:
        code_gen(x.left)
        emit_byte(PRTI)
    elif x.node_type == nd_Prts:
        code_gen(x.left)
        emit_byte(PRTS)
    elif x.node_type in operators:
        code_gen(x.left)
        code_gen(x.right)
        emit_byte(operators[x.node_type])
    elif x.node_type in unary_operators:
        code_gen(x.left)
        emit_byte(unary_operators[x.node_type])
    else:
        error("error in code generator - found %d, expecting operator" % (x.node_type))

#***
def code_finish():
    emit_byte(HALT)

#***
def list_code():
    print("Datasize: %d Strings: %d" % (len(globals), len(string_pool)))

    for k in sorted(string_pool, key=string_pool.get):
        print(k)

    pc = 0
    while pc < len(code):
        print("%4d " % (pc), end='')
        op = code[pc]
        pc += 1
        if op == FETCH:
            x = bytes_to_int(code[pc:pc+word_size])[0]
            print("fetch [%d]" % (x));
            pc += word_size
        elif op == STORE:
            x = bytes_to_int(code[pc:pc+word_size])[0]
            print("store [%d]" % (x));
            pc += word_size
        elif op == PUSH:
            x = bytes_to_int(code[pc:pc+word_size])[0]
            print("push  %d" % (x));
            pc += word_size
        elif op == ADD:   print("add")
        elif op == SUB:   print("sub")
        elif op == MUL:   print("mul")
        elif op == DIV:   print("div")
        elif op == MOD:   print("mod")
        elif op == LT:    print("lt")
        elif op == GT:    print("gt")
        elif op == LE:    print("le")
        elif op == GE:    print("ge")
        elif op == EQ:    print("eq")
        elif op == NE:    print("ne")
        elif op == AND:   print("and")
        elif op == OR:    print("or")
        elif op == NEG:   print("neg")
        elif op == NOT:   print("not")
        elif op == JMP:
            x = bytes_to_int(code[pc:pc+word_size])[0]
            print("jmp    (%d) %d" % (x, pc + x));
            pc += word_size
        elif op == JZ:
            x = bytes_to_int(code[pc:pc+word_size])[0]
            print("jz     (%d) %d" % (x, pc + x));
            pc += word_size
        elif op == PRTC:  print("prtc")
        elif op == PRTI:  print("prti")
        elif op == PRTS:  print("prts")
        elif op == HALT:  print("halt")
        else: error("list_code: Unknown opcode %d", (op));

def load_ast():
    line = input_file.readline()
    line_list = shlex.split(line, False, False)

    text = line_list[0]
    if text == ";":
        return None
    node_type = all_syms[text]

    if len(line_list) > 1:
        value = line_list[1]
        if value.isdigit():
            value = int(value)
        return make_leaf(node_type, value)

    left = load_ast()
    right = load_ast()
    return make_node(node_type, left, right)

#*** main driver
input_file = sys.stdin
if len(sys.argv) > 1:
    try:
        input_file = open(sys.argv[1], "r", 4096)
    except IOError as e:
        error("Can't open %s" % sys.argv[1])

n = load_ast()
code_gen(n)
code_finish()
list_code()


Compiler/lexical analyzer

The C and Python versions can be considered reference implementations.

;Related Tasks
* Syntax Analyzer task
* Code Generator task
* Virtual Machine Interpreter task
* AST Interpreter task

Solution:
from __future__ import print_function
import sys

# following two must remain in the same order

tk_EOI, tk_Mul, tk_Div, tk_Mod, tk_Add, tk_Sub, tk_Negate, tk_Not, tk_Lss, tk_Leq, tk_Gtr, \
tk_Geq, tk_Eq, tk_Neq, tk_Assign, tk_And, tk_Or, tk_If, tk_Else, tk_While, tk_Print,       \
tk_Putc, tk_Lparen, tk_Rparen, tk_Lbrace, tk_Rbrace, tk_Semi, tk_Comma, tk_Ident,          \
tk_Integer, tk_String = range(31)

all_syms = ["End_of_input", "Op_multiply", "Op_divide", "Op_mod", "Op_add", "Op_subtract",
    "Op_negate", "Op_not", "Op_less", "Op_lessequal", "Op_greater", "Op_greaterequal",
    "Op_equal", "Op_notequal", "Op_assign", "Op_and", "Op_or", "Keyword_if",
    "Keyword_else", "Keyword_while", "Keyword_print", "Keyword_putc", "LeftParen",
    "RightParen", "LeftBrace", "RightBrace", "Semicolon", "Comma", "Identifier",
    "Integer", "String"]

# single character only symbols
symbols = { '{': tk_Lbrace, '}': tk_Rbrace, '(': tk_Lparen, ')': tk_Rparen, '+': tk_Add, '-': tk_Sub,
    '*': tk_Mul, '%': tk_Mod, ';': tk_Semi, ',': tk_Comma }

key_words = {'if': tk_If, 'else': tk_Else, 'print': tk_Print, 'putc': tk_Putc, 'while': tk_While}

the_ch = " "    # dummy first char - but it must be a space
the_col = 0
the_line = 1
input_file = None

#*** show error and exit
def error(line, col, msg):
    print(line, col, msg)
    exit(1)

#*** get the next character from the input
def next_ch():
    global the_ch, the_col, the_line

    the_ch = input_file.read(1)
    the_col += 1
    if the_ch == '\n':
        the_line += 1
        the_col = 0
    return the_ch

#*** 'x' - character constants
def char_lit(err_line, err_col):
    n = ord(next_ch())              # skip opening quote
    if the_ch == '\'':
        error(err_line, err_col, "empty character constant")
    elif the_ch == '\\':
        next_ch()
        if the_ch == 'n':
            n = 10
        elif the_ch == '\\':
            n = ord('\\')
        else:
            error(err_line, err_col, "unknown escape sequence \\%c" % (the_ch))
    if next_ch() != '\'':
        error(err_line, err_col, "multi-character constant")
    next_ch()
    return tk_Integer, err_line, err_col, n

#*** process divide or comments
def div_or_cmt(err_line, err_col):
    if next_ch() != '*':
        return tk_Div, err_line, err_col

    # comment found
    next_ch()
    while True:
        if the_ch == '*':
            if next_ch() == '/':
                next_ch()
                return gettok()
        elif len(the_ch) == 0:
            error(err_line, err_col, "EOF in comment")
        else:
            next_ch()

#*** "string"
def string_lit(start, err_line, err_col):
    global the_ch
    text = ""

    while next_ch() != start:
        if len(the_ch) == 0:
            error(err_line, err_col, "EOF while scanning string literal")
        if the_ch == '\n':
            error(err_line, err_col, "EOL while scanning string literal")
        if the_ch == '\\':
            next_ch()
            if the_ch != 'n':
                error(err_line, err_col, "escape sequence unknown \\%c" % the_ch)
            the_ch = '\n'
        text += the_ch

    next_ch()
    return tk_String, err_line, err_col, text

#*** handle identifiers and integers
def ident_or_int(err_line, err_col):
    is_number = True
    text = ""

    while the_ch.isalnum() or the_ch == '_':
        text += the_ch
        if not the_ch.isdigit():
            is_number = False
        next_ch()

    if len(text) == 0:
        error(err_line, err_col, "ident_or_int: unrecognized character: (%d) '%c'" % (ord(the_ch), the_ch))

    if text[0].isdigit():
        if not is_number:
            error(err_line, err_col, "invalid number: %s" % (text))
        n = int(text)
        return tk_Integer, err_line, err_col, n

    if text in key_words:
        return key_words[text], err_line, err_col

    return tk_Ident, err_line, err_col, text

#*** look ahead for '>=', etc.
def follow(expect, ifyes, ifno, err_line, err_col):
    if next_ch() == expect:
        next_ch()
        return ifyes, err_line, err_col

    if ifno == tk_EOI:
        error(err_line, err_col, "follow: unrecognized character: (%d) '%c'" % (ord(the_ch), the_ch))

    return ifno, err_line, err_col

#*** return the next token type
def gettok():
    while the_ch.isspace():
        next_ch()

    err_line = the_line
    err_col  = the_col

    if len(the_ch) == 0:    return tk_EOI, err_line, err_col
    elif the_ch == '/':     return div_or_cmt(err_line, err_col)
    elif the_ch == '\'':    return char_lit(err_line, err_col)
    elif the_ch == '<':     return follow('=', tk_Leq, tk_Lss,    err_line, err_col)
    elif the_ch == '>':     return follow('=', tk_Geq, tk_Gtr,    err_line, err_col)
    elif the_ch == '=':     return follow('=', tk_Eq,  tk_Assign, err_line, err_col)
    elif the_ch == '!':     return follow('=', tk_Neq, tk_Not,    err_line, err_col)
    elif the_ch == '&':     return follow('&', tk_And, tk_EOI,    err_line, err_col)
    elif the_ch == '|':     return follow('|', tk_Or,  tk_EOI,    err_line, err_col)
    elif the_ch == '"':     return string_lit(the_ch, err_line, err_col)
    elif the_ch in symbols:
        sym = symbols[the_ch]
        next_ch()
        return sym, err_line, err_col
    else: return ident_or_int(err_line, err_col)

#*** main driver
input_file = sys.stdin
if len(sys.argv) > 1:
    try:
        input_file = open(sys.argv[1], "r", 4096)
    except IOError as e:
        error(0, 0, "Can't open %s" % sys.argv[1])

while True:
    t = gettok()
    tok  = t[0]
    line = t[1]
    col  = t[2]

    print("%5d  %5d   %-14s" % (line, col, all_syms[tok]), end='')

    if tok == tk_Integer:  print("   %5d" % (t[3]))
    elif tok == tk_Ident:  print("  %s" %   (t[3]))
    elif tok == tk_String: print('  "%s"' % (t[3]))
    else:                  print("")

    if tok == tk_EOI:
        break


Compiler/syntax analyzer

The C and Python versions can be considered reference implementations.

;Related Tasks

* Lexical Analyzer task
* Code Generator task
* Virtual Machine Interpreter task
* AST Interpreter task

__TOC__

Solution:
from __future__ import print_function
import sys, shlex, operator

tk_EOI, tk_Mul, tk_Div, tk_Mod, tk_Add, tk_Sub, tk_Negate, tk_Not, tk_Lss, tk_Leq, tk_Gtr, \
tk_Geq, tk_Eql, tk_Neq, tk_Assign, tk_And, tk_Or, tk_If, tk_Else, tk_While, tk_Print,      \
tk_Putc, tk_Lparen, tk_Rparen, tk_Lbrace, tk_Rbrace, tk_Semi, tk_Comma, tk_Ident,          \
tk_Integer, tk_String = range(31)

nd_Ident, nd_String, nd_Integer, nd_Sequence, nd_If, nd_Prtc, nd_Prts, nd_Prti, nd_While, \
nd_Assign, nd_Negate, nd_Not, nd_Mul, nd_Div, nd_Mod, nd_Add, nd_Sub, nd_Lss, nd_Leq,     \
nd_Gtr, nd_Geq, nd_Eql, nd_Neq, nd_And, nd_Or = range(25)

# must have same order as above
Tokens = [
    ["EOI"             , False, False, False, -1, -1        ],
    ["*"               , False, True,  False, 13, nd_Mul    ],
    ["/"               , False, True,  False, 13, nd_Div    ],
    ["%"               , False, True,  False, 13, nd_Mod    ],
    ["+"               , False, True,  False, 12, nd_Add    ],
    ["-"               , False, True,  False, 12, nd_Sub    ],
    ["-"               , False, False, True,  14, nd_Negate ],
    ["!"               , False, False, True,  14, nd_Not    ],
    ["<"               , False, True,  False, 10, nd_Lss    ],
    ["<="              , False, True,  False, 10, nd_Leq    ],
    [">"               , False, True,  False, 10, nd_Gtr    ],
    [">="              , False, True,  False, 10, nd_Geq    ],
    ["=="              , False, True,  False,  9, nd_Eql    ],
    ["!="              , False, True,  False,  9, nd_Neq    ],
    ["="               , False, False, False, -1, nd_Assign ],
    ["&&"              , False, True,  False,  5, nd_And    ],
    ["||"              , False, True,  False,  4, nd_Or     ],
    ["if"              , False, False, False, -1, nd_If     ],
    ["else"            , False, False, False, -1, -1        ],
    ["while"           , False, False, False, -1, nd_While  ],
    ["print"           , False, False, False, -1, -1        ],
    ["putc"            , False, False, False, -1, -1        ],
    ["("               , False, False, False, -1, -1        ],
    [")"               , False, False, False, -1, -1        ],
    ["{"               , False, False, False, -1, -1        ],
    ["}"               , False, False, False, -1, -1        ],
    [";"               , False, False, False, -1, -1        ],
    [","               , False, False, False, -1, -1        ],
    ["Ident"           , False, False, False, -1, nd_Ident  ],
    ["Integer literal" , False, False, False, -1, nd_Integer],
    ["String literal"  , False, False, False, -1, nd_String ]
    ]

all_syms = {"End_of_input"   : tk_EOI,     "Op_multiply"    : tk_Mul,
            "Op_divide"      : tk_Div,     "Op_mod"         : tk_Mod,
            "Op_add"         : tk_Add,     "Op_subtract"    : tk_Sub,
            "Op_negate"      : tk_Negate,  "Op_not"         : tk_Not,
            "Op_less"        : tk_Lss,     "Op_lessequal"   : tk_Leq,
            "Op_greater"     : tk_Gtr,     "Op_greaterequal": tk_Geq,
            "Op_equal"       : tk_Eql,     "Op_notequal"    : tk_Neq,
            "Op_assign"      : tk_Assign,  "Op_and"         : tk_And,
            "Op_or"          : tk_Or,      "Keyword_if"     : tk_If,
            "Keyword_else"   : tk_Else,    "Keyword_while"  : tk_While,
            "Keyword_print"  : tk_Print,   "Keyword_putc"   : tk_Putc,
            "LeftParen"      : tk_Lparen,  "RightParen"     : tk_Rparen,
            "LeftBrace"      : tk_Lbrace,  "RightBrace"     : tk_Rbrace,
            "Semicolon"      : tk_Semi,    "Comma"          : tk_Comma,
            "Identifier"     : tk_Ident,   "Integer"        : tk_Integer,
            "String"         : tk_String}

Display_nodes = ["Identifier", "String", "Integer", "Sequence", "If", "Prtc", "Prts",
    "Prti", "While", "Assign", "Negate", "Not", "Multiply", "Divide", "Mod", "Add",
    "Subtract", "Less", "LessEqual", "Greater", "GreaterEqual", "Equal", "NotEqual",
    "And", "Or"]

TK_NAME         = 0
TK_RIGHT_ASSOC  = 1
TK_IS_BINARY    = 2
TK_IS_UNARY     = 3
TK_PRECEDENCE   = 4
TK_NODE         = 5

input_file = None
err_line   = None
err_col    = None
tok        = None
tok_text   = None

#*** show error and exit
def error(msg):
    print("(%d, %d) %s" % (int(err_line), int(err_col), msg))
    exit(1)

#***
def gettok():
    global err_line, err_col, tok, tok_text, tok_other
    line = input_file.readline()
    if len(line) == 0:
        error("empty line")

    line_list = shlex.split(line, False, False)
    # line col Ident var_name
    # 0    1   2     3

    err_line = line_list[0]
    err_col  = line_list[1]
    tok_text = line_list[2]

    tok = all_syms.get(tok_text)
    if tok == None:
        error("Unknown token %s" % (tok_text))

    tok_other = None
    if tok in [tk_Integer, tk_Ident, tk_String]:
        tok_other = line_list[3]

class Node:
    def __init__(self, node_type, left = None, right = None, value = None):
        self.node_type  = node_type
        self.left  = left
        self.right = right
        self.value = value

#***
def make_node(oper, left, right = None):
    return Node(oper, left, right)

#***
def make_leaf(oper, n):
    return Node(oper, value = n)

#***
def expect(msg, s):
    if tok == s:
        gettok()
        return
    error("%s: Expecting '%s', found '%s'" % (msg, Tokens[s][TK_NAME], Tokens[tok][TK_NAME]))

#***
def expr(p):
    x = None

    if tok == tk_Lparen:
        x = paren_expr()
    elif tok in [tk_Sub, tk_Add]:
        op = (tk_Negate if tok == tk_Sub else tk_Add)
        gettok()
        node = expr(Tokens[tk_Negate][TK_PRECEDENCE])
        x = (make_node(nd_Negate, node) if op == tk_Negate else node)
    elif tok == tk_Not:
        gettok()
        x = make_node(nd_Not, expr(Tokens[tk_Not][TK_PRECEDENCE]))
    elif tok == tk_Ident:
        x = make_leaf(nd_Ident, tok_other)
        gettok()
    elif tok == tk_Integer:
        x = make_leaf(nd_Integer, tok_other)
        gettok()
    else:
        error("Expecting a primary, found: %s" % (Tokens[tok][TK_NAME]))

    while Tokens[tok][TK_IS_BINARY] and Tokens[tok][TK_PRECEDENCE] >= p:
        op = tok
        gettok()
        q = Tokens[op][TK_PRECEDENCE]
        if not Tokens[op][TK_RIGHT_ASSOC]:
            q += 1

        node = expr(q)
        x = make_node(Tokens[op][TK_NODE], x, node)

    return x

#***
def paren_expr():
    expect("paren_expr", tk_Lparen)
    node = expr(0)
    expect("paren_expr", tk_Rparen)
    return node

#***
def stmt():
    t = None

    if tok == tk_If:
        gettok()
        e = paren_expr()
        s = stmt()
        s2 = None
        if tok == tk_Else:
            gettok()
            s2 = stmt()
        t = make_node(nd_If, e, make_node(nd_If, s, s2))
    elif tok == tk_Putc:
        gettok()
        e = paren_expr()
        t = make_node(nd_Prtc, e)
        expect("Putc", tk_Semi)
    elif tok == tk_Print:
        gettok()
        expect("Print", tk_Lparen)
        while True:
            if tok == tk_String:
                e = make_node(nd_Prts, make_leaf(nd_String, tok_other))
                gettok()
            else:
                e = make_node(nd_Prti, expr(0))

            t = make_node(nd_Sequence, t, e)
            if tok != tk_Comma:
                break
            gettok()
        expect("Print", tk_Rparen)
        expect("Print", tk_Semi)
    elif tok == tk_Semi:
        gettok()
    elif tok == tk_Ident:
        v = make_leaf(nd_Ident, tok_other)
        gettok()
        expect("assign", tk_Assign)
        e = expr(0)
        t = make_node(nd_Assign, v, e)
        expect("assign", tk_Semi)
    elif tok == tk_While:
        gettok()
        e = paren_expr()
        s = stmt()
        t = make_node(nd_While, e, s)
    elif tok == tk_Lbrace:
        gettok()
        while tok != tk_Rbrace and tok != tk_EOI:
            t = make_node(nd_Sequence, t, stmt())
        expect("Lbrace", tk_Rbrace)
    elif tok == tk_EOI:
        pass
    else:
        error("Expecting start of statement, found: %s" % (Tokens[tok][TK_NAME]))

    return t

#***
def parse():
    t = None
    gettok()
    while True:
        t = make_node(nd_Sequence, t, stmt())
        if tok == tk_EOI or t == None:
            break
    return t

def prt_ast(t):
    if t == None:
        print(";")
    else:
        print("%-14s" % (Display_nodes[t.node_type]), end='')
        if t.node_type in [nd_Ident, nd_Integer]:
            print("%s" % (t.value))
        elif t.node_type == nd_String:
            print("%s" %(t.value))
        else:
            print("")
            prt_ast(t.left)
            prt_ast(t.right)

#*** main driver
input_file = sys.stdin
if len(sys.argv) > 1:
    try:
        input_file = open(sys.argv[1], "r", 4096)
    except IOError as e:
        error(0, 0, "Can't open %s" % sys.argv[1])
t = parse()
prt_ast(t)


Compiler/virtual machine interpreter

The C and Python versions can be considered reference implementations.

;Related Tasks

* Lexical Analyzer task
* Syntax Analyzer task
* Code Generator task
* AST Interpreter task

__TOC__

Solution:
from __future__ import print_function
import sys, struct

FETCH, STORE, PUSH, ADD, SUB, MUL, DIV, MOD, LT, GT, LE, GE, EQ, NE, AND, OR, NEG, NOT, \
JMP, JZ, PRTC, PRTS, PRTI, HALT = range(24)

code_map = {
    "fetch": FETCH,
    "store": STORE,
    "push":  PUSH,
    "add":   ADD,
    "sub":   SUB,
    "mul":   MUL,
    "div":   DIV,
    "mod":   MOD,
    "lt":    LT,
    "gt":    GT,
    "le":    LE,
    "ge":    GE,
    "eq":    EQ,
    "ne":    NE,
    "and":   AND,
    "or":    OR,
    "not":   NOT,
    "neg":   NEG,
    "jmp":   JMP,
    "jz":    JZ,
    "prtc":  PRTC,
    "prts":  PRTS,
    "prti":  PRTI,
    "halt":  HALT
}

input_file  = None
code        = bytearray()
string_pool = []
word_size   = 4

#*** show error and exit
def error(msg):
    print("%s" % (msg))
    exit(1)

def int_to_bytes(val):
    return struct.pack("<i", val)

def bytes_to_int(bstr):
    return struct.unpack("<i", bstr)

#***
def emit_byte(x):
    code.append(x)

#***
def emit_word(x):
    s = int_to_bytes(x)
    for x in s:
        code.append(x)

#***
def run_vm(data_size):
    stack = [0 for i in range(data_size + 1)]
    pc = 0
    while True:
        op = code[pc]
        pc += 1

        if op == FETCH:
            stack.append(stack[bytes_to_int(code[pc:pc+word_size])[0]]);
            pc += word_size
        elif op == STORE:
            stack[bytes_to_int(code[pc:pc+word_size])[0]] = stack.pop();
            pc += word_size
        elif op == PUSH:
            stack.append(bytes_to_int(code[pc:pc+word_size])[0]);
            pc += word_size
        elif op == ADD:   stack[-2] += stack[-1]; stack.pop()
        elif op == SUB:   stack[-2] -= stack[-1]; stack.pop()
        elif op == MUL:   stack[-2] *= stack[-1]; stack.pop()
        # use C like division semantics
        elif op == DIV:   stack[-2] = int(float(stack[-2]) / stack[-1]); stack.pop()
        elif op == MOD:   stack[-2] = int(float(stack[-2]) % stack[-1]); stack.pop()
        elif op == LT:    stack[-2] = stack[-2] <  stack[-1]; stack.pop()
        elif op == GT:    stack[-2] = stack[-2] >  stack[-1]; stack.pop()
        elif op == LE:    stack[-2] = stack[-2] <= stack[-1]; stack.pop()
        elif op == GE:    stack[-2] = stack[-2] >= stack[-1]; stack.pop()
        elif op == EQ:    stack[-2] = stack[-2] == stack[-1]; stack.pop()
        elif op == NE:    stack[-2] = stack[-2] != stack[-1]; stack.pop()
        elif op == AND:   stack[-2] = stack[-2] and stack[-1]; stack.pop()
        elif op == OR:    stack[-2] = stack[-2] or  stack[-1]; stack.pop()
        elif op == NEG:   stack[-1] = -stack[-1]
        elif op == NOT:   stack[-1] = not stack[-1]
        elif op == JMP:   pc += bytes_to_int(code[pc:pc+word_size])[0]
        elif op == JZ:
            if stack.pop():
                pc += word_size
            else:
                pc += bytes_to_int(code[pc:pc+word_size])[0]
        elif op == PRTC:  print("%c" % (stack[-1]), end=''); stack.pop()
        elif op == PRTS:  print("%s" % (string_pool[stack[-1]]), end=''); stack.pop()
        elif op == PRTI:  print("%d" % (stack[-1]), end=''); stack.pop()
        elif op == HALT:  break

def str_trans(srce):
    dest = ""
    i = 0
    while i < len(srce):
        if srce[i] == '\\' and i + 1 < len(srce):
            if srce[i + 1] == 'n':
                dest += '\n'
                i += 2
            elif srce[i + 1] == '\\':
                dest += '\\'
                i += 2
        else:
            dest += srce[i]
            i += 1

    return dest

#***
def load_code():
    global string_pool

    line = input_file.readline()
    if len(line) == 0:
        error("empty line")

    line_list = line.split()
    data_size = int(line_list[1])
    n_strings = int(line_list[3])

    for i in range(n_strings):
        string_pool.append(str_trans(input_file.readline().strip('"\n')))

    while True:
        line = input_file.readline()
        if len(line) == 0:
            break
        line_list = line.split()
        offset = int(line_list[0])
        instr  = line_list[1]
        opcode = code_map.get(instr)
        if opcode == None:
            error("Unknown instruction %s at %d" % (instr, offset))
        emit_byte(opcode)
        if opcode in [JMP, JZ]:
            p = int(line_list[3])
            emit_word(p - (offset + 1))
        elif opcode == PUSH:
            value = int(line_list[2])
            emit_word(value)
        elif opcode in [FETCH, STORE]:
            value = int(line_list[2].strip('[]'))
            emit_word(value)

    return data_size

#*** main driver
input_file = sys.stdin
if len(sys.argv) > 1:
    try:
        input_file = open(sys.argv[1], "r", 4096)
    except IOError as e:
        error(0, 0, "Can't open %s" % sys.argv[1])

data_size = load_code()
run_vm(data_size)


Composite numbers k with no single digit factors whose factors are all substrings of k

Find the composite numbers '''k''' in base 10, that have no single digit prime factors and whose prime factors are all a substring of '''k'''.

;Task

* Find and show here, on this page, the first ten elements of the sequence.

;Stretch

* Find and show the next ten elements.

Solution:
from sympy import isprime, factorint

def contains_its_prime_factors_all_over_7(n):
    if n < 10 or isprime(n):
        return False
    strn = str(n)
    pfacs = factorint(n).keys()
    return all(f > 9 and str(f) in strn for f in pfacs)

found = 0
for n in range(1_000_000_000):
    if contains_its_prime_factors_all_over_7(n):
        found += 1
        print(f'{n: 12,}', end = '\n' if found % 10 == 0 else '')
        if found == 20:
            break


Conjugate transpose

Suppose that a conjugate transpose of M is a matrix M^H containing the [[complex conjugate]]s of the [[matrix transposition]] of M.

::: (M^H)_{ji} = \overline{M_{ij}}

This means that   row j, column i of the conjugate transpose equals the
complex conjugate of row i, column j of the original matrix.

In the next list, M must also be a square matrix.

* A Hermitian matrix equals its own conjugate transpose: M^H = M.
* A multiplication with its conjugate transpose: M^HM = MM^H.
* A iff M^HM = I_n and iff MM^H = I_n, where I_n is the identity matrix.

;Task:
Given some matrix of complex numbers, find its conjugate transpose.

Also determine if the matrix is a:
::* Hermitian matrix,
::* normal matrix,  or
::* unitary matrix.

;See also:
* MathWorld entry: conjugate transpose
* MathWorld entry: Hermitian matrix
* MathWorld entry: normal matrix
* MathWorld entry: unitary matrix

Solution:
def conjugate_transpose(m):
    return tuple(tuple(n.conjugate() for n in row) for row in zip(*m))

def mmul( ma, mb):
    return tuple(tuple(sum( ea*eb for ea,eb in zip(a,b)) for b in zip(*mb)) for a in ma)

def mi(size):
    'Complex Identity matrix'
    sz = range(size)
    m = [[0 + 0j for i in sz] for j in sz]
    for i in range(size):
        m[i][i] = 1 + 0j
    return tuple(tuple(row) for row in m)

def __allsame(vector):
    first, rest = vector[0], vector[1:]
    return all(i == first for i in rest)

def __allnearsame(vector, eps=1e-14):
    first, rest = vector[0], vector[1:]
    return all(abs(first.real - i.real) < eps and abs(first.imag - i.imag) < eps
               for i in rest)

def isequal(matrices, eps=1e-14):
    'Check any number of matrices for equality within eps'
    x = [len(m) for m in matrices]
    if not __allsame(x): return False
    y = [len(m[0]) for m in matrices]
    if not __allsame(y): return False
    for s in range(x[0]):
        for t in range(y[0]):
            if not __allnearsame([m[s][t] for m in matrices], eps): return False
    return True

def ishermitian(m, ct):
    return isequal([m, ct])

def isnormal(m, ct):
    return isequal([mmul(m, ct), mmul(ct, m)])

def isunitary(m, ct):
    mct, ctm = mmul(m, ct), mmul(ct, m)
    mctx, mcty, cmx, ctmy = len(mct), len(mct[0]), len(ctm), len(ctm[0])
    ident = mi(mctx)
    return isequal([mct, ctm, ident])

def printm(comment, m):
    print(comment)
    fields = [['%g%+gj' % (f.real, f.imag) for f in row] for row in m]
    width = max(max(len(f) for f in row) for row in fields)
    lines = (', '.join('%*s' % (width, f) for f in row) for row in fields)
    print('\n'.join(lines))

if __name__ == '__main__':
    for matrix in [
            ((( 3.000+0.000j), (+2.000+1.000j)),
            (( 2.000-1.000j), (+1.000+0.000j))),

            ((( 1.000+0.000j), (+1.000+0.000j), (+0.000+0.000j)),
            (( 0.000+0.000j), (+1.000+0.000j), (+1.000+0.000j)),
            (( 1.000+0.000j), (+0.000+0.000j), (+1.000+0.000j))),

            ((( 2**0.5/2+0.000j), (+2**0.5/2+0.000j), (+0.000+0.000j)),
            (( 0.000+2**0.5/2j), (+0.000-2**0.5/2j), (+0.000+0.000j)),
            (( 0.000+0.000j), (+0.000+0.000j), (+0.000+1.000j)))]:
        printm('\nMatrix:', matrix)
        ct = conjugate_transpose(matrix)
        printm('Its conjugate transpose:', ct)
        print('Hermitian? %s.' % ishermitian(matrix, ct))
        print('Normal?    %s.' % isnormal(matrix, ct))
        print('Unitary?   %s.' % isunitary(matrix, ct))


Continued fraction

A number may be represented as a continued fraction (see Mathworld for more information) as follows:
:a_0 + \cfrac{b_1}{a_1 + \cfrac{b_2}{a_2 + \cfrac{b_3}{a_3 + \ddots}}}

The task is to write a program which generates such a number and prints a real representation of it. The code should be tested by calculating and printing the square root of 2, Napier's Constant, and Pi, using the following coefficients:

For the square root of 2, use a_0 = 1 then a_N = 2. b_N is always 1.

:\sqrt{2} = 1 + \cfrac{1}{2 + \cfrac{1}{2 + \cfrac{1}{2 + \ddots}}}

For Napier's Constant, use a_0 = 2, then a_N = N. b_1 = 1 then b_N = N-1.

:e = 2 + \cfrac{1}{1 + \cfrac{1}{2 + \cfrac{2}{3 + \cfrac{3}{4 + \ddots}}}}

For Pi, use a_0 = 3 then a_N = 6. b_N = (2N-1)^2.

:\pi = 3 + \cfrac{1}{6 + \cfrac{9}{6 + \cfrac{25}{6 + \ddots}}}

;See also:
:*   [[Continued fraction/Arithmetic]] for tasks that do arithmetic over continued fractions.

Solution:
from fractions import Fraction
import itertools
try: zip = itertools.izip
except: pass

# The Continued Fraction
def CF(a, b, t):
  terms = list(itertools.islice(zip(a, b), t))
  z = Fraction(1,1)
  for a, b in reversed(terms):
    z = a + b / z
  return z

# Approximates a fraction to a string
def pRes(x, d):
  q, x = divmod(x, 1)
  res = str(q)
  res += "."
  for i in range(d):
    x *= 10
    q, x = divmod(x, 1)
    res += str(q)
  return res

# Test the Continued Fraction for sqrt2
def sqrt2_a():
  yield 1
  for x in itertools.repeat(2):
    yield x

def sqrt2_b():
  for x in itertools.repeat(1):
    yield x

cf = CF(sqrt2_a(), sqrt2_b(), 950)
print(pRes(cf, 200))
#1.41421356237309504880168872420969807856967187537694807317667973799073247846210703885038753432764157273501384623091229702492483605585073721264412149709993583141322266592750559275579995050115278206057147

# Test the Continued Fraction for Napier's Constant
def Napier_a():
  yield 2
  for x in itertools.count(1):
    yield x

def Napier_b():
  yield 1
  for x in itertools.count(1):
    yield x

cf = CF(Napier_a(), Napier_b(), 950)
print(pRes(cf, 200))
#2.71828182845904523536028747135266249775724709369995957496696762772407663035354759457138217852516642742746639193200305992181741359662904357290033429526059563073813232862794349076323382988075319525101901

# Test the Continued Fraction for Pi
def Pi_a():
  yield 3
  for x in itertools.repeat(6):
    yield x

def Pi_b():
  for x in itertools.count(1,2):
    yield x*x

cf = CF(Pi_a(), Pi_b(), 950)
print(pRes(cf, 10))
#3.1415926532


Continued fraction

Solution:
from decimal import Decimal, getcontext

def calc(fun, n):
    temp = Decimal("0.0")

    for ni in xrange(n+1, 0, -1):
        (a, b) = fun(ni)
        temp = Decimal(b) / (a + temp)

    return fun(0)[0] + temp

def fsqrt2(n):
    return (2 if n > 0 else 1, 1)

def fnapier(n):
    return (n if n > 0 else 2, (n - 1) if n > 1 else 1)

def fpi(n):
    return (6 if n > 0 else 3, (2 * n - 1) ** 2)

getcontext().prec = 50
print calc(fsqrt2, 200)
print calc(fnapier, 200)
print calc(fpi, 200)


Continued fraction/Arithmetic/Construct from rational number

To understand this task in context please see [[Continued fraction arithmetic]]
The purpose of this task is to write a function \mathit{r2cf}(\mathrm{int} N_1, \mathrm{int} N_2), or \mathit{r2cf}(\mathrm{Fraction} N), which will output a continued fraction assuming:
:N_1 is the numerator
:N_2 is the denominator

The function should output its results one digit at a time each time it is called, in a manner sometimes described as lazy evaluation.

To achieve this it must determine: the integer part; and remainder part, of N_1 divided by N_2. It then sets N_1 to N_2 and N_2 to the determined remainder part. It then outputs the determined integer part. It does this until \mathrm{abs}(N_2) is zero.

Demonstrate the function by outputing the continued fraction for:
: 1/2
: 3
: 23/8
: 13/11
: 22/7
: -151/77
\sqrt 2 should approach [1; 2, 2, 2, 2, \ldots] try ever closer rational approximations until boredom gets the better of you:
: 14142,10000
: 141421,100000
: 1414214,1000000
: 14142136,10000000

Try :
: 31,10
: 314,100
: 3142,1000
: 31428,10000
: 314285,100000
: 3142857,1000000
: 31428571,10000000
: 314285714,100000000

Observe how this rational number behaves differently to \sqrt 2 and convince yourself that, in the same way as 3.7 may be represented as 3.70 when an extra decimal place is required, [3;7] may be represented as [3;7,\infty] when an extra term is required.

Solution:
def r2cf(n1,n2):
  while n2:
    n1, (t1, n2) = n2, divmod(n1, n2)
    yield t1

print(list(r2cf(1,2)))    # => [0, 2]
print(list(r2cf(3,1)))    # => [3]
print(list(r2cf(23,8)))    # => [2, 1, 7]
print(list(r2cf(13,11)))    # => [1, 5, 2]
print(list(r2cf(22,7)))    # => [3, 7]
print(list(r2cf(14142,10000)))    # => [1, 2, 2, 2, 2, 2, 1, 1, 29]
print(list(r2cf(141421,100000)))    # => [1, 2, 2, 2, 2, 2, 2, 3, 1, 1, 3, 1, 7, 2]
print(list(r2cf(1414214,1000000)))    # => [1, 2, 2, 2, 2, 2, 2, 2, 3, 6, 1, 2, 1, 12]
print(list(r2cf(14142136,10000000)))    # => [1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 1, 2, 4, 1, 1, 2]


Continued fraction/Arithmetic/G(matrix ng, continued fraction n)

This task investigates mathmatical operations that can be performed on a single continued fraction. This requires only a baby version of NG:
: \begin{bmatrix}
  a_1 & a \\
  b_1 & b
\end{bmatrix}
I may perform perform the following operations:
:Input the next term of N1
:Output a term of the continued fraction resulting from the operation.

I output a term if the integer parts of \frac{a}{b} and \frac{a_1}{b_1} are equal. Otherwise I input a term from N. If I need a term from N but N has no more terms I inject \infty.

When I input a term t my internal state: \begin{bmatrix}
  a_1 & a \\
  b_1 & b
\end{bmatrix} is transposed thus \begin{bmatrix} a + a_1 * t & a_1  \\
  b + b_1 * t & b_1
\end{bmatrix}

When I output a term t my internal state: \begin{bmatrix}
  a_1 & a \\
  b_1 & b
\end{bmatrix} is transposed thus \begin{bmatrix} b_1 & b  \\
  a_1 - b_1 * t & a - b * t
\end{bmatrix}

When I need a term t but there are no more my internal state: \begin{bmatrix}
  a_1 & a \\
  b_1 & b
\end{bmatrix} is transposed thus \begin{bmatrix} a_1 & a_1 \\
  b_1 & b_1
\end{bmatrix}

I am done when b1 and b are zero.

Demonstrate your solution by calculating:
:[1;5,2] + 1/2
:[3;7] + 1/2
:[3;7] divided by 4
Using a generator for \sqrt{2} (e.g., from [[Continued fraction]]) calculate \frac{1}{\sqrt{2}}. You are now at the starting line for using Continued Fractions to implement [[Arithmetic-geometric mean]] without ulps and epsilons.

The first step in implementing [[Arithmetic-geometric mean]] is to calculate \frac{1 + \frac{1}{\sqrt{2}}}{2} do this now to cross the starting line and begin the race.

Solution:
class NG:
  def __init__(self, a1, a, b1, b):
    self.a1, self.a, self.b1, self.b = a1, a, b1, b

  def ingress(self, n):
    self.a, self.a1 = self.a1, self.a + self.a1 * n
    self.b, self.b1 = self.b1, self.b + self.b1 * n

  @property
  def needterm(self):
    return (self.b == 0 or self.b1 == 0) or not self.a//self.b == self.a1//self.b1

  @property
  def egress(self):
    n = self.a // self.b
    self.a,  self.b  = self.b,  self.a  - self.b  * n
    self.a1, self.b1 = self.b1, self.a1 - self.b1 * n
    return n

  @property
  def egress_done(self):
    if self.needterm: self.a, self.b = self.a1, self.b1
    return self.egress

  @property
  def done(self):
    return self.b == 0 and self.b1 == 0


Convert decimal number to rational

The task is to write a program to transform a decimal number into a fraction in lowest terms.

It is not always possible to do this exactly. For instance, while rational numbers can be converted to decimal representation, some of them need an infinite number of digits to be represented exactly in decimal form. Namely, repeating decimals such as 1/3 = 0.333...

Because of this, the following fractions cannot be obtained (reliably) unless the language has some way of representing repeating decimals:
* 67 / 74 = 0.9(054) = 0.9054054...
* 14 / 27 = 0.(518)  = 0.518518...

Acceptable output:

* 0.9054054 - 4527027 / 5000000
* 0.518518  - 259259 / 500000

Finite decimals are of course no problem:

* 0.75      - 3 / 4

Solution:
>>> from fractions import Fraction
>>> for d in (0.9054054, 0.518518, 0.75): print(d, Fraction.from_float(d).limit_denominator(100))

0.9054054 67/74
0.518518 14/27
0.75 3/4
>>> for d in '0.9054054 0.518518 0.75'.split(): print(d, Fraction(d))

0.9054054 4527027/5000000
0.518518 259259/500000
0.75 3/4
>>>


Convert decimal number to rational

Solution:
'''Approximate rationals from decimals'''

from math import (floor, gcd)
import sys

# approxRatio :: Float -> Float -> Ratio
def approxRatio(epsilon):
    '''The simplest rational approximation to
       n within the margin given by epsilon.
    '''
    def gcde(e, x, y):
        def _gcd(a, b):
            return a if b < e else _gcd(b, a % b)
        return _gcd(abs(x), abs(y))
    return lambda n: (lambda c=(
        gcde(epsilon if 0 < epsilon else (0.0001), 1, n)
    ): ratio(floor(n / c))(floor(1 / c)))()

# main :: IO ()
def main():
    '''Conversions at different levels of precision.'''

    xs = [0.9054054, 0.518518, 0.75]
    print(
        fTable(__doc__ + ' (epsilon of 1/10000):\n')(str)(
            lambda r: showRatio(r) + ' -> ' + repr(fromRatio(r))
        )(
            approxRatio(1 / 10000)
        )(xs)
    )
    print('\n')

    e = minBound(float)
    print(
        fTable(__doc__ + ' (epsilon of ' + repr(e) + '):\n')(str)(
            lambda r: showRatio(r) + ' -> ' + repr(fromRatio(r))
        )(
            approxRatio(e)
        )(xs)
    )

# GENERIC -------------------------------------------------

# fromRatio :: Ratio Int -> Float
def fromRatio(r):
    '''A floating point value derived from a
       a rational value.
    '''
    return r.get('numerator') / r.get('denominator')

# minBound :: Bounded Type -> a
def minBound(t):
    '''Minimum value for a bounded type.'''
    maxsize = sys.maxsize
    float_infomin = sys.float_info.min
    return {
        int: (-maxsize - 1),
        float: float_infomin,
        bool: False,
        str: chr(0)
    }[t]

# ratio :: Int -> Int -> Ratio Int
def ratio(n):
    '''Rational value constructed
       from a numerator and a denominator.
    '''
    def go(n, d):
        g = gcd(n, d)
        return {
            'type': 'Ratio',
            'numerator': n // g, 'denominator': d // g
        }
    return lambda d: go(n * signum(d), abs(d))

# showRatio :: Ratio -> String
def showRatio(r):
    '''String representation of the ratio r.'''
    d = r.get('denominator')
    return str(r.get('numerator')) + (
        ' / ' + str(d) if 1 != d else ''
    )

# signum :: Num -> Num
def signum(n):
    '''The sign of n.'''
    return -1 if 0 > n else (1 if 0 < n else 0)

# DISPLAY -------------------------------------------------

# fTable :: String -> (a -> String) ->
#                     (b -> String) -> (a -> b) -> [a] -> String
def fTable(s):
    '''Heading -> x display function -> fx display function ->
                     f -> xs -> tabular string.
    '''
    def go(xShow, fxShow, f, xs):
        ys = [xShow(x) for x in xs]
        w = max(map(len, ys))
        return s + '\n' + '\n'.join(map(
            lambda x, y: y.rjust(w, ' ') + ' -> ' + fxShow(f(x)),
            xs, ys
        ))
    return lambda xShow: lambda fxShow: lambda f: lambda xs: go(
        xShow, fxShow, f, xs
    )

# MAIN ---
if __name__ == '__main__':
    main()


Convert seconds to compound duration

Write a function or program which:
*   takes a positive integer representing a duration in seconds as input (e.g., 100), and
*   returns a string which shows the same duration decomposed into:
:::*   weeks,
:::*   days,
:::*   hours,
:::*   minutes,   and
:::*   seconds.

This is detailed below (e.g., "2 hr, 59 sec").

Demonstrate that it passes the following three test-cases:

'''''Test Cases'''''

:::::{| class="wikitable"
|-
! input number
! output string
|-
| 7259
| 2 hr, 59 sec
|-
| 86400
| 1 d
|-
| 6000000
| 9 wk, 6 d, 10 hr, 40 min
|}

'''''Details'''''

The following five units should be used:
:::::{| class="wikitable"
|-
! unit
! suffix used in output
! conversion
|-
| week
| wk
| 1 week = 7 days
|-
| day
| d
| 1 day = 24 hours
|-
| hour
| hr
| 1 hour = 60 minutes
|-
| minute
| min
| 1 minute = 60 seconds
|-
| second
| sec
|
|}

However, '''only''' include quantities with non-zero values in the output (e.g., return "1 d" and not "0 wk, 1 d, 0 hr, 0 min, 0 sec").

Give larger units precedence over smaller ones as much as possible (e.g., return 2 min, 10 sec and not 1 min, 70 sec or 130 sec)

Mimic the formatting shown in the test-cases (quantities sorted from largest unit to smallest and separated by comma+space; value and unit of each quantity separated by space).

Solution:
'''Compound duration'''

from functools import reduce
from itertools import chain

# compoundDurationFromUnits :: [Num] -> [String] -> Num -> [(Num, String)]
def compoundDurationFromUnits(qs):
    '''A list of compound string representions of a number n of time units,
       in terms of the multiples given in qs, and the labels given in ks.
    '''
    return lambda ks: lambda n: list(
        chain.from_iterable(map(
            lambda v, k: [(v, k)] if 0 < v else [],
            mapAccumR(
                lambda a, x: divmod(a, x) if 0 < x else (1, a)
            )(n)(qs)[1],
            ks
        ))
    )

# --------------------------TEST---------------------------
# main :: IO ()
def main():
    '''Tests of various durations, with a
       particular set of units and labels.
    '''

    print(
        fTable('Compound durations from numbers of seconds:\n')(str)(
            quoted("'")
        )(
            lambda n: ', '.join([
                str(v) + ' ' + k for v, k in
                compoundDurationFromUnits([0, 7, 24, 60, 60])(
                    ['wk', 'd', 'hr', 'min', 'sec']
                )(n)
            ])
        )([7259, 86400, 6000000])
    )

# -------------------------GENERIC-------------------------

# fTable :: String -> (a -> String) ->
# (b -> String) -> (a -> b) -> [a] -> String
def fTable(s):
    '''Heading -> x display function -> fx display function ->
       f -> xs -> tabular string.
    '''
    def go(xShow, fxShow, f, xs):
        ys = [xShow(x) for x in xs]
        w = max(map(len, ys))
        return s + '\n' + '\n'.join(map(
            lambda x, y: y.rjust(w, ' ') + ' -> ' + fxShow(f(x)),
            xs, ys
        ))
    return lambda xShow: lambda fxShow: lambda f: lambda xs: go(
        xShow, fxShow, f, xs
    )

# mapAccumR :: (acc -> x -> (acc, y)) -> acc -> [x] -> (acc, [y])
def mapAccumR(f):
    '''A tuple of an accumulation and a list derived by a combined
       map and fold, with accumulation from right to left.
    '''
    def go(a, x):
        acc, y = f(a[0], x)
        return (acc, [y] + a[1])
    return lambda acc: lambda xs: (
        reduce(go, reversed(xs), (acc, []))
    )

# quoted :: Char -> String -> String
def quoted(c):
    '''A string flanked on both sides
       by a specified quote character.
    '''
    return lambda s: c + s + c

# MAIN ---
if __name__ == '__main__':
    main()


Copy stdin to stdout

Create an executable file that copies stdin to stdout, or else a script that does so through the invocation of an interpreter at the command line.

Solution: python -c 'import sys; sys.stdout.write(sys.stdin.read())'


Count the coins

There are four types of common coins in   US   currency:
:::#   quarters   (25 cents)
:::#   dimes   (10 cents)
:::#   nickels   (5 cents),   and
:::#   pennies   (1 cent)

There are six ways to make change for 15 cents:
:::#   A dime and a nickel
:::#   A dime and 5 pennies
:::#   3 nickels
:::#   2 nickels and 5 pennies
:::#   A nickel and 10 pennies
:::#   15 pennies

;Task:
How many ways are there to make change for a dollar using these common coins?     (1 dollar = 100 cents).

;Optional:
Less common are dollar coins (100 cents);   and very rare are half dollars (50 cents).   With the addition of these two coins, how many ways are there to make change for $1000?

(Note:   the answer is larger than   232).

;References:
* an algorithm from the book ''Structure and Interpretation of Computer Programs''.
* an article in the algorithmist.
* Change-making problem on Wikipedia.

Solution:
def changes(amount, coins):
    ways = [0] * (amount + 1)
    ways[0] = 1
    for coin in coins:
        for j in xrange(coin, amount + 1):
            ways[j] += ways[j - coin]
    return ways[amount]

print changes(100, [1, 5, 10, 25])
print changes(100000, [1, 5, 10, 25, 50, 100])


Count the coins

Solution:
try:
    import psyco
    psyco.full()
except ImportError:
    pass

def count_changes(amount_cents, coins):
    n = len(coins)
    # max([]) instead of max() for Psyco
    cycle = max([c+1 for c in coins if c <= amount_cents]) * n
    table = [0] * cycle
    for i in xrange(n):
        table[i] = 1

    pos = n
    for s in xrange(1, amount_cents + 1):
        for i in xrange(n):
            if i == 0 and pos >= cycle:
                pos = 0
            if coins[i] <= s:
                q = pos - coins[i] * n
                table[pos]= table[q] if (q >= 0) else table[q + cycle]
            if i:
                table[pos] += table[pos - 1]
            pos += 1
    return table[pos - 1]

def main():
    us_coins = [100, 50, 25, 10, 5, 1]
    eu_coins = [200, 100, 50, 20, 10, 5, 2, 1]

    for coins in (us_coins, eu_coins):
        print count_changes(     100, coins[2:])
        print count_changes(  100000, coins)
        print count_changes( 1000000, coins)
        print count_changes(10000000, coins), "\n"

main()


Create an HTML table

Create an HTML table.
* The table body should have at least three rows of three columns.
* Each of these three columns should be labelled "X", "Y", and "Z".
* An extra column should be added at either the extreme left or the extreme right of the table that has no heading, but is filled with sequential row numbers.
* The rows of the "X", "Y", and "Z" columns should be filled with random or sequential integers having 4 digits or less.
* The numbers should be aligned in the same fashion for all columns.

Solution:
import random

def rand9999():
    return random.randint(1000, 9999)

def tag(attr='', **kwargs):
    for tag, txt in kwargs.items():
        return '<{tag}{attr}>{txt}</{tag}>'.format(**locals())

if __name__ == '__main__':
    header = tag(tr=''.join(tag(th=txt) for txt in ',X,Y,Z'.split(','))) + '\n'
    rows = '\n'.join(tag(tr=tag(' style="font-weight: bold;"', td=i)
                                    + ''.join(tag(td=rand9999())
                                              for j in range(3)))
                     for i in range(1, 6))
    table = tag(table='\n' + header + rows + '\n')
    print(table)


Create an HTML table

Solution:
from functools import (reduce)
import itertools
import random

# HTML RENDERING ----------------------------------------

# treeHTML :: tree
#      {tag :: String, text :: String, kvs :: Dict}
#      -> HTML String
def treeHTML(tree):
    return foldTree(
        lambda x: lambda xs: (
            f"<{x['tag'] + attribString(x)}>" + (
                str(x['text']) if 'text' in x else '\n'
            ) + ''.join(xs) + f"</{x['tag']}>\n"
        )
    )(tree)

# attribString :: Dict -> String
def attribString(dct):
    kvs = dct['kvs'] if 'kvs' in dct else None
    return ' ' + reduce(
        lambda a, k: a + k + '="' + kvs[k] + '" ',
        kvs.keys(), ''
    ).strip() if kvs else ''

# HTML TABLE FROM GENERATED DATA ------------------------

def main():
    # Number of columns and rows to generate.
    n = 3

    # Table details -------------------------------------
    strCaption = 'Table generated with Python'
    colNames = take(n)(enumFrom('A'))
    dataRows = map(
        lambda x: (x, map(
            lambda _: random.randint(100, 9999),
            colNames
        )), take(n)(enumFrom(1)))
    tableStyle = {
        'style': "width:25%; border:2px solid silver;"
    }
    trStyle = {
        'style': "border:1px solid silver;text-align:right;"
    }

    # TREE STRUCTURE OF TABLE ---------------------------
    tableTree = Node({'tag': 'table', 'kvs': tableStyle})([
        Node({
            'tag': 'caption',
            'text': strCaption
        })([]),

        # HEADER ROW --------------------------------
        (Node({'tag': 'tr'})(
            Node({
                'tag': 'th',
                'kvs': {'style': 'text-align:right;'},
                'text': k
            })([]) for k in ([''] + colNames)
        ))
    ] +
        # DATA ROWS ---------------------------------
        list(Node({'tag': 'tr', 'kvs': trStyle})(
            [Node({'tag': 'th', 'text': tpl[0]})([])] +
            list(Node(
                {'tag': 'td', 'text': str(v)})([]) for v in tpl[1]
            )
        ) for tpl in dataRows)
    )

    print(
        treeHTML(tableTree)
        # dataRows
    )

# GENERIC -----------------------------------------------

# Node :: a -> [Tree a] -> Tree a
def Node(v):
    return lambda xs: {'type': 'Node', 'root': v, 'nest': xs}

# enumFrom :: Enum a => a -> [a]
def enumFrom(x):
    return itertools.count(x) if type(x) is int else (
        map(chr, itertools.count(ord(x)))
    )

# foldTree :: (a -> [b] -> b) -> Tree a -> b
def foldTree(f):
    def go(node):
        return f(node['root'])(
            list(map(go, node['nest']))
        )
    return lambda tree: go(tree)

# take :: Int -> [a] -> [a]
# take :: Int -> String -> String
def take(n):
    return lambda xs: (
        xs[0:n]
        if isinstance(xs, list)
        else list(itertools.islice(xs, n))
    )

if __name__ == '__main__':
    main()


Cullen and Woodall numbers

A Cullen number is a number of the form '''n x 2n + 1''' where '''n''' is a natural number.

A Woodall number is very similar. It is a number of the form '''n x 2n - 1''' where '''n''' is a natural number.

So for each '''n''' the associated Cullen number and Woodall number differ by 2.

''Woodall numbers are sometimes referred to as Riesel numbers or Cullen numbers of the second kind.''

'''Cullen primes''' are Cullen numbers that are prime. Similarly, '''Woodall primes''' are Woodall numbers that are prime.

It is common to list the Cullen and Woodall primes by the value of '''n''' rather than the full evaluated expression. They tend to get very large very quickly. For example, the third Cullen prime, '''n''' == 4713, has 1423 digits when evaluated.

;Task

* Write procedures to find Cullen numbers and Woodall numbers.

* Use those procedures to find and show here, on this page the first 20 of each.

;Stretch

* Find and show the first '''5''' '''Cullen primes''' in terms of '''n'''.

* Find and show the first '''12''' '''Woodall primes''' in terms of '''n'''.

;See also

* OEIS:A002064 - Cullen numbers: a(n) = n*2^n + 1

* OEIS:A003261 - Woodall (or Riesel) numbers: n*2^n - 1

* OEIS:A005849 - Indices of prime Cullen numbers: numbers k such that k*2^k + 1 is prime

* OEIS:A002234 - Numbers k such that the Woodall number k*2^k - 1 is prime

Solution:
print("working...")
print("First 20 Cullen numbers:")

for n in range(1,21):
    num = n*pow(2,n)+1
    print(str(num),end= " ")

print()
print("First 20 Woodall numbers:")

for n in range(1,21):
    num = n*pow(2,n)-1
    print(str(num),end=" ")

print()
print("done...")


Cullen and Woodall numbers

Solution:
def cullen(n): return((n<<n)+1)

def woodall(n): return((n<<n)-1)

print("First 20 Cullen numbers:")
for i in range(1,21):
	print(cullen(i),end=" ")
print()
print()
print("First 20 Woodall numbers:")
for i in range(1,21):
	print(woodall(i),end=" ")
print()


Currency

Show how to represent currency in a simple example, using a data type that represent exact values of dollars and cents.

;Note:
The '''IEEE 754''' binary floating point representations of numbers like   '''2.86'''   and   '''.0765'''   are not exact.

For this example, data will be two items with prices in dollars and cents, a quantity for each, and a tax rate.

Use the values:
::* 4000000000000000 hamburgers at $5.50 each       (four quadrillion burgers)
::* 2 milkshakes at $2.86 each, and
::* a tax rate of 7.65%.

(That number of hamburgers is a 4 with 15 zeros after it.    The number is contrived to exclude naive task solutions using 64 bit floating point types.)

Compute and output (show results on this page):
::* the total price before tax
::* the tax
::* the total with tax

The tax value must be computed by rounding to the nearest whole cent and this exact value must be added to the total price before tax.

The output must show dollars and cents with a decimal point.

The three results displayed should be:
::* 22000000000000005.72
::* 1683000000000000.44
::* 23683000000000006.16

Dollar signs and thousands separators are optional.

Solution:
from decimal import Decimal as D
from collections import namedtuple

Item = namedtuple('Item', 'price, quant')

items = dict( hamburger=Item(D('5.50'), D('4000000000000000')),
              milkshake=Item(D('2.86'), D('2')) )
tax_rate = D('0.0765')

fmt = "%-10s %8s %18s %22s"
print(fmt % tuple('Item Price Quantity Extension'.upper().split()))

total_before_tax = 0
for item, (price, quant) in sorted(items.items()):
    ext = price * quant
    print(fmt % (item, price, quant, ext))
    total_before_tax += ext
print(fmt % ('', '', '', '--------------------'))
print(fmt % ('', '', 'subtotal', total_before_tax))

tax = (tax_rate * total_before_tax).quantize(D('0.00'))
print(fmt % ('', '', 'Tax', tax))

total = total_before_tax + tax
print(fmt % ('', '', '', '--------------------'))
print(fmt % ('', '', 'Total', total))


Currying

{{Wikipedia|Currying}}

;Task:
Create a simple demonstrative example of Currying in a specific language.

Add any historic details as to how the feature made its way into the language.

Solution:
# AUTOMATIC CURRYING AND UNCURRYING OF EXISTING FUNCTIONS

# curry :: ((a, b) -> c) -> a -> b -> c
def curry(f):
    return lambda a: lambda b: f(a, b)

# uncurry :: (a -> b -> c) -> ((a, b) -> c)
def uncurry(f):
    return lambda x, y: f(x)(y)

# EXAMPLES --------------------------------------

# A plain uncurried function with 2 arguments,

# justifyLeft :: Int -> String -> String
def justifyLeft(n, s):
    return (s + (n * ' '))[:n]

# and a similar, but manually curried, function.

# justifyRight :: Int -> String -> String
def justifyRight(n):
    return lambda s: (
        ((n * ' ') + s)[-n:]
    )

# CURRYING and UNCURRYING at run-time:

def main():
    for s in [
        'Manually curried using a lambda:',
        '\n'.join(map(
            justifyRight(5),
            ['1', '9', '10', '99', '100', '1000']
        )),

        '\nAutomatically uncurried:',
        uncurry(justifyRight)(5, '10000'),

        '\nAutomatically curried',
        '\n'.join(map(
            curry(justifyLeft)(10),
            ['1', '9', '10', '99', '100', '1000']
        ))
    ]:
        print (s)

main()


Curzon numbers

A '''Curzon number''' is defined to be a positive integer '''n''' for which '''2n + 1''' is evenly divisible by  '''2 x n + 1'''.

'''Generalized Curzon numbers''' are those where the positive integer '''n''', using a base integer '''k''', satisfy the condition that '''kn + 1''' is evenly divisible by  '''k x n + 1'''.

''Base here does not imply the radix of the counting system; rather the integer the equation is based on. All calculations should be done in base 10.''

Generalized Curzon numbers only exist for even base integers.

;Task

* Find and show the first '''50 Generalized Curzon numbers''' for even base integers from '''2''' through '''10'''.

;Stretch

* Find and show the '''one thousandth'''.

;See also

;* Numbers Aplenty - Curzon numbers
;* OEIS:A224486 - Numbers k such that 2*k+1 divides 2^k+1 (Curzon numbers)

''and even though it is not specifically mentioned that they are Curzon numbers:''

;* OEIS:A230076 - (A007521(n)-1)/4 (Generalized Curzon numbers with a base 4)

Solution:
def is_Curzon(n, k):
    r = k * n
    return pow(k, n, r + 1) == r

for k in [2, 4, 6, 8, 10]:
    n, curzons = 1, []
    while len(curzons) < 1000:
        if is_Curzon(n, k):
            curzons.append(n)
        n += 1
    print(f'Curzon numbers with k = {k}:')
    for i, c in enumerate(curzons[:50]):
        print(f'{c: 5,}', end='\n' if (i + 1) % 25 == 0 else '')
    print(f'    Thousandth Curzon with k = {k}: {curzons[999]}.\n')


Cut a rectangle

A given rectangle is made from ''m'' x ''n'' squares. If ''m'' and ''n'' are not both odd, then it is possible to cut a path through the rectangle along the square edges such that the rectangle splits into two connected pieces with the same shape (after rotating one of the pieces by 180deg). All such paths for 2 x 2 and 4 x 3 rectangles are shown below.

[[file:rect-cut.svg]]

Write a program that calculates the number of different ways to cut an ''m'' x ''n'' rectangle.  Optionally, show each of the cuts.

Possibly related task: [[Maze generation]] for depth-first search.

Solution:
try:
    import psyco
except ImportError:
    pass
else:
    psyco.full()

w, h = 0, 0
count = 0
vis = []

def cwalk(y, x, d):
    global vis, count, w, h
    if not y or y == h or not x or x == w:
        count += 1
        return

    vis[y][x] = vis[h - y][w - x] = 1

    if x and not vis[y][x - 1]:
        cwalk(y, x - 1, d | 1)
    if (d & 1) and x < w and not vis[y][x+1]:
        cwalk(y, x + 1, d|1)
    if y and not vis[y - 1][x]:
        cwalk(y - 1, x, d | 2)
    if (d & 2) and y < h and not vis[y + 1][x]:
        cwalk(y + 1, x, d | 2)

    vis[y][x] = vis[h - y][w - x] = 0

def count_only(x, y):
    global vis, count, w, h
    count = 0
    w = x
    h = y

    if (h * w) & 1:
        return count
    if h & 1:
        w, h = h, w

    vis = [[0] * (w + 1) for _ in xrange(h + 1)]
    vis[h // 2][w // 2] = 1

    if w & 1:
        vis[h // 2][w // 2 + 1] = 1

    res = 0
    if w > 1:
        cwalk(h // 2, w // 2 - 1, 1)
        res = 2 * count - 1
        count = 0
        if w != h:
            cwalk(h // 2 + 1, w // 2, 3 if (w & 1) else 2)

        res += 2 * count - (not (w & 1))
    else:
        res = 1

    if w == h:
        res = 2 * res + 2
    return res

def main():
    for y in xrange(1, 10):
        for x in xrange(1, y + 1):
            if not (x & 1) or not (y & 1):
                print "%d x %d: %d" % (y, x, count_only(x, y))

main()


Cyclotomic polynomial

The nth Cyclotomic polynomial, for any positive integer n, is the unique irreducible polynomial of largest degree with integer coefficients that is a divisor of x^n - 1, and is not a divisor of x^k - 1 for any k < n.

;Task:
*   Find and print the first 30 cyclotomic polynomials.
*   Find and print the order of the first 10 cyclotomic polynomials that have n or -n as a coefficient.

;See also
*   Wikipedia article, Cyclotomic polynomial, showing ways to calculate them.
*   The sequence A013594 with the smallest order of cyclotomic polynomial containing n or -n as a coefficient.

Solution:
from itertools import count, chain
from collections import deque

def primes(_cache=[2, 3]):
    yield from _cache
    for n in count(_cache[-1]+2, 2):
        if isprime(n):
            _cache.append(n)
            yield n

def isprime(n):
    for p in primes():
        if n%p == 0:
            return False
        if p*p > n:
            return True

def factors(n):
    for p in primes():
    # prime factoring is such a non-issue for small numbers that, for
    # this example, we might even just say
    # for p in count(2):
        if p*p > n:
            if n > 1:
                yield(n, 1, 1)
            break

        if n%p == 0:
            cnt = 0
            while True:
                n, cnt = n//p, cnt+1
                if n%p != 0: break
            yield p, cnt, n
# ^^ not the most sophisticated prime number routines, because no need

# Returns (list1, list2) representing the division between
# two polinomials. A list p of integers means the product
#   (x^p[0] - 1) * (x^p[1] - 1) * ...
def cyclotomic(n):
    def poly_div(num, den):
        return (num[0] + den[1], num[1] + den[0])

    def elevate(poly, n): # replace poly p(x) with p(x**n)
        powerup = lambda p, n: [a*n for a in p]
        return poly if n == 1 else (powerup(poly[0], n), powerup(poly[1], n))

    if n == 0:
        return ([], [])
    if n == 1:
        return ([1], [])

    p, m, r = next(factors(n))
    poly = cyclotomic(r)
    return elevate(poly_div(elevate(poly, p), poly), p**(m-1))

def to_text(poly):
    def getx(c, e):
        if e == 0:
            return '1'
        elif e == 1:
            return 'x'
        return 'x' + (''.join('⁰¹²³⁴⁵⁶⁷⁸⁹'[i] for i in map(int, str(e))))

    parts = []
    for (c,e) in (poly):
        if c < 0:
            coef = ' - ' if c == -1 else f' - {-c} '
        else:
            coef = (parts and ' + ' or '') if c == 1 else f' + {c}'
        parts.append(coef + getx(c,e))
    return ''.join(parts)

def terms(poly):
    # convert above representation of division to (coef, power) pairs

    def merge(a, b):
        # a, b should be deques. They may change during the course.
        while a or b:
            l = a[0] if a else (0, -1) # sentinel value
            r = b[0] if b else (0, -1)
            if l[1] > r[1]:
                a.popleft()
            elif l[1] < r[1]:
                b.popleft()
                l = r
            else:
                a.popleft()
                b.popleft()
                l = (l[0] + r[0], l[1])
            yield l

    def mul(poly, p): # p means polynomial x^p - 1
        poly = list(poly)
        return merge(deque((c, e+p) for c,e in poly),
                     deque((-c, e) for c,e in poly))

    def div(poly, p): # p means polynomial x^p - 1
        q = deque()
        for c,e in merge(deque(poly), q):
            if c:
                q.append((c, e - p))
                yield (c, e - p)
            if e == p: break

    p = [(1, 0)]  # 1*x^0, i.e. 1

    for x in poly[0]: # numerator
        p = mul(p, x)
    for x in sorted(poly[1], reverse=True): # denominator
        p = div(p, x)
    return p

for n in chain(range(11), [2]):
    print(f'{n}: {to_text(terms(cyclotomic(n)))}')

want = 1
for n in count():
    c = [c for c,_ in terms(cyclotomic(n))]
    while want in c or -want in c:
        print(f'C[{want}]: {n}')
        want += 1


Damm algorithm

The '''Damm''' algorithm is a checksum algorithm which detects all single digit errors and adjacent transposition errors.

The algorithm is named after H. Michael Damm.

;Task:
Verify the checksum, stored as last digit of an input.

Solution:
def damm(num: int) -> bool:
    row = 0
    for digit in str(num):
        row = _matrix[row][int(digit)]
    return row == 0

_matrix = (
    (0, 3, 1, 7, 5, 9, 8, 6, 4, 2),
    (7, 0, 9, 2, 1, 5, 4, 8, 6, 3),
    (4, 2, 0, 6, 8, 7, 1, 3, 5, 9),
    (1, 7, 5, 0, 9, 8, 3, 4, 2, 6),
    (6, 1, 2, 3, 0, 4, 5, 9, 7, 8),
    (3, 6, 7, 4, 2, 0, 9, 5, 8, 1),
    (5, 8, 6, 9, 7, 2, 0, 1, 3, 4),
    (8, 9, 4, 5, 3, 6, 2, 0, 1, 7),
    (9, 4, 3, 8, 6, 1, 7, 2, 0, 5),
    (2, 5, 8, 1, 4, 3, 6, 7, 9, 0)
)

if __name__ == '__main__':
    for test in [5724, 5727, 112946]:
        print(f'{test}\t Validates as: {damm(test)}')


De Bruijn sequences

{{DISPLAYTITLE:de Bruijn sequences}}
The sequences are named after the Dutch mathematician   Nicolaas Govert de Bruijn.

A note on Dutch capitalization:   Nicolaas' last name is   '''de Bruijn''',   the   '''de'''   isn't normally capitalized
unless it's the first word in a sentence.   Rosetta Code (more or less by default or by fiat) requires the first word in the task name to be
capitalized.

In combinatorial mathematics,   a   '''de Bruijn sequence'''   of order    ''n''    on
a    size-''k''    alphabet (computer science)    ''A''    is a cyclic sequence in which every
possible    length-''n''    string (computer science, formal theory)   on    ''A''    occurs
exactly once as a contiguous substring.

Such a sequence is denoted by    ''B''(''k'', ''n'')    and has
length   ''k''''n'',   which is also the number of distinct substrings of
length   ''n''   on   ''A'';
de Bruijn sequences are therefore optimally short.

There are:
                          (k!)k(n-1)   /   kn
distinct de Bruijn sequences    ''B''(''k'', ''n'').

;Task:
For this Rosetta Code task,   a   '''de Bruijn'''   sequence is to be generated that can be used to shorten a brute-force attack on
a   PIN-like   code lock that does not have an "enter"
key and accepts the last    ''n''    digits entered.

Note:   automated teller machines (ATMs)   used to work like
this,   but their software has been updated to not allow a brute-force attack.

;Example:
A   digital door lock   with a 4-digit code would
have ''B'' (10, 4) solutions,   with a length of   '''10,000'''   (digits).

Therefore, only at most     '''10,000 + 3'''     (as the solutions are cyclic or ''wrap-around'')   presses are needed to
open the lock.

Trying all 4-digit codes separately would require   '''4 x 10,000'''   or   '''40,000'''   presses.

;Task requirements:
:*   Generate a de Bruijn sequence for a 4-digit (decimal) PIN code.
:::*   Show the length of the generated de Bruijn sequence.
:::*   (There are many possible de Bruijn sequences that solve this task,   one solution is shown on the ''discussion'' page).
:::*   Show the first and last   '''130'''   digits of the de Bruijn sequence.
:*   Verify that all four-digit (decimal)   '''1,000'''   PIN codes are contained within the de Bruijn sequence.
:::*   0000, 0001, 0002, 0003,   ...   9996, 9997, 9998, 9999   (note the leading zeros).
:*   Reverse the de Bruijn sequence.
:*   Again, perform the (above) verification test.
:*   Replace the 4,444th digit with a period (.) in the original de Bruijn sequence.
:::*   Perform the verification test (again).   There should be four PIN codes missing.

(The last requirement is to ensure that the verification tests performs correctly.   The verification processes should list
any and all missing PIN codes.)

Show all output here, on this page.

;References:
:*   Wikipedia           entry:   de Bruijn sequence.
:*   MathWorld           entry:   de Bruijn sequence.
:*   An  OEIS  entry:   A166315 lexicographically earliest binary de Bruijn sequences, B(2,n)     --- Not B(10,4),   but possibly relevant.

Solution:
# from https://en.wikipedia.org/wiki/De_Bruijn_sequence

def de_bruijn(k, n):
    """
    de Bruijn sequence for alphabet k
    and subsequences of length n.
    """
    try:
        # let's see if k can be cast to an integer;
        # if so, make our alphabet a list
        _ = int(k)
        alphabet = list(map(str, range(k)))

    except (ValueError, TypeError):
        alphabet = k
        k = len(k)

    a = [0] * k * n
    sequence = []

    def db(t, p):
        if t > n:
            if n % p == 0:
                sequence.extend(a[1:p + 1])
        else:
            a[t] = a[t - p]
            db(t + 1, p)
            for j in range(a[t - p] + 1, k):
                a[t] = j
                db(t + 1, t)
    db(1, 1)
    return "".join(alphabet[i] for i in sequence)

def validate(db):
    """

    Check that all 10,000 combinations of 0-9 are present in
    De Bruijn string db.

    Validating the reversed deBruijn sequence:
      No errors found

    Validating the overlaid deBruijn sequence:
      4 errors found:
        PIN number 1459 missing
        PIN number 4591 missing
        PIN number 5814 missing
        PIN number 8145 missing

    """

    dbwithwrap = db+db[0:3]

    digits = '0123456789'

    errorstrings = []

    for d1 in digits:
        for d2 in digits:
            for d3 in digits:
                for d4 in digits:
                    teststring = d1+d2+d3+d4
                    if teststring not in dbwithwrap:
                        errorstrings.append(teststring)

    if len(errorstrings) > 0:
        print("  "+str(len(errorstrings))+" errors found:")
        for e in errorstrings:
            print("  PIN number "+e+"  missing")
    else:
        print("  No errors found")

db = de_bruijn(10, 4)

print(" ")
print("The length of the de Bruijn sequence is ", str(len(db)))
print(" ")
print("The first 130 digits of the de Bruijn sequence are: "+db[0:130])
print(" ")
print("The last 130 digits of the de Bruijn sequence are: "+db[-130:])
print(" ")
print("Validating the deBruijn sequence:")
validate(db)
dbreversed = db[::-1]
print(" ")
print("Validating the reversed deBruijn sequence:")
validate(dbreversed)
dboverlaid = db[0:4443]+'.'+db[4444:]
print(" ")
print("Validating the overlaid deBruijn sequence:")
validate(dboverlaid)


Deceptive numbers

Repunits are numbers that consist entirely of repetitions of the digit one (unity).  The notation '''Rn''' symbolizes the repunit made up of '''n''' ones.

Every prime '''p''' larger than 5, evenly divides the repunit '''Rp-1'''.

;E.G.

The repunit '''R6''' is evenly divisible by '''7'''.

111111 / 7 = 15873

The repunit '''R42''' is evenly divisible by '''43'''.

111111111111111111111111111111111111111111 / 43 = 2583979328165374677002583979328165374677

And so on.

There are composite numbers that also have this same property. They are often referred to as ''deceptive non-primes'' or ''deceptive numbers''.

The repunit '''R90''' is evenly divisible by the composite number '''91''' (=7*13).

111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 / 91 = 1221001221001221001221001221001221001221001221001221001221001221001221001221001221001221

;Task

* Find and show at least the first '''10 deceptive numbers'''; composite numbers '''n''' that evenly divide the repunit '''Rn-1'''

;See also

;* Numbers Aplenty - Deceptive numbers
;* OEIS:A000864 - Deceptive nonprimes: composite numbers k that divide the repunit R_{k-1}

Solution:
from itertools import count, islice
from math import isqrt

def is_deceptive(n):
    if n & 1 and n % 3 and n % 5 and pow(10, n - 1, n) == 1:
        for d in range(7, isqrt(n) + 1, 6):
            if not (n % d and n % (d + 4)): return True
    return False

print(*islice(filter(is_deceptive, count()), 100))


Deming's funnel

W Edwards Deming was an American statistician and management guru who used physical demonstrations to illuminate his teachings.  In one demonstration Deming repeatedly dropped marbles through a funnel at a target, marking where they landed, and observing the resulting pattern.  He applied a sequence of "rules" to try to improve performance.  In each case the experiment begins with the funnel positioned directly over the target.

* '''Rule 1''': The funnel remains directly above the target.
* '''Rule 2''': Adjust the funnel position by shifting the target to compensate after each drop.  E.g. If the last drop missed 1 cm east, move the funnel 1 cm to the west of its current position.
* '''Rule 3''': As rule 2, but first move the funnel back over the target, before making the adjustment.  E.g. If the funnel is 2 cm north, and the marble lands 3 cm north, move the funnel 3 cm south of the target.
* '''Rule 4''': The funnel is moved directly over the last place a marble landed.

Apply the four rules to the set of 50 pseudorandom displacements provided (e.g in the Racket solution) for the dxs and dys.  '''Output''': calculate the mean and standard-deviations of the resulting x and y values for each rule.

Note that rules 2, 3, and 4 give successively worse results.  Trying to deterministically compensate for a random process is counter-productive, but -- according to Deming -- quite a popular pastime: see the Further Information, below for examples.

'''Stretch goal 1''': Generate fresh pseudorandom data.  The radial displacement of the drop from the funnel position is given by a Gaussian distribution (standard deviation is 1.0) and the angle of displacement is uniformly distributed.

'''Stretch goal 2''': Show scatter plots of all four results.

;Further information:
* Further explanation and interpretation
* Video demonstration of the funnel experiment at the Mayo Clinic.

Solution:
import math

dxs = [-0.533, 0.27, 0.859, -0.043, -0.205, -0.127, -0.071, 0.275, 1.251,
       -0.231, -0.401, 0.269, 0.491, 0.951, 1.15, 0.001, -0.382, 0.161, 0.915,
       2.08, -2.337, 0.034, -0.126, 0.014, 0.709, 0.129, -1.093, -0.483, -1.193,
       0.02, -0.051, 0.047, -0.095, 0.695, 0.34, -0.182, 0.287, 0.213, -0.423,
       -0.021, -0.134, 1.798, 0.021, -1.099, -0.361, 1.636, -1.134, 1.315, 0.201,
       0.034, 0.097, -0.17, 0.054, -0.553, -0.024, -0.181, -0.7, -0.361, -0.789,
       0.279, -0.174, -0.009, -0.323, -0.658, 0.348, -0.528, 0.881, 0.021, -0.853,
       0.157, 0.648, 1.774, -1.043, 0.051, 0.021, 0.247, -0.31, 0.171, 0.0, 0.106,
       0.024, -0.386, 0.962, 0.765, -0.125, -0.289, 0.521, 0.017, 0.281, -0.749,
       -0.149, -2.436, -0.909, 0.394, -0.113, -0.598, 0.443, -0.521, -0.799,
       0.087]

dys = [0.136, 0.717, 0.459, -0.225, 1.392, 0.385, 0.121, -0.395, 0.49, -0.682,
       -0.065, 0.242, -0.288, 0.658, 0.459, 0.0, 0.426, 0.205, -0.765, -2.188,
       -0.742, -0.01, 0.089, 0.208, 0.585, 0.633, -0.444, -0.351, -1.087, 0.199,
       0.701, 0.096, -0.025, -0.868, 1.051, 0.157, 0.216, 0.162, 0.249, -0.007,
       0.009, 0.508, -0.79, 0.723, 0.881, -0.508, 0.393, -0.226, 0.71, 0.038,
       -0.217, 0.831, 0.48, 0.407, 0.447, -0.295, 1.126, 0.38, 0.549, -0.445,
       -0.046, 0.428, -0.074, 0.217, -0.822, 0.491, 1.347, -0.141, 1.23, -0.044,
       0.079, 0.219, 0.698, 0.275, 0.056, 0.031, 0.421, 0.064, 0.721, 0.104,
       -0.729, 0.65, -1.103, 0.154, -1.72, 0.051, -0.385, 0.477, 1.537, -0.901,
       0.939, -0.411, 0.341, -0.411, 0.106, 0.224, -0.947, -1.424, -0.542, -1.032]

def funnel(dxs, rule):
    x, rxs = 0, []
    for dx in dxs:
        rxs.append(x + dx)
        x = rule(x, dx)
    return rxs

def mean(xs): return sum(xs) / len(xs)

def stddev(xs):
    m = mean(xs)
    return math.sqrt(sum((x-m)**2 for x in xs) / len(xs))

def experiment(label, rule):
    rxs, rys = funnel(dxs, rule), funnel(dys, rule)
    print label
    print 'Mean x, y    : %.4f, %.4f' % (mean(rxs), mean(rys))
    print 'Std dev x, y : %.4f, %.4f' % (stddev(rxs), stddev(rys))
    print

experiment('Rule 1:', lambda z, dz: 0)
experiment('Rule 2:', lambda z, dz: -dz)
experiment('Rule 3:', lambda z, dz: -(z+dz))
experiment('Rule 4:', lambda z, dz: z+dz)