Related
Give a base b and a length n, I'd like to find through all integers in base b, with leading zeroes to reach length n, that satisfy:
For digits i and j, if i < j then the count of i's is >= the count of j's.
E.g., base 3, length 4:
0000, 0001, 0010, 0011, 0012, 0021, 0100,
0101, 0102, 0110, 0120, 0201, 0210 1000,
1001, 1002, 1010, 1020, 1100, 1200, 2001,
2010, 2100
My current approach is to increment through all integers in the range in base 10, convert to base b, count digits, and reject if the digit counts fail our criterion. This is slow.
I think the language I'm using is irrelevant but if it matters, it's Rust.
This problem is equivalent to generating integer partitions of value n into b parts, then using every partition elements as counts of digits and applying permutations (last stage alike Shridhar R Kulkarni approach, but another combinatorial object is used)
For n=7 and b=4 some intermediate parition of 7 into 4 parts is [3, 2, 2, 0] that denotes digit combination [0, 0, 0, 1, 1, 2, 2], then we permute the last one in lexicographic order. partitions function provides non-increasing parts order, so if i < j then the count of i's is >= the count of j's. condition is fulfilled.
Ideone code to play with.
def next_permutation(arr):
#https://www.nayuki.io/page/next-lexicographical-permutation-algorithm
i = len(arr) - 1
while i > 0 and arr[i - 1] >= arr[i]:
i -= 1
if i <= 0:
return False
j = len(arr) - 1
while arr[j] <= arr[i - 1]:
j -= 1
arr[i - 1], arr[j] = arr[j], arr[i - 1]
arr[i : ] = arr[len(arr) - 1 : i - 1 : -1]
return True
def partitions(Sum, K, lst, Minn = 0):
if K == 0:
if Sum == 0:
#print(lst) [3, 1, 0] denotes three zeros and one 1
arr = []
for i in range(len(lst)):
if lst[i]:
arr.extend([i]*lst[i])
#transform [3, 1, 0] to [0,0,0,1]
print(arr)
while next_permutation(arr):
print(arr)
return
for i in range(Minn, min(Sum + 1, Sum + 1)):
partitions(Sum - i, K - 1, [i] + lst, i)
b = 3
n = 4
partitions(n, b, [])
result
[0, 0, 0, 0] [0, 0, 0, 1] [0, 0, 1, 0] [0, 1, 0, 0]
[1, 0, 0, 0] [0, 0, 1, 1] [0, 1, 0, 1] [0, 1, 1, 0]
[1, 0, 0, 1] [1, 0, 1, 0] [1, 1, 0, 0] [0, 0, 1, 2]
[0, 0, 2, 1] [0, 1, 0, 2] [0, 1, 2, 0] [0, 2, 0, 1]
[0, 2, 1, 0] [1, 0, 0, 2] [1, 0, 2, 0] [1, 2, 0, 0]
[2, 0, 0, 1] [2, 0, 1, 0] [2, 1, 0, 0]
This problem can be solved with dynamic programming. Here is one approach (using Python):
from functools import lru_cache
from collections import Counter
from itertools import product
def naive(base, length):
result = 0
for tup in product(range(base), repeat=length):
ctr = Counter(tup)
is_valid = all(ctr[i] >= ctr[i+1] for i in range(base))
if is_valid:
result += 1
return result
#lru_cache(None)
def binom(n, k):
# compute binomial coefficient
if n == 0:
if k == 0:
return 1
else:
return 0
return binom(n - 1, k) + binom(n - 1, k - 1)
def count_seq(base, length):
#lru_cache(None)
def count_helper(base, length, max_repeats):
if base < 0 or length < 0:
return 0
elif length == 0:
return 1
return sum(binom(length, k) * count_helper(base - 1, length - k, k)
for k in range(max_repeats+1))
return count_helper(base, length, length)
assert all(count_seq(base, length) == naive(base, length)
for base in range(7) for length in range(7))
print(count_seq(100, 60))
#21047749425803338154212116084613212619618570995864645505458031212645031666717071397
The key function is count_helper(base, length, max_repeats) that counts the number of valid sequences s.t. the most common digit does not repeat more than max_repeats times. Ignoring the base case, this function satisfies a recurrence relation:
count_helper(base, length, max_repeats) = sum(
binom(length, k) * count_helper(base - 1, length - k, k)
for k in range(max_repeats+1))
At this point, we are deciding how many copies of digit base to insert into the sequence. We can choose any number k between 0 and max_repeats inclusive. For a given, value of k, there are length choose k ways to insert the digit we are adding. Each choice of k leads to a recursive call to a subproblem where base is reduced by 1, length is reduced by k and max_repeats is set to k.
When base = 3 and length = 4, the answer would be
['0000', '0001', '0010', '0011', '0012', '0021', '0100', '0101', '0102', '0110', '0120', '0201', '0210', '1000', '1001', '1002', '1010', '1020', '1100', '1111', '1112', '1121', '1122', '1200', '1211', '1212', '1221', '2001', '2010', '2100', '2111', '2112', '2121', '2211', '2222']
We can observe that all the numbers in the answer would be permutations of ['0000', '0001', '0011', '0012', '1111', '1112', '1122', '2222']. Let us call them unique_numbers.
So, our solution is easy and simple. Generate all the unique_numbers and add their permutations to the result.
from itertools import permutations
base = 3
length = 4
unique_numbers = []
def getUniqueNumbers(curr_digit, curr_count, max_count, curr_num):
#Add the curr_num to unique_numbers
if len(curr_num) == length:
unique_numbers.append(curr_num)
return
#Try to include the curr_digit again
if curr_count + 1 <= max_count:
getUniqueNumbers(curr_digit, curr_count + 1, max_count, curr_num + str(curr_digit))
#Try to include the next digit
if curr_digit + 1 < base:
getUniqueNumbers(curr_digit+1, 1, curr_count, curr_num + str(curr_digit+1))
#Try generating unique numbers starting with every digit
for i in range(base):
getUniqueNumbers(i, 0, length, "")
result = set()
for num in unique_numbers:
permList = permutations(num)
for perm in list(permList):
result.add(''.join(perm))
print(result)
I need to draw an n sample from the uniform distribution on the interval [a,b] such that no two numbers are closer than d > 0. I can draw a sample and check this property and then throw it away and try again if not, but if n is large relative to b-a that could take a looong time. Is there a simple and nice algorithm to solve this problem? The numbers got to be uniformly distributed on [a,b], no deterministic setup.
This problem is equivalent to choosing n numbers greater than or equal to d and whose sum is equal to b - a.
There will be some solution provided that n * d <= b - a. We can write a recursive algorithm that looks for one:
b - a - X < (n - 1) * D
X > b - a - (n - 1) * d
FindSpacedSample(n, d, a, b)
1. if n * d > b - a then return "no solution"
2. avail = [d, b - a - (n - 1) * d]
3. guess = random(avail)
4. print(guess)
5. FindSpacedSample(n - 1, d, a + guess, b)
Example: n = 5, a = 0, b = 10, d = 1, assuming real numbers
FindSpacedSample(5, 1, 0, 10)
5 * 1 >? b - a? no
avail = [1, 10 - 0 - 4 * 1] = [1, 6]
guess = random(avail) = 2 (for the sake of argument)
print(2)
FindSpacedSample(4, 1, 2, 10)
4 * 1 >? 10 - 2? no
avail = [1, 10 - 2 - 3 * 1] = [1, 5]
guess = random(avail) = 4 (for the sake of argument)
print(4)
FindSpacedSample(3, 1, 6, 10)
3 * 1 >? 10 - 6? no
avail = [1, 10 - 6 - 2 * 1] = [1, 2]
guess = random(avail) = 1 (for the sake of argument)
print(1)
FindSpacedSample(2, 1, 7, 10)
2 * 1 >? 10 - 7? no
avail = [1, 10 - 7 - 1 * 1] = [1, 2]
guess = random(avail) = 2 (for the sake of argument)
print(2)
FindSpacedSample(1, 1, 9, 10)
1 * 1 >? 10 - 9? no
avail = [1, 10 - 9 - 0 * 1] = [1, 1]
guess = 1
print(1)
We should also have stopping condition n = 0. Then we get the sequence of spaces 2, 4, 1, 2, 1; we see these sum to ten; and we can get the values as follows:
point1 = 2 = 2
point2 = 2 + 4 = 6
point3 = 2 + 4 + 1 = 7
point4 = 2 + 4 + 1 + 2 = 9
point5 = 2 + 4 + 1 + 2 + 1 = 10
Now, there are a couple of ways in which this result is less than totally uniform:
the first number will never be less than d
earlier numbers tend to be spaced further apart
We can fix these by:
shuffling the spacings before converting to points
subtracting from each point some random value from [0, point1 - a].
So, if we shuffled 2, 4, 1, 2, 1 to 4, 1, 1, 2, 2 we'd get points 4, 5, 6, 8, 10; and if we subtracted 3 from each one (taken randomly between 0 and 4) we'd get 1, 2, 3, 5, 7.
Does this give you a uniform distribution over the set of all possible solutions? I'd be surprised if it did, but I'd also be surprised if what this does give you differs from that truly uniform distribution to an appreciable degree.
In the past I've often used loops of the following kind (Haskell example):
upperBoundToTuples :: Int -> [(Int, Int)]
upperBoundToTuples n = [(x,y) | x <- [0..n], y <- [x+1..n]]
The above code produces tuples of range (0,1)..(n,n) where for all x < y.
I was wondering if it there was an efficient way of getting those (x,y) indices given a single index? Possible applications include optimization problems on the GPU where loops are not allowed and each thread only gets an index.
Also if it is possible for the 2D case, could such an algorithm be generalized to multiple dimensions?
You're asking for a bijection from [0, N(N+1)/2) to pairs (x, y) with 0 <= x < y <= N.
Here's one simple way to define it (in pseudocode, but should be trivial to convert to Haskell):
x0, y0 = i / (N + 1), i % (N + 1)
if x0 < y0 then result = (x0, y0)
else result = (N - 1 - x0, N - y0)
Here's a visualisation of the function for N=6. The map is laid out in a table with rows of length N+1=7, with the first row representing the value of the function for i=0 to 6, the next i=7 to 13 and so on. If you look very closely and carefully, you can see that things above the leading diagonal map to their own location in the table, and things on or below the diagonal map rotationally to the later entries.
5,6 0,1 0,2 0,3 0,4 0,5 0,6
4,6 4,5 1,2 1,3 1,4 1,5 1,6
3,6 3,5 3,4 2,3 2,4 2,5 2,6
And here's the opposite of this visualisation: a table T of size (N+1) by (N+1) with T[x, y] = i where i is mapped to (x, y) by the function above.
- 1 2 3 4 5 6
- - 9 10 11 12 13
- - - 17 18 19 20
- - - - 16 15 14
- - - - - 8 7
- - - - - - 0
- - - - - - -
Higher dimensions
This method can probably be made to work in higher dimensions, but I don't immediately see how. As an alternative, here's a simple but somewhat inefficient method that does work in arbitrary dimensions.
First, note there's choose(N + 1, k) increasing sequences of length k from the numbers from 0 to N (where choose(N, k) is the binomial coefficient). Of those, choose(N, k - 1) of them end with N. That gives this recursive function that generates the sequences in descending colexicographical order (again in pseudocode):
sequence(N, k, index)
= [] if k == 0
= sequence(N - 1, k - 1, index) + [N] if index < choose(N, k - 1)
= sequence(N - 1, k, index - choose(N, k - 1)) otherwise
Here's, sequence(5, 3, index) for index between 0 and 19:
0 -> [3, 4, 5]
1 -> [2, 4, 5]
2 -> [1, 4, 5]
3 -> [0, 4, 5]
4 -> [2, 3, 5]
5 -> [1, 3, 5]
6 -> [0, 3, 5]
7 -> [1, 2, 5]
8 -> [0, 2, 5]
9 -> [0, 1, 5]
10 -> [2, 3, 4]
11 -> [1, 3, 4]
12 -> [0, 3, 4]
13 -> [1, 2, 4]
14 -> [0, 2, 4]
15 -> [0, 1, 4]
16 -> [1, 2, 3]
17 -> [0, 2, 3]
18 -> [0, 1, 3]
19 -> [0, 1, 2]
We may equivalently consider [(x,y) | x<-[0..n], y<-[0..x-1]]. This list has length
ℓn = x=0∑n x
= n·(n+1)/2.
Hence we can get, to a given ℓ, the nearest lower n through
2·ℓn = n·(n+1) = n2 + n
n~ = -½ ± √(¼ + 2·ℓn)
In particular, for a given index i,
ni− = ⌊-½ ± √(¼ + 2·i)⌋
is the x-length of the last fully completed triangle. Thus, the index i lies in the row ni−+1. That triangle had an area of
ℓni− = ni−·(ni−+1)/2
which we therefore need to subtract from i to get the remainder index (in y-direction). This gives rise to the definition
lowerTriangularTuple :: Int -> (Int,Int)
lowerTriangularTuple i = (nmin+1, i - (nmin*(nmin+1))`div`2)
where nmin = floor $ -1/2 + sqrt(1/4 + 2 * fromIntegral i)
Example:
GHCi> lowerTriangularTuple <$> [0..30]
[(1,0),(2,0),(2,1),(3,0),(3,1),(3,2),(4,0),(4,1),(4,2),(4,3),(5,0),(5,1),(5,2),(5,3),(5,4),(6,0),(6,1),(6,2),(6,3),(6,4),(6,5),(7,0),(7,1),(7,2),(7,3),(7,4),(7,5),(7,6),(8,0),(8,1),(8,2)]
I have a list of numbers:
[1, 2, 3, 4, 5, 6, 7]
I'm interested in finding an algorithm that can sum the total children in this list if the list where a tree:
1
/ \
2 3
/ \ / \
4 5 6 7
I'm looking for an algorithm that would give:
[6, 2, 2, 0, 0, 0, 0]
A = 6
B = 2
C = 2
D = 0
E = 0
F = 0
G = 0
Each node (except the leaves) has two children. The only exception is if the list if even:
1
/ \
2 3
/ \ /
4 5 6
I would like to avoid building a tree and then counting the number of children at each node. There must be a simple mathematical way to count the number of children from a list?
1-indexed the array.
Then for node with index i, the left son is with the index 2*i, and right is the 2*i+1.
Then go through the array from the end, for the node now:
if index of his (left or right)son is out of bound of array, then he has no (left or right)son.
If not, then you can know the number of the children of his son(we go through the array from then end).The result = number of children of now's son + number of now's son.
For example:
[1, 2, 3, 4, 5, 6, 7]
A is the result array.
1.A=[0, 0, 0, 0, 0, 0, 0],now(now is a index) = 7(1-indexed) since 7*2>7, a[7]=0
2.A=[0, 0, 0, 0, 0, 0, 0],now = 6,since 6*2>7, a[6]=0
3.A=[0, 0, 0, 0, 0, 0, 0],now = 5,since 5*2>7, a[5]=0
4.A=[0, 0, 0, 0, 0, 0, 0],now = 4,since 4*2>7, a[4]=0
5.A=[0, 0, 2, 0, 0, 0, 0],now = 3,since 3*2<7 and 3*2+1<7, a[3]=2+a[6]+a[7]=2
6.A=[0, 2, 2, 0, 0, 0, 0],now = 2,since 2*2<7 and 2*2+1<7, a[2]=2+a[4]+a[5]=2
7.A=[6, 2, 2, 0, 0, 0, 0],now = 1,since 1*2<7 and 1*2+1<7, a[1]=2+a[2]+a[3]=6
For the case where the tree is balanced (i.e. the number of elements in the input list is odd), this can be calculated with:
n = length of elements in input list
Then for element i in the output list:
d = depth of element in tree = floor(log2(i+1))+1
Then the number of children below that element in the tree is:
n_children = n - ((2^d)-1) / 2^(d-1)
So for your example of [1,2,3,4,5,6,7]:
n = 7
For array position 0 (i.e. node 1):
d = depth = floor(log2(1))+1 = 1
n_children = (7 - ((2^1)-1)) / 2^(1-1)
= (7 - 1) / 2^0
= 6 / 1
= 6
Then for then array position 1, (i.e. node 2):
d = depth = floor(log2(2))+1 = 2
n_children = (7 - ((2^2)-1)) / 2^(2-1)
= (7 - 3) / 2
= 2
Carrying on with this gives [6, 2, 2, 0, 0, 0, 0] for i=0 to i=6.
Python code for this would look like:
import math
def n_children(list_size, i):
depth = math.floor(math.log(i+1,2)) + 1
return (list_size - ((2**depth)-1)) / 2**(depth-1)
print [n_children(7, i) for i in range(7)]
This outputs [6.0, 2.0, 2.0, 0.0, 0.0, 0.0, 0.0].
It'd need some modification to deal with even numbered input arrays though (easiest way might be to round array size up to nearest odd number, then subtract 1 from any odd numbered values of i, or similar).
Interpret the first array as a heap, in which the children of node n are at 2*n+1 and 2*n+2, then recursively travel the tree:
def children(t, n):
if 2 * n + 1 >= t:
return 0
elif 2 * n + 2 >= t:
return 1
else:
return 2 + children(t, 2 * n + 1) + children(t, 2 * n + 2)
size = 7
childcounts = [ children(size, i) for i in range(size) ]
print(childcounts)
This will print:
[6, 2, 2, 0, 0, 0, 0]
Like we do in heap,
children[i] = sum of children of all its child + number of child
Like for 0th element, a[0] = number of children of its left child + number of children of its right child + number of its child
so a[0] = 2 + 2 + 2
for(int i=n-1;i>=0;i--) {
if(i*2+2 < n)
a[i]+=a[i*2+2]+1;
if(i*2+1 < n)
a[i]+=a[i*2+1]+1;
}
I think I can illustrate this best with an example:
Suppose I have A = [ 1, 4, 2, 3;
0,-1, 2, -1]
I want to turn it into
[1, 2, 3, 4;
0, 2, -1, -1]
i.e. keep columns intact, sort by entries in first row. How do I do this?
The sortrows command does what you want:
>> A = [ 1, 4, 2, 3; 0,-1, 2, -1];
>> sortrows(A.').'
ans =
1 2 3 4
0 2 -1 -1
You can also use the second return value from sort to get the column permutation necessary to turn your matrix into the one you want:
>> [~,ii] = sort(A(1,:))
ii =
1 3 4 2
>> A(:,ii)
ans =
1 2 3 4
0 2 -1 -1