Select K random lines from a text file - c++

This is an extension of the original question of selecting a random line from a text of X lines where the probability of the text line selected is 1/X. The trick is to select the Jth line if you query a random variable Y with a range of [0,1) and it returns a value less than 1/J.
Now in this new version of the problem we have to select K random lines where K is less than X. I believe the probability for each line should be K/X.
I'm stuck on how to extend the original solution to K lines. Is it possible? any explanations would be great.

This can be solved using a generalization of the original algorithm. The intuition is as follows: maintain a list of k candidate lines from the file, which are initially seeded to the first k lines. Then, from that point forward, upon seeing the nth line of the file:
Choose a random value x between 1 and n, inclusive.
If x > k, ignore this element.
Otherwise, replace element x with the nth line of the file.
The proof that this correctly samples each element with probability k / n, where n is the total number of lines in the file, is as follows. Assume that n ≥ k. We prove by induction that each element has probability k / n of being picked by showing that after seeing z elements, each of those elements has probability k / z of being chosen. In particular, this means that after seeing n elements, each has probability k / n as required.
As our inductive basis, if we see exactly k elements, then each is picked. Thus the probability of being chosen is k / k, as required.
For the inductive step, assume that for some z ≥ k, each of the first z elements have been chosen with probability k / z and consider the (z + 1)st element. We choose a random natural number in the range [1, z + 1]. With probability k / (z + 1), we decide to choose this element, then evict some old element. This means that the new element is chosen with probability k / (z + 1). For each of the z original elements, the probability that it is chosen at this point is then the probability that we had chosen it after the first z elements were inspected (probability k / z, by our inductive hypothesis), and the probability that we retain it is z / (z + 1), since we replace it with probability 1 / (z + 1). Thus the new probability that it is chosen is (k / z) (z / (z + 1)) = k / (z + 1). Thus all of the first z + 1 elements are chosen with probability k / (z + 1), completing the induction.
Moreover, this algorithm runs in O(n) time and uses only O(k) space, meaning that the runtime is independent of the value of k. To see this, note that each iteration does O(1) work, and there are a total of O(n) interations.
If you're curious, I have an implementation of this algorithm as a C++ STL-style algorithm available here on my personal site.
Hope this helps!

First select the first element randomly out of the X lines using the first algorithm. Then select the second out of the remaining X-1 lines. Run this process K times.
The probability of any given set of K lines is (X choose K). I'll leave it up to you to verify that this algorithm gives the desired uniform distribution.

Related

How to plot lines according to some condition?

