import%20marimo%0A%0A__generated_with%20%3D%20%220.15.2%22%0Aapp%20%3D%20marimo.App(width%3D%22medium%22)%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20import%20marimo%20as%20mo%0A%20%20%20%20import%20numpy%20as%20np%0A%20%20%20%20import%20matplotlib.pyplot%20as%20plt%0A%20%20%20%20return%20mo%2C%20np%2C%20plt%0A%0A%0A%40app.cell%0Adef%20_(np%2C%20plt)%3A%0A%20%20%20%20t%20%3D%20np.pi%20%2F%207%0A%20%20%20%20rotmat0%20%3D%20np.array(%5B%5Bnp.cos(t)%2C%20-np.sin(t)%5D%2C%20%5Bnp.sin(t)%2C%20np.cos(t)%5D%5D)%0A%0A%20%20%20%20b%20%3D%20np.array(%5B%5B0%2C%201.133%5D%2C%20%5B1%2C%20-0.667%5D%2C%20%5B-1%2C%20-0.667%5D%5D)%0A%20%20%20%20%23%20x%20%3D%20(rotmat0%20%40%20b.T).T%0A%20%20%20%20x%20%3D%20np.array(%5B%5B-0.357%2C%201.33%5D%2C%20%5B1.193%2C%20-0.297%5D%2C%20%5B-0.837%2C%20-1.127%5D%5D)%0A%20%20%20%20plt.scatter(*b.T)%0A%20%20%20%20plt.scatter(*x.T)%0A%20%20%20%20return%20b%2C%20t%2C%20x%0A%0A%0A%40app.cell%0Adef%20_(b%2C%20np%2C%20plt%2C%20x)%3A%0A%20%20%20%20n%20%3D%20np.linalg.norm(b%2C%20axis%3D1)%0A%20%20%20%20b2%20%3D%20b%20%2F%20n.max()%0A%20%20%20%20%23%20b2%20%3D%20b2%5Bnp.argsort(n)%2C%20%3A%5D%0A%20%20%20%20n%20%3D%20np.linalg.norm(x%2C%20axis%3D1)%0A%20%20%20%20x2%20%3D%20x%20%2F%20n.max()%0A%20%20%20%20%23%20x2%20%3D%20x2%5Bnp.argsort(n)%2C%20%3A%5D%0A%20%20%20%20plt.scatter(*b2.T)%0A%20%20%20%20plt.scatter(*x2.T)%0A%20%20%20%20return%20b2%2C%20x2%0A%0A%0A%40app.cell%0Adef%20_(b%2C%20np%2C%20x)%3A%0A%20%20%20%20np.linalg.norm(b%2C%20axis%3D1)%2C%20np.linalg.norm(x%2C%20axis%3D1)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(b2%2C%20np%2C%20x2)%3A%0A%20%20%20%20ca%20%3D%20(b2%5B%3A%2C%201%5D%20*%20x2%5B%3A%2C%200%5D%20-%20b2%5B%3A%2C%200%5D%20*%20x2%5B%3A%2C%201%5D).sum()%0A%20%20%20%20cs%20%3D%20-np.linalg.vecdot(x2%2C%20b2%2C%20axis%3D1).sum()%0A%20%20%20%20return%20ca%2C%20cs%0A%0A%0A%40app.cell%0Adef%20_(ca%2C%20cs%2C%20np)%3A%0A%20%20%20%20angle%20%3D%20np.arctan2(-ca%2C%20-cs)%0A%20%20%20%20%5Bca%2C%20np.cos(angle)%5D%2C%20%5Bcs%2C%20np.sin(angle)%5D%0A%20%20%20%20return%20(angle%2C)%0A%0A%0A%40app.cell%0Adef%20_(angle%2C%20t)%3A%0A%20%20%20%20angle%2C%20t%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(angle%2C%20ca%2C%20cs%2C%20np)%3A%0A%20%20%20%20ca%20*%20np.cos(angle)%20-%20cs%20*%20np.sin(angle)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(angle%2C%20np)%3A%0A%20%20%20%20rotmat%20%3D%20np.array(%20%23%20the%20reconstructed%20rotation%20matrix%0A%20%20%20%20%20%20%20%20%5B%5Bnp.cos(angle)%2C%20-np.sin(angle)%5D%2C%20%5Bnp.sin(angle)%2C%20np.cos(angle)%5D%5D%0A%20%20%20%20)%0A%20%20%20%20return%20(rotmat%2C)%0A%0A%0A%40app.cell%0Adef%20_(b2%2C%20plt%2C%20rotmat%2C%20x2)%3A%0A%20%20%20%20b3%20%3D%20rotmat%20%40%20b2.T%0A%20%20%20%20plt.scatter(*b3)%0A%20%20%20%20plt.scatter(*x2.T)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20r%22%22%22%0A%20%20%20%20Man%20hat%20zwei%20Punktmengen%20(Dreiecke)%20%24x%5E1%2Cx%5E2%2C...%2Cx%5EN%24%20und%20%24b%5E1%2Cb%5E2%2C...%2Cb%5EN%24%20(beim%20Dreieck%20%24N%3D3%24).%0A%20%20%20%20Man%20will%20jetzt%20die%20optimale%20Rotation%20%24R(%5Ctheta)%24%20bestimmen%20die%20%24x%5E1%24%20(ungef%C3%A4hr)%20auf%20%24b%5E1%24%20dreht%2C%20%24x%5E2%24%20auf%20%24b%5E2%24%20usw.%20also%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Cmin_%5Ctheta%20%5Csum_%7Bi%3D1%7D%5EN%20%5ClVert%20R(%5Ctheta)x%5Ei%20-%20b%5Ei%20%5CrVert_2%5E2.%0A%20%20%20%20%24%24%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Cmin_%5Ctheta%20%5Csum_%7Bi%3D1%7D%5EN%20(%5Ctext%7BAbstand%20von%20%7D%20R(%5Ctheta)x%5Ei%20%5Ctext%7B%20und%20%7D%20b%5Ei)%5E2.%0A%20%20%20%20%24%24%0A%0A%20%20%20%20Die%20Funktionen%20%24f_i(%5Ctheta)%20%3A%3D%20%5ClVert%20R(%5Ctheta)x%5Ei%20-%20b%5Ei%20%5CrVert_2%5E2%24%20sind%20differenzierbar%20usw.%2C%20daher%20ist%20das%20optimal%20%24%5Ctheta%24%20gerade%20das%20bei%20dem%20die%20Ableitung%20Null%20ist%2C%20also%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Cfrac%7Bd%7D%7Bd%5Ctheta%7D%20%5Csum_%7Bi%3D1%7D%5EN%20%5ClVert%20R(%5Ctheta)x%5Ei%20-%20b%5Ei%20%5CrVert_2%5E2%20%3D%200.%0A%20%20%20%20%24%24%0A%0A%20%20%20%20Mit%20Kettenregel%20kann%20man%20diese%20Ableitungen%20ausrechnen%20und%20bekommt%20dadurch%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Csum_%7Bi%3D1%7D%5EN%20(R(%5Ctheta)x%5Ei%20-%20p%5Ei)%5ET%20(%5Cfrac%7Bd%7D%7Bd%5Ctheta%7DR)(%5Ctheta)x%5Ei%20%3D%20%5Csum_%7Bi%3D1%7D%5EN%20(x%5Ei)%5ET%20R(%5Ctheta)%5ET%20(%5Cfrac%7Bd%7D%7Bd%5Ctheta%7DR)(%5Ctheta)x%5Ei%20-%20(p%5Ei)%5ET%20(%5Cfrac%7Bd%7D%7Bd%5Ctheta%7DR)(%5Ctheta)x%5Ei%0A%20%20%20%20%24%24%0A%0A%20%20%20%20Jetzt%20kann%20man%20einen%20nicen%20Fact%20%C3%BCber%20solche%20Rotationsmatrizen%20nutzen%20(%22Schiefsymmetrie%22)%20wodurch%20der%20ganze%20linke%20Term%20wegf%C3%A4llt.%20Also%20ist%20die%20Ableitung%20einfach%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Csum_%7Bi%3D1%7D%5EN%20-%20(p%5Ei)%5ET%20(%5Cfrac%7Bd%7D%7Bd%5Ctheta%7DR)(%5Ctheta)x%5Ei%0A%20%20%20%20%24%24%0A%0A%20%20%20%20und%20da%20man%20Nullstellen%20sucht%20kann%20man%20sich%20das%20Minus%20auch%20sparen.%20Man%20kann%20relativ%20straightforward%20ausrechnen%2C%20dass%0A%0A%20%20%20%20%24%24%0A%20%20%20%20(%5Cfrac%7Bd%7D%7Bd%5Ctheta%7DR)(%5Ctheta)%20%3D%20%5Cbegin%7Bpmatrix%7D%20-%5Csin(%5Ctheta)%20%26%20-%5Ccos(%5Ctheta)%20%5C%5C%20%5Ccos(%5Ctheta)%20%26%20-%5Csin(%5Ctheta)%20%5Cend%7Bpmatrix%7D.%0A%20%20%20%20%24%24%0A%0A%20%20%20%20Das%20setzt%20man%20in%20die%20obige%20Ableitung%20ein%2C%20multipliziert%20aus%20und%20gruppiert%20die%20Terme%20mit%20%24%5Ccos(%5Ctheta)%24%20und%20mit%20%24%5Csin(%5Ctheta)%24.%20Dann%20bekommt%20man%20die%20Gleichung%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Ccos(%5Ctheta)%20%5Csum_%7Bk%3D1%7D%5EN%20(b_2%5Ek%20x_1%5Ek%20-%20b_1%5Ek%20x_2%5Ek)%20-%20%5Csin(%5Ctheta)%20%5Csum_%7Bk%3D1%7D%5EN%20(b_1%5Ek%20x_1%5Ek%20%2B%20b_2%5Ek%20x_2%5Ek)%20%3D%200.%0A%20%20%20%20%24%24%0A%0A%20%20%20%20Also%20im%20Endeffekt%20%24%5Ccos(%5Ctheta)A%20%2B%20%5Csin(%5Ctheta)B%20%3D%200%24%20f%C3%BCr%20h%C3%A4ssliche%20%24A%2CB%24.%20Und%20die%20L%C3%B6sung%20dazu%20ist%20%24%5Ctheta%20%3D%20atan2(-A%2CB)%24.%0A%20%20%20%20%22%22%22%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%23%23%20Alternative%20method%20using%20SVD%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(b2%2C%20x2)%3A%0A%20%20%20%20data_mat%20%3D%20x2.T%20%40%20b2%20%23%20same%20as%20sum(x2%5B%5Bi%5D%5D.T%20%40%20b2%5B%5Bi%5D%5D%20for%20i%20in%20range(len(x2)))%0A%20%20%20%20return%20(data_mat%2C)%0A%0A%0A%40app.cell%0Adef%20_(data_mat%2C%20np)%3A%0A%20%20%20%20svd%20%3D%20np.linalg.svd(data_mat)%0A%20%20%20%20svd%0A%20%20%20%20opt_rot%20%3D%20svd.U%20%40%20np.diag(%5B1%2C%20np.linalg.det(svd.U)%20*%20np.linalg.det(svd.Vh)%5D)%20%40%20svd.Vh%20%23%20this%20can%20be%20implemented%20more%20efficiently%3A%20explicitly%20forming%20the%20diagonal%20matrix%20isn't%20necessary%0A%20%20%20%20%23%20note%20that%20the%20product%20of%20the%20determinants%20here%20is%20always%20either%20%2B1%20or%20-1%20---%20it%20just%20makes%20sure%20that%20we%20really%20get%20a%20rotation%20in%20total.%0A%20%20%20%20return%20(opt_rot%2C)%0A%0A%0A%40app.cell%0Adef%20_(np%2C%20opt_rot%2C%20rotmat)%3A%0A%20%20%20%20%23%20Observe%20that%20both%20methods%20yields%20the%20same%20rotation%20matrix%3A%0A%20%20%20%20np.isclose(opt_rot%2C%20rotmat).all()%0A%20%20%20%20return%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20app.run()%0A
43f192d0f9b724a21e6ed46581c0553e1451cb5edccb4d6de56ed4c3056c627a