Gdzie pójdzie kot? (mechanika orbitalna)

16

Prawie bezmasowy kot upuszczany jest w przestrzeń (nie martw się, z skafandrem i wszystkim) w punkcie (x, y, z)z prędkością (vx, vy, vz). W tym punkcie znajduje się stała, nieskończenie gęsta planeta (o objętości 0) (0, 0, 0)i przyciąga obiekty z odległości rz przyspieszeniem 1/r^2. Zgodnie z grawitacją Newtona, dokąd obiekt zmierza po czasie t?

Prawie bezmasowa w tym przypadku oznacza, że ​​wyprowadzasz wartość lim (mass --> 0) <position of cat>. Na masę ma wpływ grawitacja planety, ale grawitacja kota nie ma wpływu na planetę. Innymi słowy, ciało centralne jest nieruchome.

Jest to nieco podobne do Code Golf: Jaki jest los statku kosmicznego? [wersja zmiennoprzecinkowa] , ale jest inaczej, ponieważ mierzy dokładność.

Możesz wdrożyć rozwiązanie oparte na symulacji, które musi działać w mniej niż 3 sekundy, LUB możesz wdrożyć program, który podaje dokładną wartość (musi również działać w mniej niż 3 sekundy). Zobacz szczegóły punktacji poniżej. Jeśli wdrożysz symulację, nie musi ona być dokładna, ale twój wynik będzie niższy z powodu niedokładności.

Dane wejściowe : x y z vx vy vz tniekoniecznie liczby całkowite reprezentujące współrzędne x, y, z, prędkość odpowiednio w kierunkach x, y i z. Gwarantuje się, że prędkość kota jest ściśle mniejsza niż prędkość ucieczki na tej wysokości. Dane wejściowe można pobierać z dowolnego miejsca, w tym parametrów do funkcji. Program musi działać na moim laptopie w mniej niż trzy sekundy t < 2^30, co oznacza, że ​​jeśli prowadzisz symulację, musisz odpowiednio dostosować swój czas. Jeśli planujesz osiągnąć 3-sekundowy limit dla każdego przypadku testowego, upewnij się, że istnieje parametr dostrajający, który może uczynić go bardziej dokładnym / mniej dokładnym dla przyrostów prędkości, dzięki czemu mogę uruchomić go w ciągu trzech sekund na moim komputerze.

Wyjście : x y zpozycja po czasie t.

Ponieważ problem dwóch ciał można idealnie rozwiązać, teoretycznie możliwe jest uzyskanie idealnej, poprawnej odpowiedzi.

Punktacja : dla każdego przypadku testowego błąd jest definiowany jako odległość między twoimi danymi wyjściowymi a „prawdziwymi” danymi wyjściowymi. Prawdziwe dane wyjściowe są zdefiniowane jako generowane przez fragment kodu przypadku testowego. Jeśli błąd jest mniejszy niż 10^(-8), błąd jest zaokrąglany w dół do zera. Twój wynik to średni błąd w 100 (lub więcej) losowych przypadkach testowych. Jeśli napiszesz idealnie dokładną odpowiedź, powinieneś otrzymać wynik 0; wygrywa najniższy wynik, a remisy zostaną zerwane przez długość kodu.

Przypadki testowe :

1 0 0 0 -1 0 1000000000 --> 0.83789 -0.54584 0

W tym przypadku orbita jest idealnie okrągła z okresem 2 * pi, więc po okrążeniu 159154943 razy kot kończy w przybliżeniu (0,83789, -0,54584). To nie jest przypadek testowy, na którym zostanie przetestowany kod; jeśli prześlesz idealnie dokładną odpowiedź, możesz chcieć ją przetestować.

Poniższy fragment kodu generuje losowe dodatkowe przypadki testowe i będzie używany do oceny zgłoszeń; daj mi znać, jeśli występuje w tym błąd:

soktinpk
źródło
Czy czas jest tpodawany w sekundach? Jeśli tak, to czy prędkość byłaby podawana w jednostkach na sekundę, czy może coś mniejszego?
R. Kap
@R. Kap To nie ma znaczenia. tjest podawany w jednostkach czasu, cokolwiek to jest, a prędkość użyje tej samej jednostki. Czy to w sekundach, czy godzinach, odpowiedź będzie taka sama.
soktinpk
nearly massless catJaka byłaby dokładna masa kota? Czy powinniśmy użyć 0jako wartości masy tego kota?
R. Kap
@R. Kap Tak. Ale nadal działa na nią grawitacja (zwykle Newton nie uważał, że grawitacja ma wpływ na przedmioty bez masy). Powinniśmy więc uznać, że ma dowolnie małą masę, a twoją odpowiedzią jest pozycja, gdy masa kota spada do zera. Chodzi przede wszystkim o to, że kot nie wpływa na samą planetę.
soktinpk
2
@soktinpk może być łatwiej po prostu wyraźnie powiedzieć, że ciało centralne jest naprawione.
Maltysen

