From ff992380c9461e495adca7c30d365f086c3cfbfc Mon Sep 17 00:00:00 2001 From: TerenceLiu98 Date: Fri, 14 Oct 2022 13:01:23 +0800 Subject: [PATCH] update --- algorithm/interactive.ipynb | 141 ++++++++++++++---- .../.ipynb_checkpoints/gd-checkpoint.py | 69 ++++++++- .../__pycache__/gd.cpython-39.pyc | Bin 7537 -> 15498 bytes algorithm/optimization/gd.py | 69 ++++++++- 4 files changed, 237 insertions(+), 42 deletions(-) diff --git a/algorithm/interactive.ipynb b/algorithm/interactive.ipynb index 914cb85..b6ac3b7 100644 --- a/algorithm/interactive.ipynb +++ b/algorithm/interactive.ipynb @@ -12,34 +12,120 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "id": "0a5c51d2-8b18-4143-b6f1-73a909ccb623", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "0bcac263607a46d19fead8b1cf79e498", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "VBox(children=(HBox(children=(VBox(children=(Text(value='x**3 - x**(1/2)', description='Expression:', style=Te…" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "3f64c031482d41799291390431aa3264", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Output()" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "0504d25c3aab477ca0acf3d054dbaf92", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Output()" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "gd1 = gradient_descent_1d(environ=\"jupyterlab\")" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "id": "15c6e757-cde3-422b-be7e-3f55b7752142", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "fca48b98af304f1d821c948d8dcc8629", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "VBox(children=(HBox(children=(Dropdown(index=2, options=(('(sin(x1) - 2) + (sin(x2) - 2) ** 2', '(sin(x1) - 2)…" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "f25a00c1bb294530973475c7a5c8bb10", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Output()" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "4afc98f7c6954a58aba389526ba09164", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Output()" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "gd2 = gradient_descent_2d(environ=\"jupyterlab\")" ] }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 4, "id": "694b7e27-cc21-44f4-9a89-7a6b97725a64", "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "08df46f6a3b54543a15dd79d71c334bc", + "model_id": "f1d170fccfee4e5891a3c33ad564c197", "version_major": 2, "version_minor": 0 }, @@ -53,7 +139,21 @@ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "ee2bc3a3c2b843aeae594ece6e02596e", + "model_id": "e6a5a98d84b54da7b1ac6deaa408ed5d", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Output()" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "5b35d3e6383947cfb24f1663388ef556", "version_major": 2, "version_minor": 0 }, @@ -69,33 +169,10 @@ "gd2_race = gradient_descent_2d_race(environ=\"jupyterlab\")" ] }, - { - "cell_type": "code", - "execution_count": 6, - "id": "5a2aec3f-e47b-44ab-b3da-2275578e9636", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[array([-4., -4.]),\n", - " array([-1.2519118 , 0.90778485]),\n", - " array([-2.02500166, 2.8935338 ])]" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "gd2_race.df_list_p1" - ] - }, { "cell_type": "code", "execution_count": null, - "id": "b89040ec-4318-419b-95eb-60320f146877", + "id": "d6001078-5cf2-402e-b37e-a6dad90674a6", "metadata": {}, "outputs": [], "source": [] @@ -117,7 +194,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.13" + "version": "3.9.13" } }, "nbformat": 4, diff --git a/algorithm/optimization/.ipynb_checkpoints/gd-checkpoint.py b/algorithm/optimization/.ipynb_checkpoints/gd-checkpoint.py index 04e5100..de0e56e 100644 --- a/algorithm/optimization/.ipynb_checkpoints/gd-checkpoint.py +++ b/algorithm/optimization/.ipynb_checkpoints/gd-checkpoint.py @@ -330,12 +330,16 @@ class gradient_descent_2d_race(object): def __init__(self, environ:str="jupyterlab"): pio.renderers.default = environ # 'notebook' or 'colab' or 'jupyterlab' self.wg_expr = widgets.Text(value="(sin(x1) - 2) ** 2 + (sin(x2) - 2) ** 2", description="Expression:") - self.wg_person_one = widgets.Text(value="(0, 0)", description="coordinate 1:") - self.wg_person_two = widgets.Text(value="(0, 0)", description="coordinate 2:") + self.wg_person_one = widgets.Text(value="(5, 5)", description="candidate 1:") + self.wg_person_two = widgets.Text(value="(5, 5)", description="candidate 2:") self.button_compute = widgets.Button(description="Compute") self.button_plot = widgets.Button(description="Plot") + self.compute_output = widgets.Output() - self.config = widgets.VBox([self.wg_expr, self.wg_person_one, self.wg_person_two, self.button_compute]) + self.plot_output = widgets.Output() + + self.button_box = widgets.HBox([self.button_compute, self.button_plot], description="operations") + self.config = widgets.VBox([self.wg_expr, self.wg_person_one, self.wg_person_two, self.button_box]) self.xn_list_p1, self.df_list_p1 = [], [] self.xn_list_p2, self.df_list_p2 = [], [] self.initialization() @@ -344,8 +348,8 @@ class gradient_descent_2d_race(object): display(self.config) self.button_compute.on_click(self.compute) display(self.compute_output) - #self.button_plot.on_click(self.plot) - #display(self.plot_output) + self.button_plot.on_click(self.plot) + display(self.plot_output) def compute(self, *args): with self.compute_output: @@ -375,5 +379,60 @@ class gradient_descent_2d_race(object): print("player two: gradient= {}".format(gradient)) clear_output(wait=True) return None + + def plot(self, *args): + with self.plot_output: + clear_output(wait=True) + #x0 = np.array(self.wg_x0.value.split(","), dtype=float) + x1 = symbols("x1") + x2 = symbols("x2") + expr = sympify(self.wg_expr.value) + xx1 = np.arange(np.array(self.xn_list_p1)[:, 0].min()*0.5, np.array(self.xn_list_p1)[:, 0].max()*1.5, 0.1) + xx2 = np.arange(np.array(self.xn_list_p1)[:, 1].min()*0.5, np.array(self.xn_list_p1)[:, 1].max()*1.5, 0.1) + xx1, xx2 = np.meshgrid(xx1, xx2) + + f = lambdify((x1, x2), expr, "numpy") + fx = f(xx1, xx2) + f_xn_p1 = f(np.array(self.xn_list_p1)[:, 0], np.array(self.xn_list_p1)[:, 1]) + f_xn_p2 = f(np.array(self.xn_list_p2)[:, 0], np.array(self.xn_list_p2)[:, 1]) + + frames, steps = [], [] + for k in range(len(f_xn_p1)): + tmp_trace1 = go.Scatter3d(x=np.array(self.xn_list_p1)[:k,0], y=np.array(self.xn_list_p1)[:k,1], z=f_xn_p1) + tmp_trace2 = go.Scatter3d(x=np.array(self.xn_list_p2)[:k,0], y=np.array(self.xn_list_p2)[:k,1], z=f_xn_p2) + frame = go.Frame(dict(data=[tmp_trace1, tmp_trace2], name=f'frame{k+1}'), traces=[1, 2]) + frames.append(frame) + step = dict( + method="update", + args=[{"visible": [True]}, + {"title": "Slider switched to step: " + str(k+1)}], # layout attribute + ) + steps.append(step) + + sliders = [dict(steps= [dict(method= 'animate', + args= [[f'frame{k+1}'], + dict(mode= 'immediate', + frame= dict( duration=0, redraw= True ), + transition=dict( duration=0) + ) + ], + #label='Date : {}'.format(date_range[k]) + ) for k in range(0,len(frames))], + transition= dict(duration=0), + x=0, + y=0, + currentvalue=dict(font=dict(size=12), visible=True, xanchor= 'center'), + len=1.0) + ] + + trace1 = go.Surface(x=xx1, y=xx2, z=fx, showscale=True, opacity=0.4) + trace2 = go.Scatter3d(x=None, y=None, z=None) + trace3 = go.Scatter3d(x=None, y=None, z=None) + fig = go.Figure(data=[trace1, trace2, trace3], frames=frames) + fig.update_layout(updatemenus=[dict(type="buttons", buttons=[dict(label="Play", method="animate", args=[None, dict(fromcurrent=True)]), \ + dict(label="Pause", method="animate", args=[[None], dict(fromcurrent=True, mode='immediate', transition= {'duration': 0}, frame=dict(redraw=True, duration=0))])])], + margin=dict(l=20, r=20, b=20, t=20), sliders=sliders) + fig.show() + \ No newline at end of file diff --git a/algorithm/optimization/__pycache__/gd.cpython-39.pyc b/algorithm/optimization/__pycache__/gd.cpython-39.pyc index 8c812214c772829b012360d38697367a5810204d..4796c7f3483ad2daf8e6267584bf11833091af0c 100644 GIT binary patch literal 15498 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 delta 2008 zcmZvdYiv|S6oBW?=pID z91t3gwbr;-z%ix=mpdTqhS+k|69?F(+B-Kb-}Rp1uy=WH;91`GuWy5}cJA0U^oIw( zc3aH^8~)oaIe`O1r9%6`P~)K#n5q`q1Gm+k(2Kqb8KQnAbYOiM`%SMY&0@xqr*I$- zlg3rZ77^x*ET|LVZIPyC3NhhGGi}+jq&^LgCuhlcKVh11fbcTnsA`LR1)b_nh z>w*9k^-ENbx8an|WjmR5AS$liTX)MY^;-L|`g{G2&MDN{&mkE2xfl2YKUar3QtBH| zzq-(I8O|=ZcYX(|G2~Id#S-2e8p@OEer)?jy+`h(5p8943!AA&Uut^naz5+Gd3B^K z)2|2QKAL%haFuY3aFg)4`l)LG7Sz#!xa#OWyd{jvD2flo&U3~VAjhuqDrxPFz0c2BZxv1-*)$LeEizouX`V=OtAA@1SfftHNs1n z0x?{z_0rkF5qjyz!B`C!eZqF0Ut&&sqhpE9X;m%PS@l+Z)d2bv7LmFK80un97mh)+ zp+xI$(N3Ob*j%t0Y;-%Ad{s?!BpLe9DSX%2O)g?LIHe=L*Co0|yw2xBRjrY9YVElm zaui!)b?OEe$-0M(FS3g;$wiOoJ?D3NoxTM&5A*N}5c@tkAXVJmj)kO%!g*wHskK}RefWv zT71518@I=IFlelb+^2NhDLDOw$i11Nfykq5t+(nrt&CG zOJxMgvXryZ&O}8ALra&6PH9@&6BRi@7e>BCFbQdbAXtb>IG-(A_LhPvPg>G`+%b8J zjOfnDtUA&gQ(p%IHS##as_ev@bKtNX33pr#H>MHBOt30o%3;)!?0;HL+65+Dc;uMe zDDEl6a+Oy7tE`Y0Wn?s{}kZ@3890_U9mkTp z#A6qgYK@eHRt;%YlU5;l2X%K*Y`TM97hhQe-N5gAxf?<&m91)BTc-;2C2MkqUZ#R3 z-z8KDa|pw8#Ke#ofo!2*iLB{ZO~06yrjsodb>8$!OGxvy{1Q!ZA9RpS4a-~6&XUDy zNY0>EzDE}BCghtSoA7oM937fo3`r(i)N3g@L`HtXQ|gaw(8N5!MQ{@a2