I was solving a coding problem and came across this one. It states :
We have an infinitely planar cartesian coordinate system on which N points are plotted. Cartesian coordinates of the point I am represented by (Xi, Yi).
Now we want to draw (N-1) line segments which may have arbitrary lengths and the points need not lie on the lines. The slope of each line must be 1 or -1.
Let's denote the minimum distance we have to walk from a point I to reach a line by Di and let's say a = max(D1, D2, D3,..., DN). We want this distance to be minimum as possible.
Thus we have to plot lines in such a way that it minimizes 'a' and compute a*sqrt(2)
Constraints :
1 <= T <= 100
2 <= N <= 10^4
|Xi|, |Yi| <= 10^9 for each valid i
Here T denotes number of test cases.
Sample input 1 :
N = 3
Points : (0,0) , (0,1) , (0,-1)
Sample output 1 :
0.5
Explanation: We should draw lines described by equations y−x+0.5=0 and y−x−0.5=0
Sample input 2 :
N = 3
Points : (0,1) , (1,0) , (-1,0)
Sample output 2 :
0
Explanation: We should draw lines described by equations y−x−1=0 and y+x−1=0
Output format :
For each test case, print a single line containing one real number — the minimum distance a multiplied by sqrt(2). Your answer will be considered correct if its absolute or relative error does not exceed 10^(-6).
Time limit: 1 sec
My understanding is as the slopes are 1 or -1 the equations of the lines would be y = x + c or y = -x + c and we just have to find the y-intercept c which minimizes the distance 'a' in the problem. Also, the minimum distance from a point to the line is the length of the perpendicular to the line.
So I am having difficulty to devise an algorithm which will check all possible values of 'c' and find the optimal one.
Let us denote M[i] the point (x[i], y[i])
The fist step is to compute the distance between a point M(x, y) and a line D, slope of which is equal to +/-1.
Let us denote D and D' the lines
D: y + x + c = 0
D': y - x + c = 0
Then, a few calculations allow to show that
the distance between M and D is equal to d(M, D) = abs(y + x + c)/sqrt(2)
the distance between M and D' is equal to d(M, D') = abs(y - x + c)/sqrt(2)
Let us now consider two different points, for example M[0] and M[1], and let us calculate the minimum distance between these two points and a line D of parameter c and slope +/-1.
Formally, we have two find the minimum, over c and slope, of
max(d(M[0], D), d(M[1], D))
If the slope is -1, i.e. if the equation is y+x+c=0, one can easily show the the optimum c parameter is equal to
c = -(x0 + y0 + x1 + y1)/2
The corresponding distance is equal to abs(x0+y0-x1-y1)/(2*sqrt(2))
If the slope is 1, i.e. if the equation is y-x+c=0, one can show the the optimum c parameter is equal to
c = (x0 - y0 + x1 - y1)/2
The corresponding distance is equal to abs(y0 - x0 - y1 + x1)/(2*sqrt(2))
Therefore, the minimum distance from these two points to an optimal line is the minimum of the previous two distances.
This leads to define the following quantities, for each points M[i]:
a|i] = y[i] - x[i]
b[i] = y[i] + x[i]
And then to define a distance between points M[i] and M[j] as :
d(M[i], M[j]) = min (abs(b[i]-b[j]), abs(a[i]-a[j]))
The proposed algorithm consists in finding the pair (M[i], M[j]) such that this distance is minimized.
Then the wanted result is equal to half this distance.
This corresponds to consider that a line will pass through the distant points (according to the defined distance), except the two closest ones, for which we will draw a line just in between.
(EDIT)
The complexity is not O(n^2) as previously stated.
The complexity to find the min of d(M[i], M[j]) is O(N logN).
This is obtained by sorting the a[i] and to get the min of the differences between adjacent values, i.e. min(a[i+1] - a[i]).
Then by doing the same for the b[i], and finally taking the minimum of the two obtained values.

Find the summation of forces between all possible pairs of points?

There are n points with each having two attributes:
1. Position (from axis)
2. Attraction value (integer)
Attraction force between two points A & B is given by:
Attraction_force(A, B) = (distance between them) * Max(Attraction_val_A, Attraction_val_B);
Find the summation of all the forces between all possible pairs of points?
I tried by calculating and adding forces between all the pairs
for(int i=0; i<n-1; i++) {
for(int j=i+1; j<n; j++) {
force += abs(P[i].pos - P[j].pos) * max(P[i].attraction_val, P[j].attraction_val);
}
}
Example:
Points P1 P2 P3
Points distance: 2 3 4
Attraction Val: 4 5 6
Force = abs(2 - 3) * max(4, 5) + abs(2 - 4) * max(4, 6) + abs(3 - 4) * max(5, 6) = 23
But this takes O(n^2) time, I can't think of a way to reduce it further!!
Scheme of a solution:
Sort all points by their attraction value and process them one-by-one, starting with the one with lowest attraction.
For each point you have to quickly calculate sum of distances to all previously added points. That can be done using any online Range Sum Query problem solution, like segment tree or BIT. Key idea is that all points to the left are really not different and sum of their coordinates is enough to calculate sum of distances to them.
For each newly added point you just multiply that sum of distances (obtained on step 2) by point's attraction value and add that to the answer.
Intuitive observations that I made in order to invent this solution:
We have two "bad" functions here (somewhat "discrete"): max and modulo (in distance).
We can get rid of max by sorting our points and processing them in a specific order.
We can get rid of modulo if we process points to the left and to the right separately.
After all these transformations, we have to calculate something which, after some simple algebraic transformations, converts to an online RSQ problem.
An algorithm of:
O(N2)
is optimal, because you need the actual distance between all possible pairs.

Basic color reduction algorithm in OpenCV

