K-d tree

{{wikipedia|K-d tree}}

A k-d tree (short for ''k''-dimensional tree) is a space-partitioning data structure for organizing points in a k-dimensional space. k-d trees are a useful data structure for several applications, such as searches involving a multidimensional search key (e.g. range searches and nearest neighbor searches).
k-d trees are a special case of binary space partitioning trees.

k-d trees are not suitable, however, for efficiently finding the nearest neighbor in high dimensional spaces. As a general rule, if the dimensionality is ''k'', the number of points in the data, ''N'', should be ''N''  2''k''.
Otherwise, when k-d trees are used with high-dimensional data, most of the points in the tree will be evaluated and the efficiency is no better than exhaustive search, and other methods such as approximate nearest-neighbor are used instead.

'''Task:''' Construct a k-d tree and perform a nearest neighbor search for two example data sets:

# The Wikipedia example data of [(2,3), (5,4), (9,6), (4,7), (8,1), (7,2)].
# 1000 3-d points uniformly distributed in a 3-d cube.

For the Wikipedia example, find the nearest neighbor to point (9, 2)
For the random data, pick a random location and find the nearest neighbor.

In addition, instrument your code to count the number of nodes visited in the nearest neighbor search.  Count a node as visited if any field of it is accessed.

Output should show the point searched for, the point found,
the distance to the point, and the number of nodes visited.

There are variant algorithms for constructing the tree.
You can use a simple median strategy or implement something more efficient.
Variants of the nearest neighbor search include nearest N neighbors, approximate nearest neighbor, and range searches.
You do not have to implement these.
The requirement for this task is specifically the nearest single neighbor.
Also there are algorithms for inserting, deleting, and balancing k-d trees.
These are also not required for the task.

Solution:
from random import seed, random
from time import time
from operator import itemgetter
from collections import namedtuple
from math import sqrt
from copy import deepcopy

def sqd(p1, p2):
    return sum((c1 - c2) ** 2 for c1, c2 in zip(p1, p2))

class KdNode(object):
    __slots__ = ("dom_elt", "split", "left", "right")

    def __init__(self, dom_elt, split, left, right):
        self.dom_elt = dom_elt
        self.split = split
        self.left = left
        self.right = right

class Orthotope(object):
    __slots__ = ("min", "max")

    def __init__(self, mi, ma):
        self.min, self.max = mi, ma

class KdTree(object):
    __slots__ = ("n", "bounds")

    def __init__(self, pts, bounds):
        def nk2(split, exset):
            if not exset:
                return None
            exset.sort(key=itemgetter(split))
            m = len(exset) // 2
            d = exset[m]
            while m + 1 < len(exset) and exset[m + 1][split] == d[split]:
                m += 1
            d = exset[m]

            s2 = (split + 1) % len(d)  # cycle coordinates
            return KdNode(d, split, nk2(s2, exset[:m]),
                                    nk2(s2, exset[m + 1:]))
        self.n = nk2(0, pts)
        self.bounds = bounds

T3 = namedtuple("T3", "nearest dist_sqd nodes_visited")

def find_nearest(k, t, p):
    def nn(kd, target, hr, max_dist_sqd):
        if kd is None:
            return T3([0.0] * k, float("inf"), 0)

        nodes_visited = 1
        s = kd.split
        pivot = kd.dom_elt
        left_hr = deepcopy(hr)
        right_hr = deepcopy(hr)
        left_hr.max[s] = pivot[s]
        right_hr.min[s] = pivot[s]

        if target[s] <= pivot[s]:
            nearer_kd, nearer_hr = kd.left, left_hr
            further_kd, further_hr = kd.right, right_hr
        else:
            nearer_kd, nearer_hr = kd.right, right_hr
            further_kd, further_hr = kd.left, left_hr

        n1 = nn(nearer_kd, target, nearer_hr, max_dist_sqd)
        nearest = n1.nearest
        dist_sqd = n1.dist_sqd
        nodes_visited += n1.nodes_visited

        if dist_sqd < max_dist_sqd:
            max_dist_sqd = dist_sqd
        d = (pivot[s] - target[s]) ** 2
        if d > max_dist_sqd:
            return T3(nearest, dist_sqd, nodes_visited)
        d = sqd(pivot, target)
        if d < dist_sqd:
            nearest = pivot
            dist_sqd = d
            max_dist_sqd = dist_sqd

        n2 = nn(further_kd, target, further_hr, max_dist_sqd)
        nodes_visited += n2.nodes_visited
        if n2.dist_sqd < dist_sqd:
            nearest = n2.nearest
            dist_sqd = n2.dist_sqd

        return T3(nearest, dist_sqd, nodes_visited)

    return nn(t.n, p, t.bounds, float("inf"))

def show_nearest(k, heading, kd, p):
    print(heading + ":")
    print("Point:           ", p)
    n = find_nearest(k, kd, p)
    print("Nearest neighbor:", n.nearest)
    print("Distance:        ", sqrt(n.dist_sqd))
    print("Nodes visited:   ", n.nodes_visited, "\n")

def random_point(k):
    return [random() for _ in range(k)]

def random_points(k, n):
    return [random_point(k) for _ in range(n)]

if __name__ == "__main__":
    seed(1)
    P = lambda *coords: list(coords)
    kd1 = KdTree([P(2, 3), P(5, 4), P(9, 6), P(4, 7), P(8, 1), P(7, 2)],
                  Orthotope(P(0, 0), P(10, 10)))
    show_nearest(2, "Wikipedia example data", kd1, P(9, 2))

    N = 400000
    t0 = time()
    kd2 = KdTree(random_points(3, N), Orthotope(P(0, 0, 0), P(1, 1, 1)))
    t1 = time()
    text = lambda *parts: "".join(map(str, parts))
    show_nearest(2, text("k-d tree with ", N,
                         " random 3D points (generation time: ",
                         t1-t0, "s)"),
                 kd2, random_point(3))


Kaprekar numbers

A positive integer is a Kaprekar number if:
* It is   '''1'''     (unity)
* The decimal representation of its square may be split once into two parts consisting of positive integers which sum to the original number.
Note that a split resulting in a part consisting purely of 0s is not valid,
as 0 is not considered positive.

;Example Kaprekar numbers:
* 2223 is a Kaprekar number, as 2223 * 2223 = 4941729, 4941729 may be split to 494 and 1729, and 494 + 1729 = 2223.
* The series of Kaprekar numbers is known as A006886, and begins as 1, 9, 45, 55, ....

;Example process:
10000 (1002) splitting from left to right:
* The first split is [1, 0000], and is invalid; the 0000 element consists entirely of 0s, and 0 is not considered positive.
* Slight optimization opportunity: When splitting from left to right, once the right part consists entirely of 0s, no further testing is needed; all further splits would also be invalid.

;Task:
Generate and show all Kaprekar numbers less than 10,000.

;Extra credit:
Optionally, count (and report the count of) how many Kaprekar numbers are less than 1,000,000.

;Extra extra credit:
The concept of Kaprekar numbers is not limited to base 10 (i.e. decimal numbers);
if you can, show that Kaprekar numbers exist in other bases too.

For this purpose, do the following:
* Find all Kaprekar numbers for base 17 between 1 and 1,000,000 (one million);
* Display each of them in base 10 representation;
* Optionally, using base 17 representation (use letters 'a' to 'g' for digits 10(10) to 16(10)), display each of the numbers, its square, and where to split the square.

For example, 225(10) is "d4" in base 17, its square "a52g", and a5(17) + 2g(17) = d4(17), so the display would be something like:225   d4  a52g  a5 + 2g

;Reference:
* The Kaprekar Numbers by Douglas E. Iannucci (2000). PDF version

;Related task:
*   [[Casting out nines]]

Solution:
def encode(n, base):
    result = ""
    while n:
        n, d = divmod(n, base)
        if d < 10:
            result += str(d)
        else:
            result += chr(d - 10 + ord("a"))
    return result[::-1]
def Kaprekar(n, base):
    if n == '1':
        return True
    sq = encode((int(n, base)**2), base)
    for i in range(1,len(sq)):
        if (int(sq[:i], base) + int(sq[i:], base) == int(n, base)) and (int(sq[:i], base) > 0) and (int(sq[i:], base)>0):
            return True
    return False
def Find(m, n, base):
    return [encode(i, base) for i in range(m,n+1) if Kaprekar(encode(i, base), base)]

m = int(raw_input('Where to start?\n'))
n = int(raw_input('Where to stop?\n'))
base = int(raw_input('Enter base:'))
KNumbers = Find(m, n, base)
for i in KNumbers:
    print i
print 'The number of Kaprekar Numbers found are',
print len(KNumbers)
raw_input()


Kernighans large earthquake problem

Brian Kernighan, in a lecture at the University of Nottingham, described a problem on which this task is based.

;Problem:
You are given a a data file of thousands of lines; each of three `whitespace` separated fields: a date, a one word name and the magnitude of the event.

Example lines from the file would be lines like:
8/27/1883    Krakatoa            8.8
5/18/1980    MountStHelens       7.6
3/13/2009    CostaRica           5.1

;Task:
* Create a program or script invocation to find all the events with magnitude greater than 6
* Assuming an appropriate name e.g. "data.txt" for the file:
:# Either: Show how your program is invoked to process a data file of that name.
:# Or: Incorporate the file name into the program, (as it is assumed that the program is single use).

Solution:
from os.path import expanduser
from functools import (reduce)
from itertools import (chain)

# largeQuakes :: Int -> [String] -> [(String, String, String)]
def largeQuakes(n):
    def quake(threshold):
        def go(x):
            ws = x.split()
            return [tuple(ws)] if threshold < float(ws[2]) else []
        return lambda x: go(x)
    return concatMap(quake(n))

# main :: IO ()
def main():
    print (
        largeQuakes(6)(
            open(expanduser('~/data.txt')).read().splitlines()
        )
    )

# GENERIC ABSTRACTION -------------------------------------

# concatMap :: (a -> [b]) -> [a] -> [b]
def concatMap(f):
    return lambda xs: list(
        chain.from_iterable(
            map(f, xs)
        )
    )

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


Keyboard input/Obtain a Y or N response

Obtain a valid   '''Y'''   or   '''N'''   response from the [[input device::keyboard]].

The keyboard should be flushed, so that any outstanding key-presses are removed, preventing any existing   '''Y'''   or   '''N'''   key-press from being evaluated.

The response should be obtained as soon as   '''Y'''   or   '''N'''   are pressed, and there should be no need to press an   enter   key.

Solution:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from curses import wrapper
#
#
def main(stdscr):
  # const
  #y = ord("y")
  #n = ord("n")
  while True:
    # keyboard input interceptor|listener
    #window.nodelay(yes)
    # - If yes is 1, getch() will be non-blocking.
    # return char code
    #kb_Inpt = stdscr.getch()
    # return string
    kb_Inpt = stdscr.getkey()
    #if kb_Inpt == (y or n):
    if kb_Inpt.lower() == ('y' or 'n'):
      break
      return None
  #
  return None
#
#*** unit test ***#
if __name__ == "__main__":
  #
  wrapper(main)


Knight's tour

Task
Problem: you have a standard 8x8 chessboard, empty but for a single knight on some square.   Your task is to emit a series of legal knight moves that result in the knight visiting every square on the chessboard exactly once. Note that it is ''not'' a requirement that the tour be "closed"; that is, the knight need not end within a single move of its start position.

Input and output may be textual or graphical, according to the conventions of the programming environment.  If textual, squares should be indicated in algebraic notation.  The output should indicate the order in which the knight visits the squares, starting with the initial position.  The form of the output may be a diagram of the board with the squares numbered according to visitation sequence, or a textual list of algebraic coordinates in order, or even an actual animation of the knight moving around the chessboard.

Input: starting square

Output: move sequence

