I know I probably should have asked this question in math.stackexchange but answers there are mostly "pen-paper" type. I need an efficient approach to implement and that is why I am asking here.
Q: Given 2 points A & B and a line L. Points and line are 3D. How to find a point on the given line L which is equidistant from the given points A & B?
The approach I followed is:
finding plane, P, perpendicular to line AB and passing through the center of A & B.
point of intersection of P and L would be the answer.
I am working on large data-set (a 3d image) and doing the above calculations involves large no. of multiplications and divisions (on total).
So is there a better way of doing it.
A working code would be very helpful.
Thanks in advance.
If line L is described by parametric vector equation
P=C+t*D
(where C is some base point, D is direction vector, t is parameter)
then point P is equidistant from the given points A & B, when vector from P to the middle of A-B segment is perpendicular to AB vector. So scalar product of these vectors is zero.
(B-A)*(C+t*D-(A+B)/2)=0
Let's
F=B-A
G=C-(A+B)/2
then (in coordinate form)
Fx*(Gx+t*Dx)+Fy*(Gy+t*Dy)+Fz*(Gz+t*Dz)=0
t*(Dx*Fx+Fy*Dy+Fz*Dz)=-(Fx*Gx+Fy*Gy+Fz*Gz)
t=-(Fx*Gx+Fy*Gy+Fz*Gz)/(Dx*Fx+Fy*Dy+Fz*Dz)
case of (Dx*Fx+Fy*Dy+Fz*Dz)=0 corresponds to perpendicular lines AB and L. In this case there is no solution when nominator (Fx*Gx+Fy*Gy+Fz*Gz) is non-zero, and there is infinity of solutions, if nominator is zero (all the points on line are equidistant)
TL;DR. The solution is at the bottom.
Alright, so let's say these are our parameters:
x0 and x1, that describe the line.
a and b, the two points.
Where
x0 = [x0, y0, z0]
x1 = [x1, y1, z1]
a = [xa, ya, za]
b = [xb, yb, zb]
δ = [δx, δy, δz] = (x1 - x0)
Then our description of the line can be seen as a parametric function:
l(λ) = x0 + λ*(x1 - x0)
So we are trying to find a value for λ that satisfies the following equation:
(l(λ) - a)2 = (l(λ) - b)2
(Here I'm cheating with notation a bit, so x2 = x.x)
So expanding everything we get:
(λx1 + (1 - λ)x0 - xa)2 +
(λy1 + (1 - λ)y0 - ya)2 +
(λz1 + (1 - λ)z0 - za)2 =
(λx1 + (1 - λ)x0 - xb)2 +
(λy1 + (1 - λ)y0 - yb)2 +
(λz1 + (1 - λ)z0 - zb)2
Simplifying, we get:
(λδx + x0 - xa)2 +
(λδy + y0 - ya)2 +
(λδz + z0 - za)2 =
(λδx + x0 - xb)2 +
(λδy + y0 - yb)2 +
(λδz + z0 - zb)2
Expanding the brackets and cancelling, we get:
-2δxxaλ + (x0 - xa)2 +
-2δyyaλ + (y0 - ya)2 +
-2δzzaλ + (z0 - za)2 =
-2δxxbλ + (x0 - xb)2 +
-2δyybλ + (y0 - yb)2 +
-2δzzbλ + (z0 - zb)2
Which we can simplify further into some nice neat vector operations:
2λδ.(xb - xa) =
(x0 - xb)2 -
(x0 - xa)2
Which is pretty simple to rearrange to get a linear equation in λ with one unique solution.
You can solve a system of equations to get the answer. A line in 3D is something of the sort of:
x = x<sub>0</sub> + t * v<sub>x</sub>
y = y<sub>0</sub> + t * v<sub>y</sub>
z = z<sub>0</sub> + t * v<sub>z</sub>
Let's denote the point we are searching for P. Now we have:
(Px - Ax)2 + (Py - Ay)2 +(Pz - Az)2 = (Px - Bx)2 +
(Py - By)2 + (Pz - Bz)2
Note that although all these equations seem to be quadtratic, the square of Px we be scratched because it appears on both sides of the equation. Now use this system of equations and the ones above to find the three variables Px, Py and Pz.
Related
Problem is from this link: https://leetcode.com/problems/sqrtx
My question is the line while (Math.abs(x0-x1) >= 1) condition. I don't understand why the moment that condition breaks, the answer would be the floor of x1. Is there no case where the break condition occurs at something like x1 equals 7 point something, but the true square root is 6 point something, giving the wrong answer of 7 when the actual answer is 6?
From my testing, this seems to be an invariant, but I don't understand why.
This is the Newton's Method solution:
class Solution {
public int mySqrt(int x) {
if (x < 2) return x;
double x0 = x;
double x1 = (x0 + x / x0) / 2.0;
while (Math.abs(x0 - x1) >= 1) {
x0 = x1;
x1 = (x0 + x / x0) / 2.0;
}
return (int)x1;
}
}
This is indeed clever, and not at all obvious.
The update rule we have is x1 = (x0 + x/x0)/2 = f(x0).
First question. What is f'(x0)?
f'(x0) = d/dx0 (x0 + x/x0) / 2
= (1 - x/x0^2) / 2
Let's note some facts.
If sqrt(x) < x0, then the derivative is positive. So f(x0) is strictly increasing over sqrt(x) < x0. But f(sqrt(x)) = sqrt(x). Therefore if sqrt(x) < x0 then sqrt(x) < f(x0).
The derivative is always < 1. So x0 - f(x0) is also strictly increasing. That's the size of the step.
We are treating x as a constant here. But we should also note that (as long as x0^2 < x), the larger x is, the smaller the step size gets.
Enough Calculus, let's do something harder - algebra!
Let's try our best to have it give an answer of k when it should be giving an answer of k-1. That means we want x < k*k. The larger x is, the smaller the step, so we'll make x as big as we can - namely k*k-1
We want k <= f(x0). But we also want x0 - f(x0) < 1. Keeping in mind point 2, let's try x0 = k+1 and see where our next point lands.
But
f(k+1) = f(x0)
= (x0 + x/x0) / 2
= ((k+1) + (k^2 - 1)/(k+1)) / 2
= ((k+1)^2 + (k^2 - 1)) / (2 * (k+1))
= ((k^2 + 2k + 1) + (k^2 - 1)) / (2 * (k+1))
= (2 k^2 + 2k) / (2 * (k+1))
= (2 * (k+1) * k) / (2 * (k+1))
= k
And whoops - x0 - f(x0) == 1 which fails our condition. Increasing x0 from there will result in a larger step size (which means we aren't finished yet), and decreasing it gives us the right answer.
So the condition is proven mathematically correct.
But...let's test it. Here is a test in Python.
def my_sqrt(x):
x0 = x
x1 = (x0 + x/x0)/2
while (1 <= abs(x1 - x0)):
x0 = x1
x1 = (x0 + x/x0)/2
return int(x1)
for i in range(2, 1000000):
if i == my_sqrt(i * i - 1):
print(i)
This finds that if k is in (314161, 599326, 599327, ...) then you get the wrong answer. Why? Because it is a delicate condition, and even one ulp of error can mess up the answer.
Suppose I have a function phi(x1,x2)=k1*x1+k2*x2 which I have evaluated over a grid where the grid is a square having boundaries at -100 and 100 in both x1 and x2 axis with some step size say h=0.1. Now I want to calculate this sum over the grid with which I'm struggling:
What I was trying :
clear all
close all
clc
D=1; h=0.1;
D1 = -100;
D2 = 100;
X = D1 : h : D2;
Y = D1 : h : D2;
[x1, x2] = meshgrid(X, Y);
k1=2;k2=2;
phi = k1.*x1 + k2.*x2;
figure(1)
surf(X,Y,phi)
m1=-500:500;
m2=-500:500;
[M1,M2,X1,X2]=ndgrid(m1,m2,X,Y)
sys=#(m1,m2,X,Y) (k1*h*m1+k2*h*m2).*exp((-([X Y]-h*[m1 m2]).^2)./(h^2*D))
sum1=sum(sys(M1,M2,X1,X2))
Matlab says error in ndgrid, any idea how I should code this?
MATLAB shows:
Error using repmat
Requested 10001x1001x2001x2001 (298649.5GB) array exceeds maximum array size preference. Creation of arrays greater
than this limit may take a long time and cause MATLAB to become unresponsive. See array size limit or preference
panel for more information.
Error in ndgrid (line 72)
varargout{i} = repmat(x,s);
Error in new_try1 (line 16)
[M1,M2,X1,X2]=ndgrid(m1,m2,X,Y)
Judging by your comments and your code, it appears as though you don't fully understand what the equation is asking you to compute.
To obtain the value M(x1,x2) at some given (x1,x2), you have to compute that sum over Z2. Of course, using a numerical toolbox such as MATLAB, you could only ever hope to compute over some finite range of Z2. In this case, since (x1,x2) covers the range [-100,100] x [-100,100], and h=0.1, it follows that mh covers the range [-1000, 1000] x [-1000, 1000]. Example: m = (-1000, -1000) gives you mh = (-100, -100), which is the bottom-left corner of your domain. So really, phi(mh) is just phi(x1,x2) evaluated on all of your discretised points.
As an aside, since you need to compute |x-hm|^2, you can treat x = x1 + i x2 as a complex number to make use of MATLAB's abs function. If you were strictly working with vectors, you would have to use norm, which is OK too, but a bit more verbose. Thus, for some given x=(x10, x20), you would compute x-hm over the entire discretised plane as (x10 - x1) + i (x20 - x2).
Finally, you can compute 1 term of M at a time:
D=1; h=0.1;
D1 = -100;
D2 = 100;
X = (D1 : h : D2); % X is in rows (dim 2)
Y = (D1 : h : D2)'; % Y is in columns (dim 1)
k1=2;k2=2;
phi = k1*X + k2*Y;
M = zeros(length(Y), length(X));
for j = 1:length(X)
for i = 1:length(Y)
% treat (x - hm) as a complex number
x_hm = (X(j)-X) + 1i*(Y(i)-Y); % this computes x-hm for all m
M(i,j) = 1/(pi*D) * sum(sum(phi .* exp(-abs(x_hm).^2/(h^2*D)), 1), 2);
end
end
By the way, this computation takes quite a long time. You can consider either increasing h, reducing D1 and D2, or changing all three of them.
I came to know that Interpolation Search is a modification of Binary Search where in binary search the input is divided into two equal halves in each iteration by computing
mid = (low + high) / 2
and in Interpolation search the mid is computed as
mid = low + (key - arr[low]) * ((high - low) / (arr[high] - arr[low]))
Now I need to understand this formula of calculating mid in interpolation search.
Ref: https://en.wikipedia.org/wiki/Interpolation_search#Sample_implementation
You can think of array arr as a function f that acts on index and return a value, which is monotone (because array is sorted). So you have your initial data f(low) = m and f(high) = M. Now you can interpolate your function f with a straight line, which is quite reasonable to do because your f is monotone and you have only 2 points.
So your interpolation should be line (linear function) that pass throw points (low, m) and (high, M). This is it's equation
(y - f(low))/(f(high) - f(low)) = (x - low)/(high - low)
So y here is the element of search space and x is from domain (x is index of array). So if your function f would be the same as it's interpolation, then index of your key would be:
x = low + (high - low)*(key - f(low))/(f(high) - f(low))
So, assuming that your function f is close to it's interpolation, you should just check the value f at x to see if it is the goal. Otherwise you just shrink your interpolation interval.
An extention to #JustAnotherCurious answer
the equation perposed by him was based on Interpolation Formula (equ of a line)
Now, thinkf() as function that takes an index and return its y axis value,
y1 = f(low)
y2 = f(high)
x1 = low
x2 = high
(y - f(low)) = [(f(high) - f(low)) / (high - low)] * (x - low);
OR
x = low + [(high - low) * (y - f(low))] / (f(high) - f(low))
here: y = key
we are looking for position(value) of x.
I already googled for the problem but only found either 2D solutions or formulas that didn't work for me (found this formula that looks nice: http://www.ogre3d.org/forums/viewtopic.php?f=10&t=55796 but seems not to be correct).
I have given:
Vec3 cannonPos;
Vec3 targetPos;
Vec3 targetVelocityVec;
float bulletSpeed;
what i'm looking for is time t such that
targetPos+t*targetVelocityVec
is the intersectionpoint where to aim the cannon to and shoot.
I'm looking for a simple, inexpensive formula for t (by simple i just mean not making many unnecessary vectorspace transformations and the like)
thanks!
The real problem is finding out where in space that the bullet can intersect the targets path. The bullet speed is constant, so in a certain amount of time it will travel the same distance regardless of the direction in which we fire it. This means that it's position after time t will always lie on a sphere. Here's an ugly illustration in 2d:
This sphere can be expressed mathematically as:
(x-x_b0)^2 + (y-y_b0)^2 + (z-z_b0)^2 = (bulletSpeed * t)^2 (eq 1)
x_b0, y_b0 and z_b0 denote the position of the cannon. You can find the time t by solving this equation for t using the equation provided in your question:
targetPos+t*targetVelocityVec (eq 2)
(eq 2) is a vector equation and can be decomposed into three separate equations:
x = x_t0 + t * v_x
y = y_t0 + t * v_y
z = z_t0 + t * v_z
These three equations can be inserted into (eq 1):
(x_t0 + t * v_x - x_b0)^2 + (y_t0 + t * v_y - y_b0)^2 + (z_t0 + t * v_z - z_b0)^2 = (bulletSpeed * t)^2
This equation contains only known variables and can be solved for t. By assigning the constant part of the quadratic subexpressions to constants we can simplify the calculation:
c_1 = x_t0 - x_b0
c_2 = y_t0 - y_b0
c_3 = z_t0 - z_b0
(v_b = bulletSpeed)
(t * v_x + c_1)^2 + (t * v_y + c_2)^2 + (t * v_z + c_3)^2 = (v_b * t)^2
Rearrange it as a standard quadratic equation:
(v_x^2+v_y^2+v_z^2-v_b^2)t^2 + 2*(v_x*c_1+v_y*c_2+v_z*c_3)t + (c_1^2+c_2^2+c_3^2) = 0
This is easily solvable using the standard formula. It can result in zero, one or two solutions. Zero solutions (not counting complex solutions) means that there's no possible way for the bullet to reach the target. One solution will probably happen very rarely, when the target trajectory intersects with the very edge of the sphere. Two solutions will be the most common scenario. A negative solution means that you can't hit the target, since you would need to fire the bullet into the past. These are all conditions you'll have to check for.
When you've solved the equation you can find the position of t by putting it back into (eq 2). In pseudo code:
# setup all needed variables
c_1 = x_t0 - x_b0
c_2 = y_t0 - y_b0
c_3 = z_t0 - z_b0
v_b = bulletSpeed
# ... and so on
a = v_x^2+v_y^2+v_z^2-v_b^2
b = 2*(v_x*c_1+v_y*c_2+v_z*c_3)
c = c_1^2+c_2^2+c_3^2
if b^2 < 4*a*c:
# no real solutions
raise error
p = -b/(2*a)
q = sqrt(b^2 - 4*a*c)/(2*a)
t1 = p-q
t2 = p+q
if t1 < 0 and t2 < 0:
# no positive solutions, all possible trajectories are in the past
raise error
# we want to hit it at the earliest possible time
if t1 > t2: t = t2
else: t = t1
# calculate point of collision
x = x_t0 + t * v_x
y = y_t0 + t * v_y
z = z_t0 + t * v_z
I have two problems. I have to calculate two equations:
X = A - inv(B) * Y * inv(B)
and
X = Y + A' * inv(B) * A
where, A, B and Y are known p*p matrices (p can be small or large, depends the situation). Matrices are quite dense, without any structure (except B being non-singular of course).
Is it possible to solve X in those equations without inverting the matrix B? I have to calculate these equations n times, n being hundreds or thousands, and all the matrices change over time.
Thank you very much.
If you can express your updates to your matrix B in the following terms:
Bnew = B + u*s*v
then you can express an update to inv(B) explicitly using the Sherman-Morrison-Woodbury formula:
inv(B + u*s*v) = inv(B) - inv(B)*u*inv(s + v*inv(B)*u)*v*inv(B)
If u and v are vectors (column and row, respectively) and s is scalar, then this expression simplifies:
inv(B + u*s*v) = inv(B) - inv(B)*u*v*inv(B)/(s + v*inv(B)*u)
You would only have to calculate inv(B) once and then update it when it changes with no additional inversions.
It may be preferable not to calculate the full inverse, just simple "matrix divisions" on y and (ynew - y) or a and (anew - a) depending on the size of "n" with respect to "p" in your problem.
Memo-ize inv(B), i.e. only invert B when it changes, and keep the inverse around.
If changes to B are small, possibly you could use a delta-approximation.