Here is the formula for basic color reduction in OpenCV that I read in a book.
//p is the value of the channel of a pixel
//n is the reduction factor
p = (p/n)*n + n/2; //integer division
I understand that the first expression (p/n)*n is the first multiple of n less than or equal to p. I think that just this is enough for color reduction by the factor of n. But I don't get what is the need to add n/2 to it.
And also, if p=255 and n=5, this formula will try to set p = 257, won't it overflow the range of p?
Please explain.
With n=255, (((p)/n)*n) would return 0 for p < 255, and 255 for p == 255.
To be balanced you would want to return 0 for p < 128 and 255 for p >= 128. This can be achieved with:
((p + n/2) / n) * n
This is a bit like ((p / n) + 0.5) * n, except that you obviously can't do that. The effect is to give rounding, instead of truncation on the the result of p/n. Actually this only works well for some values of n.
An easy way to get exactly what you want would be to use a lookup table.
I agree ((p)/n)*n + n/2 has problems, as pointed out by old-ufo
They say that n/2 is needed to have "central" position instead of minimum, but you are right it looks like not needed.
Lets assume I want to have 2 colors - black and white, so n=255. Without n/2 I would have 0 and 255 as a result. With n/2 - 127 and 382, which seems not correct.

Finding solution set of a Linear equation?

I need to find all possible solutions for this equation:
x+2y = N, x<100000 and y<100000.
given N=10, say.
I'm doing it like this in python:
for x in range(1,100000):
for y in range(1,100000):
if x + 2*y == 10:
print x, y
How should I optimize this for speed? What should I do?
Essentially this is a Language-Agnostic question. A C/C++ answer would also help.
if x+2y = N, then y = (N-x)/2 (supposing N-x is even). You don't need to iterate all over range(1,100000)
like this (for a given N)
if (N % 2): x0 = 1
else: x0 = 0
for x in range(x0, min(x,100000), 2):
print x, (N-x)/2
EDIT:
you have to take care that N-x does not turn negative. That's what min is supposed to do
The answer of Leftris is actually better than mine because these special cases are taken care of in an elegant way
we can iterate over the domain of y and calculate x. Also taking into account that x also has a limited range, we further limit the domain of y as [1, N/2] (as anything over N/2 for y will give negative value for x)
x=N;
for y in range(1,N/2-1):
x = x-2
print x, y
This just loops N/2 times (instead of 50000)
It doesn't even do those expensive multiplications and divisions
This runs in quadratic time. You can reduce it to linear time by rearranging your equation to the form y = .... This allows you to loop over x only, calculate y, and check whether it's an integer.
Lefteris E 's answer is the way to go,
but I do feel y should be in the range [1,N/2] instead of [1,2*N]
Explanation:
x+2*y = N
//replace x with N-2*y
N-2*(y) + 2*y = N
N-2*(N/2) + 2*y = N
2*y = N
//therefore, when x=0, y is maximum, and y = N/2
y = N/2
So now you can do:
for y in range(1,int(N/2)):
x = N - (y<<1)
print x, y
You may try to only examine even numbers for x given N =10;
the reason is that: 2y must be even, therefore, x must be even. This should reduce the total running time to half of examining all x.
If you also require that the answer is natural number, so negative numbers are ruled out. you can then only need to examine numbers that are even between [0,10] for x, since both x and 2y must be not larger than 10 alone.

Probability density function from a paper, implemented using C++, not working as intended