;Related tasks
* [[A* search algorithm]]
* [[N-queens problem]]
* [[Solve a Hidato puzzle]]
* [[Solve a Holy Knight's tour]]
* [[Solve a Hopido puzzle]]
* [[Solve a Numbrix puzzle]]
* [[Solve the no connection puzzle]]

Solution:
import copy

boardsize=6
_kmoves = ((2,1), (1,2), (-1,2), (-2,1), (-2,-1), (-1,-2), (1,-2), (2,-1))

def chess2index(chess, boardsize=boardsize):
    'Convert Algebraic chess notation to internal index format'
    chess = chess.strip().lower()
    x = ord(chess[0]) - ord('a')
    y = boardsize - int(chess[1:])
    return (x, y)

def boardstring(board, boardsize=boardsize):
    r = range(boardsize)
    lines = ''
    for y in r:
        lines += '\n' + ','.join('%2i' % board[(x,y)] if board[(x,y)] else '  '
                                 for x in r)
    return lines

def knightmoves(board, P, boardsize=boardsize):
    Px, Py = P
    kmoves = set((Px+x, Py+y) for x,y in _kmoves)
    kmoves = set( (x,y)
                  for x,y in kmoves
                  if 0 <= x < boardsize
                     and 0 <= y < boardsize
                     and not board[(x,y)] )
    return kmoves

def accessibility(board, P, boardsize=boardsize):
    access = []
    brd = copy.deepcopy(board)
    for pos in knightmoves(board, P, boardsize=boardsize):
        brd[pos] = -1
        access.append( (len(knightmoves(brd, pos, boardsize=boardsize)), pos) )
        brd[pos] = 0
    return access

def knights_tour(start, boardsize=boardsize, _debug=False):
    board = {(x,y):0 for x in range(boardsize) for y in range(boardsize)}
    move = 1
    P = chess2index(start, boardsize)
    board[P] = move
    move += 1
    if _debug:
        print(boardstring(board, boardsize=boardsize))
    while move <= len(board):
        P = min(accessibility(board, P, boardsize))[1]
        board[P] = move
        move += 1
        if _debug:
            print(boardstring(board, boardsize=boardsize))
            input('\n%2i next: ' % move)
    return board

if __name__ == '__main__':
    while 1:
        boardsize = int(input('\nboardsize: '))
        if boardsize < 5:
            continue
        start = input('Start position: ')
        board = knights_tour(start, boardsize)
        print(boardstring(board, boardsize=boardsize))


Knuth's algorithm S

This is a method of randomly sampling n items from a set of M items, with equal probability; where M >= n and M, the number of items is unknown until the end.
This means that the equal probability sampling should be maintained  for all successive items > n as they become available (although the content of successive samples can change).

;The algorithm:
:* Select the first n items as the sample as they become available;
:* For the i-th item where i > n, have a random chance of n/i of keeping it.  If failing this chance, the sample remains the same.  If not, have it randomly (1/n) replace one of the previously selected n items of the sample.
:* Repeat   2nd step   for any subsequent items.

;The Task:
:* Create a function s_of_n_creator that given n the maximum sample size, returns a function s_of_n that takes one parameter, item.
:* Function  s_of_n when called with successive items returns an equi-weighted random sample of up to n of its items so far, each time it is called, calculated using Knuths Algorithm S.
:* Test your functions by printing and showing the frequency of occurrences of the selected digits from 100,000 repetitions of:
:::# Use the s_of_n_creator with n == 3 to generate an s_of_n.
:::# call s_of_n with each of the digits 0 to 9 in order, keeping the returned three digits of its random sampling from its last call with argument item=9.

Note: A class taking n and generating a callable instance/function might also be used.

;Reference:
* The Art of Computer Programming, Vol 2, 3.4.2 p.142

;Related tasks:
* [[One of n lines in a file]]
* [[Accumulator factory]]

Solution:
from random import randrange

def s_of_n_creator(n):
    sample, i = [], 0
    def s_of_n(item):
        nonlocal i

        i += 1
        if i <= n:
            # Keep first n items
            sample.append(item)
        elif randrange(i) < n:
            # Keep item
            sample[randrange(n)] = item
        return sample
    return s_of_n

if __name__ == '__main__':
    bin = [0]* 10
    items = range(10)
    print("Single run samples for n = 3:")
    s_of_n = s_of_n_creator(3)
    for item in items:
        sample = s_of_n(item)
        print("  Item: %i -> sample: %s" % (item, sample))
    #
    for trial in range(100000):
        s_of_n = s_of_n_creator(3)
        for item in items:
            sample = s_of_n(item)
        for s in sample:
            bin[s] += 1
    print("\nTest item frequencies for 100000 runs:\n ",
          '\n  '.join("%i:%i" % x for x in enumerate(bin)))


Koch curve

Draw a Koch curve. See details: Koch curve

Solution:
===Functional===
Generates SVG for a Koch snowflake. To view, save as a text file with the extension .svg, and open in a browser.


Koch curve

Solution:
'''Koch curve'''

from math import cos, pi, sin
from operator import add, sub
from itertools import chain

# kochSnowflake :: Int -> (Float, Float) -> (Float, Float) -> [(Float, Float)]
def kochSnowflake(n, a, b):
    '''List of points on a Koch snowflake of order n, derived
       from an equilateral triangle with base a b.
    '''
    points = [a, equilateralApex(a, b), b]
    return chain.from_iterable(map(
        kochCurve(n),
        points,
        points[1:] + [points[0]]
    ))

# kochCurve :: Int -> (Float, Float) -> (Float, Float)
#                  -> [(Float, Float)]
def kochCurve(n):
    '''List of points on a Koch curve of order n,
       starting at point ab, and ending at point xy.
    '''
    def koch(n):
        def goTuple(abxy):
            ab, xy = abxy
            if 0 == n:
                return [xy]
            else:
                mp, mq = midThirdOfLine(ab, xy)
                points = [
                    ab,
                    mp,
                    equilateralApex(mp, mq),
                    mq,
                    xy
                ]
                return list(
                    chain.from_iterable(map(
                        koch(n - 1),
                        zip(points, points[1:])
                    ))
                )
        return goTuple

    def go(ab, xy):
        return [ab] + koch(n)((ab, xy))
    return go

# equilateralApex :: (Float, Float) -> (Float, Float) -> (Float, Float)
def equilateralApex(p, q):
    '''Apex of triangle with base p q.
    '''
    return rotatedPoint(pi / 3)(p, q)

# rotatedPoint :: Float -> (Float, Float) ->
#                (Float, Float) -> (Float, Float)
def rotatedPoint(theta):
    '''The point ab rotated theta radians
        around the origin xy.
    '''
    def go(xy, ab):
        ox, oy = xy
        a, b = ab
        dx, dy = rotatedVector(theta, (a - ox, oy - b))
        return ox + dx, oy - dy
    return go

# rotatedVector :: Float -> (Float, Float) -> (Float, Float)
def rotatedVector(theta, xy):
    '''The vector xy rotated by theta radians.
    '''
    x, y = xy
    return (
        x * cos(theta) - y * sin(theta),
        x * sin(theta) + y * cos(theta)
    )

# midThirdOfLine :: (Float, Float) -> (Float, Float)
#                -> ((Float, Float), (Float, Float))
def midThirdOfLine(ab, xy):
    '''Second of three equal segments of
       the line between ab and xy.
    '''
    vector = [x / 3 for x in map(sub, xy, ab)]

    def f(p):
        return tuple(map(add, vector, p))
    p = f(ab)
    return (p, f(p))

# -------------------------- TEST --------------------------
# main :: IO ()
def main():
    '''SVG for Koch snowflake of order 4.
    '''
    print(
        svgFromPoints(1024)(
            kochSnowflake(
                4, (200, 600), (800, 600)
            )
        )
    )

# -------------------------- SVG ---------------------------

# svgFromPoints :: Int -> [(Float, Float)] -> SVG String
def svgFromPoints(w):
    '''Width of square canvas -> Point list -> SVG string.
    '''
    def go(xys):
        xs = ' '.join(map(
            lambda xy: str(round(xy[0], 2)) + ' ' + str(round(xy[1], 2)),
            xys
        ))
        return '\n'.join([
            '<svg xmlns="http://www.w3.org/2000/svg"',
            f'width="512" height="512" viewBox="5 5 {w} {w}">',
            f'<path d="M{xs}" ',
            'stroke-width="2" stroke="red" fill="transparent"/>',
            '</svg>'
        ])
    return go

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


Kolakoski sequence

The natural numbers, (excluding zero); with the property that:
: ''if you form a new sequence from the counts of runs of the same number in the first sequence, this new sequence is the same as the first sequence''.

;Example:
This is ''not'' a Kolakoski sequence:
1,1,2,2,2,1,2,2,1,2,...
Its sequence of run counts, (sometimes called a run length encoding, (RLE); but a true RLE also gives the character that each run encodes), is calculated like this:

: Starting from the leftmost number of the sequence we have 2 ones, followed by 3 twos, then 1 ones, 2 twos, 1 one, ...

The above gives the RLE of:
2, 3, 1, 2, 1, ...

The original sequence is different from its RLE in this case. '''It would be the same for a true Kolakoski sequence'''.

;Creating a Kolakoski sequence:

Lets start with the two numbers (1, 2) that we will cycle through; i.e. they will be used in this order: 1,2,1,2,1,2,....

# We start the sequence s with the first item from the cycle c: 1
# An index, k, into the, (expanding), sequence will step, or index through each item of the sequence s from the first, at its own rate.
We will arrange that the k'th item of s states how many ''times'' the ''last'' item of sshould appear at the end of s.

We started s with 1 and therefore s[k] states that it should appear only the 1 time.

Increment k
Get the next item from c and append it to the end of sequence s. s will then become: 1, 2
k was moved to the second item in the list and s[k] states that it should appear two times, so append another of the last item to the sequence s: 1, 2,2
Increment k
Append the next item from the cycle to the list: 1, 2,2, 1
k is now at the third item in the list that states that the last item should appear twice so add another copy of the last item to the sequence s: 1, 2,2, 1,1
increment k

...

'''Note''' that the RLE of 1, 2, 2, 1, 1, ... begins 1, 2, 2 which is the beginning of the original sequence. The generation algorithm ensures that this will always be the case.

;Task:
# Create a routine/proceedure/function/... that given an initial ordered list/array/tuple etc of the natural numbers (1, 2), returns the next number from the list when accessed in a cycle.
# Create another routine that when given the initial ordered list (1, 2) and the minimum length of the sequence  to generate; uses the first routine and the algorithm above, to generate at least the requested first members of the kolakoski sequence.
# Create a routine that when given a sequence, creates the run length encoding of that sequence (as defined above) and returns the result of checking if sequence starts with the exact members of its RLE. (But ''note'', due to sampling, do not compare the last member of the RLE).
# Show, on this page, (compactly), the first 20 members of the sequence generated from (1, 2)
# Check the sequence againt its RLE.
# Show, on this page, the first 20 members of the sequence generated from (2, 1)
# Check the sequence againt its RLE.
# Show, on this page, the first 30 members of the Kolakoski sequence generated from (1, 3, 1, 2)
# Check the sequence againt its RLE.
# Show, on this page, the first 30 members of the Kolakoski sequence generated from (1, 3, 2, 1)
# Check the sequence againt its RLE.
(There are rules on generating Kolakoski sequences from this method that are broken by the last example)

Solution:
import itertools

def cycler(start_items):
	return itertools.cycle(start_items).__next__

def _kolakoski_gen(start_items):
    s, k = [], 0
    c = cycler(start_items)
    while True:
        c_next = c()
        s.append(c_next)
        sk = s[k]
        yield sk
        if sk > 1:
            s += [c_next] * (sk - 1)
        k += 1

def kolakoski(start_items=(1, 2), length=20):
    return list(itertools.islice(_kolakoski_gen(start_items), length))

def _run_len_encoding(truncated_series):
    return [len(list(group)) for grouper, group in itertools.groupby(truncated_series)][:-1]

def is_series_eq_its_rle(series):
    rle = _run_len_encoding(series)
    return (series[:len(rle)] == rle) if rle else not series

if __name__ == '__main__':
    for start_items, length in [((1, 2), 20), ((2, 1), 20),
                                ((1, 3, 1, 2), 30), ((1, 3, 2, 1), 30)]:
        print(f'\n## {length} members of the series generated from {start_items} is:')
        s = kolakoski(start_items, length)
        print(f'  {s}')
        ans = 'YES' if is_series_eq_its_rle(s) else 'NO'
        print(f'  Does it look like a Kolakoski sequence: {ans}')


Kosaraju

{{wikipedia|Graph}}

Kosaraju's algorithm (also known as the Kosaraju-Sharir algorithm) is a linear time algorithm to find the strongly connected components of a directed graph. Aho, Hopcroft and Ullman credit it to an unpublished paper from 1978 by S. Rao Kosaraju. The same algorithm was independently discovered by Micha Sharir and published by him in 1981. It makes use of the fact that the transpose graph (the same graph with the direction of every edge reversed) has exactly the same strongly connected components as the original graph.

For this task consider the directed graph with these connections:
  0 -> 1
  1 -> 2
  2 -> 0
  3 -> 1,  3 -> 2,  3 -> 4
  4 -> 3,  4 -> 5
  5 -> 2,  5 -> 6
  6 -> 5
  7 -> 4, 7  -> 6, 7 -> 7

And report the kosaraju strongly connected component for each node.

;References:
* The article on Wikipedia.

Solution:
def kosaraju(g):
    class nonlocal: pass

    # 1. For each vertex u of the graph, mark u as unvisited. Let l be empty.
    size = len(g)

    vis = [False]*size # vertexes that have been visited
    l = [0]*size
    nonlocal.x = size
    t = [[]]*size   # transpose graph

    def visit(u):
        if not vis[u]:
            vis[u] = True
            for v in g[u]:
                visit(v)
                t[v] = t[v] + [u]
            nonlocal.x = nonlocal.x - 1
            l[nonlocal.x] = u

    # 2. For each vertex u of the graph do visit(u)
    for u in range(len(g)):
        visit(u)
    c = [0]*size

    def assign(u, root):
        if vis[u]:
            vis[u] = False
            c[u] = root
            for v in t[u]:
                assign(v, root)

    # 3: For each element u of l in order, do assign(u, u)
    for u in l:
        assign(u, u)

    return c

g = [[1], [2], [0], [1,2,4], [3,5], [2,6], [5], [4,6,7]]
print kosaraju(g)


Lah numbers

Lah numbers, sometimes referred to as ''Stirling numbers of the third kind'', are coefficients of polynomial expansions expressing rising factorials in terms of falling factorials.

Unsigned Lah numbers count the number of ways a set of '''n''' elements can be partitioned into '''k''' non-empty linearly ordered subsets.

Lah numbers are closely related to Stirling numbers of the first & second kinds, and may be derived from them.

Lah numbers obey the identities and relations:
   L(n, 0), L(0, k) = 0   # for n, k > 0
   L(n, n) = 1
   L(n, 1) = n!
   L(n, k) =           ( n! * (n - 1)! ) / ( k! * (k - 1)! ) / (n - k)!      # For unsigned Lah numbers
      ''or''
   L(n, k) = (-1)**n * ( n! * (n - 1)! ) / ( k! * (k - 1)! ) / (n - k)!      # For   signed Lah numbers

;Task:
:* Write a routine (function, procedure, whatever) to find '''unsigned Lah numbers'''. There are several methods to generate unsigned Lah numbers. You are free to choose the most appropriate for your language. If your language has a built-in, or easily, publicly available library implementation, it is acceptable to use that.

:* Using the routine, generate and show here, on this page, a table (or triangle) showing the unsigned Lah numbers, '''L(n, k)''', up to '''L(12, 12)'''. it is optional to show the row / column for n == 0 and k == 0. It is optional to show places where L(n, k) == 0 (when k > n).

:* If your language supports large integers, find and show here, on this page, the maximum value of '''L(n, k)''' where '''n == 100'''.

;See also:

:* '''Wikipedia - Lah number'''
:* '''OEIS:A105278 - Unsigned Lah numbers'''
:* '''OEIS:A008297 - Signed Lah numbers'''

;Related Tasks:

:* '''Stirling numbers of the first kind'''
:* '''Stirling numbers of the second kind'''
:* '''Bell numbers'''

Solution:
from math import (comb,
                  factorial)

def lah(n, k):
    if k == 1:
        return factorial(n)
    if k == n:
        return 1
    if k > n:
        return 0
    if k < 1 or n < 1:
        return 0
    return comb(n, k) * factorial(n - 1) // factorial(k - 1)

def main():
    print("Unsigned Lah numbers: L(n, k):")
    print("n/k ", end='\t')
    for i in range(13):
        print("%11d" % i, end='\t')
    print()
    for row in range(13):
        print("%-4d" % row, end='\t')
        for i in range(row + 1):
            l = lah(row, i)
            print("%11d" % l, end='\t')
        print()
    print("\nMaximum value from the L(100, *) row:")
    max_val = max(lah(100, a) for a in range(100))
    print(max_val)

if __name__ == '__main__':
    main()


Largest int from concatenated ints

Given a set of positive integers, write a function to order the integers in such a way that the concatenation of the numbers forms the largest possible integer and return this integer.

Use the following two sets of integers as tests   and   show your program output here.

:::::*   {1, 34, 3, 98, 9, 76, 45, 4}
:::::*   {54, 546, 548, 60}

;Possible algorithms:
# A solution could be found by trying all combinations and return the best.
# Another way to solve this is to note that in the best arrangement, for any two adjacent original integers '''X''' and '''Y''', the concatenation '''X''' followed by '''Y''' will be numerically greater than or equal to the concatenation '''Y''' followed by '''X.
# Yet another way to solve this is to pad the integers to the same size by repeating the digits then sort using these repeated integers as a sort key.

;See also:
*   Algorithms: What is the most efficient way to arrange the given numbers to form the biggest number?
*   Constructing the largest number possible by rearranging a list

Solution:
try:
    cmp     # Python 2 OK or NameError in Python 3
    def maxnum(x):
        return ''.join(sorted((str(n) for n in x),
                              cmp=lambda x,y:cmp(y+x, x+y)))
except NameError:
    # Python 3
    from functools import cmp_to_key
    def cmp(x, y):
        return -1 if x<y else ( 0 if x==y else 1)
    def maxnum(x):
        return ''.join(sorted((str(n) for n in x),
                              key=cmp_to_key(lambda x,y:cmp(y+x, x+y))))

for numbers in [(1, 34, 3, 98, 9, 76, 45, 4), (54, 546, 548, 60)]:
    print('Numbers: %r\n  Largest integer: %15s' % (numbers, maxnum(numbers)))


Largest int from concatenated ints

Solution:
from fractions import Fraction
from math import log10

def maxnum(x):
    return ''.join(str(n) for n in sorted(x, reverse=True,
                          key=lambda i: Fraction(i, 10**(int(log10(i))+1)-1)))

for numbers in [(1, 34, 3, 98, 9, 76, 45, 4), (54, 546, 548, 60)]:
    print('Numbers: %r\n  Largest integer: %15s' % (numbers, maxnum(numbers)))


Largest number divisible by its digits

Find the largest base 10 integer whose digits are all different,   and   is evenly divisible by each of its individual digits.

These numbers are also known as   '''Lynch-Bell numbers''',   numbers   '''n'''   such that the
(base ten) digits are all different (and do not include zero)   and   '''n'''   is divisible by each of its individual digits.

;Example:
'''135'''   is evenly divisible by   '''1''',   '''3''',   and   '''5'''.

Note that the digit zero (0) can not be in the number as integer division by zero is undefined.

The digits must all be unique so a base ten number will have at most '''9''' digits.

Feel free to use analytics and clever algorithms to reduce the search space your example needs to visit, but it must do an actual search. (Don't just feed it the answer and verify it is correct.)

;Stretch goal:
Do the same thing for hexadecimal.

;Related tasks:
:*   gapful numbers.
:*   palindromic gapful numbers.

;Also see:
:*   The OEIS sequence:   A115569: Lynch-Bell numbers.

Solution:
===base 10===
Using the insights presented in the preamble to the Raku (base 10) example:


Largest number divisible by its digits

Solution:
'''Largest number divisible by its hex digits'''

from functools import (reduce)
from math import (gcd)

# main :: IO ()
def main():
    '''First integer evenly divisible by each of its
       hex digits, none of which appear more than once.
    '''

    # Least common multiple of digits [1..15]
    # ( -> 360360 )
    lcmDigits = foldl1(lcm)(
        enumFromTo(1)(15)
    )
    allDigits = 0xfedcba987654321

    # ( -> 1147797409030632360 )
    upperLimit = allDigits - (allDigits % lcmDigits)

    # Possible numbers
    xs = enumFromThenToNext(upperLimit)(
        upperLimit - lcmDigits
    )(1)

    print(
        hex(
            until(lambda x: 15 == len(set(showHex(x))))(
                lambda _: next(xs)
            )(next(xs))
        )
    )   # --> 0xfedcb59726a1348

# ------------------ GENERIC FUNCTIONS -------------------

# enumFromThenToNext :: Int -> Int -> Int -> Gen [Int]
def enumFromThenToNext(m):
    '''Non-finite series of integer values enumerated
       from m to n with a step size defined by nxt-m.
    '''
    def go(m, nxt):
        d = nxt - m
        v = m
        while True:
            yield v
            v = d + v
    return lambda nxt: lambda n: go(m, nxt)

# enumFromTo :: (Int, Int) -> [Int]
def enumFromTo(m):
    '''Integer enumeration from m to n.'''
    return lambda n: range(m, 1 + n)

# foldl1 :: (a -> a -> a) -> [a] -> a
def foldl1(f):
    '''Left to right reduction of the
       non-empty list xs, using the binary
       operator f, with the head of xs
       as the initial acccumulator value.
    '''
    return lambda xs: reduce(
        lambda a, x: f(a)(x), xs[1:], xs[0]
    ) if xs else None

# lcm :: Int -> Int -> Int
def lcm(x):
    '''The smallest positive integer divisible
       without remainder by both x and y.
    '''
    return lambda y: (
        0 if (0 == x or 0 == y) else abs(
            y * (x // gcd(x, y))
        )
    )

# until :: (a -> Bool) -> (a -> a) -> a -> a
def until(p):
    '''The result of repeatedly applying f until p holds.
       The initial seed value is x.
    '''
    def go(f, x):
        v = x
        while not p(v):
            v = f(v)
        return v
    return lambda f: lambda x: go(f, x)

# showHex :: Int -> String
def showHex(n):
    '''Hexadecimal string representation
       of an integer value.
    '''
    return hex(n)[2:]

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


Largest proper divisor of n

a(1) = 1; for n > 1, a(n) = '''largest''' proper divisor of n, where '''n < 101 '''.

Solution:
def lpd(n):
    for i in range(n-1,0,-1):
        if n%i==0: return i
    return 1

for i in range(1,101):
    print("{:3}".format(lpd(i)), end=i%10==0 and '\n' or '')


Last Friday of each month

Write a program or a script that returns the date of the last Fridays of each month of a given year.

The year may be given through any simple input method in your language (command line, std in, etc).

Example of an expected output:
./last_fridays 2012
2012-01-27
2012-02-24
2012-03-30
2012-04-27
2012-05-25
2012-06-29
2012-07-27
2012-08-31
2012-09-28
2012-10-26
2012-11-30
2012-12-28

;Related tasks
* [[Five weekends]]
* [[Day of the week]]
* [[Find the last Sunday of each month]]

Solution:
import calendar

def last_fridays(year):
    for month in range(1, 13):
        last_friday = max(week[calendar.FRIDAY]
            for week in calendar.monthcalendar(year, month))
        print('{:4d}-{:02d}-{:02d}'.format(year, month, last_friday))


Last letter-first letter

A certain children's game involves starting with a word in a particular category.   Each participant in turn says a word, but that word must begin with the final letter of the previous word.   Once a word has been given, it cannot be repeated.   If an opponent cannot give a word in the category, they fall out of the game.

For example, with   "animals"   as the category,

Child 1: dog
Child 2: goldfish
Child 1: hippopotamus
Child 2: snake
...

;Task:
Take the following selection of 70 English Pokemon names   (extracted from   Wikipedia's list of Pokemon)   and generate the/a sequence with the highest possible number of Pokemon names where the subsequent name starts with the final letter of the preceding name.

No Pokemon name is to be repeated.

audino bagon baltoy banette bidoof braviary bronzor carracosta charmeleon
cresselia croagunk darmanitan deino emboar emolga exeggcute gabite
girafarig gulpin haxorus heatmor heatran ivysaur jellicent jumpluff kangaskhan
kricketune landorus ledyba loudred lumineon lunatone machamp magnezone mamoswine
nosepass petilil pidgeotto pikachu pinsir poliwrath poochyena porygon2
porygonz registeel relicanth remoraid rufflet sableye scolipede scrafty seaking
sealeo silcoon simisear snivy snorlax spoink starly tirtouga trapinch treecko
tyrogue vigoroth vulpix wailord wartortle whismur wingull yamask

Extra brownie points for dealing with the full list of   646   names.

Solution:
import psyco

nsolutions = 0

def search(sequences, ord_minc, curr_word, current_path,
           current_path_len, longest_path):
    global nsolutions

    current_path[current_path_len] = curr_word
    current_path_len += 1

    if current_path_len == len(longest_path):
        nsolutions += 1
    elif current_path_len > len(longest_path):
        nsolutions = 1
        longest_path[:] = current_path[:current_path_len]

    # recursive search
    last_char_index = ord(curr_word[-1]) - ord_minc
    if last_char_index >= 0 and last_char_index < len(sequences):
        for pair in sequences[last_char_index]:
            if not pair[1]:
                pair[1] = True
                search(sequences, ord_minc, pair[0], current_path,
                       current_path_len, longest_path)
                pair[1] = False

def find_longest_chain(words):
    ord_minc = ord(min(word[0] for word in words))
    ord_maxc = ord(max(word[0] for word in words))
    sequences = [[] for _ in xrange(ord_maxc - ord_minc + 1)]
    for word in words:
        sequences[ord(word[0]) - ord_minc].append([word, False])

    current_path = [None] * len(words)
    longest_path = []

    # try each item as possible start
    for seq in sequences:
        for pair in seq:
            pair[1] = True
            search(sequences, ord_minc, pair[0],
                   current_path, 0, longest_path)
            pair[1] = False

    return longest_path

def main():
    global nsolutions

    pokemon = """audino bagon baltoy banette bidoof braviary
bronzor carracosta charmeleon cresselia croagunk darmanitan deino
emboar emolga exeggcute gabite girafarig gulpin haxorus heatmor
heatran ivysaur jellicent jumpluff kangaskhan kricketune landorus
ledyba loudred lumineon lunatone machamp magnezone mamoswine nosepass
petilil pidgeotto pikachu pinsir poliwrath poochyena porygon2
porygonz registeel relicanth remoraid rufflet sableye scolipede
scrafty seaking sealeo silcoon simisear snivy snorlax spoink starly
tirtouga trapinch treecko tyrogue vigoroth vulpix wailord wartortle
whismur wingull yamask""".lower().split()

    # remove duplicates
    pokemon = sorted(set(pokemon))

    sol = find_longest_chain(pokemon)
    print "Maximum path length:", len(sol)
    print "Paths of that length:", nsolutions
    print "Example path of that length:"
    for i in xrange(0, len(sol), 7):
        print " ", " ".join(sol[i : i+7])

psyco.full()
main()


Latin Squares in reduced form

A Latin Square is in its reduced form if the first row and first column contain items in their natural order. The order n is the number of items. For any given n there is a set of reduced Latin Squares whose size increases rapidly with n. g is a number which identifies a unique element within the set of reduced Latin Squares of order n. The objective of this task is to construct the set of all Latin Squares of a given order and to provide a means which given suitable values for g any element within the set may be obtained.

For a reduced Latin Square the first row is always 1 to n. The second row is all [[Permutations/Derangements]] of 1 to n starting with 2. The third row is all [[Permutations/Derangements]] of 1 to n starting with 3 which do not clash (do not have the same item in any column) with row 2. The fourth row is all [[Permutations/Derangements]] of 1 to n starting with 4 which do not clash with rows 2 or 3. Likewise continuing to the nth row.

Demonstrate by:
* displaying the four reduced Latin Squares of order 4.
* for n = 1 to 6 (or more) produce the set of reduced Latin Squares; produce a table which shows the size of the set of reduced Latin Squares and compares this value times n! times (n-1)! with the values in OEIS A002860.

Solution:
def dList(n, start):
    start -= 1 # use 0 basing
    a = range(n)
    a[start] = a[0]
    a[0] = start
    a[1:] = sorted(a[1:])
    first = a[1]
    # rescursive closure permutes a[1:]
    r = []
    def recurse(last):
        if (last == first):
            # bottom of recursion. you get here once for each permutation.
            # test if permutation is deranged.
            # yes, save a copy with 1 based indexing
            for j,v in enumerate(a[1:]):
                if j + 1 == v:
                    return # no, ignore it
            b = [x + 1 for x in a]
            r.append(b)
            return
        for i in xrange(last, 0, -1):
            a[i], a[last] = a[last], a[i]
            recurse(last - 1)
            a[i], a[last] = a[last], a[i]
    recurse(n - 1)
    return r

def printSquare(latin,n):
    for row in latin:
        print row
    print

def reducedLatinSquares(n,echo):
    if n <= 0:
        if echo:
            print []
        return 0
    elif n == 1:
        if echo:
            print [1]
        return 1

    rlatin = [None] * n
    for i in xrange(n):
        rlatin[i] = [None] * n
    # first row
    for j in xrange(0, n):
        rlatin[0][j] = j + 1

    class OuterScope:
        count = 0
    def recurse(i):
        rows = dList(n, i)

        for r in xrange(len(rows)):
            rlatin[i - 1] = rows[r]
            justContinue = False
            k = 0
            while not justContinue and k < i - 1:
                for j in xrange(1, n):
                    if rlatin[k][j] == rlatin[i - 1][j]:
                        if r < len(rows) - 1:
                            justContinue = True
                            break
                        if i > 2:
                            return
                k += 1
            if not justContinue:
                if i < n:
                    recurse(i + 1)
                else:
                    OuterScope.count += 1
                    if echo:
                        printSquare(rlatin, n)

    # remaining rows
    recurse(2)
    return OuterScope.count

def factorial(n):
    if n == 0:
        return 1
    prod = 1
    for i in xrange(2, n + 1):
        prod *= i
    return prod

print "The four reduced latin squares of order 4 are:\n"
reducedLatinSquares(4,True)

print "The size of the set of reduced latin squares for the following orders"
print "and hence the total number of latin squares of these orders are:\n"
for n in xrange(1, 7):
    size = reducedLatinSquares(n, False)
    f = factorial(n - 1)
    f *= f * n * size
    print "Order %d: Size %-4d x %d! x %d! => Total %d" % (n, size, n, n - 1, f)


Law of cosines - triples

The Law of cosines states that for an angle g, (gamma) of any triangle, if the sides adjacent to the angle are A and B and the side opposite is C; then the lengths of the sides are related by this formula:
           A2 + B2 - 2ABcos(g) = C2

;Specific angles:
For an angle of of   '''90o'''   this becomes the more familiar "Pythagoras equation":
           A2 + B2  =  C2

For an angle of   '''60o'''   this becomes the less familiar  equation:
           A2 + B2 - AB  =  C2

And finally for an angle of   '''120o'''   this becomes the equation:
           A2 + B2 + AB  =  C2

;Task:
*   Find all integer solutions (in order) to the three specific cases, distinguishing between each angle being considered.
*   Restrain all sides to the integers   '''1..13'''   inclusive.
*   Show how many results there are for each of the three angles mentioned above.
*   Display results on this page.

Note: Triangles with the same length sides but different order are to be treated as the same.

;Optional Extra credit:
* How many 60deg integer triples are there for sides in the range 1..10_000 ''where the sides are not all of the same length''.

;Related Task
* [[Pythagorean triples]]

;See also:
* Visualising Pythagoras: ultimate proofs and crazy contortions Mathlogger Video

Solution:
N = 13

def method1(N=N):
    squares = [x**2 for x in range(0, N+1)]
    sqrset = set(squares)
    tri90, tri60, tri120 = (set() for _ in range(3))
    for a in range(1, N+1):
        a2 = squares[a]
        for b in range(1, a + 1):
            b2 = squares[b]
            c2 = a2 + b2
            if c2 in sqrset:
                tri90.add(tuple(sorted((a, b, int(c2**0.5)))))
            ab = a * b
            c2 -= ab
            if c2 in sqrset:
                tri60.add(tuple(sorted((a, b, int(c2**0.5)))))
            c2 += 2 * ab
            if c2 in sqrset:
                tri120.add(tuple(sorted((a, b, int(c2**0.5)))))
    return  sorted(tri90), sorted(tri60), sorted(tri120)
#%%
if __name__ == '__main__':
    print(f'Integer triangular triples for sides 1..{N}:')
    for angle, triples in zip([90, 60, 120], method1(N)):
        print(f'  {angle:3}° has {len(triples)} solutions:\n    {triples}')
    _, t60, _ = method1(10_000)
    notsame = sum(1 for a, b, c in t60 if a != b or b != c)
    print('Extra credit:', notsame)


Least common multiple

Compute the   least common multiple   (LCM)   of two integers.

Given   ''m''   and   ''n'',   the least common multiple is the smallest positive integer that has both   ''m''   and   ''n''   as factors.

;Example:
The least common multiple of   '''12'''   and   '''18'''   is   '''36''',       because:
:*   '''12'''   is a factor     ('''12''' x '''3''' = '''36'''),     and
:*   '''18'''   is a factor     ('''18''' x '''2''' = '''36'''),     and
:*   there is no positive integer less than   '''36'''   that has both factors.

As a special case,   if either   ''m''   or   ''n''   is zero,   then the least common multiple is zero.

One way to calculate the least common multiple is to iterate all the multiples of   ''m'',   until you find one that is also a multiple of   ''n''.

If you already have   ''gcd''   for [[greatest common divisor]],   then this formula calculates   ''lcm''.

:::: \operatorname{lcm}(m, n) = \frac{|m \times n|}{\operatorname{gcd}(m, n)}

One can also find   ''lcm''   by merging the [[prime decomposition]]s of both   ''m''   and   ''n''.

;Related task
:*   greatest common divisor.

;See also:
*   MathWorld entry:   Least Common Multiple.
*   Wikipedia entry:   Least common multiple.

Solution:
'''Least common multiple'''

from inspect import signature

# lcm :: Int -> Int -> Int
def lcm(x):
    '''The smallest positive integer divisible
       without remainder by both x and y.
    '''
    return lambda y: 0 if 0 in (x, y) else abs(
        y * (x // gcd_(x)(y))
    )

# gcd_ :: Int -> Int -> Int
def gcd_(x):
    '''The greatest common divisor in terms of
       the divisibility preordering.
    '''
    def go(a, b):
        return go(b, a % b) if 0 != b else a
    return lambda y: go(abs(x), abs(y))

# TEST ----------------------------------------------------
# main :: IO ()
def main():
    '''Tests'''

    print(
        fTable(
            __doc__ + 's of 60 and [12..20]:'
        )(repr)(repr)(
            lcm(60)
        )(enumFromTo(12)(20))
    )

    pairs = [(0, 2), (2, 0), (-6, 14), (12, 18)]
    print(
        fTable(
            '\n\n' + __doc__ + 's of ' + repr(pairs) + ':'
        )(repr)(repr)(
            uncurry(lcm)
        )(pairs)
    )

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

# enumFromTo :: (Int, Int) -> [Int]
def enumFromTo(m):
    '''Integer enumeration from m to n.'''
    return lambda n: list(range(m, 1 + n))

# uncurry :: (a -> b -> c) -> ((a, b) -> c)
def uncurry(f):
    '''A function over a tuple, derived from
       a vanilla or curried function.
    '''
    if 1 < len(signature(f).parameters):
        return lambda xy: f(*xy)
    else:
        return lambda xy: f(xy[0])(xy[1])

# unlines :: [String] -> String
def unlines(xs):
    '''A single string derived by the intercalation
       of a list of strings with the newline character.
    '''
    return '\n'.join(xs)

# FORMATTING ----------------------------------------------

# 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()


Least common multiple

Solution:
>>> def lcm(p,q):
	p, q = abs(p), abs(q)
	m = p * q
	if not m: return 0
	while True:
		p %= q
		if not p: return m // q
		q %= p
		if not q: return m // p

>>> lcm(-6, 14)
42
>>> lcm(12, 18)
36
>>> lcm(2, 0)
0
>>>


Left factorials

'''Left factorials''',   !n,   may refer to either   ''subfactorials''   or to   ''factorial sums'';
the same notation can be confusingly seen being used for the two different definitions.

Sometimes,   ''subfactorials''   (also known as ''derangements'')   may use any of the notations:
:::::::*     !''n''`
:::::::*     !''n''
:::::::*     ''n''!

(It may not be visually obvious, but the last example uses an upside-down exclamation mark.)

This Rosetta Code task will be using this formula   (''factorial sums'')   for   '''left factorial''':

:::::    !n = \sum_{k=0}^{n-1} k!

:::: where

:::::   !0 = 0

;Task
Display the left factorials for:
*   zero      through        ten     (inclusive)
*   20   through   110          (inclusive)   by tens

Display the length (in decimal digits) of the left factorials for:
*   1,000   through   10,000   (inclusive), by thousands.

;Also see:
*   The OEIS entry: A003422 left factorials
*   The MathWorld entry: left factorial
*   The MathWorld entry: factorial sums
*   The MathWorld entry: subfactorial

;Related task:
*   permutations/derangements (subfactorials)

Solution:
from itertools import islice

def lfact():
    yield 0
    fact, summ, n = 1, 0, 1
    while 1:
        fact, summ, n = fact*n, summ + fact, n + 1
        yield summ

print('first 11:\n  %r' % [lf for i, lf in zip(range(11), lfact())])
print('20 through 110 (inclusive) by tens:')
for lf in islice(lfact(), 20, 111, 10):
    print(lf)
print('Digits in 1,000 through 10,000 (inclusive) by thousands:\n  %r'
      % [len(str(lf)) for lf in islice(lfact(), 1000, 10001, 1000)] )


Left factorials

Solution:
'''Left factorials'''

from itertools import (accumulate, chain, count, islice)
from operator import (mul, add)

# leftFact :: [Integer]
def leftFact():
    '''Left factorial series defined in terms
       of the factorial series.
    '''
    return accumulate(
        chain([0], fact()), add
    )

# fact :: [Integer]
def fact():
    '''The factorial series.
    '''
    return accumulate(
        chain([1], count(1)), mul
    )

# ------------------------- TEST -------------------------
# main :: IO ()
def main():
    '''Tests'''
    print(
        'Terms 0 thru 10 inclusive:\n  %r'
        % take(11)(leftFact())
    )

    print('\nTerms 20 thru 110 (inclusive) by tens:')
    for x in takeFromThenTo(20)(30)(110)(leftFact()):
        print(x)

    print(
        '\n\nDigit counts for terms 1k through 10k (inclusive) by k:\n  %r'
        % list(map(
            compose(len)(str),
            takeFromThenTo(1000)(2000)(10000)(
                leftFact()
            )
        ))
    )

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

# compose (<<<) :: (b -> c) -> (a -> b) -> a -> c
def compose(g):
    '''Function composition.'''
    return lambda f: lambda x: g(f(x))

# scanl :: (b -> a -> b) -> b -> [a] -> [b]
def scanl(f):
    '''scanl is like reduce, but defines a succession of
       intermediate values, building from the left.
    '''
    def go(a):
        def g(xs):
            return accumulate(chain([a], xs), f)
        return g
    return go

# take :: Int -> [a] -> [a]
# take :: Int -> String -> String
def take(n):
    '''The prefix of xs of length n,
       or xs itself if n > length xs'''
    return lambda xs: (
        xs[0:n]
        if isinstance(xs, list)
        else list(islice(xs, n))
    )

# takeFromThenTo :: Int -> Int -> Int -> [a] -> [a]
def takeFromThenTo(a):
    '''Values drawn from a series betweens positions a and b
       at intervals of size z'''
    return lambda b: lambda z: lambda xs: islice(
        xs, a, 1 + z, b - a
    )

if __name__ == '__main__':
    main()


Levenshtein distance

{{Wikipedia}}

In information theory and computer science, the '''Levenshtein distance''' is a edit distance). The Levenshtein distance between two strings is defined as the minimum number of edits needed to transform one string into the other, with the allowable edit operations being insertion, deletion, or substitution of a single character.

;Example:
The Levenshtein distance between "'''kitten'''" and "'''sitting'''" is 3, since the following three edits change one into the other, and there isn't a way to do it with fewer than three edits:
::#   '''k'''itten    '''s'''itten       (substitution of 'k' with 's')
::#   sitt'''e'''n    sitt'''i'''n       (substitution of 'e' with 'i')
::#   sittin          sittin'''g'''      (insert 'g' at the end).

''The Levenshtein distance between   "'''rosettacode'''",   "'''raisethysword'''"   is   '''8'''.

''The distance between two strings is same as that when both strings are reversed.''

;Task:
Implements a Levenshtein distance function, or uses a library function, to show the Levenshtein distance between   "kitten"   and   "sitting".

;Related task:
*   [[Longest common subsequence]]

Solution:
def levenshteinDistance(str1, str2):
    m = len(str1)
    n = len(str2)
    d = [[i] for i in range(1, m + 1)]   # d matrix rows
    d.insert(0, list(range(0, n + 1)))   # d matrix columns
    for j in range(1, n + 1):
        for i in range(1, m + 1):
            if str1[i - 1] == str2[j - 1]:   # Python (string) is 0-based
                substitutionCost = 0
            else:
                substitutionCost = 1
            d[i].insert(j, min(d[i - 1][j] + 1,
                               d[i][j - 1] + 1,
                               d[i - 1][j - 1] + substitutionCost))
    return d[-1][-1]

print(levenshteinDistance("kitten","sitting"))
print(levenshteinDistance("rosettacode","raisethysword"))


Levenshtein distance

Solution:
'''Levenshtein distance'''

from itertools import (accumulate, chain, islice)
from functools import reduce

# levenshtein :: String -> String -> Int
def levenshtein(sa):
    '''Levenshtein distance between
       two strings.'''
    s1 = list(sa)

    # go :: [Int] -> Char -> [Int]
    def go(ns, c):
        n, ns1 = ns[0], ns[1:]

        # gap :: Int -> (Char, Int, Int) -> Int
        def gap(z, c1xy):
            c1, x, y = c1xy
            return min(
                succ(y),
                succ(z),
                succ(x) if c != c1 else x
            )
        return scanl(gap)(succ(n))(
            zip(s1, ns, ns1)
        )
    return lambda sb: reduce(
        go, list(sb), enumFromTo(0)(len(s1))
    )[-1]

# TEST ----------------------------------------------------
# main :: IO ()
def main():
    '''Tests'''

    pairs = [
        ('rosettacode', 'raisethysword'),
        ('kitten', 'sitting'),
        ('saturday', 'sunday')
    ]

    print(
        tabulated(
            'Levenshtein minimum edit distances:\n'
        )(str)(str)(
            uncurry(levenshtein)
        )(concat(map(
            list,
            zip(pairs, map(swap, pairs))
        )))
    )

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

# compose (<<<) :: (b -> c) -> (a -> b) -> a -> c
def compose(g):
    '''Right to left function composition.'''
    return lambda f: lambda x: g(f(x))

# concat :: [[a]] -> [a]
# concat :: [String] -> String
def concat(xxs):
    '''The concatenation of all the elements in a list.'''
    xs = list(chain.from_iterable(xxs))
    unit = '' if isinstance(xs, str) else []
    return unit if not xs else (
        ''.join(xs) if isinstance(xs[0], str) else xs
    )

# enumFromTo :: (Int, Int) -> [Int]
def enumFromTo(m):
    '''Integer enumeration from m to n.'''
    return lambda n: list(range(m, 1 + n))

# scanl :: (b -> a -> b) -> b -> [a] -> [b]
def scanl(f):
    '''scanl is like reduce, but returns a succession of
       intermediate values, building from the left.'''
    return lambda a: lambda xs: (
        list(accumulate(chain([a], xs), f))
    )

# swap :: (a, b) -> (b, a)
def swap(tpl):
    '''The swapped components of a pair.'''
    return (tpl[1], tpl[0])

# succ :: Int => Int -> Int
def succ(x):
    '''The successor of a value.
       For numeric types, (1 +).'''
    return 1 + x

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

        ])
    return lambda xShow: lambda fxShow: (
        lambda f: lambda xs: go(
            xShow, fxShow, f, xs
        )
    )

# take :: Int -> [a] -> [a]
# take :: Int -> String -> String
def take(n):
    '''The prefix of xs of length n,
       or xs itself if n > length xs.'''
    return lambda xs: (
        xs[0:n]
        if isinstance(xs, list)
        else list(islice(xs, n))
    )

# uncurry :: (a -> b -> c) -> ((a, b) -> c)
def uncurry(f):
    '''A function over a tuple
       derived from a curried function.'''
    return lambda xy: f(xy[0])(
        xy[1]
    )

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


Levenshtein distance/Alignment

The [[Levenshtein distance]] algorithm returns the number of atomic operations (insertion, deletion or edition) that must be performed on a string in order to obtain an other one, but it does not say anything about the actual operations used or their order.

An alignment is a notation used to describe the operations used to turn a string into an other.  At some point in the strings, the minus character ('-') is placed in order to signify that a character must be added at this very place.  For instance, an alignment between the words 'place' and 'palace' is:

P-LACE
PALACE

;Task:
Write a function that shows the alignment of two strings for the corresponding levenshtein distance.

As an example, use the words "rosettacode" and "raisethysword".

You can either implement an algorithm, or use a dedicated library (thus showing us how it is named in your language).

Solution:
from difflib import ndiff

def levenshtein(str1, str2):
    result = ""
    pos, removed = 0, 0
    for x in ndiff(str1, str2):
        if pos<len(str1) and str1[pos] == x[2]:
          pos += 1
          result += x[2]
          if x[0] == "-":
              removed += 1
          continue
        else:
          if removed > 0:
            removed -=1
          else:
            result += "-"
    print(result)

levenshtein("place","palace")
levenshtein("rosettacode","raisethysword")


List rooted trees

You came back from grocery shopping.    After putting away all the goods, you are left with a pile of plastic bags, which you want to save for later use, so you take one bag and stuff all the others into it, and throw it under the sink.   In doing so, you realize that there are various ways of nesting the bags, with all bags viewed as identical.

If we use a matching pair of parentheses to represent a bag, the ways are:

For 1 bag, there's one way:
  ()	<- a bag

for 2 bags, there's one way:
  (())	<- one bag in another

for 3 bags, there are two:
  ((())) <- 3 bags nested Russian doll style
  (()()) <- 2 bags side by side, inside the third

for 4 bags, four:
  (()()())
  ((())())
  ((()()))
  (((())))

Note that because all bags are identical, the two 4-bag strings ((())()) and (()(())) represent the same configuration.

It's easy to see that each configuration for ''n'' bags represents a ''n''-node rooted tree, where a bag is a tree node, and a bag with its content forms a subtree.  The outermost bag is the tree root.  Number of configurations for given ''n'' is given by OEIS A81.

;Task:
Write a program that, when given ''n'', enumerates all ways of nesting ''n'' bags.   You can use the parentheses notation above, or any tree representation that's unambiguous and preferably intuitive.

This task asks for enumeration of trees only; for counting solutions without enumeration, that OEIS page lists various formulas, but that's not encouraged by this task, especially if implementing it would significantly increase code size.

As an example output, run 5 bags.   There should be 9 ways.

Solution:
def bags(n,cache={}):
	if not n: return [(0, "")]

	upto = sum([bags(x) for x in range(n-1, 0, -1)], [])
	return [(c+1, '('+s+')') for c,s in bagchain((0, ""), n-1, upto)]

def bagchain(x, n, bb, start=0):
	if not n: return [x]

	out = []
	for i in range(start, len(bb)):
		c,s = bb[i]
		if c <= n: out += bagchain((x[0] + c, x[1] + s), n-c, bb, i)
	return out

# Maybe this lessens eye strain. Maybe not.
def replace_brackets(s):
	depth,out = 0,[]
	for c in s:
		if c == '(':
			out.append("([{"[depth%3])
			depth += 1
		else:
			depth -= 1
			out.append(")]}"[depth%3])
	return "".join(out)

for x in bags(5): print(replace_brackets(x[1]))


Long literals, with continuations

This task is about writing a computer program that has long literals   (character
literals that may require specifying the words/tokens on more than one (source)
line,   either with continuations or some other method, such as abutments or
concatenations   (or some other mechanisms).

The literal is to be in the form of a "list",    a literal that contains many
words (tokens) separated by a blank (space),   in this case   (so as to have a
common list),   the (English) names of the chemical elements of the periodic table.

The list is to be in (ascending) order of the (chemical) element's atomic number:

 ''hydrogen helium lithium beryllium boron carbon nitrogen oxygen fluorine neon sodium aluminum silicon ...''

... up to the last known (named) chemical element   (at this time).

Do not include any of the   "unnamed"   chemical element names such as:

 ''ununennium unquadnilium triunhexium penthextrium penthexpentium septhexunium octenntrium ennennbium''

To make computer programming languages comparable,   the statement widths should be
restricted to less than   '''81'''   bytes (characters),   or less
if a computer programming language has more restrictive limitations or standards.

Also mention what column the programming statements can start in if   ''not''
in column one.

The list   ''may''   have leading/embedded/trailing blanks during the
declaration   (the actual program statements),   this is allow the list to be
more readable.   The "final" list shouldn't have any leading/trailing or superfluous
blanks   (when stored in the program's "memory").

This list should be written with the idea in mind that the
program   ''will''   be updated,   most likely someone other than the
original author,   as there will be newer (discovered) elements of the periodic
table being added   (possibly in the near future).   These future updates
should be one of the primary concerns in writing these programs and it should be "easy"
for someone else to add chemical elements to the list   (within the computer
program).

Attention should be paid so as to not exceed the   ''clause length''   of
continued or specified statements,   if there is such a restriction.   If the
limit is greater than (say) 4,000 bytes or so,   it needn't be mentioned here.

;Task:
:*   Write a computer program (by whatever name) to contain a list of the known elements.
:*   The program should eventually contain a long literal of words   (the elements).
:*   The literal should show how one could create a long list of blank-delineated words.
:*   The "final" (stored) list should only have a single blank between elements.
:*   Try to use the most idiomatic approach(es) in creating the final list.
:*   Use continuation if possible, and/or show alternatives   (possibly using concatenation).
:*   Use a program comment to explain what the continuation character is if it isn't obvious.
:*   The program should contain a variable that has the date of the last update/revision.
:*   The program, when run, should display with verbiage:
:::*   The last update/revision date   (and should be unambiguous).
:::*   The number of chemical elements in the list.
:::*   The name of the highest (last) element name.

Show all output here, on this page.

Solution:
"""Long string literal. Requires Python 3.6+ for f-strings."""

revision = "October 13th 2020"

# String literal continuation. Notice the trailing space at the end of each
# line but the last, and the lack of commas. There is exactly one "blank"
# between each item in the list.
elements = (
    "hydrogen helium lithium beryllium boron carbon nitrogen oxygen fluorine "
    "neon sodium magnesium aluminum silicon phosphorous sulfur chlorine argon "
    "potassium calcium scandium titanium vanadium chromium manganese iron "
    "cobalt nickel copper zinc gallium germanium arsenic selenium bromine "
    "krypton rubidium strontium yttrium zirconium niobium molybdenum "
    "technetium ruthenium rhodium palladium silver cadmium indium tin "
    "antimony tellurium iodine xenon cesium barium lanthanum cerium "
    "praseodymium neodymium promethium samarium europium gadolinium terbium "
    "dysprosium holmium erbium thulium ytterbium lutetium hafnium tantalum "
    "tungsten rhenium osmium iridium platinum gold mercury thallium lead "
    "bismuth polonium astatine radon francium radium actinium thorium "
    "protactinium uranium neptunium plutonium americium curium berkelium "
    "californium einsteinium fermium mendelevium nobelium lawrencium "
    "rutherfordium dubnium seaborgium bohrium hassium meitnerium darmstadtium "
    "roentgenium copernicium nihonium flerovium moscovium livermorium "
    "tennessine oganesson"
)

def report():
    """Write a summary report to stdout."""
    items = elements.split()

    print(f"Last revision date: {revision}")
    print(f"Number of elements: {len(items)}")
    print(f"Last element      : {items[-1]}")

if __name__ == "__main__":
    report()


Long year

Most years have 52 weeks, some have 53, according to ISO8601.

;Task:
Write a function which determines if a given year is long (53 weeks) or not, and demonstrate it.

Solution:
'''Long Year ?'''

from datetime import date

# longYear :: Year Int -> Bool
def longYear(y):
    '''True if the ISO year y has 53 weeks.'''
    return 52 < date(y, 12, 28).isocalendar()[1]

# --------------------------TEST---------------------------
# main :: IO ()
def main():
    '''Longer (53 week) years in the range 2000-2100'''
    for year in [
            x for x in range(2000, 1 + 2100)
            if longYear(x)
    ]:
        print(year)

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


Longest common subsequence

'''Introduction'''

Define a ''subsequence'' to be any output string obtained by deleting zero or more symbols from an input string.

The '''Longest Common Subsequence''' ('''LCS''') is a subsequence of maximum length common to two or more strings.

Let ''A''  ''A''[0]... ''A''[m - 1] and ''B''  ''B''[0]... ''B''[n - 1], m < n be strings drawn from an alphabet S of size s, containing every distinct symbol in A + B.

An ordered pair (i, j) will be referred to as a match if ''A''[i] = ''B''[j], where 0 <= i < m and 0 <= j < n.

The set of matches '''M''' defines a relation over matches: '''M'''[i, j] = (i, j)  '''M'''.

Define a ''non-strict'' product-order (<=) over ordered pairs, such that (i1, j1) <= (i2, j2) = i1 <= i2 and j1 <= j2.  We define (>=) similarly.

We say ordered pairs p1 and p2 are ''comparable'' if either p1 <= p2 or p1 >= p2 holds.  If i1 < i2 and j2 < j1 (or i2 < i1 and j1 < j2) then neither p1 <= p2 nor p1 >= p2 are possible, and we say p1 and p2 are ''incomparable''.

Define the ''strict'' product-order (<) over ordered pairs, such that (i1, j1) < (i2, j2) = i1 < i2 and j1 < j2.  We define (>) similarly.

A chain '''C''' is a subset of '''M''' consisting of at least one element m; and where either m1 < m2 or m1 > m2 for every pair of distinct elements m1 and m2.  An antichain '''D''' is any subset of '''M''' in which every pair of distinct elements m1 and m2 are incomparable.

A chain can be visualized as a strictly increasing curve that passes through matches (i, j) in the m*n coordinate space of '''M'''[i, j].

Every Common Sequence of length ''q'' corresponds to a chain of cardinality ''q'', over the set of matches '''M'''.  Thus, finding an LCS can be restated as the problem of finding a chain of maximum cardinality ''p''.

According to [Dilworth 1950], this cardinality ''p'' equals the minimum number of disjoint antichains into which '''M''' can be decomposed.  Note that such a decomposition into the minimal number p of disjoint antichains may not be unique.

'''Background'''

Where the number of symbols appearing in matches is small relative to the length of the input strings, reuse of the symbols increases; and the number of matches will tend towards O(''m*n'') quadratic growth.  This occurs, for example, in the Bioinformatics application of nucleotide and protein sequencing.

The divide-and-conquer approach of [Hirschberg 1975] limits the space required to O(''n'').  However, this approach requires O(''m*n'') time even in the best case.

This quadratic time dependency may become prohibitive, given very long input strings.  Thus, heuristics are often favored over optimal Dynamic Programming solutions.

In the application of comparing file revisions, records from the input files form a large symbol space; and the number of symbols approaches the length of the LCS.  In this case the number of matches reduces to linear, O(''n'') growth.

A binary search optimization due to [Hunt and Szymanski 1977] can be applied to the basic Dynamic Programming approach, resulting in an expected performance of O(''n log m'').  Performance can degrade to O(''m*n log m'') time in the worst case, as the number of matches grows to O(''m*n'').

'''Note'''

[Rick 2000] describes a linear-space algorithm with a time bound of O(''n*s + p*min(m, n - p)'').

'''Legend'''

 A, B are input strings of lengths m, n respectively
 p is the length of the LCS
 M is the set of matches (i, j) such that A[i] = B[j]
 r is the magnitude of M
 s is the magnitude of the alphabet S of distinct symbols in A + B

'''References'''

[Dilworth 1950] "A decomposition theorem for partially ordered sets"
by Robert P. Dilworth, published January 1950,
Annals of Mathematics [Volume 51, Number 1, ''pp.'' 161-166]

[Goeman and Clausen 2002] "A New Practical Linear Space Algorithm for the Longest Common
Subsequence Problem" by Heiko Goeman and Michael Clausen,
published 2002, Kybernetika [Volume 38, Issue 1, ''pp.'' 45-66]

[Hirschberg 1975] "A linear space algorithm for computing maximal common subsequences"
by Daniel S. Hirschberg, published June 1975
Communications of the ACM [Volume 18, Number 6, ''pp.'' 341-343]

[Hunt and McIlroy 1976] "An Algorithm for Differential File Comparison"
by James W. Hunt and M. Douglas McIlroy, June 1976
Computing Science Technical Report, Bell Laboratories 41

[Hunt and Szymanski 1977] "A Fast Algorithm for Computing Longest Common Subsequences"
by James W. Hunt and Thomas G. Szymanski, published May 1977
Communications of the ACM [Volume 20, Number 5, ''pp.'' 350-353]

[Rick 2000] "Simple and fast linear space computation of longest common subsequences"
by Claus Rick, received 17 March 2000, Information Processing Letters,
Elsevier Science [Volume 75, ''pp.'' 275-281]

'''Examples'''

The sequences "1234" and "1224533324" have an LCS of "1234":
 '''1234'''
 '''12'''245'''3'''332'''4'''

For a string example, consider the sequences "thisisatest" and "testing123testing". An LCS would be "tsitest":
 '''t'''hi'''si'''sa'''test'''
 '''t'''e'''s'''t'''i'''ng123'''test'''ing

In this puzzle, your code only needs to deal with strings. Write a function which returns an LCS of two strings (case-sensitive). You don't need to show multiple LCS's.

For more information on this problem please see Wikipedia.

Solution:
def lcs(a, b):
    # generate matrix of length of longest common subsequence for substrings of both words
    lengths = [[0] * (len(b)+1) for _ in range(len(a)+1)]
    for i, x in enumerate(a):
        for j, y in enumerate(b):
            if x == y:
                lengths[i+1][j+1] = lengths[i][j] + 1
            else:
                lengths[i+1][j+1] = max(lengths[i+1][j], lengths[i][j+1])

    # read a substring from the matrix
    result = ''
    j = len(b)
    for i in range(1, len(a)+1):
        if lengths[i][j] != lengths[i-1][j]:
            result += a[i-1]

    return result


Longest common substring

Write a function that returns the longest common substring of two strings.

Use it within a program that demonstrates sample output from the function, which will consist of the longest common substring between "thisisatest" and "testing123testing".

Note that substrings are consecutive characters within a string.   This distinguishes them from subsequences, which is any sequence of characters within a string, even if there are extraneous characters in between them.

Hence, the [[longest common subsequence]] between "thisisatest" and "testing123testing" is "tsitest", whereas the longest common sub''string'' is just "test".

;References:
*Generalize Suffix Tree
*[[Ukkonen's Suffix Tree Construction]]

Solution:
s1 = "thisisatest"
s2 = "testing123testing"
len1, len2 = len(s1), len(s2)
ir, jr = 0, -1
for i1 in range(len1):
    i2 = s2.find(s1[i1])
    while i2 >= 0:
        j1, j2 = i1, i2
        while j1 < len1 and j2 < len2 and s2[j2] == s1[j1]:
            if j1-i1 >= jr-ir:
                ir, jr = i1, j1
            j1 += 1; j2 += 1
        i2 = s2.find(s1[i1], i2+1)
print (s1[ir:jr+1])


Longest common substring

Solution:
'''Longest common substring'''

from itertools import accumulate, chain
from functools import reduce

# longestCommon :: String -> String -> String
def longestCommon(s1):
    '''The longest common substring of
       two given strings.
    '''
    def go(s2):
        return max(intersect(
            *map(lambda s: map(
                concat,
                concatMap(tails)(
                    compose(tail, list, inits)(s)
                )
            ), [s1, s2])
        ), key=len)
    return go

# ------------------------- TEST -------------------------
def main():
    '''Test'''
    print(
        longestCommon(
            "testing123testing"
        )(
            "thisisatest"
        )
    )

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

# compose :: ((a -> a), ...) -> (a -> a)
def compose(*fs):
    '''Composition, from right to left,
       of a series of functions.
    '''
    def go(f, g):
        def fg(x):
            return f(g(x))
        return fg
    return reduce(go, fs, lambda x: x)

# concat :: [String] -> String
def concat(xs):
    '''The concatenation of all the elements
       in a list or iterable.
    '''
    return ''.join(xs)

# concatMap :: (a -> [b]) -> [a] -> [b]
def concatMap(f):
    '''A concatenated list over which a function has been
       mapped.
       The list monad can be derived by using a function f
       which wraps its output in a list, (using an empty
       list to represent computational failure).
    '''
    def go(xs):
        return chain.from_iterable(map(f, xs))
    return go

# inits :: [a] -> [[a]]
def inits(xs):
    '''all initial segments of xs, shortest first.'''
    return accumulate(chain([[]], xs), lambda a, x: a + [x])

# intersect :: [a] -> [a] -> [a]
def intersect(xs, ys):
    '''The ordered intersection of xs and ys.
       intersect([1,2,2,3,4])([6,4,4,2]) -> [2,2,4]
    '''
    s = set(ys)
    return (x for x in xs if x in s)

# scanl :: (b -> a -> b) -> b -> [a] -> [b]
def scanl(f):
    '''scanl is like reduce, but defines a succession of
       intermediate values, building from the left.
    '''
    def go(a):
        def g(xs):
            return accumulate(chain([a], xs), f)
        return g
    return go

# tail :: [a] -> [a]
# tail :: Gen [a] -> [a]
def tail(xs):
    '''The elements following the head of a
       (non-empty) list.
    '''
    return xs[1:]

# tails :: [a] -> [[a]]
def tails(xs):
    '''All final segments of xs,
       longest first.
    '''
    return [
        xs[i:] for i in
        range(0, 1 + len(xs))
    ]

# MAIN ---
main()


Longest increasing subsequence

Calculate and show here a longest increasing subsequence of the list:
:\{3, 2, 6, 4, 5, 1\}
And of the list:
:\{0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15\}

Note that a list may have more than one subsequence that is of the maximum length.

;Ref:
# Dynamic Programming #1: Longest Increasing Subsequence on YouTube
# An efficient solution can be based on Patience sorting.

Solution:
def longest_increasing_subsequence(X):
    """Returns the Longest Increasing Subsequence in the Given List/Array"""
    N = len(X)
    P = [0] * N
    M = [0] * (N+1)
    L = 0
    for i in range(N):
       lo = 1
       hi = L
       while lo <= hi:
           mid = (lo+hi)//2
           if (X[M[mid]] < X[i]):
               lo = mid+1
           else:
               hi = mid-1

       newL = lo
       P[i] = M[newL-1]
       M[newL] = i

       if (newL > L):
           L = newL

    S = []
    k = M[L]
    for i in range(L-1, -1, -1):
        S.append(X[k])
        k = P[k]
    return S[::-1]

if __name__ == '__main__':
    for d in [[3,2,6,4,5,1], [0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15]]:
        print('a L.I.S. of %s is %s' % (d, longest_increasing_subsequence(d)))


Lucky and even lucky numbers

Note that in the following explanation list indices are assumed to start at ''one''.

;Definition of lucky numbers
''Lucky numbers'' are positive integers that are formed by:

# Form a list of all the positive odd integers > 01, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39 ...
# Return the first number from the list (which is '''1''').
# (Loop begins here)
#* Note then return the second number from the list (which is '''3''').
#* Discard every third, (as noted), number from the list to form the new list1, 3, 7, 9, 13, 15, 19, 21, 25, 27, 31, 33, 37, 39, 43, 45, 49, 51, 55, 57 ...
# (Expanding the loop a few more times...)
#* Note then return the third number from the list (which is '''7''').
#* Discard every 7th, (as noted), number from the list to form the new list1, 3, 7, 9, 13, 15, 21, 25, 27, 31, 33, 37, 43, 45, 49, 51, 55, 57, 63, 67 ...
#* Note then return the 4th number from the list (which is '''9''').
#* Discard every 9th, (as noted), number from the list to form the new list1, 3, 7, 9, 13, 15, 21, 25, 31, 33, 37, 43, 45, 49, 51, 55, 63, 67, 69, 73 ...
#* Take the 5th, i.e. '''13'''.  Remove every 13th.
#* Take the 6th, i.e. '''15'''.  Remove every 15th.
#* Take the 7th, i.e. '''21'''.  Remove every 21th.
#* Take the 8th, i.e. '''25'''.  Remove every 25th.
# (Rule for the loop)
#* Note the nth, which is m.
#* Remove every mth.
#* Increment n.

;Definition of even lucky numbers
This follows the same rules as the definition of lucky numbers above ''except for the very first step'':
# Form a list of all the positive '''even''' integers > 02, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40 ...
# Return the first number from the list (which is '''2''').
# (Loop begins here)
#* Note then return the second number from the list (which is '''4''').
#* Discard every 4th, (as noted), number from the list to form the new list2, 4, 6, 10, 12, 14, 18, 20, 22, 26, 28, 30, 34, 36, 38, 42, 44, 46, 50, 52 ...
# (Expanding the loop a few more times...)
#* Note then return the third number from the list (which is '''6''').
#* Discard every 6th, (as noted), number from the list to form the new list2, 4, 6, 10, 12, 18, 20, 22, 26, 28, 34, 36, 38, 42, 44, 50, 52, 54, 58, 60 ...
#* Take the 4th, i.e. '''10'''.  Remove every 10th.
#* Take the 5th, i.e. '''12'''.  Remove every 12th.
# (Rule for the loop)
#* Note the nth, which is m.
#* Remove every mth.
#* Increment n.

;Task requirements
* Write one or two subroutines (functions) to generate ''lucky numbers'' and ''even lucky numbers''
* Write a command-line interface to allow selection of which kind of numbers and which number(s). Since input is from the command line, tests should be made for the common errors:
** missing arguments
** too many arguments
** number (or numbers) aren't legal
** misspelled argument ('''lucky''' or '''evenLucky''')
* The command line handling should:
** support mixed case handling of the (non-numeric) arguments
** support printing a particular number
** support printing a range of numbers by their index
** support printing a range of numbers by their values
* The resulting list of numbers should be printed on a single line.

The program should support the arguments:

                             what is displayed  (on a single line)
       argument(s)              (optional verbiage is encouraged)
  +-------------------+----------------------------------------------------+
  |  j                |  Jth       lucky number                            |
  |  j  ,      lucky  |  Jth       lucky number                            |
  |  j  ,  evenLucky  |  Jth  even lucky number                            |
  |                   |                                                    |
  |  j  k             |  Jth  through  Kth (inclusive)       lucky numbers |
  |  j  k      lucky  |  Jth  through  Kth (inclusive)       lucky numbers |
  |  j  k  evenLucky  |  Jth  through  Kth (inclusive)  even lucky numbers |
  |                   |                                                    |
  |  j -k             |  all       lucky numbers in the range  j --> |k|   |
  |  j -k      lucky  |  all       lucky numbers in the range  j --> |k|   |
  |  j -k  evenLucky  |  all  even lucky numbers in the range  j --> |k|   |
  +-------------------+----------------------------------------------------+
                           where    |k|    is the absolute value of   k

Demonstrate the program by:
* showing the first twenty ''lucky'' numbers
* showing the first twenty ''even lucky'' numbers
* showing all ''lucky'' numbers between 6,000 and 6,100 (inclusive)
* showing all ''even lucky'' numbers in the same range as above
* showing the 10,000th ''lucky'' number (extra credit)
* showing the 10,000th ''even lucky'' number (extra credit)

;See also:
* This task is related to the [[Sieve of Eratosthenes]] task.
* OEIS Wiki Lucky numbers.
* Sequence A000959 lucky numbers on The On-Line Encyclopedia of Integer Sequences.
* Sequence A045954 even lucky numbers or ELN on The On-Line Encyclopedia of Integer Sequences.
* Entry lucky numbers on The Eric Weisstein's World of Mathematics.

Solution:
from itertools import islice
import sys, re

class ArgumentError(Exception):
    pass
def arghandler(argstring):
    match_obj = re.match( r"""(?mx)
    (?:
      (?P<SINGLE>
         (?: ^ (?P<SINGLEL> \d+ ) (?:  | \s , \s lucky ) \s* $ )
        |(?: ^ (?P<SINGLEE> \d+ ) (?:  | \s , \s evenLucky ) \s* $ )
      )
     |(?P<KTH>
         (?: ^ (?P<KTHL> \d+ \s \d+ ) (?:  | \s lucky ) \s* $ )
        |(?: ^ (?P<KTHE> \d+ \s \d+ ) (?:  | \s evenLucky ) \s* $ )
      )
     |(?P<RANGE>
         (?: ^ (?P<RANGEL> \d+ \s -\d+ ) (?:  | \s lucky ) \s* $ )
        |(?: ^ (?P<RANGEE> \d+ \s -\d+ ) (?:  | \s evenLucky ) \s* $ )
      )
    )""", argstring)

    if match_obj:
        # Retrieve group(s) by name
        SINGLEL = match_obj.group('SINGLEL')
        SINGLEE = match_obj.group('SINGLEE')
        KTHL = match_obj.group('KTHL')
        KTHE = match_obj.group('KTHE')
        RANGEL = match_obj.group('RANGEL')
        RANGEE = match_obj.group('RANGEE')
        if SINGLEL:
            j = int(SINGLEL)
            assert 0 < j < 10001, "Argument out of range"
            print("Single %i'th lucky number:" % j, end=' ')
            print( list(islice(lgen(), j-1, j))[0] )
        elif SINGLEE:
            j = int(SINGLEE)
            assert 0 < j < 10001, "Argument out of range"
            print("Single %i'th even lucky number:" % j, end=' ')
            print( list(islice(lgen(even=True), j-1, j))[0] )
        elif KTHL:
            j, k = [int(num) for num in KTHL.split()]
            assert 0 < j < 10001, "first argument out of range"
            assert 0 < k < 10001 and k > j, "second argument out of range"
            print("List of %i ... %i lucky numbers:" % (j, k), end=' ')
            for n, luck in enumerate(lgen(), 1):
                if n > k: break
                if n >=j: print(luck, end = ', ')
            print('')
        elif KTHE:
            j, k = [int(num) for num in KTHE.split()]
            assert 0 < j < 10001, "first argument out of range"
            assert 0 < k < 10001 and k > j, "second argument out of range"
            print("List of %i ... %i even lucky numbers:" % (j, k), end=' ')
            for n, luck in enumerate(lgen(even=True), 1):
                if n > k: break
                if n >=j: print(luck, end = ', ')
            print('')
        elif RANGEL:
            j, k = [int(num) for num in RANGEL.split()]
            assert 0 < j < 10001, "first argument out of range"
            assert 0 < -k < 10001 and -k > j, "second argument out of range"
            k = -k
            print("List of lucky numbers in the range %i ... %i :" % (j, k), end=' ')
            for n in lgen():
                if n > k: break
                if n >=j: print(n, end = ', ')
            print('')
        elif RANGEE:
            j, k = [int(num) for num in RANGEE.split()]
            assert 0 < j < 10001, "first argument out of range"
            assert 0 < -k < 10001 and -k > j, "second argument out of range"
            k = -k
            print("List of even lucky numbers in the range %i ... %i :" % (j, k), end=' ')
            for n in lgen(even=True):
                if n > k: break
                if n >=j: print(n, end = ', ')
            print('')
    else:
        raise ArgumentError('''

  Error Parsing Arguments!

  Expected Arguments of the form (where j and k are integers):

      j                #  Jth       lucky number
      j  ,      lucky  #  Jth       lucky number
      j  ,  evenLucky  #  Jth  even lucky number
                       #
      j  k             #  Jth  through  Kth (inclusive)       lucky numbers
      j  k      lucky  #  Jth  through  Kth (inclusive)       lucky numbers
      j  k  evenLucky  #  Jth  through  Kth (inclusive)  even lucky numbers
                       #
      j -k             #  all       lucky numbers in the range  j --? |k|
      j -k      lucky  #  all       lucky numbers in the range  j --? |k|
      j -k  evenLucky  #  all  even lucky numbers in the range  j --? |k|
        ''')

if __name__ == '__main__':
    arghandler(' '.join(sys.argv[1:]))


Lychrel numbers

::#   Take an integer n, greater than zero.
::#   Form the next n of its series by reversing the digits of the current n and adding the result to the current n.
::#   Stop when n becomes palindromic - i.e. the digits of n in reverse order == n.

The above recurrence relation when applied to most starting numbers n = 1, 2, ... terminates in a palindrome quite quickly.

;Example:
If n0 = 12 we get

       12
       12 +  21 =  33,   a palindrome!

And if n0 = 55 we get

       55
       55 +  55 = 110
      110 + 011 = 121,   a palindrome!

Notice that the check for a palindrome happens   ''after''   an addition.

Some starting numbers seem to go on forever; the recurrence relation for 196 has been calculated for millions of repetitions forming numbers with millions of digits, without forming a palindrome.

These numbers that do not end in a palindrome are called '''Lychrel numbers'''.

For the purposes of this task a Lychrel number is any starting number that does not form a palindrome within 500 (or more) iterations.

;Seed and related Lychrel numbers:
Any integer produced in the sequence of a Lychrel number is also a Lychrel number.

In general, any sequence from one Lychrel number ''might'' converge to join the sequence from a prior Lychrel number candidate; for example the sequences for the numbers 196 and then 689 begin:

        196
        196 +    691 =   887
        887 +    788 =  1675
       1675 +   5761 =  7436
       7436 +   6347 = 13783
      13783 +  38731 = 52514
      52514 +  41525 = 94039
       ...

        689
        689 +    986 =  1675
       1675 +   5761 =  7436
       ...

So we see that the sequence starting with 689 converges to, and continues with the same numbers as that for 196.

Because of this we can further split the Lychrel numbers into true '''Seed''' Lychrel number candidates, and '''Related''' numbers that produce no palindromes but have integers in their sequence seen as part of the sequence generated from a lower Lychrel number.

;Task:
*   Find the number of seed Lychrel number candidates and related numbers for n in the range 1..10000 inclusive. (With that iteration limit of 500).
*    Print the number of seed Lychrels found; the actual seed Lychrels; and just the ''number'' of relateds found.
*    Print any seed Lychrel or related number that is itself a palindrome.

Show all output here.

;References:
*   What's special about 196? Numberphile video.
*   A023108 Positive integers which apparently never result in a palindrome under repeated applications of the function f(x) = x + (x with digits reversed).
*   Status of the 196 conjecture? Mathoverflow.

Solution:
from __future__ import print_function

def add_reverse(num, max_iter=1000):
    i, nums = 0, {num}
    while True:
        i, num = i+1, num + reverse_int(num)
        nums.add(num)
        if reverse_int(num) == num or i >= max_iter:
            break
    return nums

#@functools.lru_cache(maxsize=2**20)
def reverse_int(num):
    return int(str(num)[::-1])

def split_roots_from_relateds(roots_and_relateds):
    roots = roots_and_relateds[::]
    i = 1
    while i < len(roots):
        this = roots[i]
        if any(this.intersection(prev) for prev in roots[:i]):
            del roots[i]
        else:
            i += 1
    root = [min(each_set) for each_set in roots]
    related = [min(each_set) for each_set in roots_and_relateds]
    related = [n for n in related if n not in root]
    return root, related

def find_lychrel(maxn, max_reversions):
    'Lychrel number generator'
    series = [add_reverse(n, max_reversions*2) for n in range(1, maxn + 1)]
    roots_and_relateds = [s for s in series if len(s) > max_reversions]
    return split_roots_from_relateds(roots_and_relateds)

if __name__ == '__main__':
    maxn, reversion_limit = 10000, 500
    print("Calculations using n = 1..%i and limiting each search to 2*%i reverse-digits-and-adds"
          % (maxn, reversion_limit))
    lychrel, l_related = find_lychrel(maxn, reversion_limit)
    print('  Number of Lychrel numbers:', len(lychrel))
    print('    Lychrel numbers:', ', '.join(str(n) for n in lychrel))
    print('  Number of Lychrel related:', len(l_related))
    #print('    Lychrel related:', ', '.join(str(n) for n in l_related))
    pals = [x for x in lychrel + l_related  if x == reverse_int(x)]
    print('  Number of Lychrel palindromes:', len(pals))
    print('    Lychrel palindromes:', ', '.join(str(n) for n in pals))


Mad Libs

{{wikipedia}}

Mad Libs is a phrasal template word game where one player prompts another for a list of words to substitute for blanks in a story, usually with funny results.

;Task;
Write a program to create a Mad Libs like story.

The program should read an arbitrary multiline story from input.

The story will be terminated with a blank line.

Then, find each replacement to be made within the story, ask the user for a word to replace it with, and make all the replacements.

Stop when there are none left and print the final story.

The input should be an arbitrary story in the form:

 went for a walk in the park.
found a .  decided to take it home.

Given this example, it should then ask for a name, a he or she and a noun ( gets replaced both times with the same value).

Solution:
import re

# Optional Python 2.x compatibility
#try: input = raw_input
#except: pass

template = '''<name> went for a walk in the park. <he or she>
found a <noun>. <name> decided to take it home.'''

def madlibs(template):
    print('The story template is:\n' + template)
    fields = sorted(set( re.findall('<[^>]+>', template) ))
    values = input('\nInput a comma-separated list of words to replace the following items'
                   '\n  %s: ' % ','.join(fields)).split(',')
    story = template
    for f,v in zip(fields, values):
        story = story.replace(f, v)
    print('\nThe story becomes:\n\n' + story)

madlibs(template)


Magic 8-ball

Create Magic 8-Ball.

See details at:   Magic 8-Ball.

Solution:
import random

s = ('It is certain', 'It is decidedly so', 'Without a doubt', 'Yes, definitely',
 'You may rely on it', 'As I see it, yes', 'Most likely', 'Outlook good',
 'Signs point to yes', 'Yes', 'Reply hazy, try again', 'Ask again later',
 'Better not tell you now', 'Cannot predict now', 'Concentrate and ask again',
 "Don't bet on it", 'My reply is no', 'My sources say no', 'Outlook not so good',
 'Very doubtful')

q_and_a = {}

while True:
    question = input('Ask your question:')
    if len(question) == 0: break

    if question in q_and_a:
        print('Your question has already been answered')
    else:
        answer = random.choice(s)
        q_and_a[question] = answer
        print(answer)


Magic constant

A magic square is a square grid containing consecutive integers from 1 to N2, arranged so that every row, column and diagonal adds up to the same number. That number is a constant. There is no way to create a valid N x N magic square that does not sum to the associated constant.

;EG

A 3 x 3 magic square ''always'' sums to 15.

    +---+---+---+
    | 2 | 7 | 6 |
    +---+---+---+
    | 9 | 5 | 1 |
    +---+---+---+
    | 4 | 3 | 8 |
    +---+---+---+

A 4 x 4 magic square ''always'' sums to 34.

Traditionally, the sequence leaves off terms for n = 0 and n = 1 as the magic squares of order 0 and 1 are trivial; and a term for n = 2 because it is impossible to form a magic square of order 2.

;Task

* Starting at order 3, show the first 20 magic constants.
* Show the 1000th magic constant. (Order 1003)
* Find and show the order of the smallest N x N magic square whose constant is greater than 101 through 1010.

;Stretch

* Find and show the order of the smallest N x N magic square whose constant is greater than 1011 through 1020.

;See also

* Wikipedia: Magic constant
* OEIS: A006003 (Similar sequence, though it includes terms for 0, 1 & 2.)
* [[Magic squares of odd order]]
* [[Magic squares of singly even order]]
* [[Magic squares of doubly even order]]

Solution:
#!/usr/bin/python

def a(n):
    n += 2
    return n*(n**2 + 1)/2

def inv_a(x):
    k = 0
    while k*(k**2+1)/2+2 < x:
        k+=1
    return k

if __name__ == '__main__':
    print("The first 20 magic constants are:");
    for n in range(1, 20):
        print(int(a(n)), end = " ");
    print("\nThe 1,000th magic constant is:",int(a(1000)));

    for e in range(1, 20):
        print(f'10^{e}: {inv_a(10**e)}');


Magic squares of doubly even order

Solution:
def MagicSquareDoublyEven(order):
    sq = [range(1+n*order,order + (n*order)+1) for n in range(order) ]
    n1 = order/4
    for r in range(n1):
        r1 = sq[r][n1:-n1]
        r2 = sq[order -r - 1][n1:-n1]
        r1.reverse()
        r2.reverse()
        sq[r][n1:-n1] = r2
        sq[order -r - 1][n1:-n1] = r1
    for r in range(n1, order-n1):
        r1 = sq[r][:n1]
        r2 = sq[order -r - 1][order-n1:]
        r1.reverse()
        r2.reverse()
        sq[r][:n1] = r2
        sq[order -r - 1][order-n1:] = r1
    return sq

def printsq(s):
    n = len(s)
    bl = len(str(n**2))+1
    for i in range(n):
        print ''.join( [ ("%"+str(bl)+"s")%(str(x)) for x in s[i]] )
    print "\nMagic constant = %d"%sum(s[0])

printsq(MagicSquareDoublyEven(8))