White-box and Black-box testing of recursive functions - recursion

I learned white-box and black-box testing in terms of iterative functions. Now i need to do white-box and black-box testing of several recursive functions (in F#). take the following recursive algorithm for gcd:
gcd (m, n)
if (m % n) = 0 then
n
else
gcd n ( m % n)
For the white-box test: how exactly do i go about covering the different branches of the algorithm? Naively one could say there are two branches but when the function is called more than once the possible branches will obviously increase. Should i do testing with arguments which results in different amounts of recursive calls or how exactly do i determine which values to test with?
black-box: i get the general idea of black box testing. we should look at possible values we might want to call the function with without having knowledge of its inner workings. In this case i am just not sure which are values we might want to call it with. one way could be just to start with two values m and n for which gcd = 1 and then do the same for values m and for which gcd = 2 up to some gcd= n for some arbitrary number n. Is this how one is supposed to go about this?

First of all, I don't think there is one single established definition of how to do white-box and black-box testing of recursive functions, but here is how I interpret it.
White-box testing. We want to test the function based on its inner working. In case of recursive functions, I think this means that we want to test that the recursive calls it makes are the ones we would expect. One way to do this is to log all recursive calls. A simple implementation of gcd that does this adds a parameter to keep a log and returns it with the result:
let rec gcd log m n =
let log = (m, n)::log
if (m % n) = 0 then List.rev log, n
else gcd log n (m % n)
Now, for some two parameters, say 54 and 22, you can do the calculation by hand, decide what the parameters of the recursive calls should be and write a test for that:
let log, res = gcd [] 54 22
log |> shouldEqual [ (54, 22); (22, 10); (10, 2) ]
Black-box testing. Here, we assume we do not know how exactly the function works, so we cannot test its internals. All we can do is to test it using a number of inputs. It is probably a good idea to think of corner-case or tricky inputs because those are the ones that could cause problems. Given a simple implementation:
let rec gcd m n =
if (m % n) = 0 then n
else gcd n (m % n)
I would probably write tests for the following:
// A random case where one of the numbers is the result
gcd 100 50 |> shouldEqual 50
gcd 50 100 |> shouldEqual 50
// A random case where the only divisor is 1
gcd 13 123 |> shouldEqual 1
gcd 123 13 |> shouldEqual 1
// The following are problematic and I'm not sure what the right behaviour is
gcd 0 0 // This probably should not be allowed
gcd 10 -5 // This returns -5, but I'm not sure that's what we want
Random testing.
You could also use random testing (which is a form of black box testing) to generate multiple test cases automatically. There are at least two random tests I can think of:
Generate two random numbers, a and b and check that gcd a b = gcd b a. This is testing only a very basic property, but it can cover quite a lot of cases.
Pick a random number a and a couple of primes p1, p2, .... Then split the primes into two groups and produce a*p1*p3*p5 and a*p2*p4*p6. Write a test that checks that the GCD of the two numbers is a.

Related

Schroders Big number sequence

I am implementing a recursive program to calculate the certain values in the Schroder sequence, and I'm having two problems:
I need to calculate the number of calls in the program;
Past a certain number, the program will generate incorrect values (I think it's because the number is too big);
Here is the code:
let rec schroder n =
if n <= 0 then 1
else if n = 1 then 2
else 3 * schroder (n-1) + sum n 1
and sum n k =
if (k > n-2) then 0
else schroder k * schroder (n-k-1) + sum n (k+1)
When I try to return tuples (1.), the function sum stops working because it's trying to return int when it has type int * int;
Regarding 2., when I do schroder 15 it returns:
-357364258
when it should be returning
3937603038.
EDIT:
firstly thanks for the tips, secondly after some hours of deep struggle, i manage to create the function, now my problem is that i'm struggling to install zarith. I think I got it installed, but ..
in terminal when i do ocamlc -I +zarith test.ml i get an error saying Required module 'Z' is unavailable.
in utop after doing #load "zarith.cma";; and #install_printer Z.pp_print;; i can compile, run the function and it works. However i'm trying to implement a Scanf.scanf so that i can print different values of the sequence. With this being said whenever i try to run the scanf, i dont get a chance to write any number as i get a message saying that '\\n' is not a decimal digit.
With this being said i will most probably also have problems with printing the value, because i dont think that i'm going to be able to print such a big number with a %d. The let r1,c1 = in the following code, is a example of what i'm talking about.
Here's what i'm using :
(function)
..
let v1, v2 = Scanf.scanf "%d %d" (fun v1 v2-> v1,v2);;
let r1,c1 = schroder_a (Big_int_Z.of_int v1) in
Printf.printf "%d %d\n" (Big_int_Z.int_of_big_int r1) (Big_int_Z.int_of_big_int c1);
let r2,c2 = schroder_a v2 in
Printf.printf "%d %d\n" r2 c2;
P.S. 'r1' & 'r2' stands for result, and 'c1' and 'c2' stands for the number of calls of schroder's recursive function.
P.S.S. the prints are written differently because i was just testing, but i cant even pass through the scanf so..
This is the third time I've seen this problem here on StackOverflow, so I assume it's some kind of school assignment. As such, I'm just going to make some comments.
OCaml doesn't have a function named sum built in. If it's a function you've written yourself, the obvious suggestion would be to rewrite it so that it knows how to add up the tuples that you want to return. That would be one approach, at any rate.
It's true, ints in OCaml are subject to overflow. If you want to calculate larger values you need to use a "big number" package. The one to use with a modern OCaml is Zarith (I have linked to the description on ocaml.org).
However, none of the other people solving this assignment have mentioned overflow as a problem. It could be that you're OK if you just solve for representable OCaml int values.
3937603038 is larger than what a 32-bit int can hold, and will therefore overflow. You can fix this by using int64 instead (until you overflow that too). You'll have to use int64 literals, using the L suffix, and operations from the Int64 module. Here's your code converted to compute the value as an int64:
let rec schroder n =
if n <= 0 then 1L
else if n = 1 then 2L
else Int64.add (Int64.mul 3L (schroder (n-1))) (sum n 1)
and sum n k =
if (k > n-2) then 0L
else Int64.add (Int64.mul (schroder k) (schroder (n-k-1))) (sum n (k+1))
I need to calculate the number of calls in the program;
...
the function 'sum' stops working because it's trying to return 'int' when it has type 'int * int'
Make sure that you have updated all the recursive calls to shroder. Remember it is now returning a pair not a number, so you can't, for example, just to add it and you need to unpack the pair first. E.g.,
...
else
let r,i = schroder (n-1) (i+1) in
3 * r + sum n 1 and ...
and so on.
Past a certain number, the program will generate incorrect values (I think it's because the number is too big);
You need to use an arbitrary-precision numbers, e.g., zarith

How to find n as sum of dustinct prime numbers (when n is even number)

This problem gives you a positive integer number which is less than or equal to 100000 (10^5). You have to find out the following things for the number:
i. Is the number prime number? If it is a prime number, then print YES.
ii. If the number is not a prime number, then can we express the number as summation of unique prime numbers? If it is possible, then print YES. Here unique means, you can use any prime number only for one time.
If above two conditions fail for any integer number, then print NO. For more clarification please see the input, output section and their explanations.
Input
At first you are given an integer T (T<=100), which is the number of test cases. For each case you will be given a positive integer X which is less than or equal 100000.
Output
For every test case, print only YES or NO.
Sample
Input Output
3
7
6
10 YES
NO
YES
Case – 1 Explanation: 7 is a prime number.
Case – 2 Explanation: 6 is not a prime number. 6 can be expressed as 6 = 3 + 3 or 6 = 2 + 2 + 2. But you can’t use any prime number more than 1 time. Also there is no way to express 6 as two or three unique prime numbers summation.
Case – 3 Explanation: 10 is not prime number but 10 can be expressed as 10 = 3 + 7 or 10 = 2 + 3 + 5. In this two expressions, every prime number is used only for one time.
Without employing any mathematical tricks (not sure if any exist...you'd think as a mathematician I'd have more insight here), you will have to iterate over every possible summation. Hence, you'll definitely need to iterate over every possible prime, so I'd recommend the first step being to find all the primes at most 10^5. A basic (Sieve of Eratosthenes)[https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes] will probably be good enough, though faster sieves exist nowadays. I know your question is language agnostic, but you could consider the following as vectorized pseudocode for such a sieve.
import numpy as np
def sieve(n):
index = np.ones(n+1, dtype=bool)
index[:2] = False
for i in range(2, int(np.sqrt(n))):
if index[i]:
index[i**2::i] = False
return np.where(index)[0]
There are some other easy optimizations, but for simplicity this assumes that we have an array index where the indices correspond exactly to whether the number is prime or not. We start with every number being prime, mark 0 and 1 as not prime, and then for every prime we find we mark every multiple of it as not prime. The np.where() at the end just returns the indices where our index corresponds to True.
From there, we can consider a recursive algorithm for actually solving your problem. Note that you might feasibly have a huge number of distinct primes necessary. The number 26 is the sum of 4 distinct primes. It is also the sum of 3 and 23. Since the checks are more expensive for 4 primes than for 2, I think it's reasonable to start by checking the smallest number possible.
In this case, the way we're going to do that is to define an auxiliary function to find whether a number is the sum of precisely k primes and then sequentially test that auxiliary function for k from 1 to whatever the maximum possible number of addends is.
primes = sieve(10**5)
def sum_of_k_primes(x, k, excludes=()):
if k == 1:
if x not in excludes and x in primes:
return (x,)+excludes
else:
return ()
for p in (p for p in primes if p not in excludes):
if x-p < 2:
break
temp = sum_of_k_primes(x-p, k-1, (p,)+excludes)
if temp:
return temp
return ()
Running through this, first we check the case where k is 1 (this being the base case for our recursion). That's the same as asking if x is prime and isn't in one of the primes we've already found (the tuple excludes, since you need uniqueness). If k is at least 2, the rest of the code executes instead. We check all the primes we might care about, stopping early if we'd get an impossible result (no primes in our list are less than 2). We recursively call the same function for smaller k, and if we succeed we propagate that result up the call stack.
Note that we're actually returning the smallest possible tuple of unique prime addends. This is empty if you want your answer to be "NO" as specified, but otherwise it allows you to easily come up with an explanation for why you answered "YES".
partial = np.cumsum(primes)
def max_primes(x):
return np.argmax(partial > x)
def sum_of_primes(x):
for k in range(1, max_primes(x)+1):
temp = sum_of_k_primes(x, k)
if temp:
return temp
return ()
For the rest of the code, we store the partial sums of all the primes up to a given point (e.g. with primes 2, 3, 5 the partial sums would be 2, 5, 10). This gives us an easy way to check what the maximum possible number of addends is. The function just sequentially checks if x is prime, if it is a sum of 2 primes, 3 primes, etc....
As some example output, we have
>>> sum_of_primes(1001)
(991, 7, 3)
>>> sum_of_primes(26)
(23, 3)
>>> sum_of_primes(27)
(19, 5, 3)
>>> sum_of_primes(6)
()
At a first glance, I thought caching some intermediate values might help, but I'm not convinced that the auxiliary function would ever be called with the same arguments twice. There might be a way to use dynamic programming to do roughly the same thing but in a table with a minimum number of computations to prevent any duplicated efforts with the recursion. I'd have to think more about it.
As far as the exact output your teacher is expecting and the language this needs to be coded in, that'll be up to you. Hopefully this helps on the algorithmic side of things a little.

Time complexity of this recursive block

int recursiveFunc(int n) {
if (n == 1) return 0;
for (int i = 2; i < n; i++)
if (n % i == 0) return i + recursiveFunc(n / i);
return n;
}
I know Complexity = length of tree from root node to leaf node * number of leaf nodes, but having hard time to come to an equation.
This one is tricky, because the runtime is highly dependent on what number you provide in as input in a way that most recursive functions are not.
For starters, notice that the way that this recursion works, it takes in a number and then either
returns without making any further calls if the number is prime, or
recursively calls itself on number divided by that proper factor.
This means that in one case, the function, called on a number n, will do Θ(n) work and make no calls (which happens if the number is prime), and in the other case will do Θ(d) work and then make a recursive call on the number n / d, which happens if n is composite and is the largest divisor of n.
One useful fact we'll use to analyze this function is that given a composite number n, the smallest factor d of n is never any greater than √n. If it were, then we would have that n = df for some other factor f, and since d is the smallest proper divisor, we'd have that f ≥ d, so df > √n √ n = n, which would be impossible.
With that in mind, we can argue that the worst-case runtime of this function is O(n), and in fact that happens when n is prime. Here's how to see this. Imagine the worst-case amount of time this function can take if it ends up making a recursive call. In that case, the function will do at most Θ(√n) work (let's assume our smallest divisor is as large as possible), then recursively makes a call on a number whose size is at most n / 2 (which is the absolute largest number we could get as part of the recursive call. In that case, we'd get this recurrence relation under the pessimistic assumption that we do the maximum work possible
T(n) = T(n / 2) + √n
This solves, by the Master Theorem, to Θ(√n), which is less work than what we'd do if we had a prime number as an input.
But what happens if, instead, we do the maximum amount of work possible for some number of iterations, and then end up with a prime number and stop? In that case, using the iteration method, we'd see that the work done would be
n1/2 + n1/4 + ... + n / 2k,
which would happen if we stopped after k iterations. In this case, notice that this expression is maximized when we pick k to be as small as possible - which would correspond to stopping as soon as possible, which happens if we pick a prime number for n.
So in this sense, the worst-case runtime of this function is Θ(n), which happens for n being a prime number, with composite numbers terminating much faster than this.
So how fast can this function be? Well, imagine, for example, that we have a number of the form pk, where p is some prime number. In that case, this function will do Θ(p) work to discover p as a prime factor, then recursively call itself on the number pk-1. If you think about what this will look like, this function will end up doing Θ(p) work Θ(k) times for a total runtime of Θ(pk). And since n = pk, we'd have k = logp n, so the runtime would be Θ(p logp n). That's minimized at either p = 2 or p = 3, and in either case gives us a runtime of Θ(log n) in this case.
I strongly suspect that's the best case here, though I'm not entirely sure. But what this does mean is that
the worst-case runtime is definitely Θ(n), occurring at prime numbers, and
the best-case runtime is O(log n), which I'm fairly certain is a tight bound but I'm not 100% sure how to prove.

Recursive formula for recurrence that takes 2 arguments

I can create a recursive formula from recurrences where it only passes down one argument (something like $T(n/2)$). However, for a case like this where the value of $u$ and $v$ are different, how do I put them together? This is the problem:
The call to recursive function RecursiveFunction(n, n) for some n > 2
RecursiveFunction(a, b)
if a >= 2 and b >= 2
u=a/2
v=b-1
RecursiveFunction(u, v)
The end goal is to find the tight asymptotic bounds for the worst-case running time, but I just need a formula to start first.
There are in fact two different answers to this, depending on the relative sizes of a and b.
The function can be written as follows:
Where C is some constant work done per call (if statement, pushing u, v onto the call stack etc.). Since the two variables evolve independently, we can analyse their evolution separately.
a - consider the following function:
Expanding the iterative case by m times:
The stopping condition a < 2 is such that:
b - as before:
The complexity of T(a, b) thus depends on which variable reaches its stopping condition first, i.e. the smallest between m and n:

How to shuffle list in O(n) in OCaml?

It is not hard to shuffle an array in O(n), with in place swapping,
How to do it for list in OCaml, with O(n)?
Requirement:
No array or in place usage
Consider this as an interview question
Lists are immutable, and there's often a log n price to pay for working with immutable data. If you're willing to pay this cost, there's an obvious n log n approach: tag each list element with a random value, sort based on random value, remove random values. This is the way I shuffle lists in my production code.
Here is the shuffle code from the iOS apps that I sell:
let shuffle d =
let nd = List.map (fun c -> (Random.bits (), c)) d in
let sond = List.sort compare nd in
List.map snd sond
You could mimick the riffle shuffle for cards.
A riffle shuffle of a deck of cards means to:
cut the deck in two parts
interleave the two parts
It is actually easier to do the reverse permutation:
have two auxiliary lists A and B, iter through your original list L and push each element randomly (with probability 1/2) in front of A or B.
L := List.rev A # List.rev B (this can be tail recursive with a custom List.rev).
repeat k times.
According to "Mathematical developments from the analysis of riffle shuffling, by Persi Diaconis, 2002", choose k = 3/2 log_2(n) + c. Indeed, the total variation distance between uniformity and the result falls exponentially fast to 0: it is approximately halved each time you increment c. You could choose c=10.
Space O(1) (if you destroy L), time O(n log n). But there are O(n log n) calls to the random generator, while Jeffrey Scofield's solution only needs O(n) random bits, but Θ(n) space.

Resources