So i'm implementing a heuristic algorithm, and i've come across this function.
I have an array of 1 to n (0 to n-1 on C, w/e). I want to choose a number of elements i'll copy to another array. Given a parameter y, (0 < y <= 1), i want to have a distribution of numbers whose average is (y * n). That means that whenever i call this function, it gives me a number, between 0 and n, and the average of these numbers is y*n.
According to the author, "l" is a random number: 0 < l < n . On my test code its currently generating 0 <= l <= n. And i had the right code, but i'm messing with this for hours now, and i'm lazy to code it back.
So i coded the first part of the function, for y <= 0.5
I set y to 0.2, and n to 100. That means it had to return a number between 0 and 99, with average 20.
And the results aren't between 0 and n, but some floats. And the bigger n is, smaller this float is.
This is the C test code. "x" is the "l" parameter.
//hate how code tag works, it's not even working now
int n = 100;
float y = 0.2;
float n_copy;
for(int i = 0 ; i < 20 ; i++)
{
float x = (float) (rand()/(float)RAND_MAX); // 0 <= x <= 1
x = x * n; // 0 <= x <= n
float p1 = (1 - y) / (n*y);
float p2 = (1 - ( x / n ));
float exp = (1 - (2*y)) / y;
p2 = pow(p2, exp);
n_copy = p1 * p2;
printf("%.5f\n", n_copy);
}
And here are some results (5 decimals truncated):
0.03354
0.00484
0.00003
0.00029
0.00020
0.00028
0.00263
0.01619
0.00032
0.00000
0.03598
0.03975
0.00704
0.00176
0.00001
0.01333
0.03396
0.02795
0.00005
0.00860
The article is:
http://www.scribd.com/doc/3097936/cAS-The-Cunning-Ant-System
pages 6 and 7.
or search "cAS: cunning ant system" on google.
So what am i doing wrong? i don't believe the author is wrong, because there are more than 5 papers describing this same function.
all my internets to whoever helps me. This is important to my work.
Thanks :)
You may misunderstand what is expected of you.
Given a (properly normalized) PDF, and wanting to throw a random distribution consistent with it, you form the Cumulative Probability Distribution (CDF) by integrating the PDF, then invert the CDF, and use a uniform random predicate as the argument of the inverted function.
A little more detail.
f_s(l) is the PDF, and has been normalized on [0,n).
Now you integrate it to form the CDF
g_s(l') = \int_0^{l'} dl f_s(l)
Note that this is a definite integral to an unspecified endpoint which I have called l'. The CDF is accordingly a function of l'. Assuming we have the normalization right, g_s(N) = 1.0. If this is not so we apply a simple coefficient to fix it.
Next invert the CDF and call the result G^{-1}(x). For this you'll probably want to choose a particular value of gamma.
Then throw uniform random number on [0,n), and use those as the argument, x, to G^{-1}. The result should lie between [0,1), and should be distributed according to f_s.
Like Justin said, you can use a computer algebra system for the math.
dmckee is actually correct, but I thought that I would elaborate more and try to explain away some of the confusion here. I could definitely fail. f_s(l), the function you have in your pretty formula above, is the probability distribution function. It tells you, for a given input l between 0 and n, the probability that l is the segment length. The sum (integral) for all values between 0 and n should be equal to 1.
The graph at the top of page 7 confuses this point. It plots l vs. f_s(l), but you have to watch out for the stray factors it puts on the side. You notice that the values on the bottom go from 0 to 1, but there is a factor of x n on the side, which means that the l values actually go from 0 to n. Also, on the y-axis there is a x 1/n which means these values don't actually go up to about 3, they go to 3/n.
So what do you do now? Well, you need to solve for the cumulative distribution function by integrating the probability distribution function over l which actually turns out to be not too bad (I did it with the Wolfram Mathematica Online Integrator by using x for l and using only the equation for y <= .5). That however was using an indefinite integral and you are really integration along x from 0 to l. If we set the resulting equation equal to some variable (z for instance), the goal now is to solve for l as a function of z. z here is a random number between 0 and 1. You can try using a symbolic solver for this part if you would like (I would). Then you have not only achieved your goal of being able to pick random ls from this distribution, you have also achieved nirvana.
A little more work done
I'll help a little bit more. I tried doing what I said about for y <= .5, but the symbolic algebra system I was using wasn't able to do the inversion (some other system might be able to). However, then I decided to try using the equation for .5 < y <= 1. This turns out to be much easier. If I change l to x in f_s(l) I get
y / n / (1 - y) * (x / n)^((2 * y - 1) / (1 - y))
Integrating this over x from 0 to l I got (using Mathematica's Online Integrator):
(l / n)^(y / (1 - y))
It doesn't get much nicer than that with this sort of thing. If I set this equal to z and solve for l I get:
l = n * z^(1 / y - 1) for .5 < y <= 1
One quick check is for y = 1. In this case, we get l = n no matter what z is. So far so good. Now, you just generate z (a random number between 0 and 1) and you get an l that is distributed as you desired for .5 < y <= 1. But wait, looking at the graph on page 7 you notice that the probability distribution function is symmetric. That means that we can use the above result to find the value for 0 < y <= .5. We just change l -> n-l and y -> 1-y and get
n - l = n * z^(1 / (1 - y) - 1)
l = n * (1 - z^(1 / (1 - y) - 1)) for 0 < y <= .5
Anyway, that should solve your problem unless I made some error somewhere. Good luck.
Given that for any values l, y, n as described, the terms you call p1 and p2 are both in [0,1) and exp is in [1,..) making pow(p2, exp) also in [0,1) thus I don't see how you'd ever get an output with the range [0,n)