Odpowiedzi:

6

Python 3.5 + NumPy, dokładny, 186 bajtów

from math import*
def o(r,v,t):
 d=(r@r)**.5;W=2/d-v@v;U=W**1.5;b=[0,t*U+9]
 while 1:
  a=sum(b)/2;x=1-cos(a);y=sin(a)/U;k=r@v*x/W+d*y*W
  if a in b:return k*v-r*x/W/d+r
  b[k+a/U-y>t]=a

To jest dokładne rozwiązanie, wykorzystując formułę opracowaną przeze mnie na podstawie Jespera Göranssonhisa, „Symetria problemu Keplera”, 2015 . Wykorzystuje binarne wyszukiwanie do rozwiązania równania transcendentalnego Ax + B cos x + C sin x = D, które nie ma rozwiązania w formie zamkniętej.

Funkcja oczekuje, że pozycja i prędkość zostaną przekazane jako tablice NumPy:

>>> from numpy import array
>>> o(array([1,0,0]),array([0,-1,0]),1000000000)
array([ 0.83788718, -0.54584345,  0.        ])
>>> o(array([-1.1740058273269156,8.413493259550673,0.41996042044140003]),array([0.150014367067652,-0.09438816345868332,0.37294941703455975]),7999.348650387233)
array([-4.45269544,  6.93224929, -9.27292488])
Anders Kaseorg
źródło
Czego @zrobić?
R. Kap
1
Jest to nowy operator w Pythonie 3.5, dla którego NumPy przeciąża numpy.dot(iloczyn iloczynu / macierzy). Zobacz PEP 465.
Anders Kaseorg
To wspaniale, że gra w golfa, ale jest to wyzwanie dla kodu, czy możesz zrobić to trochę jaśniej, miałem trochę zadrapań w Pythonie i mogę obliczyć anomalię, theta, ekscentryczność, okres itp., Ale utknąłem na określeniu znak theta i określenie obrotu od płaszczyzny odniesienia xy do przestrzeni 3d. To naprawdę świetne rzeczy
mile
@miles Ponieważ więzi są zerwane przez długość kodu, sensowne jest, aby grało w golfa.
Mego
To prawda, ponieważ pracowałem również nad dokładnym rozwiązaniem, ponieważ generator przypadków testowych tworzy tylko eliptyczne orbity
mile
2

JavaScript

To tylko po to, aby piłka się potoczyła, ponieważ nikt nie wydaje odpowiedzi. Oto bardzo naiwny, prosty sposób, który można znacznie poprawić:

function simulate(x, y, z, vx, vy, vz, t) {
  var loops = 1884955; // tune this parameter
  var timestep = t / loops;
  for (var i = 0; i < t; i += timestep) {
    var distanceSq = x*x + y*y + z*z; // distance squared from origin
    var distance = Math.sqrt(distanceSq);
    var forceMag = 1/distanceSq; // get the force of gravity
    var forceX = -x / distance * forceMag;
    var forceY = -y / distance * forceMag;
    var forceZ = -z / distance * forceMag;
    vx += forceX * timestep;
    vy += forceY * timestep;
    vz += forceZ * timestep;
    x += vx * timestep;
    y += vy * timestep;
    z += vz * timestep;
  }
  return [x, y, z];
}

Testowanie:

simulate(1, 0, 0, 0, -1, 0, Math.PI*2) --> [0.9999999999889703, -0.0000033332840909716455, 0]

Hej, to całkiem nieźle. Ma błąd około 3,333 * 10 ^ (- 6), co nie wystarcza do zaokrąglenia w dół ... jest blisko.

Dla żartu:

console.log(simulate(1, 0, 0, 0, -1, 0, 1000000000))
--> [-530516643639.4616, -1000000000.0066016, 0]

No cóż; więc to nie jest najlepsze.

I na losowym przypadku testowym z generatora:

simulate(-1.1740058273269156,8.413493259550673,0.41996042044140003,0.150014367067652,-0.09438816345868332,0.37294941703455975,7999.348650387233)
-->    [-4.528366392498373, 6.780385554803544, -9.547824236472668]
Actual:[-4.452695438880813, 6.932249293597744, -9.272924876103785]

Z błędem tylko około 0,32305!

Można to znacznie poprawić, stosując coś takiego jak integracja Verleta lub jakiś wymyślny algorytm. W rzeczywistości algorytmy te mogą nawet uzyskać doskonałe wyniki, mimo że są symulacjami.

soktinpk
źródło