I am bussy porting IronPython to Windows Phone 8 sothat I can run Skeinforge and I am almost finished. I can already run scripts and import most modules. My problem is that I am now trying to get the "Random" module implemented. My largest problem was that the library used 'SHA512' to compute random numbers. This is a problem because Microsoft did not implement this hash as well as some others used by IronPython in the mobile .Net framework because they are "unsecure". I have worked around this by removing the unsupported hashes from hashlib.py (this seems to have worked). I then tried changing the reference to 'SHA512' in random.py to 'SHA256'. My problem is that I now get this very random error:
expected Random, got Random
If any of you know how to, please help me. I will document this after I am done sothat everyone can enjoy IPY on WP8.
Here is the random.py module:
from __future__ import division
from warnings import warn as _warn
from types import MethodType as _MethodType, BuiltinMethodType as _BuiltinMethodType
from math import log as _log, exp as _exp, pi as _pi, e as _e, ceil as _ceil
from math import sqrt as _sqrt, acos as _acos, cos as _cos, sin as _sin
from os import urandom as _urandom
from binascii import hexlify as _hexlify
import hashlib as _hashlib
__all__ = ["Random","seed","random","uniform","randint","choice","sample",
"randrange","shuffle","normalvariate","lognormvariate",
"expovariate","vonmisesvariate","gammavariate","triangular",
"gauss","betavariate","paretovariate","weibullvariate",
"getstate","setstate","jumpahead", "WichmannHill", "getrandbits",
"SystemRandom"]
NV_MAGICCONST = 4 * _exp(-0.5)/_sqrt(2.0)
TWOPI = 2.0*_pi
LOG4 = _log(4.0)
SG_MAGICCONST = 1.0 + _log(4.5)
BPF = 53 # Number of bits in a float
RECIP_BPF = 2**-BPF
import _random
class Random(_random.Random):
VERSION = 3 # used by getstate/setstate
def __init__(self, x=None):
self.seed(x)
self.gauss_next = None
def seed(self, a=None):
if a is None:
try:
a = long(_hexlify(_urandom(16)), 16)
except NotImplementedError:
import time
a = long(time.time() * 256) # use fractional seconds
super(Random, self).seed(a)
self.gauss_next = None
def getstate(self):
return self.VERSION, super(Random, self).getstate(), self.gauss_next
def setstate(self, state):
version = state[0]
if version == 3:
version, internalstate, self.gauss_next = state
super(Random, self).setstate(internalstate)
elif version == 2:
version, internalstate, self.gauss_next = state
try:
internalstate = tuple( long(x) % (2**32) for x in internalstate )
except ValueError, e:
raise TypeError, e
super(Random, self).setstate(internalstate)
else:
raise ValueError("state with version %s passed to "
"Random.setstate() of version %s" %
(version, self.VERSION))
def jumpahead(self, n):
s = repr(n) + repr(self.getstate())
n = int(_hashlib.new('sha256', s).hexdigest(), 16)
super(Random, self).jumpahead(n)
def __getstate__(self): # for pickle
return self.getstate()
def __setstate__(self, state): # for pickle
self.setstate(state)
def __reduce__(self):
return self.__class__, (), self.getstate()
def randrange(self, start, stop=None, step=1, int=int, default=None,
maxwidth=1L<<BPF):
istart = int(start)
if istart != start:
raise ValueError, "non-integer arg 1 for randrange()"
if stop is default:
if istart > 0:
if istart >= maxwidth:
return self._randbelow(istart)
return int(self.random() * istart)
raise ValueError, "empty range for randrange()"
istop = int(stop)
if istop != stop:
raise ValueError, "non-integer stop for randrange()"
width = istop - istart
if step == 1 and width > 0:
if width >= maxwidth:
return int(istart + self._randbelow(width))
return int(istart + int(self.random()*width))
if step == 1:
raise ValueError, "empty range for randrange() (%d,%d, %d)" % (istart, istop, width)
istep = int(step)
if istep != step:
raise ValueError, "non-integer step for randrange()"
if istep > 0:
n = (width + istep - 1) // istep
elif istep < 0:
n = (width + istep + 1) // istep
else:
raise ValueError, "zero step for randrange()"
if n <= 0:
raise ValueError, "empty range for randrange()"
if n >= maxwidth:
return istart + istep*self._randbelow(n)
return istart + istep*int(self.random() * n)
def randint(self, a, b):
return self.randrange(a, b+1)
def _randbelow(self, n, _log=_log, int=int, _maxwidth=1L<<BPF,
_Method=_MethodType, _BuiltinMethod=_BuiltinMethodType):
try:
getrandbits = self.getrandbits
except AttributeError:
pass
else:
if type(self.random) is _BuiltinMethod or type(getrandbits) is _Method:
k = int(1.00001 + _log(n-1, 2.0)) # 2**k > n-1 > 2**(k-2)
r = getrandbits(k)
while r >= n:
r = getrandbits(k)
return r
if n >= _maxwidth:
_warn("Underlying random() generator does not supply \n"
"enough bits to choose from a population range this large")
return int(self.random() * n)
def choice(self, seq):
return seq[int(self.random() * len(seq))] # raises IndexError if seq is empty
def shuffle(self, x, random=None, int=int):
if random is None:
random = self.random
for i in reversed(xrange(1, len(x))):
j = int(random() * (i+1))
x[i], x[j] = x[j], x[i]
def sample(self, population, k):
n = len(population)
if not 0 <= k <= n:
raise ValueError("sample larger than population")
random = self.random
_int = int
result = [None] * k
setsize = 21 # size of a small set minus size of an empty list
if k > 5:
setsize += 4 ** _ceil(_log(k * 3, 4)) # table size for big sets
if n <= setsize or hasattr(population, "keys"):
pool = list(population)
for i in xrange(k): # invariant: non-selected at [0,n-i)
j = _int(random() * (n-i))
result[i] = pool[j]
pool[j] = pool[n-i-1] # move non-selected item into vacancy
else:
try:
selected = set()
selected_add = selected.add
for i in xrange(k):
j = _int(random() * n)
while j in selected:
j = _int(random() * n)
selected_add(j)
result[i] = population[j]
except (TypeError, KeyError): # handle (at least) sets
if isinstance(population, list):
raise
return self.sample(tuple(population), k)
return result
def uniform(self, a, b):
"Get a random number in the range [a, b) or [a, b] depending on rounding."
return a + (b-a) * self.random()
def triangular(self, low=0.0, high=1.0, mode=None):
u = self.random()
c = 0.5 if mode is None else (mode - low) / (high - low)
if u > c:
u = 1.0 - u
c = 1.0 - c
low, high = high, low
return low + (high - low) * (u * c) ** 0.5
def normalvariate(self, mu, sigma):
random = self.random
while 1:
u1 = random()
u2 = 1.0 - random()
z = NV_MAGICCONST*(u1-0.5)/u2
zz = z*z/4.0
if zz <= -_log(u2):
break
return mu + z*sigma
def lognormvariate(self, mu, sigma):
return _exp(self.normalvariate(mu, sigma))
def expovariate(self, lambd):
random = self.random
u = random()
while u <= 1e-7:
u = random()
return -_log(u)/lambd
def vonmisesvariate(self, mu, kappa):
random = self.random
if kappa <= 1e-6:
return TWOPI * random()
a = 1.0 + _sqrt(1.0 + 4.0 * kappa * kappa)
b = (a - _sqrt(2.0 * a))/(2.0 * kappa)
r = (1.0 + b * b)/(2.0 * b)
while 1:
u1 = random()
z = _cos(_pi * u1)
f = (1.0 + r * z)/(r + z)
c = kappa * (r - f)
u2 = random()
if u2 < c * (2.0 - c) or u2 <= c * _exp(1.0 - c):
break
u3 = random()
if u3 > 0.5:
theta = (mu % TWOPI) + _acos(f)
else:
theta = (mu % TWOPI) - _acos(f)
return theta
def gammavariate(self, alpha, beta):
if alpha <= 0.0 or beta <= 0.0:
raise ValueError, 'gammavariate: alpha and beta must be > 0.0'
random = self.random
if alpha > 1.0:
ainv = _sqrt(2.0 * alpha - 1.0)
bbb = alpha - LOG4
ccc = alpha + ainv
while 1:
u1 = random()
if not 1e-7 < u1 < .9999999:
continue
u2 = 1.0 - random()
v = _log(u1/(1.0-u1))/ainv
x = alpha*_exp(v)
z = u1*u1*u2
r = bbb+ccc*v-x
if r + SG_MAGICCONST - 4.5*z >= 0.0 or r >= _log(z):
return x * beta
elif alpha == 1.0:
u = random()
while u <= 1e-7:
u = random()
return -_log(u) * beta
else: # alpha is between 0 and 1 (exclusive)
while 1:
u = random()
b = (_e + alpha)/_e
p = b*u
if p <= 1.0:
x = p ** (1.0/alpha)
else:
x = -_log((b-p)/alpha)
u1 = random()
if p > 1.0:
if u1 <= x ** (alpha - 1.0):
break
elif u1 <= _exp(-x):
break
return x * beta
def gauss(self, mu, sigma):
random = self.random
z = self.gauss_next
self.gauss_next = None
if z is None:
x2pi = random() * TWOPI
g2rad = _sqrt(-2.0 * _log(1.0 - random()))
z = _cos(x2pi) * g2rad
self.gauss_next = _sin(x2pi) * g2rad
return mu + z*sigma
def betavariate(self, alpha, beta):
y = self.gammavariate(alpha, 1.)
if y == 0:
return 0.0
else:
return y / (y + self.gammavariate(beta, 1.))
def paretovariate(self, alpha):
u = 1.0 - self.random()
return 1.0 / pow(u, 1.0/alpha)
def weibullvariate(self, alpha, beta):
u = 1.0 - self.random()
return alpha * pow(-_log(u), 1.0/beta)
class WichmannHill(Random):
VERSION = 1 # used by getstate/setstate
def seed(self, a=None):
if a is None:
try:
a = long(_hexlify(_urandom(16)), 16)
except NotImplementedError:
import time
a = long(time.time() * 256) # use fractional seconds
if not isinstance(a, (int, long)):
a = hash(a)
a, x = divmod(a, 30268)
a, y = divmod(a, 30306)
a, z = divmod(a, 30322)
self._seed = int(x)+1, int(y)+1, int(z)+1
self.gauss_next = None
def random(self):
x, y, z = self._seed
x = (171 * x) % 30269
y = (172 * y) % 30307
z = (170 * z) % 30323
self._seed = x, y, z
return (x/30269.0 + y/30307.0 + z/30323.0) % 1.0
def getstate(self):
return self.VERSION, self._seed, self.gauss_next
def setstate(self, state):
version = state[0]
if version == 1:
version, self._seed, self.gauss_next = state
else:
raise ValueError("state with version %s passed to "
"Random.setstate() of version %s" %
(version, self.VERSION))
def jumpahead(self, n):
if not n >= 0:
raise ValueError("n must be >= 0")
x, y, z = self._seed
x = int(x * pow(171, n, 30269)) % 30269
y = int(y * pow(172, n, 30307)) % 30307
z = int(z * pow(170, n, 30323)) % 30323
self._seed = x, y, z
def __whseed(self, x=0, y=0, z=0):
if not type(x) == type(y) == type(z) == int:
raise TypeError('seeds must be integers')
if not (0 <= x < 256 and 0 <= y < 256 and 0 <= z < 256):
raise ValueError('seeds must be in range(0, 256)')
if 0 == x == y == z:
import time
t = long(time.time() * 256)
t = int((t&0xffffff) ^ (t>>24))
t, x = divmod(t, 256)
t, y = divmod(t, 256)
t, z = divmod(t, 256)
self._seed = (x or 1, y or 1, z or 1)
self.gauss_next = None
def whseed(self, a=None):
if a is None:
self.__whseed()
return
a = hash(a)
a, x = divmod(a, 256)
a, y = divmod(a, 256)
a, z = divmod(a, 256)
x = (x + a) % 256 or 1
y = (y + a) % 256 or 1
z = (z + a) % 256 or 1
self.__whseed(x, y, z)
class SystemRandom(Random):
def random(self):
return (long(_hexlify(_urandom(7)), 16) >> 3) * RECIP_BPF
def getrandbits(self, k):
if k <= 0:
raise ValueError('number of bits must be greater than zero')
if k != int(k):
raise TypeError('number of bits should be an integer')
bytes = (k + 7) // 8 # bits / 8 and rounded up
x = long(_hexlify(_urandom(bytes)), 16)
return x >> (bytes * 8 - k) # trim excess bits
def _stub(self, *args, **kwds):
"Stub method. Not used for a system random number generator."
return None
seed = jumpahead = _stub
def _notimplemented(self, *args, **kwds):
"Method should not be called for a system random number generator."
raise NotImplementedError('System entropy source does not have state.')
getstate = setstate = _notimplemented
def _test_generator(n, func, args):
import time
print n, 'times', func.__name__
total = 0.0
sqsum = 0.0
smallest = 1e10
largest = -1e10
t0 = time.time()
for i in range(n):
x = func(*args)
total += x
sqsum = sqsum + x*x
smallest = min(x, smallest)
largest = max(x, largest)
t1 = time.time()
print round(t1-t0, 3), 'sec,',
avg = total/n
stddev = _sqrt(sqsum/n - avg*avg)
print 'avg %g, stddev %g, min %g, max %g' % \
(avg, stddev, smallest, largest)
def _test(N=2000):
_test_generator(N, random, ())
_test_generator(N, normalvariate, (0.0, 1.0))
_test_generator(N, lognormvariate, (0.0, 1.0))
_test_generator(N, vonmisesvariate, (0.0, 1.0))
_test_generator(N, gammavariate, (0.01, 1.0))
_test_generator(N, gammavariate, (0.1, 1.0))
_test_generator(N, gammavariate, (0.1, 2.0))
_test_generator(N, gammavariate, (0.5, 1.0))
_test_generator(N, gammavariate, (0.9, 1.0))
_test_generator(N, gammavariate, (1.0, 1.0))
_test_generator(N, gammavariate, (2.0, 1.0))
_test_generator(N, gammavariate, (20.0, 1.0))
_test_generator(N, gammavariate, (200.0, 1.0))
_test_generator(N, gauss, (0.0, 1.0))
_test_generator(N, betavariate, (3.0, 3.0))
_test_generator(N, triangular, (0.0, 1.0, 1.0/3.0))
_inst = Random()
seed = _inst.seed
random = _inst.random
uniform = _inst.uniform
triangular = _inst.triangular
randint = _inst.randint
choice = _inst.choice
randrange = _inst.randrange
sample = _inst.sample
shuffle = _inst.shuffle
normalvariate = _inst.normalvariate
lognormvariate = _inst.lognormvariate
expovariate = _inst.expovariate
vonmisesvariate = _inst.vonmisesvariate
gammavariate = _inst.gammavariate
gauss = _inst.gauss
betavariate = _inst.betavariate
paretovariate = _inst.paretovariate
weibullvariate = _inst.weibullvariate
getstate = _inst.getstate
setstate = _inst.setstate
jumpahead = _inst.jumpahead
getrandbits = _inst.getrandbits
if __name__ == '__main__':
_test()
After some labor intensive debugging I have determined that the following line most likely causes the error:
_inst = new Random()
Related
Lets N be a number (10<=N<=10^5).
I have to break it into 3 numbers (x,y,z) such that it validates the following conditions.
1. x<=y<=z
2. x^2+y^2=z^2-1;
3. x+y+z<=N
I have to find how many combinations I can get from the given numbers in a method.
I have tried as follows but it's taking so much time for a higher number and resulting in a timeout..
int N= Int32.Parse(Console.ReadLine());
List<String> res = new List<string>();
//x<=y<=z
int mxSqrt = N - 2;
int a = 0, b = 0;
for (int z = 1; z <= mxSqrt; z++)
{
a = z * z;
for (int y = 1; y <= z; y++)
{
b = y * y;
for (int x = 1; x <= y; x++)
{
int x1 = b + x * x;
int y1 = a - 1;
if (x1 == y1 && ((x + y + z) <= N))
{
res.Add(x + "," + y + "," + z);
}
}
}
}
Console.WriteLine(res.Count());
My question:
My solution is taking time for a bigger number (I think it's the
for loops), how can I improve it?
Is there any better approach for the same?
Here's a method that enumerates the triples, rather than exhaustively testing for them, using number theory as described here: https://mathoverflow.net/questions/29644/enumerating-ways-to-decompose-an-integer-into-the-sum-of-two-squares
Since the math took me a while to comprehend and a while to implement (gathering some code that's credited above it), and since I don't feel much of an authority on the subject, I'll leave it for the reader to research. This is based on expressing numbers as Gaussian integer conjugates. (a + bi)*(a - bi) = a^2 + b^2. We first factor the number, z^2 - 1, into primes, decompose the primes into Gaussian conjugates and find different expressions that we expand and simplify to get a + bi, which can be then raised, a^2 + b^2.
A perk of reading about the Sum of Squares Function is discovering that we can rule out any candidate z^2 - 1 that contains a prime of form 4k + 3 with an odd power. Using that check alone, I was able to reduce Prune's loop on 10^5 from 214 seconds to 19 seconds (on repl.it) using the Rosetta prime factoring code below.
The implementation here is just a demonstration. It does not have handling or optimisation for limiting x and y. Rather, it just enumerates as it goes. Play with it here.
Python code:
# https://math.stackexchange.com/questions/5877/efficiently-finding-two-squares-which-sum-to-a-prime
def mods(a, n):
if n <= 0:
return "negative modulus"
a = a % n
if (2 * a > n):
a -= n
return a
def powmods(a, r, n):
out = 1
while r > 0:
if (r % 2) == 1:
r -= 1
out = mods(out * a, n)
r /= 2
a = mods(a * a, n)
return out
def quos(a, n):
if n <= 0:
return "negative modulus"
return (a - mods(a, n))/n
def grem(w, z):
# remainder in Gaussian integers when dividing w by z
(w0, w1) = w
(z0, z1) = z
n = z0 * z0 + z1 * z1
if n == 0:
return "division by zero"
u0 = quos(w0 * z0 + w1 * z1, n)
u1 = quos(w1 * z0 - w0 * z1, n)
return(w0 - z0 * u0 + z1 * u1,
w1 - z0 * u1 - z1 * u0)
def ggcd(w, z):
while z != (0,0):
w, z = z, grem(w, z)
return w
def root4(p):
# 4th root of 1 modulo p
if p <= 1:
return "too small"
if (p % 4) != 1:
return "not congruent to 1"
k = p/4
j = 2
while True:
a = powmods(j, k, p)
b = mods(a * a, p)
if b == -1:
return a
if b != 1:
return "not prime"
j += 1
def sq2(p):
if p % 4 != 1:
return "not congruent to 1 modulo 4"
a = root4(p)
return ggcd((p,0),(a,1))
# https://rosettacode.org/wiki/Prime_decomposition#Python:_Using_floating_point
from math import floor, sqrt
def fac(n):
step = lambda x: 1 + (x<<2) - ((x>>1)<<1)
maxq = long(floor(sqrt(n)))
d = 1
q = n % 2 == 0 and 2 or 3
while q <= maxq and n % q != 0:
q = step(d)
d += 1
return q <= maxq and [q] + fac(n//q) or [n]
# My code...
# An answer for https://stackoverflow.com/questions/54110614/
from collections import Counter
from itertools import product
from sympy import I, expand, Add
def valid(ps):
for (p, e) in ps.items():
if (p % 4 == 3) and (e & 1):
return False
return True
def get_sq2(p, e):
if p == 2:
if e & 1:
return [2**(e / 2), 2**(e / 2)]
else:
return [2**(e / 2), 0]
elif p % 4 == 3:
return [p, 0]
else:
a,b = sq2(p)
return [abs(a), abs(b)]
def get_terms(cs, e):
if e == 1:
return [Add(cs[0], cs[1] * I)]
res = [Add(cs[0], cs[1] * I)**e]
for t in xrange(1, e / 2 + 1):
res.append(
Add(cs[0] + cs[1]*I)**(e-t) * Add(cs[0] - cs[1]*I)**t)
return res
def get_lists(ps):
items = ps.items()
lists = []
for (p, e) in items:
if p == 2:
a,b = get_sq2(2, e)
lists.append([Add(a, b*I)])
elif p % 4 == 3:
a,b = get_sq2(p, e)
lists.append([Add(a, b*I)**(e / 2)])
else:
lists.append(get_terms(get_sq2(p, e), e))
return lists
def f(n):
for z in xrange(2, n / 2):
zz = (z + 1) * (z - 1)
ps = Counter(fac(zz))
is_valid = valid(ps)
if is_valid:
print "valid (does not contain a prime of form\n4k + 3 with an odd power)"
print "z: %s, primes: %s" % (z, dict(ps))
lists = get_lists(ps)
cartesian = product(*lists)
for element in cartesian:
print "prime square decomposition: %s" % list(element)
p = 1
for item in element:
p *= item
print "complex conjugates: %s" % p
vals = p.expand(complex=True, evaluate=True).as_coefficients_dict().values()
x, y = vals[0], vals[1] if len(vals) > 1 else 0
print "x, y, z: %s, %s, %s" % (x, y, z)
print "x^2 + y^2, z^2-1: %s, %s" % (x**2 + y**2, z**2 - 1)
print ''
if __name__ == "__main__":
print f(100)
Output:
valid (does not contain a prime of form
4k + 3 with an odd power)
z: 3, primes: {2: 3}
prime square decomposition: [2 + 2*I]
complex conjugates: 2 + 2*I
x, y, z: 2, 2, 3
x^2 + y^2, z^2-1: 8, 8
valid (does not contain a prime of form
4k + 3 with an odd power)
z: 9, primes: {2: 4, 5: 1}
prime square decomposition: [4, 2 + I]
complex conjugates: 8 + 4*I
x, y, z: 8, 4, 9
x^2 + y^2, z^2-1: 80, 80
valid (does not contain a prime of form
4k + 3 with an odd power)
z: 17, primes: {2: 5, 3: 2}
prime square decomposition: [4 + 4*I, 3]
complex conjugates: 12 + 12*I
x, y, z: 12, 12, 17
x^2 + y^2, z^2-1: 288, 288
valid (does not contain a prime of form
4k + 3 with an odd power)
z: 19, primes: {2: 3, 3: 2, 5: 1}
prime square decomposition: [2 + 2*I, 3, 2 + I]
complex conjugates: (2 + I)*(6 + 6*I)
x, y, z: 6, 18, 19
x^2 + y^2, z^2-1: 360, 360
valid (does not contain a prime of form
4k + 3 with an odd power)
z: 33, primes: {17: 1, 2: 6}
prime square decomposition: [4 + I, 8]
complex conjugates: 32 + 8*I
x, y, z: 32, 8, 33
x^2 + y^2, z^2-1: 1088, 1088
valid (does not contain a prime of form
4k + 3 with an odd power)
z: 35, primes: {17: 1, 2: 3, 3: 2}
prime square decomposition: [4 + I, 2 + 2*I, 3]
complex conjugates: 3*(2 + 2*I)*(4 + I)
x, y, z: 18, 30, 35
x^2 + y^2, z^2-1: 1224, 1224
Here is a simple improvement in Python (converting to the faster equivalent in C-based code is left as an exercise for the reader). To get accurate timing for the computation, I removed printing the solutions themselves (after validating them in a previous run).
Use an outer loop for one free variable (I chose z), constrained only by its relation to N.
Use an inner loop (I chose y) constrained by the outer loop index.
The third variable is directly computed per requirement 2.
Timing results:
-------------------- 10
1 solutions found in 2.3365020751953125e-05 sec.
-------------------- 100
6 solutions found in 0.00040078163146972656 sec.
-------------------- 1000
55 solutions found in 0.030081748962402344 sec.
-------------------- 10000
543 solutions found in 2.2078349590301514 sec.
-------------------- 100000
5512 solutions found in 214.93411707878113 sec.
That's 3:35 for the large case, plus your time to collate and/or print the results.
If you need faster code (this is still pretty brute-force), look into Diophantine equations and parameterizations to generate (y, x) pairs, given the target value of z^2 - 1.
import math
import time
def break3(N):
"""
10 <= N <= 10^5
return x, y, z triples such that:
x <= y <= z
x^2 + y^2 = z^2 - 1
x + y + z <= N
"""
"""
Observations:
z <= x + y
z < N/2
"""
count = 0
z_limit = N // 2
for z in range(3, z_limit):
# Since y >= x, there's a lower bound on y
target = z*z - 1
ymin = int(math.sqrt(target/2))
for y in range(ymin, z):
# Given y and z, compute x.
# That's a solution iff x is integer.
x_target = target - y*y
x = int(math.sqrt(x_target))
if x*x == x_target and x+y+z <= N:
# print("solution", x, y, z)
count += 1
return count
test = [10, 100, 1000, 10**4, 10**5]
border = "-"*20
for case in test:
print(border, case)
start = time.time()
print(break3(case), "solutions found in", time.time() - start, "sec.")
The bounds of x and y are an important part of the problem. I personally went with this Wolfram Alpha query and checked the exact forms of the variables.
Thanks to #Bleep-Bloop and comments, a very elegant bound optimization was found, which is x < n and x <= y < n - x. The results are the same and the times are nearly identical.
Also, since the only possible values for x and y are positive even integers, we can reduce the amount of loop iterations by half.
To optimize even further, since we compute the upper bound of x, we build a list of all possible values for x and make the computation parallel. That saves a massive amount of time on higher values of N but it's a bit slower for smaller values because of the overhead of the parallelization.
Here's the final code:
Non-parallel version, with int values:
List<string> res = new List<string>();
int n2 = n * n;
double maxX = 0.5 * (2.0 * n - Math.Sqrt(2) * Math.Sqrt(n2 + 1));
for (int x = 2; x < maxX; x += 2)
{
int maxY = (int)Math.Floor((n2 - 2.0 * n * x - 1.0) / (2.0 * n - 2.0 * x));
for (int y = x; y <= maxY; y += 2)
{
int z2 = x * x + y * y + 1;
int z = (int)Math.Sqrt(z2);
if (z * z == z2 && x + y + z <= n)
res.Add(x + "," + y + "," + z);
}
}
Parallel version, with long values:
using System.Linq;
...
// Use ConcurrentBag for thread safety
ConcurrentBag<string> res = new ConcurrentBag<string>();
long n2 = n * n;
double maxX = 0.5 * (2.0 * n - Math.Sqrt(2) * Math.Sqrt(n2 + 1L));
// Build list to parallelize
int nbX = Convert.ToInt32(maxX);
List<int> xList = new List<int>();
for (int x = 2; x < maxX; x += 2)
xList.Add(x);
Parallel.ForEach(xList, x =>
{
int maxY = (int)Math.Floor((n2 - 2.0 * n * x - 1.0) / (2.0 * n - 2.0 * x));
for (long y = x; y <= maxY; y += 2)
{
long z2 = x * x + y * y + 1L;
long z = (long)Math.Sqrt(z2);
if (z * z == z2 && x + y + z <= n)
res.Add(x + "," + y + "," + z);
}
});
When ran individually on a i5-8400 CPU, I get these results:
N: 10; Solutions: 1;
Time elapsed: 0.03 ms (Not parallel, int)
N: 100; Solutions: 6;
Time elapsed: 0.05 ms (Not parallel, int)
N: 1000; Solutions: 55;
Time elapsed: 0.3 ms (Not parallel, int)
N: 10000; Solutions: 543;
Time elapsed: 13.1 ms (Not parallel, int)
N: 100000; Solutions: 5512;
Time elapsed: 849.4 ms (Parallel, long)
You must use long when N is greater than 36340, because when it's squared, it overflows an int's max value. Finally, the parallel version starts to get better than the simple one when N is around 23000, with ints.
No time to properly test it, but seemed to yield the same results as your code (at 100 -> 6 results and at 1000 -> 55 results).
With N=1000 a time of 2ms vs your 144ms also without List
and N=10000 a time of 28ms
var N = 1000;
var c = 0;
for (int x = 2; x < N; x+=2)
{
for (int y = x; y < (N - x); y+=2)
{
long z2 = x * x + y * y + 1;
int z = (int) Math.Sqrt(z2);
if (x + y + z > N)
break;
if (z * z == z2)
c++;
}
}
Console.WriteLine(c);
#include<iostream>
#include<math.h>
int main()
{
int N = 10000;
int c = 0;
for (int x = 2; x < N; x+=2)
{
for (int y = x; y < (N - x); y+=2)
{
auto z = sqrt(x * x + y * y + 1);
if(x+y+z>N){
break;
}
if (z - (int) z == 0)
{
c++;
}
}
}
std::cout<<c;
}
This is my solution. On testing the previous solutions for this problem I found that x,y are always even and z is odd. I dont know the mathematical nature behind this, I am currently trying to figure that out.
I want to get it done in C# and it should be covering all the test
cases based on condition provided in the question.
The basic code, converted to long to process the N <= 100000 upper limit, with every optimizaion thrown in I could. I used alternate forms from #Mat's (+1) Wolfram Alpha query to precompute as much as possible. I also did a minimal perfect square test to avoid millions of sqrt() calls at the upper limit:
public static void Main()
{
int c = 0;
long N = long.Parse(Console.ReadLine());
long N_squared = N * N;
double half_N_squared = N_squared / 2.0 - 0.5;
double x_limit = N - Math.Sqrt(2) / 2.0 * Math.Sqrt(N_squared + 1);
for (long x = 2; x < x_limit; x += 2)
{
long x_squared = x * x + 1;
double y_limit = (half_N_squared - N * x) / (N - x);
for (long y = x; y < y_limit; y += 2)
{
long z_squared = x_squared + y * y;
int digit = (int) z_squared % 10;
if (digit == 3 || digit == 7)
{
continue; // minimalist non-perfect square elimination
}
long z = (long) Math.Sqrt(z_squared);
if (z * z == z_squared)
{
c++;
}
}
}
Console.WriteLine(c);
}
I followed the trend and left out "the degenerate solution" as implied by the OP's code but not explicitly stated.
static void Main(string[] args)
{
Console.WriteLine("Enter your number: ");
int number= Convert.ToInt32(Console.ReadLine());
int number2 = Convert.ToInt32(Console.ReadLine());
double factorial = Factorial(number,number2);
Console.WriteLine("Factorial of " + number +" / "+ number2 + " = " + factorial );
Console.ReadKey();
}
//Factorial function added
public static double Factorial(int number, int number2)
{
if (number == 1 && number2 ==1 )
{
return 1;
}
double factorial = 1;
double factorial1 = 1;
double factorial2 = 1;
for (int i = number, j = number2; i >= 1 && j >= 1; i--, j--)
{
factorial1 = (factorial * i);
factorial2 = (factorial * j);
factorial = factorial1 / factorial2;
}
return factorial;
}
Your attempted solution is simply so overcomplicated, I wouldn't know where to begin. This usually happens when you don't stop to think about how you'd resolve this problem by hand:
So, the question is, whats 5!/3!? Ok, lets write it out:
(5 * 4 * 3 * 2 * 1) / (3 * 2 * 1)
Wow, that looks like it can be simplified simply to 5 * 4.
The key insight here is that m! % n! = 0 if n is less or equal to m. In other words, m! is always divisible by n! because there is always an integer r such that r * n! = m!, and you don't need to evaluate m! or n! to figure out what r is, you simple do:
r = m * (m - 1) * (m - 2) * ... * (n + 1); // m >= n
If n > m, r is zero unless you are looking for a real number solution in which case you would simply evaluate r as n! / m! and then return 1.0 / r because m! / n! = 1 / (n! / m!).
How to evaluate r?
public static long DivideFactorials(int m, int n)
{
if (n > m)
return 0;
var r = 1L;
for (var k = m; k > n; k--)
r *= k;
return r;
}
Or the real number solution:
public static double DivideFactorials(int m, int n)
{
if (n > m)
return 1 / DivideFactorials(n, m);
var r = 1.0;
for (var k = m; k > n; k--)
r *= k;
return r;
}
If I had to save your try:
public static double Factorial(int number, int number2)
{
if (number == 1 && number2 == 1)
{
return 1;
}
double facNum = 1;
double facNum2 = 1;
// counting up is easier, we start at 2 as we initialized to 1
// we count up to the max of both numbers
for (int i = 2; i <= Math.Max(number, number2); i++)
{
if (i <= number)
facNum *= i; // we mult this until we reached number
if (i <= number2)
facNum2 *= i; // we mult this until we reach number2
}
// return the devision of both - this wont handle number < number2 well!
return facNum / facNum2; // do this outside the loop
}
If I had to create a solution:
Factorial division of integers has 3 outcomes (I can think of):
N! / O! with N == O:
let N=3, O=3
N! = 1*2*3
O! = 1*2*3
N! / O! = 1*2*3/(1*2*3) == 1
N! / O! with N > O:
let N=5, O=3
N! = 1*2*3*4*5
O! = 1*2*3
N! / O! == 1*2*3*4*5/(1*2*3) == 4*5 == 20
N! / O! with N < O:
let N=3, O=5
N! = 1*2*3
O! = 1*2*3*4*5
N! / O! == 1*2*3/(1*2*3*4*5) == 1/(4*5) == 1/20
Based on this I would model the problem like that:
using System;
using System.Collections.Generic;
using System.Linq;
internal class Program
{
public static decimal CalcFactDivision(int n1, int n2)
{
// calclulate the division of a factorial by another, num1 must be >= num2
IEnumerable<int> getRemaining(int num1, int num2)
{
// special cases: div by 0 and 0 div something
if (num2 == 0)
num2 = 1; // 0! == 1
else if (num1 == 0)
return new[] { 0 };
// get all numbers that make up the factorial in one step
// I can guarantee that num1 will always be bigger then num2
// by how I call this
return Enumerable.Range(num2 + 1, num1 - num2);
}
// calculate the product of an ienumerable of ints
int product(IEnumerable<int> nums) => nums.Aggregate((a, b) => a * b);
if (n1 == n2)
return 1;
else if (n1 > n2) // use product(...) to calc
return product(getRemaining(n1, n2));
else // flip them and use 1/product(...) to calc
return (decimal)1 / product(getRemaining(n2, n1));
}
static void Main(string[] args)
{
foreach (var a in Enumerable.Range(1, 10))
Console.WriteLine($"{a}! / {10 - a}! = {CalcFactDivision(a, 10 - a)} ");
Console.ReadLine();
}
}
Output:
1! / 9! = 0,0000027557319223985890652557
2! / 8! = 0,0000496031746031746031746032
3! / 7! = 0,0011904761904761904761904762
4! / 6! = 0,0333333333333333333333333333
5! / 5! = 1
6! / 4! = 30
7! / 3! = 840
8! / 2! = 20160
9! / 1! = 362880
10! / 0! = 3628800
In reference to the widely used CalculateRamp code at:
Changing image contrast with GDI+ and C#
public static void CalculateRamp(double level, double gamma, double brightness, double contrast)
{
ramp.Red = new ushort[256];
ramp.Green = new ushort[256];
ramp.Blue = new ushort[256];
gamma /= 10;
brightness = 1 + (((brightness - 50) / 100) * 65535);
contrast = 1 + ((contrast - 50) / 100);
level = 1 + ((level - 50) / 100);
for (int i = 0; i < 256; i++)
{
double value = i * 256;
value = (Math.Pow(value / 65535, 1 / gamma) * 65535) + 0.5;
value = ((((value / 65535) - 0.5) * contrast) + 0.5) * 65535;
value = value += brightness;
value *= level;
ramp.Red[i] = ramp.Green[i] = ramp.Blue[i] = (ushort)Math.Min((double)65535, Math.Max((double)0, value));
}
SetDeviceGammaRamp(GetDC(IntPtr.Zero), ref ramp);
}
How would you calculate the input values (arguments) for this method directly from the existing Gamma Ramp? In other words, what would be the reverse method?
If I am going to provide these utilities to the user, I need to present them with their current settings prior to their making the adjustments.
I have tried for three days to come up with a solution, and must admit that this is beyond my capabilities.
Update Sept 8, 2016 - My best solution...
While I worked long and hard looking for a mathematical solution, I finally went back and played around with the iteration method.
A blunt force iteration that calculates each and every possible setting and then checks for a match will run for more than 20 minutes; which is unacceptable.
I found that I could take a single sample point in the middle of the array and quickly iterate through all possible settings to find a match for that one sample; and then perform all 256 of the calculations for the array to see if we had a complete match. This operation generally runs in less than a second.
But I realized that there was yet another problem. If the Gamma Ramp was not programmed using the CalculateRamp algorithm (such as factory setting) then it is unlikely that we will find an exact match for our settings; and our solution will fail.
So I devised a backup plan that uses four sample points from across the gamma ramp array; and then set up a "span" of acceptable values that would provide a close approximation for our settings. The criteria for "span" would broaden after each failure, and re-enter the search. This scenario will produce an approximation of the Gamma Ramp Settings usually within about three seconds. This is acceptable since my main program can perform this operation during the program startup sequence.
Here is my C++ solution...
//---------------------------------------------------------------------------
int __fastcall TForm1::Round( double flt ){
int num = (int) flt;
if( flt >= 0 ){
if( flt - num >= .5 ){ num++;}
}else{
if( flt - num <= -.5 ){ num--;}
}
return( num );
}
//----------------------------------------------------------------------------
void __fastcall TForm1::GetGammaRampSettings(void){
// level should be between 2 and 100
// gamma should be between 2 and 50
// brigntess should be between 0 and 100
// contrast should be between 0 and 100
double i,j,k,m;
double gamma,bright,cntrst,level;
double v1,v2,v3,v4;
double c1,c2,c3,c4;
double a1,a2,a3,a4,b1,b2,b3,b4; //for best estimate criteria
int x1,x2,x3,x4,x5;
int d,n;
WORD span = 8;
bool tog = false;
TDateTime strt, end;
WORD GammaArray[3][256]; //Gamma Ramp Array buffer
WORD CompArray[256]; //Array buffer for comparison
HDC GammaDC = GetDC( NULL ); //fetch the gamma ramp array
GetDeviceGammaRamp( GammaDC, GammaArray );
ReleaseDC( NULL, GammaDC );
strt=Now();
//Find two endpoints for the GammaArray
for( x1 = 0; x1 < 256; x1++ ){
if( GammaArray[0][x1] > 0 ){ break;}
}
for( x2 = 0; x2 < 256; x2++ ){
if( GammaArray[0][x2] == 65535 ){ break;}
}
if( x2 == 256 ){ x2 = 255; }
x5 = x1 + Round( (double)( x2 - x1 ) / 2.0 );
Memo1->Lines->Add( "x1 = " + IntToStr( x1 )); //start
Memo1->Lines->Add( "x2 = " + IntToStr( x2 )); //end
Memo1->Lines->Add( "x5 = " + IntToStr( x5 )); //mid
//neutral settings are as follows...
//Bright = 50
//Contrast = 50
//Level = 50
//Gamma = 10
//The following code will look for an exact match to the settings
//but it may fail if the gamma ramp was not programmed using the
//original CalculateRamp code. ie: A factory setting, or other
for(n=0;n<=40;){//gamma
if( n < 9 ){ //gamma begins with a neutral setting of 10 and
if( tog ){ //then increments high and low depending on tog
i = ( 10 - n );
tog = false; n++;
if( i == 10 ){ continue;}
}else{
i = ( 10 + n );
tog = true;
}
}else{
i = ( 10 + n++ );
}
gamma = i / 10;
v1 = ( pow( (double)(x5 * 256) / 65535, 1 / gamma) * 65535) + 0.5;
for( j = 2; j < 101 ; j++ ){//level //980,000 possible iterations
level = 1 + ((j - 50) / 100);
for( k = 0; k < 101; k++ ){//bright
bright = 1 + (((k - 50) / 100) * 65535);
for( m = 0; m < 101; m++ ){//contrast
cntrst = 1 + ((m - 50) / 100);
//Test only the mid-line value at first
//To see if a complete comparison is warranted
c1 = (((( v1 / 65535 ) - 0.5) * cntrst) + 0.5) * 65535;
c1 = c1 += bright;
c1 *= level;
if( c1 > 65535){ c1 = 65535; }
if( c1 < 0 ){ c1 = 0; }
if( (WORD) c1 == GammaArray[0][x5] ){
for( d = 0; d < 256; d++ ){
c1 = ( pow( (double)(d * 256) / 65535, 1 / gamma) * 65535) + 0.5;
c1 = ((( (c1 / 65535) - 0.5) * cntrst) + 0.5) * 65535;
c1 = c1 += bright;
c1 *= level;
if( c1 > 65535 ){ c1 = 65535;}
if( c1 < 0 ){ c1 = 0;}
CompArray[d] = (WORD) c1;
}
if(memcmp( &CompArray[0], &GammaArray[0][0], 2*256) == 0){
goto ENDIT;
}
}
}
}
}
}
//Since an exact match could not be found for the current
//gamma ramp settings, we will broaden our criteria and
//search for the best match for our gamma ramp settings.
//Here our search is based on the start and end values,
//plus two additional values that are 1/4 of the overall distance
//above the start point; and 1/4 the distance below the end point.
Memo1->Lines->Add("Values NOT Discovered!!!");
Memo1->Lines->Add("Widening the Search....");
x3 = x1 + Round( (double)( x2 - x1 ) / 4.0 );
x4 = x1 + Round(( (double)( x2 - x1 ) / 4.0 )*3);
Memo1->Lines->Add( "x1 = " + IntToStr( x1 )); //start
Memo1->Lines->Add( "x2 = " + IntToStr( x2 )); //end
Memo1->Lines->Add( "x3 = " + IntToStr( x3 )); // 1/4
Memo1->Lines->Add( "x4 = " + IntToStr( x4 )); // 3/4
BROADEN:
a1 = GammaArray[0][x1]+span; //these are our high and low
b1 = GammaArray[0][x1]-span; //values that the ramp values must
//fall within to be accepted
a2 = GammaArray[0][x2]+span;
b2 = GammaArray[0][x2]-span; //span begins at 8 and increments upwards
//with each loop, ever widening the
a3 = GammaArray[0][x3]+span; //the search criteria
b3 = GammaArray[0][x3]-span;
a4 = GammaArray[0][x4]+span;
b4 = GammaArray[0][x4]-span;
tog=false;
for(n=0;n<=40;){//gamma
if( n < 9 ){ //gamma begins with a neutral setting of 10 and
if( tog ){ //then increments high and low depending on tog
i = ( 10 - n );
tog = false; n++;
if( i == 10 ){ continue;} //prevents two instances of i == 10
}else{
i = ( 10 + n );
tog = true;
}
}else{
i = ( 10 + n++ );
}
gamma = i / 10;
v1 = ( pow( (double)(x1 * 256) / 65535, 1 / gamma) * 65535) + 0.5;
v2 = ( pow( (double)(x2 * 256) / 65535, 1 / gamma) * 65535) + 0.5;
v3 = ( pow( (double)(x3 * 256) / 65535, 1 / gamma) * 65535) + 0.5;
v4 = ( pow( (double)(x4 * 256) / 65535, 1 / gamma) * 65535) + 0.5;
for( j = 2; j < 101 ; j++ ){//level //980,000 possible iterations
level = 1 + ((j - 50) / 100);
for( k = 0; k < 101; k++ ){//bright
bright = 1 + (((k - 50) / 100) * 65535);
for( m = 0; m < 101; m++ ){//contrast
cntrst = 1 + ((m - 50) / 100);
//Test the four sample values to see if the
//results falls within our acceptance criteria.
c1 = (((( v1 / 65535 ) - 0.5) * cntrst) + 0.5) * 65535;
c1 = c1 += bright;
c1 *= level;
c2 = (((( v2 / 65535 ) - 0.5) * cntrst) + 0.5) * 65535;
c2 = c2 += bright;
c2 *= level;
c3 = (((( v3 / 65535 ) - 0.5) * cntrst) + 0.5) * 65535;
c3 = c3 += bright;
c3 *= level;
c4 = (((( v4 / 65535 ) - 0.5) * cntrst) + 0.5) * 65535;
c4 = c4 += bright;
c4 *= level;
if( c1 <= a1 && c1 >= b1 && c2 <= a2 && c2 >= b2 &&
c3 <= a3 && c3 >= b3 && c4 <= a4 && c4 >= b4 ){
Memo1->Lines->Add("Best Estimate +/- " + IntToStr( span ));
goto ENDIT;
}
}
}
}
}
if( span < 256){
span *= 2;
goto BROADEN;
}else if( span <= 4096 ){ //set the maximum allowance for "span"
span += 128; //which is the basis for the allowable
goto BROADEN; //search criteria
}
//if we get to this point then we have utterly failed.
Memo1->Lines->Add("Values STILL NOT Discovered.");
Memo1->Lines->Add("GetGammaRampSettings Failed.");
return;
ENDIT:
end=Now();
Memo1->Lines->Add("Execution duration was "+
FormatDateTime("nn:ss:zzz",end-strt));
//Report on findings...
Memo1->Lines->Add("Bright = " + IntToStr( (int) k ));
Memo1->Lines->Add("Cntrst = " + IntToStr( (int) m ));
Memo1->Lines->Add("Level = " + IntToStr( (int) j ));
Memo1->Lines->Add("Gamma = " + IntToStr( (int) i ));
}
//---------------------------------------------------------------------------
I apologize for the simplicity of this question, it's just past 3AM and I can't think :)
I need to get a random number n between 0.25 and 10.0, however I need P( 0.25 <= n < 1.0 ) == P( 1.0 < n <= 10.0 ) && n != 1.0.
Right now my current code is biased towards 1.0 <= n <= 10.0 like so:
Double n = new Random().NextDouble(); // 0 <= n <= 1.0
n = 0.25 + (10.0 * n);
Of course this also has a bug where n == 10.25 if n = 1.0 initially.
Ta!
If I understand correctly, you want this:
var random = new Random();
Double n1 = random.NextDouble(); // 0 <= n < 1.0
Double n = random.NextDouble(); // 0 <= n < 1.0
if (n1 < 0.5)
n = 0.25 + 0.75 * n; // 0.25 <= n < 1.0
else
n = 10.0 - 9.0 * n; // 1 < n <= 10
This function should work:
double GetRandomValue(Random rand)
{
return rand.Next(0, 2) == 0
? 0.25 + 0.75 * rand.NextDouble()
: 10.0 - 9.0 * rand.NextDouble();
}
First random value selects whether you should use values below or above 1. For values above 1, you wanted to include 10.0 in the range, hence the subtraction.
I think this is it.
Double n = new Random().NextDouble();
n = n < 0.5? (0.25 + (0.75 * n * 2)) : 1.0 + double.Epsilon + (9.0 * n * 2);
The double.Epsilon ensures you don't get n=1.0 since NextDouble() produces 0 <= n < 1.0.
Double n = new Random().NextDouble(); // 0 <= n <= 1.0
Double extremlySmallValue = 0.00000001;
n *= 9.75; // 0 <= n <= 9.75
n += 0.25; // 0.25 <= n <= 10.0
//few ifs now:
if(n == 10.0)
n -= extremlySmallValue;
else if (n==1.0)
n += extremlySmallValue;
Its not perfect linear distribution, but i think its acceptable, because Random does not provide perfect linear distribution too.. You can also make another NextDouble() when you get 1.0 or 10.0
You don't say what distribution you want within each range, however, assuming you want uniformity, just linearly map the bottom half of NextDouble's range to your lower range, and the top half to the top range.
However, there's a little thought required with getting the half-openness of your target intervals right. NextDouble returns a double in [0, 1) (that is, lower-inclusive and upper-exclusive). We can split this in half to [0, 0.5) and [0.5, 1) but then since your required upper range is (1, 10], we should flip the upper range during the transform.
var n = myRandom.NextDouble();
if (n < 0.5)
{
// Map from [0, 0.5) to [0.25, 1.0)
return 0.25 + (n * 1.5);
}
else
{
// Map from [0.5, 1.0) to (1.0, 10] by reversing the input range
var flipped = 1.0 - n;
// Now flipped is in [0.5, 0), which is to say (0, 0.5]
// So scale up by 18 times to get a value in (0, 9], and shift
return 1 + (flipped * 18);
}
Trying to find functions that will assist us to draw a 3D line through a series of points.
For each point we know: Date&Time, Latitude, Longitude, Altitude, Speed and Heading.
Data might be recorded every 10 seconds and we would like to be able to guestimate the points in between and increase granularity to 1 second. Thus creating a virtual flight path in 3D space.
I have found a number of curve fitting algorithms that will approximate a line through a series of points but they do not guarantee that the points are intersected. They also do not take into account speed and heading to determine the most likely path taken by the object to reach the next point.
From a physics viewpoint:
You have to assume something about the acceleration in your intermediate points to get the interpolation.
If your physical system is relatively well-behaved (as a car or a plane), as opposed to for example a bouncing ball, you may go ahead supposing an acceleration varying linearly with time between your points.
The vector equation for a constant varying accelerated movement is:
x''[t] = a t + b
where all magnitudes except t are vectors.
For each segment you already know v(t=t0) x(t=t0) tfinal and x(tfinal) v(tfinal)
By solving the differential equation you get:
Eq 1:
x[t_] := (3 b t^2 Tf + a t^3 Tf - 3 b t Tf^2 - a t Tf^3 - 6 t X0 + 6 Tf X0 + 6 t Xf)/(6 Tf)
And imposing the initial and final contraints for position and velocity you get:
Eqs 2:
a -> (6 (Tf^2 V0 - 2 T0 Tf Vf + Tf^2 Vf - 2 T0 X0 + 2 Tf X0 +
2 T0 Xf - 2 Tf Xf))/(Tf^2 (3 T0^2 - 4 T0 Tf + Tf^2))
b -> (2 (-2 Tf^3 V0 + 3 T0^2 Tf Vf - Tf^3 Vf + 3 T0^2 X0 -
3 Tf^2 X0 - 3 T0^2 Xf + 3 Tf^2 Xf))/(Tf^2 (3 T0^2 - 4 T0 Tf + Tf^2))}}
So inserting the values for eqs 2 into eq 1 you get the temporal interpolation for your points, based on the initial and final position and velocities.
HTH!
Edit
A few examples with abrupt velocity change in two dimensions (in 3D is exactly the same). If the initial and final speeds are similar, you'll get "straighter" paths.
Suppose:
X0 = {0, 0}; Xf = {1, 1};
T0 = 0; Tf = 1;
If
V0 = {0, 1}; Vf = {-1, 3};
V0 = {0, 1}; Vf = {-1, 5};
V0 = {0, 1}; Vf = {1, 3};
Here is an animation where you may see the speed changing from V0 = {0, 1} to Vf = {1, 5}:
Here you may see an accelerating body in 3D with positions taken at equal intervals:
Edit
A full problem:
For convenience, I'll work in Cartesian coordinates. If you want to convert from lat/log/alt to Cartesian just do:
x = rho sin(theta) cos(phi)
y = rho sin(theta) sin(phi)
z = rho cos(theta)
Where phi is the longitude, theta is the latitude, and rho is your altitude plus the radius of the Earth.
So suppose we start our segment at:
t=0 with coordinates (0,0,0) and velocity (1,0,0)
and end at
t=10 with coordinates (10,10,10) and velocity (0,0,1)
I clearly made a change in the origin of coordinates to set the origin at my start point. That is just for getting nice round numbers ...
So we replace those numbers in the formulas for a and b and get:
a = {-(3/50), -(3/25), -(3/50)} b = {1/5, 3/5, 2/5}
With those we go to eq 1, and the position of the object is given by:
p[t] = {1/60 (60 t + 6 t^2 - (3 t^3)/5),
1/60 (18 t^2 - (6 t^3)/5),
1/60 (12 t^2 - (3 t^3)/5)}
And that is it. You get the position from 1 to 10 secs replacing t by its valus in the equation above.
The animation runs:
Edit 2
If you don't want to mess with the vertical acceleration (perhaps because your "speedometer" doesn't read it), you could just assign a constant speed to the z axis (there is a very minor error for considering it parallel to the Rho axis), equal to (Zfinal - Zinit)/(Tf-T0), and then solve the problem in the plane forgetting the altitude.
What you're asking is a general interpolation problem. My guess is your actual problem isn't due to the curve-fitting algorithm being used, but rather your application of it to all discrete values recorded by the system instead of the relevant set of values.
Let's decompose your problem. You're currently drawing a point in spherically-mapped 3D space, adjusting for linear and curved paths. If we discretize the operations performed by an object with six degrees of freedom (roll, pitch, and yaw), the only operations you're particularly interested in are linear paths and curved paths accounting for pitch and yaw in any direction. Accounting for acceleration and deceleration also possible given understanding of basic physics.
Dealing with the spherical mapping is easy. Simply unwrap your points relative to their position on a plane, adjusting for latitude, longitude, and altitude. This should allow you to flatten data that would otherwise exist along a curved path, though this may not strictly be necessary for the solutions to your problem (see below).
Linear interpolation is easy. Given an arbitrary number of points backwards in time that fit a line within n error as determined by your system,* construct the line and compute the distance in time between each point. From here, attempt to fit the time points to one of two cases: constant velocity or constant acceleration.
Curve interpolation is a little more difficult, but still plausible. For cases of pitch, yaw, or combined pitch+yaw, construct a plane containing an arbitrary number of points backwards in time, within m error for curved readouts from your system.* From these data, construct a planar curve and once again account for constant velocity or acceleration along the curve.
You can do better than this by attempting to predict the expected operations of a plane in flight as part of a decision tree or neural network relative to the flight path. I'll leave that as an exercise for the reader.
Best of luck designing your system.
--
* Both error readouts are expected to be from GPS data, given the description of the problem. Accounting and adjusting for errors in these data is a separate interesting problem.
What you need (instead of modeling the physics) is to fit a spline through the data. I used a numerical recipies book (http://www.nrbook.com/a has free C and FORTRAN algorithms. Look into F77 section 3.3 to get the math needed). If you want to be simple then just fit lines through the points, but that will not result in a smooth flight path at all. Time will be your x value, and each parameter loged will have it's own cublic spline parameters.
Since we like long postings for this question here is the full code:
//driver program
static void Main(string[] args)
{
double[][] flight_data = new double[][] {
new double[] { 0, 10, 20, 30 }, // time in seconds
new double[] { 14500, 14750, 15000, 15125 }, //altitude in ft
new double[] { 440, 425, 415, 410 }, // speed in knots
};
CubicSpline altitude = new CubicSpline(flight_data[0], flight_data[1]);
CubicSpline speed = new CubicSpline(flight_data[0], flight_data[2]);
double t = 22; //Find values at t
double h = altitude.GetY(t);
double v = speed.GetY(t);
double ascent = altitude.GetYp(t); // ascent rate in ft/s
}
// Cubic spline definition
using System.Linq;
/// <summary>
/// Cubic spline interpolation for tabular data
/// </summary>
/// <remarks>
/// Adapted from numerical recipies for FORTRAN 77
/// (ISBN 0-521-43064-X), page 110, section 3.3.
/// Function spline(x,y,yp1,ypn,y2) converted to
/// C# by jalexiou, 27 November 2007.
/// Spline integration added also Nov 2007.
/// </remarks>
public class CubicSpline
{
double[] xi;
double[] yi;
double[] yp;
double[] ypp;
double[] yppp;
double[] iy;
#region Constructors
public CubicSpline(double x_min, double x_max, double[] y)
: this(Sequence(x_min, x_max, y.Length), y)
{ }
public CubicSpline(double x_min, double x_max, double[] y, double yp1, double ypn)
: this(Sequence(x_min, x_max, y.Length), y, yp1, ypn)
{ }
public CubicSpline(double[] x, double[] y)
: this(x, y, double.NaN, double.NaN)
{ }
public CubicSpline(double[] x, double[] y, double yp1, double ypn)
{
if( x.Length == y.Length )
{
int N = x.Length;
xi = new double[N];
yi = new double[N];
x.CopyTo(xi, 0);
y.CopyTo(yi, 0);
if( N > 0 )
{
double p, qn, sig, un;
ypp = new double[N];
double[] u = new double[N];
if( double.IsNaN(yp1) )
{
ypp[0] = 0;
u[0] = 0;
}
else
{
ypp[0] = -0.5;
u[0] = (3 / (xi[1] - xi[0])) *
((yi[1] - yi[0]) / (x[1] - x[0]) - yp1);
}
for (int i = 1; i < N-1; i++)
{
double hp = x[i] - x[i - 1];
double hn = x[i + 1] - x[i];
sig = hp / hn;
p = sig * ypp[i - 1] + 2.0;
ypp[i] = (sig - 1.0) / p;
u[i] = (6 * ((y[i + 1] - y[i]) / hn) - (y[i] - y[i - 1]) / hp)
/ (hp + hn) - sig * u[i - 1] / p;
}
if( double.IsNaN(ypn) )
{
qn = 0;
un = 0;
}
else
{
qn = 0.5;
un = (3 / (x[N - 1] - x[N - 2])) *
(ypn - (y[N - 1] - y[N - 2]) / (x[N - 1] - x[N - 2]));
}
ypp[N - 1] = (un - qn * u[N - 2]) / (qn * ypp[N - 2] + 1.0);
for (int k = N-2; k > 0; k--)
{
ypp[k] = ypp[k] * ypp[k + 1] + u[k];
}
// Calculate 1st derivatives
yp = new double[N];
double h;
for( int i = 0; i < N - 1; i++ )
{
h = xi[i + 1] - xi[i];
yp[i] = (yi[i + 1] - yi[i]) / h
- h / 6 * (ypp[i + 1] + 2 * ypp[i]);
}
h = xi[N - 1] - xi[N - 2];
yp[N - 1] = (yi[N - 1] - yi[N - 2]) / h
+ h / 6 * (2 * ypp[N - 1] + ypp[N - 2]);
// Calculate 3rd derivatives as average of dYpp/dx
yppp = new double[N];
double[] jerk_ij = new double[N - 1];
for( int i = 0; i < N - 1; i++ )
{
h = xi[i + 1] - xi[i];
jerk_ij[i] = (ypp[i + 1] - ypp[i]) / h;
}
Yppp = new double[N];
yppp[0] = jerk_ij[0];
for( int i = 1; i < N - 1; i++ )
{
yppp[i] = 0.5 * (jerk_ij[i - 1] + jerk_ij[i]);
}
yppp[N - 1] = jerk_ij[N - 2];
// Calculate Integral over areas
iy = new double[N];
yi[0] = 0; //Integration constant
for( int i = 0; i < N - 1; i++ )
{
h = xi[i + 1] - xi[i];
iy[i + 1] = h * (yi[i + 1] + yi[i]) / 2
- h * h * h / 24 * (ypp[i + 1] + ypp[i]);
}
}
else
{
yp = new double[0];
ypp = new double[0];
yppp = new double[0];
iy = new double[0];
}
}
else
throw new IndexOutOfRangeException();
}
#endregion
#region Actions/Functions
public int IndexOf(double x)
{
//Use bisection to find index
int i1 = -1;
int i2 = Xi.Length;
int im;
double x1 = Xi[0];
double xn = Xi[Xi.Length - 1];
bool ascending = (xn >= x1);
while( i2 - i1 > 1 )
{
im = (i1 + i2) / 2;
double xm = Xi[im];
if( ascending & (x >= Xi[im]) ) { i1 = im; } else { i2 = im; }
}
if( (ascending && (x <= x1)) || (!ascending & (x >= x1)) )
{
return 0;
}
else if( (ascending && (x >= xn)) || (!ascending && (x <= xn)) )
{
return Xi.Length - 1;
}
else
{
return i1;
}
}
public double GetIntY(double x)
{
int i = IndexOf(x);
double x1 = xi[i];
double x2 = xi[i + 1];
double y1 = yi[i];
double y2 = yi[i + 1];
double y1pp = ypp[i];
double y2pp = ypp[i + 1];
double h = x2 - x1;
double h2 = h * h;
double a = (x-x1)/h;
double a2 = a*a;
return h / 6 * (3 * a * (2 - a) * y1
+ 3 * a2 * y2 - a2 * h2 * (a2 - 4 * a + 4) / 4 * y1pp
+ a2 * h2 * (a2 - 2) / 4 * y2pp);
}
public double GetY(double x)
{
int i = IndexOf(x);
double x1 = xi[i];
double x2 = xi[i + 1];
double y1 = yi[i];
double y2 = yi[i + 1];
double y1pp = ypp[i];
double y2pp = ypp[i + 1];
double h = x2 - x1;
double h2 = h * h;
double A = 1 - (x - x1) / (x2 - x1);
double B = 1 - A;
return A * y1 + B * y2 + h2 / 6 * (A * (A * A - 1) * y1pp
+ B * (B * B - 1) * y2pp);
}
public double GetYp(double x)
{
int i = IndexOf(x);
double x1 = xi[i];
double x2 = xi[i + 1];
double y1 = yi[i];
double y2 = yi[i + 1];
double y1pp = ypp[i];
double y2pp = ypp[i + 1];
double h = x2 - x1;
double A = 1 - (x - x1) / (x2 - x1);
double B = 1 - A;
return (y2 - y1) / h + h / 6 * (y2pp * (3 * B * B - 1)
- y1pp * (3 * A * A - 1));
}
public double GetYpp(double x)
{
int i = IndexOf(x);
double x1 = xi[i];
double x2 = xi[i + 1];
double y1pp = ypp[i];
double y2pp = ypp[i + 1];
double h = x2 - x1;
double A = 1 - (x - x1) / (x2 - x1);
double B = 1 - A;
return A * y1pp + B * y2pp;
}
public double GetYppp(double x)
{
int i = IndexOf(x);
double x1 = xi[i];
double x2 = xi[i + 1];
double y1pp = ypp[i];
double y2pp = ypp[i + 1];
double h = x2 - x1;
return (y2pp - y1pp) / h;
}
public double Integrate(double from_x, double to_x)
{
if( to_x < from_x ) { return -Integrate(to_x, from_x); }
int i = IndexOf(from_x);
int j = IndexOf(to_x);
double x1 = xi[i];
double xn = xi[j];
double z = GetIntY(to_x) - GetIntY(from_x); // go to nearest nodes (k) (j)
for( int k = i + 1; k <= j; k++ )
{
z += iy[k]; // fill-in areas in-between
}
return z;
}
#endregion
#region Properties
public bool IsEmpty { get { return xi.Length == 0; } }
public double[] Xi { get { return xi; } set { xi = value; } }
public double[] Yi { get { return yi; } set { yi = value; } }
public double[] Yp { get { return yp; } set { yp = value; } }
public double[] Ypp { get { return ypp; } set { ypp = value; } }
public double[] Yppp { get { return yppp; } set { yppp = value; } }
public double[] IntY { get { return yp; } set { iy = value; } }
public int Count { get { return xi.Length; } }
public double X_min { get { return xi.Min(); } }
public double X_max { get { return xi.Max(); } }
public double Y_min { get { return yi.Min(); } }
public double Y_max { get { return yi.Max(); } }
#endregion
#region Helpers
static double[] Sequence(double x_min, double x_max, int double_of_points)
{
double[] res = new double[double_of_points];
for (int i = 0; i < double_of_points; i++)
{
res[i] = x_min + (double)i / (double)(double_of_points - 1) * (x_max - x_min);
}
return res;
}
#endregion
}
You can find an approximation of a line that intersects points in 3d and 2d space using a Hough Transformation algorithm. I am only familiar with it's uses in 2d however but it will still work for 3d spaces given that you know what kind of line you are looking for. There is a basic implementation description linked. You can Google for pre-mades and here is a link to a 2d C implementation CImg.
The algorithm process (roughly)... First you find equation of a line that you think will best approximate the shape of the line (in 2d parabolic, logarithmic, exponential, etc). You take that formula and solve for one of the parameters.
y = ax + b
becomes
b = y - ax
Next, for each point you are attempting to match, you plugin the points to the y and x values. With 3 points, you would have 3 separate functions of b with respect to a.
(2, 3) : b = 3 - 2a
(4, 1) : b = 1 - 4a
(10, -5): b = -5 - 10a
Next, the theory is that you find all possible lines which pass through each of the points, which is infinitely many for each individual point however when combined in an accumulator space only a few possible parameters best fit. In practice this is done by choosing a range space for the parameters (I chose -2 <= a <= 1, 1 <= b <= 6) and begin plugging in values for the variant parameter(s) and solving for the other. You tally up the number of intersections from each function in an accumulator. The points with the highest values give you your parameters.
Accumulator after processing b = 3 - 2a
a: -2 -1 0 1
b: 1
2
3 1
4
5 1
6
Accumulator after processing b = 1 - 4a
a: -2 -1 0 1
b: 1 1
2
3 1
4
4
5 2
6
Accumulator after processing b = -5 - 10a
a: -2 -1 0 1
b: 1 1
2
3 1
4
5 3
6
The parameter set with the highest accumulated value is (b a) = (5 -1) and the function best fit to the points given is y = 5 - x.
Best of luck.
My guess is that a serious application of this would use a http://en.wikipedia.org/wiki/Kalman_filter. By the way, that probably wouldn't guarantee that the reported points were intersected either, unless you fiddled with the parameters a bit. It would expect some degree of error in each data point given to it, so where it thinks the object is at time T would not necessarily be where it was at time T. Of course, you could set the error distribution to say that you were absolutely sure you knew where it was at time T.
Short of using a Kalman filter, I would try and turn it into an optimisation problem. Work at the 1s granularity and write down equations like
x_t' = x_t + (Vx_t + Vx_t')/2 + e,
Vx_t_reported = Vx_t + f,
Vx_t' = Vx_t + g
where e, f, and g represent the noise. Then create a penalty function such as e^2 + f^2 + g^2 +...
or some weighted version such as 1.5e^2 + 3f^2 + 2.6g^2 +... according to your idea of what the errors really are and how smooth you wnat the answer to be, and find the values that make the penalty function as small as possible - with least squares if the equations turn out nicely.