This is a further extension of @Henrik's answer, a little bit too long for a comment.
When playing with Henric's great solution, I observed that the two settings Parallelization->True
and Parallelization->False
did not make the difference I hoped for. My parallel kernel configuration shows that automatically 4 local kernels will be launched, whereas the difference between two two settings was only a factor 1.5. So I tried to do the parallelization myself.
The next function is the function testTriangle of Henric, but with Parallelization
set to False
.
origininside=
With[{Part=Compile`GetElement},
Compile[{{tr, _Real,2}},
Module[{s1, s2, s3},
s1=Sign[tr[[2,1]]tr[[3,2]]-tr[[2,2]]tr[[3,1]]];
s2=Sign[tr[[3,1]]tr[[1,2]]-tr[[3,2]]tr[[1,1]]];
s3=Sign[tr[[1, 1]]tr[[2,2]]-tr[[1,2]]tr[[2,1]]];
Boole[s1==s2==s3]],
CompilationTarget->"C",
Parallelization->False,
RuntimeAttributes->{Listable}]
];
On my quadcore computer, I launch 8 kernels:
LaunchKernels[8];
I seem to remember that a C-compiled function is not immediately available in the subkernels, so I expected that now I had to do the compilation of the function origininside
on each of the subkernels. Maybe that idea dates from a long time ago, maybe I am wrong, but I was pleasantly surprised to see that, having compiled the function in the main kernel, it is immediately avaible on the subkernels as well.
Therefore, with the following command I create and test 25,000,000 triangles:
nn=2500;
N@Total[ParallelTable[
Total[origininside @ With[{angles=RandomReal[2 Pi,{nn,3,1}]},
Join[Cos[angles],Sin[angles],3]] ], {10000}]]/10000/nn // AbsoluteTiming
{0.770372, 0.250022}
Since this timing includes the time required for the construction of the triangles, this construction of the parallelization makes the computation about 2.5 times as fast.
Addendum
This addendum contains some mathematical refinements, including a proof that the probability indeed is 1/4.
The first refinement has to do with the construction of the triangles. There is no loss in generality when we assume the first pont of the triangle is at the top of the circle: A={0,1}
. We then choose only two random points B={b1,b2}
and C={c1,c2}
on the unit circle. The condition that the origin is inside the triangle then amounts to b1
and c1
having opposite sign and the intersection of the line BC
with the vertical axis is negative. The latter gives:
Assuming[b1 c1<0, Simplify[(z /. Solve[ (1-\[Lambda]){b1,b2}+\[Lambda]{c1,c2}=={0,z}, {\[Lambda], z}][[1]]) <0]]
(b1-c1) (-b2 c1+b1 c2)<0
which can be further simplified to
b1(-b2 c1+b1 c2)<0
The function origininside
is now simpler:
origininside=With[{Part=Compile`GetElement},
Compile[{{tr, _Real, 2}},
If[tr[[1,1]]tr[[2,1]]>0, 0,
Boole[tr[[1,1]](-tr[[1,2]] tr[[2,1]]+tr[[1,1]] tr[[2,2]])<0]],
CompilationTarget->"C",
Parallelization->False,
RuntimeAttributes->{Listable}]]
The testing on 8 subkernels:
LaunchKernels[8]
(In the following command I use Henric's construction for random points on the circle; this turns out to be faster than using RandomPoint as mentioned by @Sjoerd Smit.)
nn=2500;
N@Total[ParallelTable[
Total[origininside@With[{angles=RandomReal[2 Pi,{nn,2,1}]},
Join[Cos[angles],Sin[angles],3]]],{10000}]]/10000/nn // AbsoluteTiming
{0.546887,0.25012}
This is about 25% faster.
The fact that the probability that the origin is inside a random triangle on the unit circle is 1/4 can be seen in the following way.
(Draw by hand a circle with a point A at the top and a point B at the right hand side. Let A' and B' be the opposite points of A and B. I would have placed this picture here in this answer, but I have no idea how to do that.)
The first point A
is the top of the circle. Then we choose randomly the point B
on the circle. Without loss of generality we may assume that B
is at the right hand side of the circle, as in in the figure.
Now we choose the point C
randomly on the unit circle. For the origin being inside the trangle, the point C
must be on the arc A'B'
, This arc is as long as the arc AB
.
Otherwise stated: we choose the point x
randomly in the interval [0,π]. Then we choose y
randomly in the interval[0,2π] and the criterion is that y
in a subinterval of length x
.
Therefore, the problem of finding the probability that the origin is inside a random triangle on the unit circle is equivalent with the following one:
What is the probability that when we randomly choose a number x
in the interval [0,1]
, the random number y
in the interval [0,1]
will be less than x/2
?
Obviously, the answer is
Integrate[x/2, {x, 0, 1}]
1/4
For the testing, we construct a list of 250000001 random numbers, so that we have 25000000 pairs. Then we can proceed in a lot ways, for example by partitioning the list into pairs with an increment of 1, and then count how many pairs have the property that the first element is larger than two times the second argument.
Here are two ways:
nn = 25000000; lst = RandomReal[1, {nn + 1}];
N[Total[UnitStep[ListCorrelate[{1, -2}, lst]]]/nn] // AbsoluteTiming
{0.45397, 0.250025}
lst1 = Most[lst];
Rest[lst];
N[Total[UnitStep[lst1 - 2 lst2]]/nn ] // AbsoluteTiming
{0.20445, 0.250025}
This is indeed very fast, without having used any C-compilation or parallel computing.
{Cos[a], Sin[b]}
wherea
andb
are different random numbers. Maybe you are getting on track an extension of what you want to demonstrate. BTW, can you give me the link to the proof? Your link lead me to some great mathematical video's, but I was unable to find the video you are refering to. $\endgroup$RandomPoint[Circle[], 9000]
orRandomPoint[Disk[], 9000]
(depending on what you need). $\endgroup$