Efficiently compute Knuth's up-arrow notation modulus - optimization

I'm already using memoization as a dictionary. Is there anything else I can do? I suspect the for loop might be able to be optimized. For reference I am computing knuth_arrow(2, 3, 9, 14**8)
memo = {}
def knuth_arrow(a, n, b, m):
if (a, n, b) in memo:
return memo[(a, n, b)]
if n == 0:
return (a*b) % m
if n == 1:
s = pow(a, b, m)
memo[(a, n, b)] = s
return s
if n > 1:
s = a
for i in range(b-1):
s = knuth_arrow(a, n-1, s, m)
memo[(a, n, b)] = s
return s

Related

TVM: How to represent int8 gemm with int32 output

def matmul(M, K, N, dtype):
A = te.placeholder((M, K), name="A", dtype=dtype)
B = te.placeholder((K, N), name="B", dtype=dtype)
k = te.reduce_axis((0, K), name="k")
matmul = te.compute(
(M, N),
lambda i, j: te.sum(A[i, k] * B[k, j], axis=k),
name="matmul",
attrs ={"layout_free_placeholders": [B]}, # enable automatic layout transform for tensor B
)
out = te.compute((M, N), lambda i, j: matmul[i, j] , name="out")
return [A, B, out]
The output type is also int8, result larger than int8 will be cut off during computation.
How to make out tensor become int32?

Complex matrix multiplication with tensorflow-backend of Keras

Let matrix F1 has a shape of (a * h * w * m), matrix F2 has a shape of (a * h * w * n), and matrix G has a shape of (a * m * n).
I want to implement the following formula which calculates each factor of G from factors of F1 and F2, using tensorflow backend of Keras. However I am confused by various backend functions, especially K.dot() and K.batch_dot().
$$ G_{k, i, j} = \sum^h_{s=1} \sum^w_{t=1} \dfrac{F^1_{k, s, t, i} * F^2_{k, s, t, j}}{h * w} $$ i.e.:
(Image obtained by copying the above equation within $$ and pasting it to this site)
Is there any way to implement the above formula? Thank you in advance.
Using Tensorflow tf.einsum() (which you could wrap in a Lambda layer for Keras):
import tensorflow as tf
import numpy as np
a, h, w, m, n = 1, 2, 3, 4, 5
F1 = tf.random_uniform(shape=(a, h, w, m))
F2 = tf.random_uniform(shape=(a, h, w, n))
G = tf.einsum('ahwm,ahwn->amn', F1, F2) / (h * w)
with tf.Session() as sess:
f1, f2, g = sess.run([F1, F2, G])
# Manually computing G to check our operation, reproducing naively your equation:
g_check = np.zeros(shape=(a, m, n))
for k in range(a):
for i in range(m):
for j in range(n):
for s in range(h):
for t in range(w):
g_check[k, i, j] += f1[k,s,t,i] * f2[k,s,t,j] / (h * w)
# Checking for equality:
print(np.allclose(g, g_check))
# > True

Hofstadter Female and Male sequences in SML

This is my first SML program. I am trying to write a function that returns the first number to the nth number of Hofstadter's Female or Male sequence in list form. What I have so far is:
val m = fn (n) => if n = 0 then 1 :: [] else m f (n - 1);
val f = fn (n) => if n = 0 then 0 :: [] else f m (n - 1);
You can learn about the sequence here:
https://en.wikipedia.org/wiki/Hofstadter_sequence#Hofstadter_Female_and_Male_sequences
The error that I am getting is:
[opening sequence.sml]
sequence.sml:1.49 Error: unbound variable or constructor: f
sequence.sml:1.47-1.58 Error: operator is not a function [tycon mismatch]
operator: int list
in expression:
(m <errorvar>) (n - 1)
val it = () : unit
How can I correct this?
I ended up taking this approach:
fun
m (n) = if n = 0 then 0 else n - (f (m (n - 1)))
and
f (n) = if n = 0 then 1 else n - (m (f (n - 1)));
val seq = fn n => List.tabulate((n), f);
It is quite slow. If anybody has a faster version, then I'd love to see it.
Although you have already fixed them, there were two problems with your original approach:
Function application is left-associative in SML so m f (n - 1) was being interpreted as (m f) (n - 1), not the desired m (f (n - 1)). You can fix this by explicitly specifying the bracketing m (f (n - 1)).
To be able to call f from m and m from f, you need to use the keyword fun instead of val on the first declaration (to make the function recursive), and the keyword and instead of fun or val on the second declaration (to make the function mutually recursive with the first function). This would look like
fun f n = ... (* I can call f or m from here! *)
and m n = ... (* I can call f or m from here! *)
To make it faster, you can memoize! The trick is to make f and m take as arguments memoized versions of themselves.
(* Convenience function: Update arr[i] to x, and return x. *)
fun updateAndReturn arr i x = (Array.update (arr, i, SOME x); x)
(*
* Look up result of f i in table; if it's not found, calculate f i and
* store in the table. The token is used so that deeper recursive calls
* to f can also try to store in the table.
*)
fun memo table f token i =
case Array.sub (table, i)
of NONE => updateAndReturn table i (f token i)
| SOME x => x
(*
* Given f, g, and n : int, returns a tuple (f', g') where f' and g' are memoized
* versions of f and g, respectively. f' and g' are defined only on the domain
* [0, n).
*)
fun memoizeMutual (f, g) n =
let
val fTable = Array.array (n, NONE)
val gTable = Array.array (n, NONE)
fun fMemo i = memo fTable f (fMemo, gMemo) i
and gMemo i = memo gTable g (gMemo, fMemo) i
in
(fMemo, gMemo)
end
fun female _ 0 = 1
| female (f, m) n = n - m (f (n - 1))
fun male _ 0 = 0
| male (m, f) n = n - f (m (n - 1))
fun hofstadter upTo =
let
val (male', female') = memoizeMutual (male, female) upTo
in
(List.tabulate (upTo, male'), List.tabulate (upTo, female'))
end
I renamed f and m to female and male. The memoized fMemo and gMemo are threaded through female and male by memoizeMutual. Interestingly, if we call male', then results for both male' and female' are memoized.
To confirm it's indeed faster, try evaluating hofstadter 10000. It's much faster than the forever that your version would take.
As a final note, the only recursive functions are fMemo and gMemo. Every other function I wrote could be written as an anonymous function (val memoizeMutual = fn ..., val female = fn ..., etc.), but I chose not to do so because the syntax for writing recursive functions is much more compact in SML.
To generalize this, you could replace the array version of memoizing with something like a hash table. Then we wouldn't have to specify the size of the memoization up front.

