I would like to be able to generate random numbers that all meet a given predicate, for example only generate random numbers that are even or prime. Is there an algorithm to do this in a relatively efficient way? The way I have found to do this is to go brute-force:
let randIntSatisfy (randGenerator: System.Random) (satisfy: int -> bool) =
// The maximum number of tries before returning `None`
let maxTry = 100
let rec inner i =
function
| num when satisfy num -> Some num
| num when not (satisfy num) && (i < maxTry) -> inner (i + 1) (randGenerator.Next())
| _ -> None
inner 0 (randGenerator.Next())
let example =
let randGen = new System.Random()
seq { for _ = 0 to 10 do
yield randIntSatisfy randGen (fun x -> x % 2 = 0) }
This code will not loop forever but will not guarantee to find a number that satisfies the given predicate (assuming such a number exists of course, if I ask for a negative number, then the function will return None all the time for example). Is there a way to do a little better than that?
PS: I've used F# here, but I'm not specifically asking for a language-specific answer.
Related
i have gotten an assignment requesting the following:
Write a function
sum : n:int -> int
which uses the counter value, a local mutable value s, and a while-loop to compute the
sum 1+2+ยทยทยท+n as (2). If the function is called with any value smaller than 1, then it is
to return the value 0.
Now i know that you can make a recursive factorial script using match, but i can't quite put my finger as to how you can do the same using a while loop.
Any help is appreciated .
As this is an assignment question, I'm not going to answer by just giving the solution, but I think it will help you to see a brief snippet that shows all the constructs that you need to combine:
let imperativeDemo y = // Define a function taking 'y' as an argument
let mutable x = y // Create a mutable variable 'x' initialized to 'y'
while x < 20 do // Loop while 'x' is less than 20
x <- x + 1 // Mutate 'x' - increment it by one
x // Return the final value of 'x'
This function does not do anything useful, but it should be easy to adapt to implement the logic necessary for a factorial function.
This sums up the first n integers (that's not a factorial function!):
let sum n =
let mutable s = 0
let mutable counter = n
while counter > 0 do
s <- s + counter
counter <- counter - 1
s
For comparison, the tail-recursive version:
let sumRec n =
let rec sumRecInner n accu =
if (n <= 0) then accu else
sumRecInner (n - 1) (n + accu)
sumRecInner n 0
In F# im trying to remove an occurence in the set if a condition is met, however it's not really working they way i'd like it to.
The trick to removing elements from a set is the function Set.filter, which takes a function as an argument - filter will feed in every value of the set to your function, and add it to a new set if the function returns true. An example implementation might be:
let filter f (original : Set<'T>) =
set [ for value in original do if f value then yield value ]
which has type filter : ('T -> bool) -> Set<'T> -> Set<'T>. An example of using it would be
filter (fun x -> x % 2 = 0) (set [ 1; 2; 3; 4; 5 ])
This filters the set for even numbers, so the return value would be set [ 2; 4 ].
I'm not entirely sure what problem you're having exactly, but here is a solution to the game Mastermind using Knuth's algorithm, albeit with a random starting guess, rather than his choice of "1122".
I thought it was quite a nice exercise, though writing the checkGuess function was the hardest part of it for me!
You can run a test by opening this in F# interactive by running the function playMastermind (), which will show you its guesses.
/// The colours that pegs are allowed to be.
type Peg = Blue | Red | Green | Yellow | Purple | Brown
/// A shared instance of the System.Random () class for all the random number
/// generators.
let private rnd = new System.Random ()
/// Make a random set of four peg colours.
let randomGuess () =
let randomPeg () =
match rnd.Next(1, 6) with
| 1 -> Blue
| 2 -> Red
| 3 -> Green
| 4 -> Yellow
| 5 -> Purple
| 6 -> Brown
| _ -> failwith "Random number generation failed."
[ randomPeg (); randomPeg (); randomPeg (); randomPeg () ]
/// Iterate over the colours to make all of the possible combinations.
let allPossibles =
let colours = [ Blue; Red; Green; Yellow; Purple; Brown]
set [ for a in colours do for b in colours do for c in colours do for d in colours -> [ a; b; c; d ] ]
/// Get the number of white and black pegs when comparing solution to guess.
let checkGuess solution guess =
/// Create a map of (colour -> count).
let toMap = List.countBy id >> Map.ofList
/// Compute how many pegs' colours are shared in the guesses.
let mapIntersect map1 map2 =
let overlap peg count =
match Map.tryFind peg map2 with
| None -> 0
| Some num -> min num count
Map.fold (fun acc peg count -> acc + overlap peg count) 0 map1
/// Simply compare to see if each peg is in the correct place.
let blacks = List.map2 (fun x y -> if x = y then 1 else 0) solution guess |> List.sum
// The number of pegs of the right colour but the wrong location is the
// same as the total number of pegs of the right colour subtract the ones
// that are also in the right place.
let whites = mapIntersect (toMap solution) (toMap guess) - blacks
whites, blacks
/// Get a random element of a set.
let randomSetElement set =
let arr = Set.toArray set
arr.[rnd.Next (Array.length arr)]
let playMastermind () =
// This creates a closure so we can check our guess against the solution,
// without storing the actual value of the solution.
let checkAnswer = checkGuess (randomGuess ())
let rec loop turnCount remaining =
if Set.count remaining = 1 then
let answer = Set.maxElement remaining
printfn "The answer is %A, which I calculated in %d turns." answer (turnCount - 1)
else
let guess = randomSetElement remaining
let (whites, blacks) = checkAnswer guess
printfn "On turn %d I guessed %A, which gave %d white pins and %d black pins." turnCount guess whites blacks
/// Remove all possibilities from the solution that wouldn't give the
/// same numbers of white and black pins and continue.
loop (turnCount + 1) (Set.filter (fun possible -> (whites, blacks) = checkGuess possible guess) remaining)
// Play the game!
loop 1 allPossibles
I'd make this a comment, but it's too long, so it needs to be an answer instead, even though it's not a complete answer to your problem.
One problem with your code, as it is now, is this section:
for candidate in candidateSet do
let scString = candidate.ToString()
let mutable secretList = []
for i = 0 to 3 do
let digit = (int scString.[i])-(int '0')
secretList <- secretList # [digit]
let tempCode = List.map (fun x -> numberToCodeColorPlus (x)) secretList
//Validate works and returns a peg set (b,w)..e.g. (0,0)
let secretCodePegs = validate guess tempCode
if secretCodePegs <> guessPegs then
candidateSet <- Set.remove candidate candidateSet
F#, like Python, uses indentation to denote blocks. So that let secretCodePegs = validate guess tempCode line is outside the for loop, not inside the for loop the way you clearly intended it to be. And the if secretCodePegs <> guessPegs then line that follows it, as far as F# is concerned, is part of a new block, and not part of the for loop any longer (because the let secretCodePegs = ... line ended the for loop). All you need to do is indent the let secretCodePegs = ... line by one level, and your code will work. In other words, that section should have looked like this:
for candidate in candidateSet do
let scString = candidate.ToString()
let mutable secretList = []
for i = 0 to 3 do
let digit = (int scString.[i])-(int '0')
secretList <- secretList # [digit]
let tempCode = List.map (fun x -> numberToCodeColorPlus (x)) secretList
//Validate works and returns a peg set (b,w)..e.g. (0,0)
let secretCodePegs = validate guess tempCode
if secretCodePegs <> guessPegs then
candidateSet <- Set.remove candidate candidateSet
Basically, I would like help designing an algorithm that takes a given number, and returns a random number that is unrelated to the first number. The stipulations being that a) the given output number will always be the same for a similar input number, and b) within a certain range (ex. 1-100), all output numbers are distinct. ie., no two different input numbers under 100 will give the same output number.
I know it's easy to do by creating an ordered list of numbers, shuffling them randomly, and then returning the input's index. But I want to know if it can be done without any caching at all. Perhaps with some kind of hashing algorithm? Mostly the reason for this is that if the range of possible outputs were much larger, say 10000000000, then it would be ludicrous to generate an entire range of numbers and then shuffle them randomly, if you were only going to get a few results out of it.
Doesn't matter what language it's done in, I just want to know if it's possible. I've been thinking about this problem for a long time and I can't think of a solution besides the one I've already come up with.
Edit: I just had another idea; it would be interesting to have another algorithm that returned the reverse of the first one. Whether or not that's possible would be an interesting challenge to explore.
This sounds like a non-repeating random number generator. There are several possible approaches to this.
As described in this article, we can generate them by selecting a prime number p and satisfies p % 4 = 3 that is large enough (greater than the maximum value in the output range) and generate them this way:
int randomNumberUnique(int range_len , int p , int x)
if(x * 2 < p)
return (x * x) % p
else
return p - (x * x) % p
This algorithm will cover all values in [0 , p) for an input in range [0 , p).
Here's an example in C#:
private void DoIt()
{
const long m = 101;
const long x = 387420489; // must be coprime to m
var multInv = MultiplicativeInverse(x, m);
var nums = new HashSet<long>();
for (long i = 0; i < 100; ++i)
{
var encoded = i*x%m;
var decoded = encoded*multInv%m;
Console.WriteLine("{0} => {1} => {2}", i, encoded, decoded);
if (!nums.Add(encoded))
{
Console.WriteLine("Duplicate");
}
}
}
private long MultiplicativeInverse(long x, long modulus)
{
return ExtendedEuclideanDivision(x, modulus).Item1%modulus;
}
private static Tuple<long, long> ExtendedEuclideanDivision(long a, long b)
{
if (a < 0)
{
var result = ExtendedEuclideanDivision(-a, b);
return Tuple.Create(-result.Item1, result.Item2);
}
if (b < 0)
{
var result = ExtendedEuclideanDivision(a, -b);
return Tuple.Create(result.Item1, -result.Item2);
}
if (b == 0)
{
return Tuple.Create(1L, 0L);
}
var q = a/b;
var r = a%b;
var rslt = ExtendedEuclideanDivision(b, r);
var s = rslt.Item1;
var t = rslt.Item2;
return Tuple.Create(t, s - q*t);
}
That generates numbers in the range 0-100, from input in the range 0-100. Each input results in a unique output.
It also shows how to reverse the process, using the multiplicative inverse.
You can extend the range by increasing the value of m. x must be coprime with m.
Code cribbed from Eric Lippert's article, A practical use of multiplicative inverses, and a few of the previous articles in that series.
You can not have completely unrelated (particularly if you want the reverse as well).
There is a concept of modulo inverse of a number, but this would work only if the range number is a prime, eg. 100 will not work, you would need 101 (a prime). This can provide you a pseudo random number if you want.
Here is the concept of modulo inverse:
If there are two numbers a and b, such that
(a * b) % p = 1
where p is any number, then
a and b are modular inverses of each other.
For this to be true, if we have to find the modular inverse of a wrt a number p, then a and p must be co-prime, ie. gcd(a,p) = 1
So, for all numbers in a range to have modular inverses, the range bound must be a prime number.
A few outputs for range bound 101 will be:
1 == 1
2 == 51
3 == 34
4 == 76
etc.
EDIT:
Hey...actually you know, you can use the combined approach of modulo inverse and the method as defined by #Paul. Since every pair will be unique and all numbers will be covered, your random number can be:
random(k) = randomUniqueNumber(ModuloInverse(k), p) //this is Paul's function
I have answered Project Euler Question 7 very easily using Sieve of Eratosthenes in C and I had no problem with it.
I am still quite new to F# so I tried implementing the same technique
let prime_at pos =
let rec loop f l =
match f with
| x::xs -> loop xs (l |> List.filter(fun i -> i % x <> 0 || i = x))
| _ -> l
List.nth (loop [2..pos] [2..pos*pos]) (pos-1)
which works well when pos < 1000, but will crash at 10000 with out of memory exception
I then tried changing the algorithm to
let isPrime n = n > 1 && seq { for f in [2..n/2] do yield f } |> Seq.forall(fun i -> n % i <> 0)
seq {for i in 2..(10000 * 10000) do if isPrime i then yield i} |> Seq.nth 10000 |> Dump
which runs successfully but still takes a few minutes.
If I understand correctly the first algorithm is tail optimized so why does it crash? And how can I write an algorithm that runs under 1 minute (I have a fast computer)?
Looking at your first attempt
let prime_at pos =
let rec loop f l =
match f with
| x::xs -> loop xs (l |> List.filter(fun i -> i % x <> 0 || i = x))
| _ -> l
List.nth (loop [2..pos] [2..pos*pos]) (pos-1)
At each loop iteration, you are iterating over and creating a new list. This is very slow as list creation is very slow and you don't see any benefits from the cache. Several obvious optimisations such as the factor list skipping the even numbers, are skipped. When pos=10 000 you are trying to create a list which will occupy 10 000 * 10 000 * 4 = 400MB of just integers and a further 800MB of pointers (F# lists are linked lists). Futhermore, as each list element takes up a very small amount of memory there will probably be significant overhead for things like GC overhead. In the function you then create a new list of smiliar size. As a result, I am not surprised that this causes OutOfMemoryException.
Looking at the second example,
let isPrime n =
n > 1 &&
seq { for f in [2..n/2] do yield f }
|> Seq.forall(fun i -> n % i <> 0)
Here, the problem is pretty similar as you are generating giant lists for each element you are testing.
I have written a quite fast F# sieve here https://stackoverflow.com/a/12014908/124259 which shows how to do this faster.
As already mentioned by John, your implementation is slow because it generates some temporary data structures.
In the first case, you are building a list, which needs to be fully created in memory and that introduces significant overhead.
In the second case, you are building a lazy sequence, which does not consume memory (because it is build while it is being iterated), but it still introduces indirection that slows the algorithm down.
In most cases in F#, people tend to prefer readability and so using sequences is a nice way to write the code, but here you probably care more about performance, so I'd avoid sequences. If you want to keep the same structure of your code, you can rewrite isPrime like this:
let isPrime n =
let rec nonDivisible by =
if by = 1 then true // Return 'true' if we reached the end
elif n%by = 0 then false // Return 'false' if there is a divisor
else nonDivisible (by - 1) // Otherwise continue looping
n > 1 && nonDivisible (n/2)
This just replaces the sequence and forall with a recursive function nonDivisible that returns true when the number n is not divisible by any number between 2 and n/2. The function first checks the two termination cases and otherwise performs a recursive call..
With the original implementation, I'm able to find 1000th prime in 1.5sec and with the new one, it takes 22ms. Finding 10000th prime with the new implementation takes 3.2sec on my machine.
I have the following list:
["A";"AA";"ABC";"BCD";"B";"C"]
I am randomly extracting an element from the list. But the element I extract should be of size 3 only not lesser than 3.
I am trying to do this as follows:
let randomnum = (Random.int(List.length (list)));;
let rec code c =
if (String.length c) = 3 then c
else (code ((List.nth (list) (randomnum)))) ;;
print_string (code ( (List.nth (list) (randomnum)))) ;;
This works fine if randomly a string of length 3 is picked out from the list.
But the program does not terminate if a string of length < 3 is picked up.
I am trying to do a recursive call so that new code keeps getting picked up till we get one of length = 3.
I am unable to figure out why this is does not terminate. Nothing gets output by the print statement.
What you probably want to write is
let rec code list =
let n = Random.int (List.length list) in
let s = List.nth list in
if String.length s < 3 then code list else s
Note that, depending on the size of the list and the number of strings of size greater than 3, you might want to work directly on a list with only strings greater than 3:
let code list =
let list = List.filter (fun s -> String.length s >= 3) list in
match list with
| [] -> raise Not_found
| _ -> List.nth list (Random.int (List.length list))
This second function is better, as it always terminate, especially when there are no strings greater than 3.
You only pick a random number once. Say you pick 5. You just keep recursing with 5 over and over and over. You need to get a new random number.
For your code to terminate, it would be better to first filter the list for suitable elements, then take your random number:
let code list =
let suitables = List.filter (fun x -> String.length x = 3) list in
match List.length suitables with
| 0 -> raise Not_found (* no suitable elements at all! *)
| len -> List.nth suitables (Random.int len)
Otherwise your code would take very long to terminate on a large list of elements with size <> 3; or worse on a list with no element of size 3, it would not terminate at all!