What would be the Growth Rate of the following function

What would be the growth rate of the following function in terms of Big O notation??
f (n) = Comb(1000,n) for n = 0,1,2,…
int Comb(int m, int n)
{
int pracResult = 1;
int i;
if (m > n/2) m = n-m;
for (i=1; i<= m; i++)
{
pracResult *= n-m+i;
pracResult /= i;
practicalCounter++;
}
return pracResult;
}
Recursive:
int combRecursive (int m, int n)
{
recursiveCounter++;
if (n == m) return 1;
if (m == 1) return n;
return combRecursive(n-1, m) + combRecursive(n-1, m-1);
}
I would guess n^2??? I am probably wrong though... I have always struggled to figure out how efficient things are...
Thank you in advanced.
It's O(1).
By definition, f(n) = O(g(n)) if there exists a c such that for all n, f(n) <= c*g(n)
Let c = Comb(1000,500)
For all n, Comb(1000, n) < c * 1. Hence Comb(1000, n) = O(1)
For n = 1 to 2000 there will operations proportional to n
For all n > 2000, total operations are constant.
Hence function complexity is O (1)
And I have to tell you that you gotta read some books. :)
Data-structure and algorithm by Sahni is very light read.
Algorithms by Knuth is very heavy, but amongst best.

Modules, Mathematica

I have the following problem:
I want to sum a smaller matrix M to a bigger one , N, starting from i,j in N.
Here is the code:
PutMintoN[M_, Q_, i_, j_] := Module[{Mrow, Mcol},
{Mrow, Mcol} = Dimensions[M];
For[k = 1, k <= Mrow, k++,
For[q = 1, q <= Mcol, q++,
Q[[i + k - 1, j + q - 1]] =
Q[[i + k - 1, j + q - 1]] + M[[k, q]]]];
Q
];
The problem seems not to be in the algorithm, but in the module because if i copy the inner code outside , it works.
Thanks in advance.
Great, that you found your error on your own.
I produced a more elegant and robust Module for the same purpose, by the use of ArrayPad, to bring M to the same Dimension as N and than just Add M to N. It even works, if i or j runns out of the dimensions of N, wich is a problem for your original module.
putMintoN[M_, N_, i_, j_] := Module[{Mrow, Mcol, Nrow, Ncol, mn},
{Mrow, Mcol} = Dimensions[M]; {Nrow, Ncol} = Dimensions[N];
mn = {{Min[i - 1, Nrow], Min[(Nrow - Mrow) - i + 1, Nrow]},
{Min[j - 1, Ncol], Min[(Ncol - Mcol) - j + 1, Ncol]}};
ArrayPad[M, mn] + N]
test:
IN: putMintoN[{{x, y, p}, {z, w, q}}, {{a, b, c}, {d, e, f}, {g, h, i}, {j, k, l}}, 2, 1]
OUT: {{a, b, c}, {d + x, e + y, f + p}, {g + z, h + w, i + q}, {j, k, l}}
In Mathematica it is often possible to avoid the use of for-lopes, with Listable functions, map, apply, and so on.
Hope this inspires you.
Best regards.