├── LICENSE.txt ├── README.md ├── manuscript.pdf ├── manuscript ├── img-src │ ├── blending_functions.fig │ ├── conformal.fig │ ├── cubify-proj.fig │ ├── error.fig │ ├── examples │ │ ├── 0.xyz │ │ ├── 1.xyz │ │ ├── 3n.fig │ │ ├── 3n.fig.bak │ │ ├── 3n.jpg │ │ ├── 3n.pdf │ │ ├── 3n.ps │ │ ├── 3neurons.fig │ │ ├── 3neurons.png │ │ ├── SAVE.fig │ │ ├── SAVE.fig.bak │ │ ├── a.jpg │ │ ├── a.obj │ │ ├── animation_example_3.1.py │ │ ├── animation_example_3.2.py │ │ ├── animation_example_3.4.py │ │ ├── b.jpg │ │ ├── b.obj │ │ ├── binary-classification-problem.py │ │ ├── binary-classifier-1d-linear-vs-logistic.py │ │ ├── c.jpg │ │ ├── c.obj │ │ ├── convolution.py │ │ ├── cubify-input.geogram_ascii │ │ ├── cubify.geogram_ascii │ │ ├── d.obj │ │ ├── d.xyz │ │ ├── logistic-1d-a.png │ │ ├── logistic-growth.py │ │ ├── logistic-regression-2d.png │ │ ├── logistic-regression-2d.py │ │ ├── lqr.py │ │ ├── ls-vs-crossentropy-energies.png │ │ ├── ls-vs-crossentropy-energies.py │ │ ├── ls1.fig │ │ ├── ls1.fig.bak │ │ ├── ls1.pdf │ │ ├── ls1.ps │ │ ├── lsvscrossentropy.graphite │ │ ├── lsvscrossentropy1.jpg │ │ ├── lsvscrossentropy2.jpg │ │ ├── lsvscrossentropy3.jpg │ │ ├── lsvscrossentropy4.jpg │ │ ├── lsvscrossentropy5.jpg │ │ ├── lsvscrossentropyA.jpg │ │ ├── lsvscrossentropyB.jpg │ │ ├── lsvscrossentropyC.jpg │ │ ├── lsvscrossentropyD.jpg │ │ ├── lsvscrossentropyE.jpg │ │ ├── lsvscrossentropyF.jpg │ │ ├── lsvscrossentropyG.jpg │ │ ├── lsvscrossentropyX.jpg │ │ ├── lsvscrossentropyY.jpg │ │ ├── neural-drop-obj.py │ │ ├── neural.py │ │ ├── neuron.fig │ │ ├── neuron.fig.bak │ │ ├── neuron.png │ │ ├── neuron2.fig │ │ ├── s.png │ │ ├── silhouette-better.py │ │ ├── silhouette-naive.py │ │ ├── x.obj │ │ ├── y.obj │ │ └── z.obj │ ├── fem.py │ ├── galerkin.fig │ ├── gradient-bg.svg │ ├── linsys_curvature.mp4 │ ├── linsys_curvature.py │ ├── linsys_smooth.mp4 │ ├── linsys_smooth.py │ ├── linsys_smooth_constrain.mp4 │ ├── linsys_smooth_constrain.py │ ├── lscm │ │ ├── CMakeLists.txt │ │ ├── OpenNL_psm.cpp │ │ ├── OpenNL_psm.h │ │ ├── geometry.h │ │ ├── input.obj │ │ ├── main.cpp │ │ ├── model.cpp │ │ ├── model.h │ │ └── obj-prepare │ │ │ ├── lscm-head.mtl │ │ │ ├── lscm-head.obj │ │ │ ├── lscm-head.png │ │ │ ├── siggraph-head-low.mtl │ │ │ ├── siggraph-head-low.obj │ │ │ └── siggraph-head-low.png │ ├── neural-animation.py │ ├── prepie.py │ ├── tex-mapping.fig │ └── vector_approximation.fig ├── img │ ├── 2_7x.png │ ├── 2_7x.svg │ ├── 2_7x2.png │ ├── 2_7x2.svg │ ├── 3n.jpg │ ├── 3neurons.pdf │ ├── 3neurons.png │ ├── ARAP.jpg │ ├── URI.png │ ├── arap-lap-a.jpg │ ├── arap-lap-b.jpg │ ├── axiomes.png │ ├── barycenter │ │ ├── 1ring.png │ │ ├── ls-teaser.jpg │ │ ├── ls-teaser2.jpg │ │ └── ls-teaser3.jpg │ ├── binary-classification-problem.png │ ├── binomial-05.png │ ├── binomial-07.png │ ├── blending_functions.pdf │ ├── c5aa80f6a2e9575abfa7b3dfdabf5c5a.png │ ├── caricature.jpg │ ├── cg │ │ ├── Aorth.png │ │ ├── MMA.png │ │ ├── conjuge.png │ │ ├── defpositiveness.png │ │ ├── gradient2Dconverge.pdf │ │ ├── gradient2Dconverge.png │ │ ├── gradient3Dconverge1.pdf │ │ ├── gradient3Dconverge1.png │ │ ├── laplace1d.png │ │ ├── laplace1dresults.png │ │ ├── laplace2d.png │ │ ├── problem2d.png │ │ └── proj2D.png │ ├── conformal.pdf │ ├── convolution.png │ ├── cubify-flagging.jpg │ ├── cubify-proj.pdf │ ├── cubify.jpg │ ├── error.pdf │ ├── example_3_1_0.png │ ├── example_3_1_1.png │ ├── example_3_1_2.png │ ├── example_3_1_3.png │ ├── example_3_1_4.png │ ├── example_3_1_5.png │ ├── example_3_2_0.png │ ├── example_3_2_1.png │ ├── example_3_2_2.png │ ├── example_3_2_3.png │ ├── example_3_2_4.png │ ├── example_3_2_5.png │ ├── example_3_3_0.jpg │ ├── example_3_3_1.jpg │ ├── example_3_3_2.jpg │ ├── example_3_4_0.png │ ├── example_3_4_1.png │ ├── example_3_4_2.png │ ├── example_3_4_3.png │ ├── example_3_4_4.png │ ├── example_3_4_5.png │ ├── example_6_1_a.png │ ├── example_6_1_b.png │ ├── example_6_1_c.png │ ├── example_6_3_a.png │ ├── example_6_3_b.png │ ├── example_6_3_c.png │ ├── example_6_3_d.png │ ├── example_6_3_e.png │ ├── example_8_1_a.png │ ├── example_8_1_b.png │ ├── example_8_1_c.png │ ├── fem.png │ ├── galerkin.pdf │ ├── gradient-bg.png │ ├── head-smooth.jpg │ ├── idea.png │ ├── likehood-07.png │ ├── linear-1d-a.png │ ├── linear-1d-b.png │ ├── linearly-separable-dataset.png │ ├── linearly-unseparable-dataset.png │ ├── logistic-1d-a.png │ ├── logistic-1d-b.png │ ├── logistic-regression-2d.png │ ├── ls-classification-energy.jpg │ ├── ls-vs-crossentropy-energies.jpg │ ├── ls-vs-crossentropy-energies1.jpg │ ├── ls-vs-crossentropy-energies2.jpg │ ├── lscm-head-mesh.jpg │ ├── lscm-head-textured.jpg │ ├── lscm-head-uv.jpg │ ├── matrices.png │ ├── matrix-linear.png │ ├── matrix-quadratic-form.png │ ├── minpb1d.png │ ├── minpb2d.png │ ├── neural.png │ ├── neuron.pdf │ ├── neuron.png │ ├── neuron2.pdf │ ├── peirce-conformal-map.png │ ├── pie-1d.png │ ├── pie-baseball-red.png │ ├── pie-football-red.png │ ├── pie_baseball.png │ ├── pie_football.png │ ├── pie_overlay.png │ ├── pie_poisson.png │ ├── repimage.jpg │ ├── sokolov-caricature.jpg │ ├── stop-following-me.png │ ├── tex-applied.png │ ├── tex-coords.png │ ├── tex-mapping.pdf │ ├── tex-mesh.png │ ├── tex-superposed.jpg │ ├── tex-tiger.jpg │ └── vector_approximation.pdf ├── least-squares.bib ├── least-squares.tex ├── listings │ ├── arap.m │ ├── arap.py │ ├── caricature3d.py │ ├── cubify.cpp │ ├── cubify.py │ ├── example_3.1.py │ ├── example_3.2.py │ ├── example_3.3.cpp │ ├── example_3.3.py │ ├── example_3.4.py │ ├── example_6.1_a.py │ ├── example_6.1_b.py │ ├── example_6.1_c.py │ ├── example_6.2_a.py │ ├── example_6.2_b.py │ ├── example_6.2_c.cpp │ ├── example_8.1.py │ ├── example_8.2.py │ ├── example_8.3.py │ ├── logistic-regression-2d.py │ ├── lscm.cpp │ ├── lscm.py │ ├── neural.py │ ├── poisson-1d-gauss-seidel.py │ ├── poisson-image-editing-1d.py │ └── poisson-image-editing.py └── tmp │ ├── lst_linsys01.cpp │ ├── lst_linsys01.py │ ├── lst_linsys02.cpp │ ├── lst_linsys02.py │ ├── lst_linsys03.py │ └── lst_linsys04.py ├── presentation ├── beamerthemepixel.sty ├── img │ ├── bunny.png │ ├── pixel.png │ └── pixel.svg ├── listings │ ├── arap.py │ ├── caricature.py │ ├── caricature3d.py │ ├── cubify.py │ ├── example_3.1.py │ ├── example_3.2.py │ ├── example_3.3.cpp │ ├── example_3.4.py │ ├── linear-1d.py │ ├── logistic-1d.py │ ├── logistic-growth.py │ ├── logistic-regression-2d.py │ ├── lqr2.py │ ├── lqr3.py │ ├── lscm.py │ ├── mesh.py │ ├── neural.py │ ├── poisson-1d-gauss-seidel.py │ ├── poisson-1d.py │ ├── poisson-2d.py │ ├── silhouette-better.py │ └── smooth-neanderthal.py ├── presentation.pdf ├── presentation.pdfpc ├── presentation.tex └── screenshot.jpg └── src ├── ch3 ├── example_3_1.py ├── example_3_2.py ├── example_3_3.py ├── example_3_4.py ├── input-face.obj └── mesh.py ├── ch6 ├── 1-lqr │ ├── lqr1.py │ ├── lqr2.py │ └── lqr3.py ├── 2-poisson │ ├── baseball.png │ ├── football.png │ ├── poisson-1d-gauss-seidel.py │ ├── poisson-1d-least-squares.py │ ├── poisson-2d.py │ └── result.png ├── 3-caricature │ ├── caricature3d.py │ ├── input-face.obj │ ├── mesh.py │ ├── output-face.obj │ ├── silhouette-better.py │ ├── silhouette-naive.py │ └── silhouette-winner.py ├── 4-cubify │ ├── cubify.py │ ├── input-face.obj │ ├── mesh.py │ └── output-face.obj ├── 5-lscm │ ├── input-face.obj │ ├── lscm.py │ └── mesh.py ├── 6-arap-matlab │ ├── arap.m │ ├── cotan_laplacian.m │ ├── diablo.obj │ └── readOBJ.m └── 6-arap │ ├── arap.py │ ├── diablo.obj │ ├── mesh.py │ └── output.obj └── ch8 ├── 2 └── logistic-growth.py ├── 4 └── logistic-regression-2d.py ├── 5 └── neural.py └── 1+3 ├── binary-classifier-1d-linear-vs-logistic.py └── linear-1d.py /LICENSE.txt: -------------------------------------------------------------------------------- 1 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 2 | Version 2, December 2004 3 | 4 | Copyright (C) 2004 Sam Hocevar 5 | 6 | Everyone is permitted to copy and distribute verbatim or modified 7 | copies of this license document, and changing it is allowed as long 8 | as the name is changed. 9 | 10 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 11 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 12 | 13 | 0. You just DO WHAT THE FUCK YOU WANT TO. 14 | 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Least squares for programmers 2 | ### with illustrations 3 | 4 | This repository contains the [course notes](https://github.com/ssloy/least-squares-course/blob/master/manuscript.pdf) as well as the [source code](https://github.com/ssloy/least-squares-course/tree/master/src) for the long course I gave at SIGGRAPH 2021. 5 | 6 | You can find the full video of the course on youtube: 7 | [![](https://raw.githubusercontent.com/ssloy/least-squares-course/master/presentation/screenshot.jpg)](https://youtu.be/ZDh3v8OAEIA) 8 | 9 | This course explains least squares optimization, nowadays a simple and well-mastered technology. 10 | We show how this simple method can solve a large number of problems that would be difficult to approach in any other way. 11 | This course provides a simple, understandable yet powerful tool that most coders can use, 12 | in the contrast with other algorithms sharing this paradigm (numerical simulation and deep learning) which are more complex to master. 13 | 14 | Linear regression is often underestimated being considered only as a sub-domain of statistics / data analysis, but it is much more than that. 15 | We propose to discover how the same method (least squares) applies to the manipulation of geometric objects. 16 | This first step into the numerical optimization world can be done without strong applied mathematics background; 17 | while being simple, this step suffices for many applications, and is a good starting point for learning more advanced algorithms. 18 | We strive to communicate the underlying intuitions through numerous examples of classic problems, we show different choices of variables and the ways the energies are built. 19 | Over the last two decades, the geometry processing community have used it for computing 2D maps, deformations, geodesic paths, frame fields, etc. 20 | Our examples provide many examples of applications that can be directly solved by the least squares method. 21 | Note that linear regression is an efficient tool that has deep connections to other scientific domains; 22 | we show a few such links to broaden reader's horizons. 23 | 24 | This course is intended for students/engineers/researchers who know how to program in the traditional way: 25 | by breaking down complex tasks into elementary operations that manipulate combinatorial structures (trees, graphs, meshes...). 26 | Here we present a different paradigm, in which we describe what a good result looks like, and let numerical optimization algorithms find it for us. 27 | 28 | ![](https://raw.githubusercontent.com/ssloy/least-squares-course/master/manuscript/img/caricature.jpg) 29 | 30 | -------------------------------------------------------------------------------- /manuscript.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript.pdf -------------------------------------------------------------------------------- /manuscript/img-src/blending_functions.fig: -------------------------------------------------------------------------------- 1 | #FIG 3.2 Produced by xfig version 3.2.7a 2 | Landscape 3 | Center 4 | Metric 5 | A4 6 | 100.00 7 | Single 8 | -2 9 | 1200 2 10 | 0 32 #858585 11 | 0 33 #000000 12 | 2 1 0 4 32 7 50 -1 -1 0.000 0 0 -1 0 0 2 13 | 900 0 900 90 14 | 2 1 0 2 32 7 50 -1 -1 0.000 0 0 -1 0 0 2 15 | 1800 0 1800 90 16 | 2 1 0 2 32 7 50 -1 -1 0.000 0 0 -1 0 0 2 17 | 2700 0 2700 90 18 | 2 1 0 4 32 7 50 -1 -1 0.000 0 0 -1 0 0 2 19 | 3600 0 3600 90 20 | 2 1 0 2 32 7 50 -1 -1 0.000 0 0 -1 0 0 2 21 | 900 0 900 -2700 22 | 2 1 1 2 13 7 50 -1 -1 6.000 0 0 -1 0 0 2 23 | 0 0 900 -2700 24 | 2 1 0 4 13 7 50 -1 -1 0.000 0 0 -1 0 0 2 25 | 900 -2700 1800 0 26 | 2 1 0 4 4 7 50 -1 -1 0.000 0 0 -1 0 0 3 27 | 900 0 1800 -2700 2700 0 28 | 2 1 0 4 23 7 50 -1 -1 0.000 0 0 -1 0 0 3 29 | 1800 0 2700 -2700 3600 0 30 | 2 1 0 4 1 7 50 -1 -1 0.000 0 0 -1 0 0 2 31 | 2700 0 3600 -2700 32 | 2 1 1 2 1 7 50 -1 -1 6.000 0 0 -1 0 0 2 33 | 3600 -2700 4545 0 34 | 2 1 0 2 32 7 52 -1 -1 0.000 0 0 -1 0 0 2 35 | 4545 0 0 0 36 | 2 1 0 4 32 7 52 -1 -1 0.000 0 0 -1 0 0 2 37 | 900 0 3600 0 38 | 4 0 0 50 -1 0 16 0.0000 6 135 90 720 -2520 1\001 39 | 4 0 0 50 -1 0 16 0.0000 6 135 270 1665 270 1/3\001 40 | 4 0 0 50 -1 0 16 0.0000 6 135 90 765 270 0\001 41 | 4 0 0 50 -1 0 16 0.0000 6 135 270 2565 270 2/3\001 42 | 4 0 0 50 -1 0 16 0.0000 6 135 90 3555 270 1\001 43 | 4 0 0 50 -1 0 16 0.0000 6 135 360 -45 270 -1/3\001 44 | 4 0 0 50 -1 0 16 0.0000 6 135 270 4365 270 4/3\001 45 | 4 0 13 50 -1 0 16 0.0000 6 165 720 1035 -2520 $w_0(x)$\001 46 | 4 0 4 50 -1 0 16 0.0000 6 165 720 1935 -2520 $w_1(x)$\001 47 | 4 0 5 50 -1 0 16 0.0000 6 165 720 2835 -2520 $w_2(x)$\001 48 | 4 0 1 50 -1 0 16 0.0000 6 165 720 3735 -2520 $w_3(x)$\001 49 | -------------------------------------------------------------------------------- /manuscript/img-src/conformal.fig: -------------------------------------------------------------------------------- 1 | #FIG 3.2 Produced by xfig version 3.2.7a 2 | Landscape 3 | Center 4 | Metric 5 | A4 6 | 100.00 7 | Single 8 | -2 9 | 1200 2 10 | 2 5 0 1 0 -1 50 -1 -1 0.000 0 0 -1 0 0 5 11 | 0 /home/ssloy/+/least-squares-course/manuscript/img/peirce-conformal-map.png 12 | 0 0 1800 0 1800 1800 0 1800 0 0 13 | 2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 1 3 14 | 2 1 1.00 60.00 120.00 15 | 2 1 1.00 60.00 120.00 16 | -90 1125 -90 1890 675 1890 17 | 4 0 0 50 -1 0 16 0.0000 6 135 270 -270 1260 $v$\001 18 | 4 0 0 50 -1 0 16 0.0000 6 135 270 540 2070 $u$\001 19 | -------------------------------------------------------------------------------- /manuscript/img-src/cubify-proj.fig: -------------------------------------------------------------------------------- 1 | #FIG 3.2 Produced by xfig version 3.2.7b 2 | Landscape 3 | Center 4 | Metric 5 | A4 6 | 100.00 7 | Single 8 | -2 9 | 1200 2 10 | 0 32 #afe9af 11 | 2 1 0 2 -1 11 50 -1 20 0.000 0 0 -1 1 0 2 12 | 2 1 1.00 60.00 120.00 13 | 2604 2777 3375 2205 14 | 2 1 0 1 19 7 50 -1 -1 0.000 0 0 -1 0 0 3 15 | 2520 2790 2520 2694 2611 2691 16 | 2 1 0 2 19 7 50 -1 -1 0.000 0 0 -1 1 0 2 17 | 2 1 1.00 60.00 120.00 18 | 2610 2790 2610 1980 19 | 2 1 2 2 19 7 50 -1 -1 4.500 0 0 -1 0 0 2 20 | 3358 2700 3358 2213 21 | 2 3 0 1 29 29 500 -1 20 0.000 0 0 -1 0 0 5 22 | 2146 2740 2802 2412 3786 2740 3130 3068 2146 2740 23 | 2 1 1 2 19 7 50 -1 -1 5.000 0 0 -1 0 1 2 24 | 2 1 1.00 60.00 120.00 25 | 3375 2700 2612 2775 26 | 4 0 19 50 -1 0 12 0.0000 6 165 810 2401 2261 $\\vec{a}$\001 27 | 4 0 -1 50 -1 0 12 0.0000 6 165 810 3128 2201 $\\vec{v}$\001 28 | 4 0 19 50 -1 0 12 0.0000 6 180 2070 2970 2880 proj$_{\\vec{a}}\\vec{v}$\001 29 | -------------------------------------------------------------------------------- /manuscript/img-src/error.fig: -------------------------------------------------------------------------------- 1 | #FIG 3.2 Produced by xfig version 3.2.7b 2 | Landscape 3 | Center 4 | Metric 5 | A4 6 | 100.00 7 | Single 8 | -2 9 | 1200 2 10 | 0 32 #b2ecb2 11 | 2 1 0 2 12 7 50 -1 -1 0.000 0 0 -1 1 0 2 12 | 2 1 1.00 60.00 120.00 13 | 1980 2700 2700 2340 14 | 2 1 0 2 12 11 50 -1 20 0.000 0 0 -1 1 0 2 15 | 2 1 1.00 60.00 120.00 16 | 1980 2700 3003 3022 17 | 2 1 0 2 12 11 50 -1 20 0.000 0 0 -1 1 0 2 18 | 2 1 1.00 60.00 120.00 19 | 1980 2700 4583 2943 20 | 2 1 0 2 -1 11 50 -1 20 0.000 0 0 -1 1 0 2 21 | 2 1 1.00 60.00 120.00 22 | 1980 2700 4146 1885 23 | 2 1 0 3 19 19 49 -1 20 0.000 0 0 -1 1 0 2 24 | 2 1 2.00 75.00 135.00 25 | 4140 1890 4577 2955 26 | 2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2 27 | 4140 1890 4140 2520 28 | 2 1 1 1 -1 7 50 -1 -1 4.000 0 0 -1 0 0 2 29 | 4140 2520 1980 2700 30 | 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 3 31 | 4050 2520 4050 2430 4141 2421 32 | 2 3 0 1 32 32 500 -1 20 0.000 0 0 -1 0 0 5 33 | 900 2700 2700 1800 5400 2700 3600 3600 900 2700 34 | 4 0 12 50 -1 0 12 0.0000 6 180 810 2395 2344 $\\vec{j}$\001 35 | 4 0 12 50 -1 0 12 0.0000 6 165 810 2693 3159 $\\vec{i}$\001 36 | 4 0 12 50 -1 0 12 0.0000 6 180 2700 3651 3115 $\\alpha\\vec{i} + \\beta\\vec{j}$\001 37 | 4 0 -1 50 -1 0 12 0.0000 6 165 810 3710 1942 $\\vec{b}$\001 38 | 4 0 19 50 -1 0 12 0.0000 6 180 2070 4359 2267 $\\vec{e}(\\alpha,\\beta)$\001 39 | -------------------------------------------------------------------------------- /manuscript/img-src/examples/0.xyz: -------------------------------------------------------------------------------- 1 | 0.8 0.3 0.5 2 | 0.5 0.2 0.5 3 | 0.7 0.2 0.5 4 | 0.9 0.1 0.5 5 | 0.8 0.4 0.5 6 | 0.6 0.5 0.5 7 | 0.5 0.4 0.5 8 | -------------------------------------------------------------------------------- /manuscript/img-src/examples/1.xyz: -------------------------------------------------------------------------------- 1 | 0.5 0.7 0 2 | 0.1 0.5 0 3 | 0.3 0.6 0 4 | 0.2 0.8 0 5 | 0.17 0.17 0 6 | 0.2 0.3 0 7 | 0.3 0.4 0 8 | 0.05 0.2 0 9 | 0.2 0.3 0 10 | 0.9 0.5 0 11 | 0.79 0.6 0 12 | 0.73 0.7 0 13 | 0.9 0.8 0 14 | 0.95 0.4 0 15 | -------------------------------------------------------------------------------- /manuscript/img-src/examples/3n.fig: -------------------------------------------------------------------------------- 1 | #FIG 3.2 Produced by xfig version 3.2.7a 2 | Landscape 3 | Center 4 | Metric 5 | A4 6 | 100.00 7 | Single 8 | -2 9 | 1200 2 10 | 2 5 0 1 0 -1 50 -1 -1 0.000 0 0 -1 0 0 5 11 | 0 a.jpg 12 | 0 0 1800 0 1800 1800 0 1800 0 0 13 | 2 5 0 1 0 -1 50 -1 -1 0.000 0 0 -1 0 0 5 14 | 0 b.jpg 15 | 2610 0 4410 0 4410 1800 2610 1800 2610 0 16 | 2 5 0 1 0 -1 50 -1 -1 0.000 0 0 -1 0 0 5 17 | 0 c.jpg 18 | 5760 0 7560 0 7560 1800 5760 1800 5760 0 19 | 3 0 0 3 0 7 50 -1 -1 0.000 0 0 0 6 20 | -2520 1170 -2430 1170 -2049 1175 -1869 455 -1530 450 -1440 450 21 | 0.000 1.000 1.000 1.000 1.000 0.000 22 | 4 0 0 50 -1 0 32 0.0000 6 525 3870 4230 990 $+~w_2\\Biggr)=$\001 23 | 4 0 0 50 -1 0 32 0.0000 6 495 3075 1800 990 $+~w_1\\cdot$\001 24 | 4 0 0 50 -1 0 32 0.0000 6 525 5775 -1305 990 $\\circ~~ \\Biggl( w_0\\cdot$\001 25 | -------------------------------------------------------------------------------- /manuscript/img-src/examples/3n.fig.bak: -------------------------------------------------------------------------------- 1 | #FIG 3.2 Produced by xfig version 3.2.7a 2 | Landscape 3 | Center 4 | Metric 5 | A4 6 | 100.00 7 | Single 8 | -2 9 | 1200 2 10 | 2 5 0 1 0 -1 50 -1 -1 0.000 0 0 -1 0 0 5 11 | 0 a.jpg 12 | 0 0 1800 0 1800 1800 0 1800 0 0 13 | 2 5 0 1 0 -1 50 -1 -1 0.000 0 0 -1 0 0 5 14 | 0 b.jpg 15 | 2610 0 4410 0 4410 1800 2610 1800 2610 0 16 | 2 5 0 1 0 -1 50 -1 -1 0.000 0 0 -1 0 0 5 17 | 0 c.jpg 18 | 6390 0 8190 0 8190 1800 6390 1800 6390 0 19 | 3 0 0 3 0 7 50 -1 -1 0.000 0 0 0 6 20 | -2520 1170 -2430 1170 -2049 1175 -1869 455 -1530 450 -1440 450 21 | 0.000 1.000 1.000 1.000 1.000 0.000 22 | 4 0 0 50 -1 0 32 0.0000 6 525 3870 4230 990 $+~w_2\\Biggr)=$\001 23 | 4 0 0 50 -1 0 32 0.0000 6 495 3075 1800 990 $+~w_1\\cdot$\001 24 | 4 0 0 50 -1 0 32 0.0000 6 525 5775 -1305 990 $\\circ~~ \\Biggl( w_0\\cdot$\001 25 | -------------------------------------------------------------------------------- /manuscript/img-src/examples/3n.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img-src/examples/3n.jpg -------------------------------------------------------------------------------- /manuscript/img-src/examples/3n.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img-src/examples/3n.pdf -------------------------------------------------------------------------------- /manuscript/img-src/examples/3neurons.fig: -------------------------------------------------------------------------------- 1 | #FIG 3.2 Produced by xfig version 3.2.7a 2 | Landscape 3 | Center 4 | Metric 5 | A4 6 | 100.00 7 | Single 8 | -2 9 | 1200 2 10 | 6 -360 -945 360 -225 11 | 1 4 0 2 0 7 50 -1 -1 0.000 1 0.0000 0 -585 315 315 -315 -585 315 -585 12 | 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 13 | 0 -900 0 -270 14 | 2 5 0 1 0 -1 50 -1 -1 0.000 0 0 -1 0 0 5 15 | 0 s.png 16 | 30 -718 255 -718 255 -448 30 -448 30 -718 17 | 4 0 0 50 -1 0 16 0.0000 6 135 540 -261 -545 $\\sum$\001 18 | -6 19 | 6 -360 360 360 1080 20 | 1 4 0 2 0 7 50 -1 -1 0.000 1 0.0000 0 720 315 315 -315 720 315 720 21 | 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 22 | 0 405 0 1035 23 | 2 5 0 1 0 -1 50 -1 -1 0.000 0 0 -1 0 0 5 24 | 0 s.png 25 | 30 587 255 587 255 857 30 857 30 587 26 | 4 0 0 50 -1 0 16 0.0000 6 135 540 -261 760 $\\sum$\001 27 | -6 28 | 6 1125 -360 1845 360 29 | 1 4 0 2 0 7 50 -1 -1 0.000 1 0.0000 1485 0 315 315 1170 0 1800 0 30 | 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 31 | 1485 -315 1485 315 32 | 2 5 0 1 0 -1 50 -1 -1 0.000 0 0 -1 0 0 5 33 | 0 s.png 34 | 1515 -133 1740 -133 1740 137 1515 137 1515 -133 35 | 4 0 0 50 -1 0 16 0.0000 6 135 540 1224 40 $\\sum$\001 36 | -6 37 | 1 4 0 2 0 7 50 -1 -1 0.000 1 0.0000 -1377 1056 74 74 -1447 1080 -1307 1031 38 | 1 4 0 2 0 7 50 -1 -1 0.000 1 0.0000 -1375 67 74 74 -1445 91 -1305 42 39 | 1 4 0 2 0 7 50 -1 -1 0.000 1 0.0000 -1375 -878 74 74 -1445 -854 -1305 -903 40 | 2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 41 | 1 0 2.00 90.00 180.00 42 | -1323 997 -208 -331 43 | 2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 44 | 1 0 2.00 90.00 180.00 45 | -1292 -861 -314 -629 46 | 2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 47 | 1 0 2.00 90.00 180.00 48 | -1298 36 -293 -447 49 | 2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 50 | 1 0 2.00 90.00 180.00 51 | -1316 -818 -203 508 52 | 2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 53 | 1 0 2.00 90.00 180.00 54 | -1301 97 -278 604 55 | 2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 56 | 1 0 2.00 90.00 180.00 57 | -1304 1039 -276 797 58 | 2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 59 | 1 0 2.00 90.00 180.00 60 | 304 -490 1195 -129 61 | 2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 62 | 1 0 2.00 90.00 180.00 63 | 286 590 1207 149 64 | 2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 65 | 1 0 2.00 90.00 180.00 66 | 1800 0 2655 0 67 | 3 0 0 2 0 7 50 -1 -1 0.000 0 1 0 3 68 | 1 0 2.00 90.00 180.00 69 | -1307 1103 501 1657 1440 315 70 | 0.000 1.000 0.000 71 | 4 0 0 50 -1 0 16 0.0000 6 150 540 1935 -135 output\001 72 | 4 0 0 50 -1 0 16 0.0000 6 150 450 -270 -45 $u_2$\001 73 | 4 0 0 50 -1 0 16 0.0000 6 150 450 -585 -900 $u_0$\001 74 | 4 0 0 50 -1 0 16 0.0000 6 150 450 -765 -450 $u_1$\001 75 | 4 0 0 50 -1 0 16 0.0000 6 150 450 961 -344 $w_0$\001 76 | 4 0 0 50 -1 0 16 0.0000 6 150 450 883 104 $w_1$\001 77 | 4 0 0 50 -1 0 16 0.0000 6 150 450 1364 656 $w_2$\001 78 | 4 0 0 50 -1 0 16 0.0000 6 150 450 -279 252 $v_0$\001 79 | 4 0 0 50 -1 0 16 0.0000 6 150 450 -804 573 $v_1$\001 80 | 4 0 0 50 -1 0 16 0.0000 6 150 450 -554 1017 $v_2$\001 81 | 4 0 0 50 -1 0 16 0.0000 6 135 270 -1710 1080 $1$\001 82 | 4 0 0 50 -1 0 16 0.0000 6 165 270 -1710 90 $y$\001 83 | 4 0 0 50 -1 0 16 0.0000 6 135 270 -1710 -855 $x$\001 84 | -------------------------------------------------------------------------------- /manuscript/img-src/examples/3neurons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img-src/examples/3neurons.png -------------------------------------------------------------------------------- /manuscript/img-src/examples/SAVE.fig: -------------------------------------------------------------------------------- 1 | #FIG 3.2 Produced by xfig version 3.2.7a 2 | Landscape 3 | Center 4 | Metric 5 | A4 6 | 100.00 7 | Single 8 | -2 9 | 1200 2 10 | 2 5 0 1 0 -1 999 -1 -1 0.000 0 0 -1 0 0 5 11 | 0 lsvscrossentropyA.jpg 12 | 0 0 2443 0 2443 2443 0 2443 0 0 13 | 2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 14 | 1 0 2.00 45.00 120.00 15 | 1911 2074 1280 2398 16 | 2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 17 | 1605 2034 1913 2075 18 | 2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 0 1 2 19 | 1 0 2.00 45.00 120.00 20 | 843 1937 1187 1983 21 | 2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 22 | 1 0 2.00 45.00 120.00 23 | 1906 2076 1905 1191 24 | 4 0 0 50 -1 0 12 0.0000 6 210 585 853 2136 $w_0$\001 25 | 4 0 0 50 -1 0 12 0.0000 6 180 375 1538 2424 $w$\001 26 | 4 0 0 50 -1 0 12 0.0000 6 210 2055 1960 1453 $S(b) + \\lambda \\|b\\|^2$\001 27 | -------------------------------------------------------------------------------- /manuscript/img-src/examples/SAVE.fig.bak: -------------------------------------------------------------------------------- 1 | #FIG 3.2 Produced by xfig version 3.2.7a 2 | Landscape 3 | Center 4 | Metric 5 | A4 6 | 100.00 7 | Single 8 | -2 9 | 1200 2 10 | 2 5 0 1 0 -1 999 -1 -1 0.000 0 0 -1 0 0 5 11 | 0 lsvscrossentropyA.jpg 12 | 0 0 1350 0 1350 1350 0 1350 0 0 13 | 2 5 0 1 0 -1 999 -1 -1 0.000 0 0 -1 0 0 5 14 | 0 lsvscrossentropyA.jpg 15 | 1530 0 2880 0 2880 1350 1530 1350 1530 0 16 | -------------------------------------------------------------------------------- /manuscript/img-src/examples/a.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img-src/examples/a.jpg -------------------------------------------------------------------------------- /manuscript/img-src/examples/animation_example_3.1.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | import matplotlib.animation as animation 4 | 5 | plt.rcParams["font.family"] = "serif" 6 | plt.rcParams["mathtext.fontset"] = "dejavuserif" 7 | #plt.rcParams['text.usetex'] = True 8 | plt.rc('font', size=20) 9 | fig, ax = plt.subplots(1, figsize=(6.40,2.40),dpi=100) 10 | 11 | x = [0, .8, 1, .6, .1, .4, .2, .1, .6, .3, 1, .7, .4, 0, .6, 1] 12 | n = len(x) 13 | 14 | 15 | lines = [ax.plot(range(n), x, 'bs-')[0], ax.text(0.32, -0.2, "Initialization", transform=ax.transAxes)] 16 | 17 | plt.tick_params( 18 | axis='x', # changes apply to the x-axis 19 | which='both', # both major and minor ticks are affected 20 | bottom=False, # ticks along the bottom edge are off 21 | top=False, # ticks along the top edge are off 22 | labelbottom=False) # labels along the bottom edge are off 23 | plt.tight_layout() 24 | #plt.ylim(top=3) 25 | 26 | plt.draw() 27 | 28 | #ax.grid() 29 | 30 | def animate(iteration): 31 | global x,n 32 | if (0==iteration): 33 | return lines 34 | 35 | # for z in range(0, 10): 36 | x = [ x[0] ] + [ (x[i-1]+x[i+1])/2. for i in range(1, len(x)-1) ] + [ x[-1] ] 37 | # for i in range(1, len(x)-1): 38 | # x[i] = (x[i-1]+x[i+1])/2. 39 | # x[-1] = x[-2] 40 | 41 | print(iteration) 42 | 43 | lines[0].set_data(range(n), x) # update the data. 44 | if (0==iteration): 45 | lines[1].set_text("Initialization") 46 | else: 47 | lines[1].set_text("Iteration #" + str(iteration)) 48 | plt.draw() 49 | ax.relim() 50 | ax.autoscale_view(False,True,False) 51 | # ax.autoscale_view(True,True,True) 52 | return lines 53 | 54 | ani = animation.FuncAnimation(fig, animate, frames=np.arange(0, 501), interval=100, blit=False, save_count=50) 55 | if (1): 56 | ani.save('animation.gif', dpi=100, writer='imagemagick') 57 | else: 58 | from matplotlib.animation import FFMpegWriter 59 | writer = FFMpegWriter(fps=15, metadata=dict(artist='Me'), bitrate=1800) 60 | ani.save("animation.mp4", writer=writer) 61 | 62 | #plt.show() 63 | -------------------------------------------------------------------------------- /manuscript/img-src/examples/animation_example_3.2.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | import matplotlib.animation as animation 4 | 5 | plt.rcParams["font.family"] = "serif" 6 | plt.rcParams["mathtext.fontset"] = "dejavuserif" 7 | #plt.rcParams['text.usetex'] = True 8 | plt.rc('font', size=20) 9 | fig, ax = plt.subplots(1, figsize=(6.40,2.40),dpi=100) 10 | 11 | x = [0, .8, 1, .6, .1, .4, .2, .1, .6, .3, 1, .7, .4, 0, .6, 1] 12 | n = len(x) 13 | 14 | 15 | lines = [ax.plot(range(n), x, 'bs-')[0], ax.text(0.32, -0.2, "Initialization", transform=ax.transAxes)] 16 | 17 | plt.tick_params( 18 | axis='x', # changes apply to the x-axis 19 | which='both', # both major and minor ticks are affected 20 | bottom=False, # ticks along the bottom edge are off 21 | top=False, # ticks along the top edge are off 22 | labelbottom=False) # labels along the bottom edge are off 23 | plt.tight_layout() 24 | #plt.ylim(top=3) 25 | 26 | plt.draw() 27 | 28 | #ax.grid() 29 | 30 | def animate(iteration): 31 | global x,n 32 | if (0==iteration): 33 | return lines 34 | 35 | 36 | for i in range(1, len(x)-1): 37 | x[i] = ( x[i-1] + x[i+1] )/2. 38 | 39 | print(iteration) 40 | 41 | lines[0].set_data(range(n), x) # update the data. 42 | if (0==iteration): 43 | lines[1].set_text("Initialization") 44 | else: 45 | lines[1].set_text("Iteration #" + str(iteration)) 46 | plt.draw() 47 | ax.relim() 48 | ax.autoscale_view(False,True,False) 49 | # ax.autoscale_view(True,True,True) 50 | return lines 51 | 52 | ani = animation.FuncAnimation(fig, animate, frames=np.arange(0, 501), interval=100, blit=False, save_count=50) 53 | if (1): 54 | ani.save('animation.gif', dpi=100, writer='imagemagick') 55 | else: 56 | from matplotlib.animation import FFMpegWriter 57 | writer = FFMpegWriter(fps=15, metadata=dict(artist='Me'), bitrate=1800) 58 | ani.save("animation.mp4", writer=writer) 59 | 60 | #plt.show() 61 | -------------------------------------------------------------------------------- /manuscript/img-src/examples/animation_example_3.4.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | import matplotlib.animation as animation 4 | 5 | plt.rcParams["font.family"] = "serif" 6 | plt.rcParams["mathtext.fontset"] = "dejavuserif" 7 | #plt.rcParams['text.usetex'] = True 8 | plt.rc('font', size=20) 9 | fig, ax = plt.subplots(1, figsize=(6.40,2.40),dpi=100) 10 | 11 | x = [0, .8, 1, .6, .1, .4, .2, .1, .6, .3, 1, .7, .4, 0, .6, 1] 12 | n = len(x) 13 | 14 | 15 | # plot the ground truth 16 | X = np.linspace(0., 1., num=16, endpoint=True) 17 | G = [x**3/6 + x**2/2 + x/3 for x in X] 18 | #plt.plot(G, 'g-', label='ground truth') 19 | 20 | lines = [ax.plot(range(n), x, 'bs-')[0], ax.text(0.32, -0.2, "Initialization", transform=ax.transAxes), ax.plot(G, 'g-', label="ground truth")] 21 | 22 | plt.tick_params( 23 | axis='x', # changes apply to the x-axis 24 | which='both', # both major and minor ticks are affected 25 | bottom=False, # ticks along the bottom edge are off 26 | top=False, # ticks along the top edge are off 27 | labelbottom=False) # labels along the bottom edge are off 28 | plt.tight_layout() 29 | #plt.ylim(top=3) 30 | 31 | plt.draw() 32 | 33 | #ax.grid() 34 | 35 | def animate(iteration): 36 | global x,n 37 | if (0==iteration): 38 | return lines 39 | 40 | 41 | for i in range(1, len(x)-1): 42 | x[i] = ( x[i-1] + x[i+1] - (i+15)/15**3 )/2. 43 | 44 | print(iteration) 45 | 46 | lines[0].set_data(range(n), x) # update the data. 47 | if (0==iteration): 48 | lines[1].set_text("Initialization") 49 | else: 50 | lines[1].set_text("Iteration #" + str(iteration)) 51 | plt.draw() 52 | ax.relim() 53 | ax.autoscale_view(False,True,False) 54 | # ax.autoscale_view(True,True,True) 55 | return lines 56 | 57 | ani = animation.FuncAnimation(fig, animate, frames=np.arange(0, 501), interval=100, blit=False, save_count=50) 58 | if (1): 59 | ani.save('animation.gif', dpi=100, writer='imagemagick') 60 | else: 61 | from matplotlib.animation import FFMpegWriter 62 | writer = FFMpegWriter(fps=15, metadata=dict(artist='Me'), bitrate=1800) 63 | ani.save("animation.mp4", writer=writer) 64 | 65 | #plt.show() 66 | -------------------------------------------------------------------------------- /manuscript/img-src/examples/b.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img-src/examples/b.jpg -------------------------------------------------------------------------------- /manuscript/img-src/examples/binary-classification-problem.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import numpy as np 3 | 4 | moresamples = False 5 | logistic = False 6 | samples = [[0.47,1],[0.24,1],[0.75,1],[0.00,1],[-0.80,1],[-0.59,1],[1.09,1],[1.34,1], 7 | [1.01,1],[-1.02,1],[0.50,1],[0.64,1],[-1.15,1],[-1.68,1],[-2.21,1],[-0.52,1], 8 | [3.93,1],[4.21,1],[5.18,1],[4.20,1],[4.57,1],[2.63,1],[4.52,1],[3.31,1], 9 | [6.75,1],[3.47,1],[4.32,1],[3.08,1],[4.10,1],[4.00,1],[2.99,1],[3.83,1]] 10 | n = len(samples) 11 | m = len(samples[0]) 12 | labels = [0]*(n//2) + [1]*(n//2) 13 | 14 | if moresamples: 15 | samples += [[16.2,1],[15.7,1],[15.0,1],[16.0,1],[15.4,1],[17.3,1],[15.6,1],[15.8,1],[12.8,1],[16.2,1],[14.8,1],[17.0,1],[16.1,1],[16.0,1],[16.9,1],[15.9,1]] 16 | n = len(samples) 17 | labels += [1]*(n-len(labels)) 18 | 19 | xmin = np.min([x for x,_ in samples]) 20 | xmax = np.max([x for x,_ in samples]) 21 | 22 | if logistic: 23 | U = np.matrix([[1],[0]]) 24 | for _ in range(5): 25 | JR = np.matrix(np.zeros((n+2, 2))) 26 | R = np.matrix(np.zeros((n+2, 1))) 27 | for i in range(n): 28 | ei = np.exp(-U[1,0] - samples[i][0]*U[0,0]) 29 | R[i,0] = -1/(1+ei) + labels[i] 30 | for j in range(3): 31 | JR[i, 0] = samples[i][0]*ei/(1+ei)**2 32 | JR[i, 1] = ei/(1+ei)**2 33 | l = .001 # regularization 34 | JR[n,0] = JR[n+1, 1] = 1.*l 35 | R[n,0] = -U[0]*l 36 | R[n+1,0] = -U[1]*l 37 | U = U + np.linalg.inv(JR.T*JR)*JR.T*R 38 | a,b = U.T.tolist()[0] 39 | print(a,b) 40 | sep = -b/a 41 | xred = np.linspace(xmin, sep, 100) 42 | yred = [1/(1+np.exp(-x*U[0,0] - U[1,0])) for x in xred] 43 | xgrn = np.linspace(sep, xmax, 100) 44 | ygrn = [1/(1+np.exp(-x*U[0,0] - U[1,0])) for x in xgrn] 45 | else: 46 | A = np.matrix(np.zeros((n,m))) 47 | b = np.matrix(np.zeros((n,1))) 48 | for i in range(n): 49 | A[i,:] = samples[i] 50 | b[i,0] = labels[i] 51 | 52 | X = np.linalg.inv(A.transpose()*A)*A.transpose()*b 53 | k,m = X.transpose().tolist()[0] 54 | 55 | sep = (.5-m)/k 56 | xred = np.linspace(xmin, sep, 500) 57 | yred = k*xred + m 58 | xgrn = np.linspace(sep, xmax, 500) 59 | ygrn = k*xgrn + m 60 | 61 | plt.rcParams["font.family"] = "serif" 62 | plt.rcParams["mathtext.fontset"] = "dejavuserif" 63 | plt.rcParams['text.usetex'] = True 64 | plt.rc('font', size=20) 65 | 66 | 67 | if moresamples: 68 | fig, ax = plt.subplots(1, figsize=(6.40*2,2.40),dpi=150) 69 | else: 70 | fig, ax = plt.subplots(1, figsize=(6.40,2.40),dpi=150) 71 | ax.get_yaxis().set_visible(False) 72 | 73 | 74 | plt.ylim(-.2, .2) 75 | plt.axvline(sep, ymin=0, ymax=1, color='black', linestyle='--', linewidth=3) 76 | #plt.plot(xred, yred, '-r', linewidth=2) 77 | #plt.plot(xgrn, ygrn, '-g', linewidth=2) 78 | 79 | 80 | for sample, label in zip(samples,labels): 81 | c = 'g' 82 | if (label<.5): c = 'r' 83 | label = 0 84 | plt.scatter(sample[0], label, color=c, edgecolors='black') 85 | 86 | plt.tight_layout() 87 | if logistic: 88 | if moresamples: 89 | plt.savefig("logistic-1d-b.png", bbox_inches='tight') 90 | else: 91 | plt.savefig("logistic-1d-a.png", bbox_inches='tight') 92 | else: 93 | if moresamples: 94 | plt.savefig("linear-1d-b.png", bbox_inches='tight') 95 | else: 96 | plt.savefig("linear-1d-a.png", bbox_inches='tight') 97 | plt.show() 98 | -------------------------------------------------------------------------------- /manuscript/img-src/examples/binary-classifier-1d-linear-vs-logistic.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import numpy as np 3 | 4 | moresamples = False 5 | logistic = True 6 | samples = [[0.47,1],[0.24,1],[0.75,1],[0.00,1],[-0.80,1],[-0.59,1],[1.09,1],[1.34,1], 7 | [1.01,1],[-1.02,1],[0.50,1],[0.64,1],[-1.15,1],[-1.68,1],[-2.21,1],[-0.52,1], 8 | [3.93,1],[4.21,1],[5.18,1],[4.20,1],[4.57,1],[2.63,1],[4.52,1],[3.31,1], 9 | [6.75,1],[3.47,1],[4.32,1],[3.08,1],[4.10,1],[4.00,1],[2.99,1],[3.83,1]] 10 | n = len(samples) 11 | m = len(samples[0]) 12 | labels = [0]*(n//2) + [1]*(n//2) 13 | 14 | if moresamples: 15 | samples += [[16.2,1],[15.7,1],[15.0,1],[16.0,1],[15.4,1],[17.3,1],[15.6,1],[15.8,1],[12.8,1],[16.2,1],[14.8,1],[17.0,1],[16.1,1],[16.0,1],[16.9,1],[15.9,1]] 16 | n = len(samples) 17 | labels += [1]*(n-len(labels)) 18 | 19 | xmin = np.min([x for x,_ in samples]) 20 | xmax = np.max([x for x,_ in samples]) 21 | 22 | if logistic: 23 | U = np.matrix([[1],[0]]) 24 | for _ in range(5): 25 | JR = np.matrix(np.zeros((n+2, 2))) 26 | R = np.matrix(np.zeros((n+2, 1))) 27 | for i in range(n): 28 | ei = np.exp(-U[1,0] - samples[i][0]*U[0,0]) 29 | R[i,0] = -1/(1+ei) + labels[i] 30 | for j in range(3): 31 | JR[i, 0] = samples[i][0]*ei/(1+ei)**2 32 | JR[i, 1] = ei/(1+ei)**2 33 | l = .001 # regularization 34 | JR[n,0] = JR[n+1, 1] = 1.*l 35 | R[n,0] = -U[0]*l 36 | R[n+1,0] = -U[1]*l 37 | U = U + np.linalg.inv(JR.T*JR)*JR.T*R 38 | a,b = U.T.tolist()[0] 39 | print(a,b) 40 | sep = -b/a 41 | xred = np.linspace(xmin, sep, 100) 42 | yred = [1/(1+np.exp(-x*U[0,0] - U[1,0])) for x in xred] 43 | xgrn = np.linspace(sep, xmax, 100) 44 | ygrn = [1/(1+np.exp(-x*U[0,0] - U[1,0])) for x in xgrn] 45 | else: 46 | A = np.matrix(np.zeros((n,m))) 47 | b = np.matrix(np.zeros((n,1))) 48 | for i in range(n): 49 | A[i,:] = samples[i] 50 | b[i,0] = labels[i] 51 | 52 | X = np.linalg.inv(A.transpose()*A)*A.transpose()*b 53 | k,m = X.transpose().tolist()[0] 54 | 55 | sep = (.5-m)/k 56 | xred = np.linspace(xmin, sep, 500) 57 | yred = k*xred + m 58 | xgrn = np.linspace(sep, xmax, 500) 59 | ygrn = k*xgrn + m 60 | 61 | plt.rcParams["font.family"] = "serif" 62 | plt.rcParams["mathtext.fontset"] = "dejavuserif" 63 | plt.rcParams['text.usetex'] = True 64 | plt.rc('font', size=20) 65 | 66 | 67 | if moresamples: 68 | fig, ax = plt.subplots(1, figsize=(6.40*2,2.40),dpi=150) 69 | else: 70 | fig, ax = plt.subplots(1, figsize=(6.40,2.40),dpi=150) 71 | 72 | 73 | plt.axvline(sep, ymin=-0.25, ymax=1.25, color='black', linestyle='--', linewidth=3) 74 | plt.plot(xred, yred, '-r', linewidth=2) 75 | plt.plot(xgrn, ygrn, '-g', linewidth=2) 76 | plt.ylim(-.25, 1.25) 77 | 78 | 79 | for sample, label in zip(samples,labels): 80 | c = 'g' 81 | if (label<.5): c = 'r' 82 | plt.scatter(sample[0], label, color=c, edgecolors='black') 83 | 84 | plt.tight_layout() 85 | if logistic: 86 | if moresamples: 87 | plt.savefig("logistic-1d-b.png", bbox_inches='tight') 88 | else: 89 | plt.savefig("logistic-1d-a.png", bbox_inches='tight') 90 | else: 91 | if moresamples: 92 | plt.savefig("linear-1d-b.png", bbox_inches='tight') 93 | else: 94 | plt.savefig("linear-1d-a.png", bbox_inches='tight') 95 | plt.show() 96 | -------------------------------------------------------------------------------- /manuscript/img-src/examples/c.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img-src/examples/c.jpg -------------------------------------------------------------------------------- /manuscript/img-src/examples/convolution.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | 4 | plt.rcParams["font.family"] = "serif" 5 | plt.rcParams["mathtext.fontset"] = "dejavuserif" 6 | plt.rcParams['text.usetex'] = True 7 | plt.rc('font', size=30) 8 | fig, ax = plt.subplots(1, figsize=(6.40,6.40),dpi=100) 9 | 10 | 11 | 12 | def w(x, e, i, n): 13 | if x<(i-1)/n-e: 14 | return 0 15 | if x<(i-1)/n+e: 16 | return (n*x+e*n-i+1)**2/(4*e*n) 17 | if x.5): continue 45 | print(sample[0], sample[1], .5) 46 | # plt.scatter(sample[0], sample[1], color=c, edgecolors='black',s=200,linewidths=2) 47 | ''' 48 | 49 | for p in zip(X0.flatten(), X1.flatten(), Y.flatten()): 50 | print("v %3.3f %3.3f %3.3f" % p) 51 | 52 | n = len(x0) 53 | 54 | for i in range(n-1): 55 | for j in range(n-1): 56 | print("f %d %d %d %d" %(i+j*n+1, i+1+j*n+1, i+1+(j+1)*n+1, i+(j+1)*n+1) ) 57 | -------------------------------------------------------------------------------- /manuscript/img-src/examples/neural.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | samples = [[.5,.7,1.],[.1,.5,1.],[.3,.6,1.],[.2,.8,1.],[.17,.17,1.],[.2,.3,1.], 4 | [.3,.4,1.],[.05,.2,1.], [.2,.3,1.],[.8,.3,1.],[.5,.2,1.],[.7,.2,1.], 5 | [.9,.1,1.],[.8,.4,1.],[.6,.5,1.], [.5,.4,1.], [.9, .5, 1.],[.79, .6, 1.], 6 | [.73, .7, 1.],[.9, .8, 1.],[.95, .4, 1.]] 7 | labels = [0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0] 8 | 9 | def neuron(x, w): 10 | return 1./(1.+np.exp(-np.dot(x,w))) 11 | 12 | u = np.array([0.814, 0.779, 0.103]) # small random values 13 | v = np.array([0.562, 0.310, 0.591]) 14 | w = np.array([0.884, 0.934, 0.649]) 15 | 16 | alpha = 1. # learning rate 17 | for _ in range(0,3000): 18 | E = 0 19 | for x, label in zip(samples,labels): 20 | E += (label - neuron([neuron(x, u), neuron(x, v), 1.],w))**2 21 | print("E =",E) 22 | 23 | for x, label in zip(samples,labels): 24 | out_u = neuron(x, u) 25 | out_v = neuron(x, v) 26 | out_w = neuron([out_u, out_v, 1.], w) 27 | u += alpha*(label-out_w)*out_w*(1.-out_w)*out_u*(1.-out_u)*np.array(x) 28 | v += alpha*(label-out_w)*out_w*(1.-out_w)*out_v*(1.-out_v)*np.array(x) 29 | w += alpha*(label-out_w)*out_w*(1.-out_w)*np.array([out_u, out_v, 1.]) 30 | 31 | #print(u,v,w) 32 | 33 | import matplotlib.pyplot as plt 34 | 35 | plt.rcParams["font.family"] = "serif" 36 | plt.rcParams["mathtext.fontset"] = "dejavuserif" 37 | plt.rcParams['text.usetex'] = True 38 | plt.rc('font', size=20) 39 | 40 | fig,ax = plt.subplots(1, figsize=(6.40*1.25,6.40),dpi=150) 41 | 42 | res = 100 43 | x0 = np.arange(0, 1., 1./res) 44 | x1 = np.arange(0, 1., 1./res) 45 | 46 | Y = [[neuron([neuron([a,b,1.], u), neuron([a,b,1],v), 1.], w) for a in x0] for b in x1] 47 | 48 | 49 | X0, X1 = np.meshgrid(x0, x1) 50 | #print(X0, X1, Y) 51 | plt.contourf(X0, X1, Y,100, cmap=plt.cm.RdYlGn) 52 | plt.colorbar() 53 | plt.contour(X0, X1, Y,levels=[.49995, .50005], colors='k', linestyles='--') 54 | 55 | for sample, label in zip(samples,labels): 56 | c = 'lime' 57 | if (label<.5): c = 'tomato' 58 | plt.scatter(sample[0], sample[1], color=c, edgecolors='black',s=200,linewidths=2) 59 | 60 | plt.tight_layout() 61 | plt.gca().axes.get_yaxis().set_visible(False) 62 | plt.gca().axes.get_xaxis().set_visible(False) 63 | plt.savefig("neural.png", bbox_inches='tight') 64 | plt.show() 65 | 66 | -------------------------------------------------------------------------------- /manuscript/img-src/examples/neuron.fig: -------------------------------------------------------------------------------- 1 | #FIG 3.2 Produced by xfig version 3.2.7a 2 | Landscape 3 | Center 4 | Metric 5 | A4 6 | 100.00 7 | Single 8 | -2 9 | 1200 2 10 | 1 4 0 2 0 7 50 -1 -1 0.000 1 0.0000 0 90 315 315 -315 90 315 90 11 | 1 4 0 2 0 7 50 -1 -1 0.000 1 0.0000 -1272 -808 70 70 -1342 -806 -1202 -810 12 | 1 4 0 2 0 7 50 -1 -1 0.000 1 0.0000 -1270 952 70 70 -1340 954 -1200 950 13 | 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 14 | 0 -225 0 405 15 | 2 5 0 1 0 -1 50 -1 -1 0.000 0 0 -1 0 0 5 16 | 0 s.png 17 | 30 -43 255 -43 255 227 30 227 30 -43 18 | 2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 19 | 1 0 2.00 90.00 180.00 20 | 315 90 1170 90 21 | 2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 22 | 1 0 2.00 90.00 180.00 23 | -1215 900 -270 225 24 | 2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 25 | 1 0 2.00 90.00 180.00 26 | -1215 -765 -270 -90 27 | 4 0 0 50 -1 0 16 0.0000 6 135 540 -261 130 $\\sum$\001 28 | 4 0 0 50 -1 0 16 0.0000 6 150 540 495 -45 output\001 29 | 4 0 0 50 -1 0 16 0.0000 6 150 450 -900 885 $w_0$\001 30 | 4 0 0 50 -1 0 16 0.0000 6 135 270 -900 -630 $w$\001 31 | 4 0 0 50 -1 0 16 0.0000 6 135 270 -1559 -785 $x$\001 32 | 4 0 0 50 -1 0 16 0.0000 6 135 270 -1521 1036 $1$\001 33 | -------------------------------------------------------------------------------- /manuscript/img-src/examples/neuron.fig.bak: -------------------------------------------------------------------------------- 1 | #FIG 3.2 Produced by xfig version 3.2.7a 2 | Landscape 3 | Center 4 | Metric 5 | A4 6 | 100.00 7 | Single 8 | -2 9 | 1200 2 10 | 1 4 0 2 0 7 50 -1 -1 0.000 1 0.0000 0 90 315 315 -315 90 315 90 11 | 1 4 0 2 0 7 50 -1 -1 0.000 0 -0.0000 -1490 1076 315 315 -1805 1076 -1175 1076 12 | 1 4 0 2 0 7 50 -1 -1 0.000 1 0.0000 -1490 -941 315 315 -1805 -941 -1175 -941 13 | 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 14 | 0 -225 0 405 15 | 2 5 0 1 0 -1 50 -1 -1 0.000 0 0 -1 0 0 5 16 | 0 s.png 17 | 30 -43 255 -43 255 227 30 227 30 -43 18 | 2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 19 | 1 0 2.00 90.00 180.00 20 | 315 90 1170 90 21 | 2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 22 | 1 0 2.00 90.00 180.00 23 | -1215 900 -270 225 24 | 2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 25 | 1 0 2.00 90.00 180.00 26 | -2340 1080 -1800 1080 27 | 2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 28 | 1 0 2.00 90.00 180.00 29 | -1215 -765 -270 -90 30 | 2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 31 | 1 0 2.00 90.00 180.00 32 | -2340 -945 -1800 -945 33 | 4 0 0 50 -1 0 16 0.0000 6 240 810 -261 130 $\\sum$\001 34 | 4 0 0 50 -1 0 16 0.0000 6 225 720 495 -45 output\001 35 | 4 0 0 50 -1 0 16 0.0000 6 270 720 -900 885 $w_0$\001 36 | 4 0 0 50 -1 0 16 0.0000 6 240 450 -900 -630 $w$\001 37 | 4 0 0 50 -1 0 16 0.0000 6 240 405 -2565 -900 $x$\001 38 | 4 0 0 50 -1 0 16 0.0000 6 240 405 -2565 1170 $1$\001 39 | -------------------------------------------------------------------------------- /manuscript/img-src/examples/neuron.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img-src/examples/neuron.png -------------------------------------------------------------------------------- /manuscript/img-src/examples/neuron2.fig: -------------------------------------------------------------------------------- 1 | #FIG 3.2 Produced by xfig version 3.2.7a 2 | Landscape 3 | Center 4 | Metric 5 | A4 6 | 100.00 7 | Single 8 | -2 9 | 1200 2 10 | 1 4 0 2 0 7 50 -1 -1 0.000 1 0.0000 0 90 315 315 -315 90 315 90 11 | 1 4 0 2 0 7 50 -1 -1 0.000 1 0.0000 -1275 -800 70 70 -1345 -798 -1205 -802 12 | 1 4 0 2 0 7 50 -1 -1 0.000 1 0.0000 -1272 935 70 70 -1342 937 -1202 933 13 | 1 4 0 2 0 7 50 -1 -1 0.000 1 0.0000 -1234 84 70 70 -1304 86 -1164 82 14 | 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 15 | 0 -225 0 405 16 | 2 5 0 1 0 -1 50 -1 -1 0.000 0 0 -1 0 0 5 17 | 0 s.png 18 | 30 -43 255 -43 255 227 30 227 30 -43 19 | 2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 20 | 1 0 2.00 90.00 180.00 21 | 315 90 1170 90 22 | 2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 23 | 1 0 2.00 90.00 180.00 24 | -1215 900 -270 225 25 | 2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 26 | 1 0 2.00 90.00 180.00 27 | -1215 -765 -270 -90 28 | 2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 29 | 1 0 2.00 90.00 180.00 30 | -1162 81 -321 82 31 | 4 0 0 50 -1 0 16 0.0000 6 135 540 -261 130 $\\sum$\001 32 | 4 0 0 50 -1 0 16 0.0000 6 150 540 495 -45 output\001 33 | 4 0 0 50 -1 0 16 0.0000 6 150 450 -900 885 $w_2$\001 34 | 4 0 0 50 -1 0 16 0.0000 6 150 450 -900 -630 $w_0$\001 35 | 4 0 0 50 -1 0 16 0.0000 6 150 450 -980 -53 $w_1$\001 36 | 4 0 0 50 -1 0 16 0.0000 6 135 270 -1611 -792 $x$\001 37 | 4 0 0 50 -1 0 16 0.0000 6 165 270 -1608 94 $y$\001 38 | 4 0 0 50 -1 0 16 0.0000 6 135 270 -1595 961 $1$\001 39 | -------------------------------------------------------------------------------- /manuscript/img-src/examples/s.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img-src/examples/s.png -------------------------------------------------------------------------------- /manuscript/img-src/examples/silhouette-better.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | 4 | def amplify(x): 5 | n = len(x) 6 | A = np.matrix(np.zeros((2*n,n))) 7 | b = np.matrix(np.zeros((2*n,1))) 8 | for i in range(n): 9 | A[i, i] = 1. # amplify the curvature 10 | A[i, (i+1)%n] = -1. 11 | b[i, 0] = (x[i] - x[(i+1)%n])*1.9 12 | 13 | A[n+i, i] = 1*.3 # light data fitting term 14 | b[n+i, 0] = x[i]*.3 15 | return (np.linalg.inv(A.T*A)*A.T*b).tolist() 16 | 17 | x = [100,100,97,93,91,87,84,83,85,87,88,89,90,90,90,88,87,86,84,82,80, 18 | 77,75,72,69,66,62,58,54,47,42,38,34,32,28,24,22,20,17,15,13,12,9, 19 | 7,8,9,8,6,0,0,2,0,0,2,3,2,0,0,1,4,8,11,14,19,24,27,25,23,21,19] 20 | y = [0,25,27,28,30,34,37,41,44,47,51,54,59,64,66,70,74,78,80,83,86,90,93, 21 | 95,96,98,99,99,100,99,99,99,98,98,96,94,93,91,90,87,85,79,75,70,65, 22 | 62,60,58,52,49,46,44,41,37,34,30,27,20,17,15,16,17,17,19,18,14,11,6,4,1] 23 | 24 | plt.plot(x+[x[0]], y+[y[0]], 'g--') 25 | 26 | x = amplify(x) 27 | y = amplify(y) 28 | 29 | plt.plot(x+[x[0]], y+[y[0]], 'k-', linewidth=3) 30 | plt.axis('off') 31 | plt.gca().set_aspect('equal', adjustable='box') 32 | plt.savefig('silhouette-better.png', bbox_inches='tight') 33 | plt.show() 34 | 35 | -------------------------------------------------------------------------------- /manuscript/img-src/examples/silhouette-naive.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | 4 | x = [100,100,97,93,91,87,84,83,85,87,88,89,90,90,90,88,87,86,84,82,80, 5 | 77,75,72,69,66,62,58,54,47,42,38,34,32,28,24,22,20,17,15,13,12,9, 6 | 7,8,9,8,6,0,0,2,0,0,2,3,2,0,0,1,4,8,11,14,19,24,27,25,23,21,19] 7 | y = [0,25,27,28,30,34,37,41,44,47,51,54,59,64,66,70,74,78,80,83,86,90,93, 8 | 95,96,98,99,99,100,99,99,99,98,98,96,94,93,91,90,87,85,79,75,70,65, 9 | 62,60,58,52,49,46,44,41,37,34,30,27,20,17,15,16,17,17,19,18,14,11,6,4,1] 10 | n = len(x) 11 | 12 | plt.plot(x+[x[0]], y+[y[0]], 'g--') 13 | 14 | cx = [x[i] - (x[(i-1+n)%n]+x[(i+1)%n])/2 for i in range(n)] 15 | cy = [y[i] - (y[(i-1+n)%n]+y[(i+1)%n])/2 for i in range(n)] 16 | 17 | for iter in range(100): 18 | for i in range(n): 19 | x[i] = (x[(i-1+n)%n]+x[(i+1)%n])/2 + cx[i]*1.9 20 | y[i] = (y[(i-1+n)%n]+y[(i+1)%n])/2 + cy[i]*1.9 21 | 22 | plt.plot(x+[x[0]], y+[y[0]], 'k-', linewidth=3) 23 | plt.xlim(-40, 160) 24 | plt.ylim(-60, 140) 25 | plt.axis('off') 26 | plt.gca().set_aspect('equal', adjustable='box') 27 | plt.savefig('silhouette-naive-100.png', bbox_inches='tight') 28 | plt.show() 29 | 30 | -------------------------------------------------------------------------------- /manuscript/img-src/fem.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | 4 | plt.rcParams["font.family"] = "serif" 5 | plt.rcParams["mathtext.fontset"] = "dejavuserif" 6 | plt.rcParams['text.usetex'] = True 7 | plt.rc('font', size=30) 8 | fig, ax = plt.subplots(1, figsize=(6.40,6.40),dpi=100) 9 | 10 | #rhs:radcan(radcan(integrate(n*(x-(i-1)/n)*(x+1),x,(i-1)/n,i/n)) + radcan(integrate(n*((i+1)/n-x)*(x+1),x,i/n,(i+1)/n))); 11 | 12 | # initialize the data array 13 | n = 3 14 | phi = [0.]*(n+1) 15 | phi[0] = 0 16 | phi[n] = 1 17 | 18 | # solve the linear system 19 | for iter in range(1000): 20 | for i in range(1,n): 21 | rhs = (n+i)/n**3 22 | phi[i] = (phi[i-1] + phi[i+1] - rhs)/2. 23 | 24 | # plot the ground truth 25 | X = np.linspace(0., 1., 100) 26 | G = [x**3/6 + x**2/2 + x/3 for x in X] 27 | plt.plot(X, G, 'r-', label='ground truth', linewidth=3) 28 | 29 | # plot the solution 30 | plt.plot(np.linspace(0., 1., n+1), phi, 'gs-', label='FEM solution', linewidth=3) 31 | 32 | plt.ylim(0., 1.) 33 | plt.xlim(0, 1.) 34 | 35 | plt.legend(frameon=False) 36 | 37 | plt.savefig("fem.png", bbox_inches='tight') 38 | plt.show() 39 | 40 | -------------------------------------------------------------------------------- /manuscript/img-src/galerkin.fig: -------------------------------------------------------------------------------- 1 | #FIG 3.2 Produced by xfig version 3.2.7b 2 | Landscape 3 | Center 4 | Metric 5 | A4 6 | 100.00 7 | Single 8 | -2 9 | 1200 2 10 | 2 1 0 2 10 11 50 -1 20 0.000 0 0 -1 1 0 2 11 | 2 1 1.00 60.00 120.00 12 | 1980 2700 4131 2617 13 | 2 1 0 2 -1 11 50 -1 20 0.000 0 0 -1 1 0 2 14 | 2 1 1.00 60.00 120.00 15 | 1980 2700 4146 1885 16 | 2 3 0 1 11 11 500 -1 20 0.000 0 0 -1 0 0 5 17 | 900 2700 2700 1800 5400 2700 3600 3600 900 2700 18 | 2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 3 19 | 3832 2613 3831 2356 4105 2335 20 | 2 1 0 3 12 11 49 -1 20 0.000 0 0 -1 1 0 2 21 | 2 1 1.00 60.00 120.00 22 | 4127 1896 4127 2623 23 | 4 0 -1 50 -1 0 16 0.0000 6 165 810 3073 2145 $\\varphi$\001 24 | 4 0 -1 50 -1 0 16 0.0000 6 135 90 1895 2895 0\001 25 | 4 0 10 50 -1 0 16 0.0000 6 165 1350 3288 2860 $\\tilde\\varphi$\001 26 | 4 0 12 50 -1 0 15 0.0000 6 135 270 4209 2223 $e$\001 27 | 4 0 -1 50 -1 0 16 0.0000 6 135 1080 3885 2547 $\\mathcal A$\001 28 | 4 0 10 50 -1 0 16 0.4712 6 180 2970 3555 3494 $\\text{span}\\{w_1\\dots w_{n-1}\\}$\001 29 | -------------------------------------------------------------------------------- /manuscript/img-src/linsys_curvature.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img-src/linsys_curvature.mp4 -------------------------------------------------------------------------------- /manuscript/img-src/linsys_curvature.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | import matplotlib.animation as animation 4 | 5 | plt.rcParams["font.family"] = "serif" 6 | plt.rcParams["mathtext.fontset"] = "dejavuserif" 7 | #plt.rcParams['text.usetex'] = True 8 | plt.rc('font', size=20) 9 | fig, ax = plt.subplots(1, figsize=(6.40,2.40),dpi=100) 10 | 11 | x = [0.] * 32 12 | x[0] = x[31] = 1. 13 | x[18] = 2. 14 | 15 | n = len(x) 16 | 17 | 18 | lines = [ax.plot(range(n), x, 'bs-')[0], ax.text(0.32, -0.2, "Iteration #0", transform=ax.transAxes)] 19 | 20 | plt.tick_params( 21 | axis='x', # changes apply to the x-axis 22 | which='both', # both major and minor ticks are affected 23 | bottom=False, # ticks along the bottom edge are off 24 | top=False, # ticks along the top edge are off 25 | labelbottom=False) # labels along the bottom edge are off 26 | plt.tight_layout() 27 | #plt.ylim(top=3) 28 | 29 | plt.draw() 30 | 31 | #ax.grid() 32 | 33 | def animate(iteration): 34 | global x,n 35 | if (0==iteration): 36 | return lines 37 | 38 | c = 23./32**2 # the curvature to prescribe 39 | for i in range(0, len(x)): 40 | if i in [0,18,31]: continue 41 | x[i] = (x[i-1]+x[i+1]+c)/2. 42 | 43 | print(iteration) 44 | 45 | lines[0].set_data(range(n), x) # update the data. 46 | lines[1].set_text("Iteration #" + str(iteration)) 47 | plt.draw() 48 | ax.relim() 49 | ax.autoscale_view(True,True,True) 50 | return lines 51 | 52 | ani = animation.FuncAnimation(fig, animate, frames=np.arange(0, 150), interval=100, blit=False, save_count=50) 53 | #ani.save('linsys_curvature.gif', dpi=100, writer='imagemagick') 54 | 55 | # To save the animation, use e.g. 56 | # 57 | #ani.save("movie.mp4") 58 | # 59 | # or 60 | # 61 | from matplotlib.animation import FFMpegWriter 62 | writer = FFMpegWriter(fps=15, metadata=dict(artist='Me'), bitrate=1800) 63 | ani.save("linsys_curvature.mp4", writer=writer) 64 | 65 | #plt.show() 66 | -------------------------------------------------------------------------------- /manuscript/img-src/linsys_smooth.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img-src/linsys_smooth.mp4 -------------------------------------------------------------------------------- /manuscript/img-src/linsys_smooth.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | import matplotlib.animation as animation 4 | 5 | plt.rcParams["font.family"] = "serif" 6 | plt.rcParams["mathtext.fontset"] = "dejavuserif" 7 | #plt.rcParams['text.usetex'] = True 8 | plt.rc('font', size=20) 9 | fig, ax = plt.subplots(1, figsize=(6.40,2.40),dpi=100) 10 | 11 | x = [0.] * 32 12 | x[0] = x[31] = 1. 13 | x[18] = 2. 14 | 15 | n = len(x) 16 | 17 | lines = [ax.plot(range(n), x, 'bs-')[0], ax.text(0.32, -0.2, "Iteration #0", transform=ax.transAxes)] 18 | 19 | plt.tick_params( 20 | axis='x', # changes apply to the x-axis 21 | which='both', # both major and minor ticks are affected 22 | bottom=False, # ticks along the bottom edge are off 23 | top=False, # ticks along the top edge are off 24 | labelbottom=False) # labels along the bottom edge are off 25 | plt.tight_layout() 26 | 27 | plt.draw() 28 | 29 | #ax.grid() 30 | 31 | def animate(iteration): 32 | global x,n 33 | if (0==iteration): 34 | return lines 35 | 36 | x[0] = x[1] 37 | for i in range(1, len(x)-1): 38 | x[i] = (x[i-1]+x[i+1])/2. 39 | x[-1] = x[-2] 40 | 41 | print(iteration) 42 | 43 | lines[0].set_data(range(n), x) # update the data. 44 | lines[1].set_text("Iteration #" + str(iteration)) 45 | plt.draw() 46 | ax.relim() 47 | ax.autoscale_view(False,True,False) 48 | return lines 49 | 50 | ani = animation.FuncAnimation(fig, animate, frames=np.arange(0, 150), interval=100, blit=False, save_count=50) 51 | #ani.save('linsys_smooth.gif', dpi=100, writer='imagemagick') 52 | 53 | # To save the animation, use e.g. 54 | # 55 | #ani.save("movie.mp4") 56 | # 57 | # or 58 | # 59 | from matplotlib.animation import FFMpegWriter 60 | writer = FFMpegWriter(fps=15, metadata=dict(artist='Me'), bitrate=1800) 61 | ani.save("linsys_smooth.mp4", writer=writer) 62 | 63 | #plt.show() 64 | -------------------------------------------------------------------------------- /manuscript/img-src/linsys_smooth_constrain.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img-src/linsys_smooth_constrain.mp4 -------------------------------------------------------------------------------- /manuscript/img-src/linsys_smooth_constrain.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | import matplotlib.animation as animation 4 | 5 | plt.rcParams["font.family"] = "serif" 6 | plt.rcParams["mathtext.fontset"] = "dejavuserif" 7 | #plt.rcParams['text.usetex'] = True 8 | plt.rc('font', size=20) 9 | fig, ax = plt.subplots(1, figsize=(6.40,2.40),dpi=100) 10 | 11 | x = [0.] * 32 12 | x[0] = x[31] = 1. 13 | x[18] = 2. 14 | 15 | n = len(x) 16 | 17 | 18 | lines = [ax.plot(range(n), x, 'bs-')[0], ax.text(0.32, -0.2, "Iteration #0", transform=ax.transAxes)] 19 | 20 | plt.tick_params( 21 | axis='x', # changes apply to the x-axis 22 | which='both', # both major and minor ticks are affected 23 | bottom=False, # ticks along the bottom edge are off 24 | top=False, # ticks along the top edge are off 25 | labelbottom=False) # labels along the bottom edge are off 26 | plt.tight_layout() 27 | 28 | plt.draw() 29 | 30 | #ax.grid() 31 | 32 | def animate(iteration): 33 | global x,n 34 | if (0==iteration): 35 | return lines 36 | 37 | for i in range(0, len(x)): 38 | if i in [0,18,31]: continue 39 | x[i] = (x[i-1]+x[i+1])/2. 40 | 41 | print(iteration) 42 | 43 | lines[0].set_data(range(n), x) # update the data. 44 | lines[1].set_text("Iteration #" + str(iteration)) 45 | plt.draw() 46 | ax.relim() 47 | ax.autoscale_view(True,True,True) 48 | return lines 49 | 50 | ani = animation.FuncAnimation(fig, animate, frames=np.arange(0, 150), interval=100, blit=False, save_count=50) 51 | #ani.save('linsys_smooth_constrain.gif', dpi=100, writer='imagemagick') 52 | 53 | 54 | from matplotlib.animation import FFMpegWriter 55 | writer = FFMpegWriter(fps=15, metadata=dict(artist='Me'), bitrate=1800) 56 | ani.save("linsys_smooth_constrain.mp4", writer=writer) 57 | 58 | #plt.show() 59 | -------------------------------------------------------------------------------- /manuscript/img-src/lscm/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 2.8) 2 | project(lscm) 3 | 4 | include(CheckCXXCompilerFlag) 5 | 6 | function(enable_cxx_compiler_flag_if_supported flag) 7 | string(FIND "${CMAKE_CXX_FLAGS}" "${flag}" flag_already_set) 8 | if(flag_already_set EQUAL -1) 9 | check_cxx_compiler_flag("${flag}" flag_supported) 10 | if(flag_supported) 11 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${flag}" PARENT_SCOPE) 12 | endif() 13 | unset(flag_supported CACHE) 14 | endif() 15 | endfunction() 16 | 17 | enable_cxx_compiler_flag_if_supported("-Wall") 18 | enable_cxx_compiler_flag_if_supported("-Wextra") 19 | enable_cxx_compiler_flag_if_supported("-pedantic") 20 | enable_cxx_compiler_flag_if_supported("-std=c++11") 21 | enable_cxx_compiler_flag_if_supported("-O3") 22 | enable_cxx_compiler_flag_if_supported("-fopenmp") 23 | 24 | file(GLOB SOURCES *.h *.cpp) 25 | 26 | add_executable(${PROJECT_NAME} ${SOURCES}) 27 | target_link_libraries(${PROJECT_NAME} m ${CMAKE_DL_LIBS}) 28 | 29 | 30 | -------------------------------------------------------------------------------- /manuscript/img-src/lscm/geometry.h: -------------------------------------------------------------------------------- 1 | #ifndef __GEOMETRY_H__ 2 | #define __GEOMETRY_H__ 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | template struct vec { 9 | vec() { for (size_t i=DIM; i--; data_[i] = T()); } 10 | T& operator[](const size_t i) { assert(i struct vec<2,T> { 19 | vec() : x(T()), y(T()) {} 20 | vec(T X, T Y) : x(X), y(Y) {} 21 | template vec<2,T>(const vec<2,U> &v); 22 | T& operator[](const size_t i) { assert(i<2); return i<=0 ? x : y; } 23 | const T& operator[](const size_t i) const { assert(i<2); return i<=0 ? x : y; } 24 | 25 | T x,y; 26 | }; 27 | 28 | ///////////////////////////////////////////////////////////////////////////////// 29 | 30 | template struct vec<3,T> { 31 | vec() : x(T()), y(T()), z(T()) {} 32 | vec(T X, T Y, T Z) : x(X), y(Y), z(Z) {} 33 | template vec<3,T>(const vec<3,U> &v); 34 | T& operator[](const size_t i) { assert(i<3); return i<=0 ? x : (1==i ? y : z); } 35 | const T& operator[](const size_t i) const { assert(i<3); return i<=0 ? x : (1==i ? y : z); } 36 | float norm() { return std::sqrt(x*x+y*y+z*z); } 37 | vec<3,T> & normalize(T l=1) { *this = (*this)*(l/norm()); return *this; } 38 | 39 | T x,y,z; 40 | }; 41 | 42 | ///////////////////////////////////////////////////////////////////////////////// 43 | 44 | template T operator*(const vec& lhs, const vec& rhs) { 45 | T ret = T(); 46 | for (size_t i=DIM; i--; ret+=lhs[i]*rhs[i]); 47 | return ret; 48 | } 49 | 50 | 51 | templatevec operator+(vec lhs, const vec& rhs) { 52 | for (size_t i=DIM; i--; lhs[i]+=rhs[i]); 53 | return lhs; 54 | } 55 | 56 | templatevec operator-(vec lhs, const vec& rhs) { 57 | for (size_t i=DIM; i--; lhs[i]-=rhs[i]); 58 | return lhs; 59 | } 60 | 61 | template vec operator*(vec lhs, const U& rhs) { 62 | for (size_t i=DIM; i--; lhs[i]*=rhs); 63 | return lhs; 64 | } 65 | 66 | template vec operator/(vec lhs, const U& rhs) { 67 | for (size_t i=DIM; i--; lhs[i]/=rhs); 68 | return lhs; 69 | } 70 | 71 | template vec embed(const vec &v, T fill=1) { 72 | vec ret; 73 | for (size_t i=LEN; i--; ret[i]=(i vec proj(const vec &v) { 78 | vec ret; 79 | for (size_t i=LEN; i--; ret[i]=v[i]); 80 | return ret; 81 | } 82 | 83 | template vec<3,T> cross(vec<3,T> v1, vec<3,T> v2) { 84 | return vec<3,T>(v1.y*v2.z - v1.z*v2.y, v1.z*v2.x - v1.x*v2.z, v1.x*v2.y - v1.y*v2.x); 85 | } 86 | 87 | template std::ostream& operator<<(std::ostream& out, vec& v) { 88 | for(unsigned int i=0; i vec2; 97 | typedef vec<2, int> vec2i; 98 | typedef vec<3, double> vec3; 99 | typedef vec<3, int> vec3i; 100 | 101 | #endif //__GEOMETRY_H__ 102 | 103 | -------------------------------------------------------------------------------- /manuscript/img-src/lscm/main.cpp: -------------------------------------------------------------------------------- 1 | #include "OpenNL_psm.h" 2 | #include "model.h" 3 | 4 | void project_triangle(const vec3& p0, const vec3& p1, const vec3& p2, vec2& z0, vec2& z1, vec2& z2) { 5 | vec3 X = (p1 - p0).normalize(); // construct an orthonormal 3d basis 6 | vec3 Z = cross(X, p2 - p0).normalize(); 7 | vec3 Y = cross(Z, X); 8 | 9 | z0 = vec2(0,0); // project the triangle to the 2d basis (X,Y) 10 | z1 = vec2((p1 - p0).norm(), 0); 11 | z2 = vec2((p2 - p0)*X, (p2 - p0)*Y); 12 | } 13 | 14 | int main() { 15 | Model m("../input.obj"); 16 | 17 | nlNewContext(); 18 | nlSolverParameteri(NL_NB_VARIABLES, 2*m.nverts()); // u0,v0,u1,v1, ... 19 | nlSolverParameteri(NL_LEAST_SQUARES, NL_TRUE); 20 | nlBegin(NL_SYSTEM); 21 | 22 | // select two arbitrary vertices to pin 23 | int lock1 = 10324 % m.nverts(), lock2 = 35492 % m.nverts(); 24 | 25 | nlSetVariable(lock1*2+0, 0); // first vertex is pinned to (0,0) 26 | nlSetVariable(lock1*2+1, 0); 27 | nlSetVariable(lock2*2+0, 1); // the second one to (1,1) 28 | nlSetVariable(lock2*2+1, 1); 29 | nlLockVariable(lock1*2+0); // eliminate 4 constrained variables from the system 30 | nlLockVariable(lock1*2+1); 31 | nlLockVariable(lock2*2+0); 32 | nlLockVariable(lock2*2+1); 33 | 34 | nlBegin(NL_MATRIX); 35 | for (int f=0; f 2 | #include 3 | #include 4 | #include 5 | #include "model.h" 6 | 7 | // fills verts and faces arrays, supposes .obj file to have "f " entries without slashes 8 | Model::Model(const char *filename) : verts(), faces(), v2h(), opposites() { 9 | std::ifstream in; 10 | in.open (filename, std::ifstream::in); 11 | if (in.fail()) { 12 | std::cerr << "Failed to open " << filename << std::endl; 13 | return; 14 | } 15 | std::string line; 16 | while (!in.eof()) { 17 | std::getline(in, line); 18 | std::istringstream iss(line.c_str()); 19 | char trash; 20 | if (!line.compare(0, 2, "v ")) { 21 | iss >> trash; 22 | vec3 v; 23 | for (int i=0;i<3;i++) iss >> v[i]; 24 | verts.push_back(v); 25 | } else if (!line.compare(0, 2, "f ")) { 26 | vec3i f; 27 | int idx, cnt=0; 28 | iss >> trash; 29 | while (iss >> idx) { 30 | idx--; // in wavefront obj all indices start at 1, not zero 31 | f[cnt++] = idx; 32 | } 33 | if (3==cnt) faces.push_back(f); 34 | } 35 | } 36 | std::cerr << "# v# " << verts.size() << " f# " << faces.size() << std::endl; 37 | 38 | v2h = std::vector >(verts.size()); 39 | for (int i=0; i(nfaces()*3, -1); 45 | compute_opposites(); 46 | } 47 | 48 | bool Model::is_boundary_vert(int v) { 49 | for (int hid : incident_halfedges(v)) { 50 | if (opp(hid)<0) return true; 51 | } 52 | return false; 53 | } 54 | 55 | int Model::from(int hid) { 56 | return vert(hid/3, hid%3); 57 | } 58 | 59 | int Model::to(int hid) { 60 | return vert(hid/3, (hid+1)%3); 61 | } 62 | 63 | int Model::opp(int hid) { 64 | return opposites[hid]; 65 | } 66 | 67 | void Model::compute_opposites() { 68 | for (int h1=0; h1 &Model::incident_halfedges(int v) { 97 | return v2h[v]; 98 | } 99 | 100 | void Model::get_bbox(vec3 &min, vec3 &max) { 101 | min = max = verts[0]; 102 | for (int i=1; i<(int)verts.size(); ++i) { 103 | for (int j=0; j<3; j++) { 104 | min[j] = std::min(min[j], verts[i][j]); 105 | max[j] = std::max(max[j], verts[i][j]); 106 | } 107 | } 108 | std::cerr << "bbox: [" << min << " : " << max << "]" << std::endl; 109 | } 110 | 111 | vec3 &Model::point(int i) { 112 | assert(i>=0 && i=0 && fi=0 && li<3); 118 | return faces[fi][li]; 119 | } 120 | 121 | std::ostream& operator<<(std::ostream& out, Model &m) { 122 | for (int i=0; i 4 | #include 5 | #include "geometry.h" 6 | 7 | class Model { 8 | private: 9 | std::vector verts; 10 | std::vector faces; 11 | std::vector > v2h; // vertex to halfedge incidency 12 | std::vector opposites; // halfedges 13 | void compute_opposites(); 14 | public: 15 | Model(const char *filename); 16 | 17 | int nverts(); 18 | int nfaces(); 19 | int nhalfedges(); 20 | 21 | vec3 &point(int i); 22 | int vert(int fi, int li); 23 | void get_bbox(vec3 &min, vec3 &max); 24 | void print_obj(); 25 | 26 | bool is_boundary_vert(int v); 27 | 28 | int from(int hid); 29 | int to(int hid); 30 | int opp(int hid); 31 | std::vector &incident_halfedges(int v); 32 | }; 33 | 34 | std::ostream& operator<<(std::ostream& out, Model &m); 35 | 36 | #endif //__MODEL_H__ 37 | 38 | -------------------------------------------------------------------------------- /manuscript/img-src/lscm/obj-prepare/lscm-head.mtl: -------------------------------------------------------------------------------- 1 | # Blender MTL File: 'None' 2 | # Material Count: 1 3 | 4 | newmtl None 5 | Ns 0.000000 6 | Ka 0.000000 0.000000 0.000000 7 | Kd 0.800000 0.800000 0.800000 8 | Ks 0.800000 0.800000 0.800000 9 | Ke 0.000000 0.000000 0.000000 10 | Ni 1.000000 11 | d 1.000000 12 | illum 2 13 | map_Kd lscm-head.png 14 | -------------------------------------------------------------------------------- /manuscript/img-src/lscm/obj-prepare/lscm-head.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img-src/lscm/obj-prepare/lscm-head.png -------------------------------------------------------------------------------- /manuscript/img-src/lscm/obj-prepare/siggraph-head-low.mtl: -------------------------------------------------------------------------------- 1 | # Blender MTL File: 'None' 2 | # Material Count: 1 3 | 4 | newmtl None 5 | Ns 0.000000 6 | Ka 0.000000 0.000000 0.000000 7 | Kd 0.800000 0.800000 0.800000 8 | Ks 0.800000 0.800000 0.800000 9 | Ke 0.000000 0.000000 0.000000 10 | Ni 1.000000 11 | d 1.000000 12 | illum 2 13 | map_Kd siggraph-head-low.png 14 | -------------------------------------------------------------------------------- /manuscript/img-src/lscm/obj-prepare/siggraph-head-low.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img-src/lscm/obj-prepare/siggraph-head-low.png -------------------------------------------------------------------------------- /manuscript/img-src/neural-animation.py: -------------------------------------------------------------------------------- 1 | import matplotlib.animation as animation 2 | import matplotlib.pyplot as plt 3 | import numpy as np 4 | import math 5 | import random 6 | 7 | def neuron(x, w): 8 | return 1./(1.+math.exp(-np.dot(x,w))) 9 | 10 | #u = [random.random(), random.random(), random.random()] 11 | #v = [random.random(), random.random(), random.random()] 12 | #w = [random.random(), random.random(), random.random()] 13 | u = [0.814, 0.779, 0.103] # small random values 14 | v = [0.562, 0.310, 0.591] 15 | w = [0.884, 0.934, 0.649] 16 | 17 | samples = [[.5, .7, 1.], [.1, .5, 1.], [.3, .6, 0.], [.2, .8, 0.], [.17, .17, 1.], [.2, .3, 1.], [.3, .4, 1.], [.05, .2, 1.], [.2, .3, 1.], [.8, .3, 1.], [.5, .2, 1.], [.7, .2, 1.], [.9, .1, 1.], [.8, .4, 1.], [.6, .5, 1.], [.5, .4, 1.]] 18 | labels = [0.,0.,0.,0.,0.,0.,0.,0.,0.,1.,1.,1.,1.,1.,1.,1.] 19 | 20 | samples2 = [[.9, .5, 1.],[.79, .6, 1.],[.73, .7, 1.],[.9, .8, 1.],[.95, .4, 1.]] 21 | labels2 = [0.,0.,0.,0.,0.] 22 | 23 | samples = samples + samples2 24 | labels = labels + labels2 25 | 26 | alpha = 1.0 # learning rate 27 | 28 | 29 | fig,ax = plt.subplots(1, figsize=(6.40,6.40),dpi=100) 30 | 31 | res = 100 32 | x0 = np.arange(0, 1., 1./res) 33 | x1 = np.arange(0, 1., 1./res) 34 | 35 | 36 | def draw(i): 37 | for iter in range(0,30): 38 | for x, label in zip(samples,labels): 39 | for i in range(3): 40 | xprime = [neuron(x, u), neuron(x, v), 1.] 41 | out_w = neuron(xprime, w) 42 | w[i] += alpha*(label-out_w)*out_w*(1.-out_w)*xprime[i] 43 | 44 | out_u = neuron(x, u) 45 | u[i] += alpha*(label-out_w)*out_w*(1.-out_w)*out_u*(1.-out_u)*x[i] 46 | 47 | out_v = neuron(x, v) 48 | v[i] += alpha*(label-out_w)*out_w*(1.-out_w)*out_v*(1.-out_v)*x[i] 49 | 50 | Y = [[neuron([neuron([a,b,1.], u), neuron([a,b,1],v), 1.], w) for a in x0] for b in x1] 51 | X0, X1 = np.meshgrid(x0, x1) 52 | plt.contourf(X0, X1, Y, 100, vmin=0., vmax=1., cmap=plt.cm.RdYlGn) 53 | # plt.colorbar() 54 | plt.contour(X0, X1, Y,levels=[.49995, .50005], colors='k', linestyles='--') 55 | 56 | for sample, label in zip(samples,labels): 57 | c = 'g' 58 | if (label<.5): c = 'r' 59 | plt.scatter(sample[0], sample[1], color=c, edgecolors='black') 60 | 61 | E = 0 62 | for x, label in zip(samples,labels): 63 | xprime = [neuron(x, u), neuron(x, v), 1.] 64 | E += (label - neuron(xprime,w))**2 65 | print("E =",E) 66 | ax.text(0.05, 0.05, ("Error: %3.3f" % E) , transform=ax.transAxes, fontsize=24) 67 | 68 | def animate(i): 69 | ax.clear() 70 | draw(i) 71 | return ax, 72 | 73 | draw(0) 74 | plt.gca().axes.get_yaxis().set_visible(False) 75 | plt.gca().axes.get_xaxis().set_visible(False) 76 | plt.tight_layout() 77 | 78 | ani = animation.FuncAnimation(fig, animate, frames=np.arange(0, 100), interval=1, blit=False, save_count=100) 79 | #ani.save('classifier.gif', dpi=80, writer='imagemagick') 80 | 81 | from matplotlib.animation import FFMpegWriter 82 | writer = FFMpegWriter(fps=15, metadata=dict(artist='Me'), bitrate=1800) 83 | ani.save("classifier.mp4", writer=writer) 84 | 85 | #plt.show() 86 | 87 | -------------------------------------------------------------------------------- /manuscript/img-src/prepie.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | fa = 1 # left constraint 4 | fb = 3 # right constraint 5 | n = 40 6 | x = np.linspace(0, 2*np.pi, n) 7 | g = [np.sin(p) for p in x] 8 | 9 | A = np.matrix(np.zeros((n-1,n-2))) 10 | b = np.matrix(np.zeros((n-1,1))) 11 | A[0,0] = 1 12 | b[0,0] = fa + g[1]-g[0] 13 | A[n-2, n-3] = -1 14 | b[n-2,0] = -fb + g[-1]-g[-2] 15 | for i in range(1,n-2): 16 | b[i,0] = g[i]-g[i-1] 17 | A[i, i-1] = -1 18 | A[i, i ] = 1 19 | 20 | f = [fa] + (np.linalg.inv(A.T*A)*A.T*b).T.tolist()[0] + [fb] 21 | 22 | import matplotlib.pyplot as plt 23 | 24 | plt.rcParams["font.family"] = "serif" 25 | plt.rcParams["mathtext.fontset"] = "dejavuserif" 26 | plt.rcParams['text.usetex'] = True 27 | plt.rc('font', size=20) 28 | #plt.rc('axes', titlesize=20, labelsize=20) 29 | #plt.rc('xtick', labelsize=40) # fontsize of the tick labels 30 | 31 | fig,ax = plt.subplots(1, figsize=(6.40,6.40),dpi=150) 32 | 33 | for item in ([ax.title, ax.xaxis.label, ax.yaxis.label] + 34 | ax.get_xticklabels() + ax.get_yticklabels()): 35 | item.set_fontsize(20) 36 | 37 | 38 | plt.plot(x, f, linewidth=3, label='$f(x)$') 39 | plt.plot(x, g, linewidth=3, label='$g(x) = \sin x$') 40 | plt.scatter([x[0], x[-1]], [fa,fb], color='red', edgecolors='black',s=200) 41 | plt.legend(frameon=False) 42 | plt.tight_layout() 43 | plt.gca().set_aspect('equal', adjustable='box') 44 | plt.savefig('prepie.png', bbox_inches='tight') 45 | plt.show() 46 | -------------------------------------------------------------------------------- /manuscript/img-src/tex-mapping.fig: -------------------------------------------------------------------------------- 1 | #FIG 3.2 Produced by xfig version 3.2.7b 2 | Landscape 3 | Center 4 | Metric 5 | A4 6 | 100.00 7 | Single 8 | -2 9 | 1200 2 10 | 2 5 0 1 0 -1 50 -1 -1 0.000 0 0 -1 0 0 5 11 | 0 /home/ssloy/+/least-squares-course/manuscript/img/tex-superposed.jpg 12 | 2250 0 4005 0 4005 1755 2250 1755 2250 0 13 | 2 5 0 1 0 -1 50 -1 -1 0.000 0 0 -1 0 0 5 14 | 0 /home/ssloy/+/least-squares-course/manuscript/img/tex-mesh.png 15 | 0 0 1215 0 1215 1755 0 1755 0 0 16 | 2 5 0 1 0 -1 50 -1 -1 0.000 0 0 -1 0 0 5 17 | 0 /home/ssloy/+/least-squares-course/manuscript/img/tex-applied.png 18 | 4950 0 6165 0 6165 1755 4950 1755 4950 0 19 | 2 1 0 3 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 20 | 2 1 2.00 90.00 150.00 21 | 1260 900 2160 900 22 | 2 1 0 3 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 23 | 2 1 2.00 90.00 150.00 24 | 4050 900 4950 900 25 | 4 0 0 50 -1 0 16 0.0000 6 180 900 1260 765 $U(x,y,z)$\001 26 | 4 0 0 50 -1 0 16 0.0000 6 165 720 1350 1170 $=(u,v)$\001 27 | 4 0 0 50 -1 0 16 0.0000 6 165 1170 4050 765 $U^{-1}(u,v)$\001 28 | 4 0 0 50 -1 0 16 0.0000 6 180 900 4029 1218 $=(x,y,z)$\001 29 | -------------------------------------------------------------------------------- /manuscript/img-src/vector_approximation.fig: -------------------------------------------------------------------------------- 1 | #FIG 3.2 Produced by xfig version 3.2.7a 2 | Landscape 3 | Center 4 | Metric 5 | A4 6 | 100.00 7 | Single 8 | -2 9 | 1200 2 10 | 0 32 #7b7b7b 11 | 0 33 #fb6063 12 | 2 1 0 3 10 7 50 -1 -1 0.000 0 0 -1 1 0 2 13 | 2 1 2.00 75.00 120.00 14 | 1350 4050 2880 2205 15 | 2 1 1 3 0 7 50 -1 -1 8.000 0 0 -1 1 0 2 16 | 2 1 2.00 75.00 120.00 17 | 1350 4050 2250 3600 18 | 2 1 0 3 33 7 51 -1 -1 0.000 0 0 -1 1 0 2 19 | 2 1 2.00 75.00 120.00 20 | 1350 4050 3690 2880 21 | 2 1 0 3 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 22 | 2 1 2.00 75.00 120.00 23 | 2862 2227 3690 2880 24 | 2 1 0 1 32 7 53 -1 -1 0.000 0 0 -1 0 0 2 25 | 1080 4185 3870 2790 26 | 2 1 1 1 32 7 53 -1 -1 4.000 0 0 -1 0 0 2 27 | 2871 2242 3291 3083 28 | 2 1 0 1 32 7 50 -1 -1 0.000 0 0 -1 0 0 3 29 | 3230 2983 3167 3012 3203 3083 30 | 4 0 9 51 -1 0 12 0.0000 6 210 1395 2475 2385 $\\vec{\\varphi}$\001 31 | 4 0 -1 50 -1 0 12 0.0000 6 210 1155 3461 2621 $\\vec{e}(a)$\001 32 | 4 0 33 50 -1 0 12 0.5236 6 210 3000 3352 3281 $\\vec{\\tilde\\varphi} = a\\,\\vec{w}$\001 33 | 4 0 -1 50 -1 0 12 0.5236 6 210 960 2085 3912 $\\vec{w}$\001 34 | -------------------------------------------------------------------------------- /manuscript/img/2_7x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/2_7x.png -------------------------------------------------------------------------------- /manuscript/img/2_7x2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/2_7x2.png -------------------------------------------------------------------------------- /manuscript/img/3n.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/3n.jpg -------------------------------------------------------------------------------- /manuscript/img/3neurons.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/3neurons.pdf -------------------------------------------------------------------------------- /manuscript/img/3neurons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/3neurons.png -------------------------------------------------------------------------------- /manuscript/img/ARAP.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/ARAP.jpg -------------------------------------------------------------------------------- /manuscript/img/URI.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/URI.png -------------------------------------------------------------------------------- /manuscript/img/arap-lap-a.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/arap-lap-a.jpg -------------------------------------------------------------------------------- /manuscript/img/arap-lap-b.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/arap-lap-b.jpg -------------------------------------------------------------------------------- /manuscript/img/axiomes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/axiomes.png -------------------------------------------------------------------------------- /manuscript/img/barycenter/1ring.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/barycenter/1ring.png -------------------------------------------------------------------------------- /manuscript/img/barycenter/ls-teaser.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/barycenter/ls-teaser.jpg -------------------------------------------------------------------------------- /manuscript/img/barycenter/ls-teaser2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/barycenter/ls-teaser2.jpg -------------------------------------------------------------------------------- /manuscript/img/barycenter/ls-teaser3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/barycenter/ls-teaser3.jpg -------------------------------------------------------------------------------- /manuscript/img/binary-classification-problem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/binary-classification-problem.png -------------------------------------------------------------------------------- /manuscript/img/binomial-05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/binomial-05.png -------------------------------------------------------------------------------- /manuscript/img/binomial-07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/binomial-07.png -------------------------------------------------------------------------------- /manuscript/img/blending_functions.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/blending_functions.pdf -------------------------------------------------------------------------------- /manuscript/img/c5aa80f6a2e9575abfa7b3dfdabf5c5a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/c5aa80f6a2e9575abfa7b3dfdabf5c5a.png -------------------------------------------------------------------------------- /manuscript/img/caricature.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/caricature.jpg -------------------------------------------------------------------------------- /manuscript/img/cg/Aorth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/cg/Aorth.png -------------------------------------------------------------------------------- /manuscript/img/cg/MMA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/cg/MMA.png -------------------------------------------------------------------------------- /manuscript/img/cg/conjuge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/cg/conjuge.png -------------------------------------------------------------------------------- /manuscript/img/cg/defpositiveness.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/cg/defpositiveness.png -------------------------------------------------------------------------------- /manuscript/img/cg/gradient2Dconverge.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/cg/gradient2Dconverge.pdf -------------------------------------------------------------------------------- /manuscript/img/cg/gradient2Dconverge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/cg/gradient2Dconverge.png -------------------------------------------------------------------------------- /manuscript/img/cg/gradient3Dconverge1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/cg/gradient3Dconverge1.pdf -------------------------------------------------------------------------------- /manuscript/img/cg/gradient3Dconverge1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/cg/gradient3Dconverge1.png -------------------------------------------------------------------------------- /manuscript/img/cg/laplace1d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/cg/laplace1d.png -------------------------------------------------------------------------------- /manuscript/img/cg/laplace1dresults.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/cg/laplace1dresults.png -------------------------------------------------------------------------------- /manuscript/img/cg/laplace2d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/cg/laplace2d.png -------------------------------------------------------------------------------- /manuscript/img/cg/problem2d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/cg/problem2d.png -------------------------------------------------------------------------------- /manuscript/img/cg/proj2D.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/cg/proj2D.png -------------------------------------------------------------------------------- /manuscript/img/conformal.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/conformal.pdf -------------------------------------------------------------------------------- /manuscript/img/convolution.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/convolution.png -------------------------------------------------------------------------------- /manuscript/img/cubify-flagging.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/cubify-flagging.jpg -------------------------------------------------------------------------------- /manuscript/img/cubify-proj.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/cubify-proj.pdf -------------------------------------------------------------------------------- /manuscript/img/cubify.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/cubify.jpg -------------------------------------------------------------------------------- /manuscript/img/error.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/error.pdf -------------------------------------------------------------------------------- /manuscript/img/example_3_1_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/example_3_1_0.png -------------------------------------------------------------------------------- /manuscript/img/example_3_1_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/example_3_1_1.png -------------------------------------------------------------------------------- /manuscript/img/example_3_1_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/example_3_1_2.png -------------------------------------------------------------------------------- /manuscript/img/example_3_1_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/example_3_1_3.png -------------------------------------------------------------------------------- /manuscript/img/example_3_1_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/example_3_1_4.png -------------------------------------------------------------------------------- /manuscript/img/example_3_1_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/example_3_1_5.png -------------------------------------------------------------------------------- /manuscript/img/example_3_2_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/example_3_2_0.png -------------------------------------------------------------------------------- /manuscript/img/example_3_2_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/example_3_2_1.png -------------------------------------------------------------------------------- /manuscript/img/example_3_2_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/example_3_2_2.png -------------------------------------------------------------------------------- /manuscript/img/example_3_2_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/example_3_2_3.png -------------------------------------------------------------------------------- /manuscript/img/example_3_2_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/example_3_2_4.png -------------------------------------------------------------------------------- /manuscript/img/example_3_2_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/example_3_2_5.png -------------------------------------------------------------------------------- /manuscript/img/example_3_3_0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/example_3_3_0.jpg -------------------------------------------------------------------------------- /manuscript/img/example_3_3_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/example_3_3_1.jpg -------------------------------------------------------------------------------- /manuscript/img/example_3_3_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/example_3_3_2.jpg -------------------------------------------------------------------------------- /manuscript/img/example_3_4_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/example_3_4_0.png -------------------------------------------------------------------------------- /manuscript/img/example_3_4_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/example_3_4_1.png -------------------------------------------------------------------------------- /manuscript/img/example_3_4_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/example_3_4_2.png -------------------------------------------------------------------------------- /manuscript/img/example_3_4_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/example_3_4_3.png -------------------------------------------------------------------------------- /manuscript/img/example_3_4_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/example_3_4_4.png -------------------------------------------------------------------------------- /manuscript/img/example_3_4_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/example_3_4_5.png -------------------------------------------------------------------------------- /manuscript/img/example_6_1_a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/example_6_1_a.png -------------------------------------------------------------------------------- /manuscript/img/example_6_1_b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/example_6_1_b.png -------------------------------------------------------------------------------- /manuscript/img/example_6_1_c.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/example_6_1_c.png -------------------------------------------------------------------------------- /manuscript/img/example_6_3_a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/example_6_3_a.png -------------------------------------------------------------------------------- /manuscript/img/example_6_3_b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/example_6_3_b.png -------------------------------------------------------------------------------- /manuscript/img/example_6_3_c.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/example_6_3_c.png -------------------------------------------------------------------------------- /manuscript/img/example_6_3_d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/example_6_3_d.png -------------------------------------------------------------------------------- /manuscript/img/example_6_3_e.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/example_6_3_e.png -------------------------------------------------------------------------------- /manuscript/img/example_8_1_a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/example_8_1_a.png -------------------------------------------------------------------------------- /manuscript/img/example_8_1_b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/example_8_1_b.png -------------------------------------------------------------------------------- /manuscript/img/example_8_1_c.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/example_8_1_c.png -------------------------------------------------------------------------------- /manuscript/img/fem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/fem.png -------------------------------------------------------------------------------- /manuscript/img/galerkin.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/galerkin.pdf -------------------------------------------------------------------------------- /manuscript/img/gradient-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/gradient-bg.png -------------------------------------------------------------------------------- /manuscript/img/head-smooth.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/head-smooth.jpg -------------------------------------------------------------------------------- /manuscript/img/idea.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/idea.png -------------------------------------------------------------------------------- /manuscript/img/likehood-07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/likehood-07.png -------------------------------------------------------------------------------- /manuscript/img/linear-1d-a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/linear-1d-a.png -------------------------------------------------------------------------------- /manuscript/img/linear-1d-b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/linear-1d-b.png -------------------------------------------------------------------------------- /manuscript/img/linearly-separable-dataset.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/linearly-separable-dataset.png -------------------------------------------------------------------------------- /manuscript/img/linearly-unseparable-dataset.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/linearly-unseparable-dataset.png -------------------------------------------------------------------------------- /manuscript/img/logistic-1d-a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/logistic-1d-a.png -------------------------------------------------------------------------------- /manuscript/img/logistic-1d-b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/logistic-1d-b.png -------------------------------------------------------------------------------- /manuscript/img/logistic-regression-2d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/logistic-regression-2d.png -------------------------------------------------------------------------------- /manuscript/img/ls-classification-energy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/ls-classification-energy.jpg -------------------------------------------------------------------------------- /manuscript/img/ls-vs-crossentropy-energies.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/ls-vs-crossentropy-energies.jpg -------------------------------------------------------------------------------- /manuscript/img/ls-vs-crossentropy-energies1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/ls-vs-crossentropy-energies1.jpg -------------------------------------------------------------------------------- /manuscript/img/ls-vs-crossentropy-energies2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/ls-vs-crossentropy-energies2.jpg -------------------------------------------------------------------------------- /manuscript/img/lscm-head-mesh.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/lscm-head-mesh.jpg -------------------------------------------------------------------------------- /manuscript/img/lscm-head-textured.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/lscm-head-textured.jpg -------------------------------------------------------------------------------- /manuscript/img/lscm-head-uv.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/lscm-head-uv.jpg -------------------------------------------------------------------------------- /manuscript/img/matrices.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/matrices.png -------------------------------------------------------------------------------- /manuscript/img/matrix-linear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/matrix-linear.png -------------------------------------------------------------------------------- /manuscript/img/matrix-quadratic-form.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/matrix-quadratic-form.png -------------------------------------------------------------------------------- /manuscript/img/minpb1d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/minpb1d.png -------------------------------------------------------------------------------- /manuscript/img/minpb2d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/minpb2d.png -------------------------------------------------------------------------------- /manuscript/img/neural.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/neural.png -------------------------------------------------------------------------------- /manuscript/img/neuron.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/neuron.pdf -------------------------------------------------------------------------------- /manuscript/img/neuron.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/neuron.png -------------------------------------------------------------------------------- /manuscript/img/neuron2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/neuron2.pdf -------------------------------------------------------------------------------- /manuscript/img/peirce-conformal-map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/peirce-conformal-map.png -------------------------------------------------------------------------------- /manuscript/img/pie-1d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/pie-1d.png -------------------------------------------------------------------------------- /manuscript/img/pie-baseball-red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/pie-baseball-red.png -------------------------------------------------------------------------------- /manuscript/img/pie-football-red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/pie-football-red.png -------------------------------------------------------------------------------- /manuscript/img/pie_baseball.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/pie_baseball.png -------------------------------------------------------------------------------- /manuscript/img/pie_football.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/pie_football.png -------------------------------------------------------------------------------- /manuscript/img/pie_overlay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/pie_overlay.png -------------------------------------------------------------------------------- /manuscript/img/pie_poisson.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/pie_poisson.png -------------------------------------------------------------------------------- /manuscript/img/repimage.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/repimage.jpg -------------------------------------------------------------------------------- /manuscript/img/sokolov-caricature.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/sokolov-caricature.jpg -------------------------------------------------------------------------------- /manuscript/img/stop-following-me.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/stop-following-me.png -------------------------------------------------------------------------------- /manuscript/img/tex-applied.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/tex-applied.png -------------------------------------------------------------------------------- /manuscript/img/tex-coords.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/tex-coords.png -------------------------------------------------------------------------------- /manuscript/img/tex-mapping.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/tex-mapping.pdf -------------------------------------------------------------------------------- /manuscript/img/tex-mesh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/tex-mesh.png -------------------------------------------------------------------------------- /manuscript/img/tex-superposed.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/tex-superposed.jpg -------------------------------------------------------------------------------- /manuscript/img/tex-tiger.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/tex-tiger.jpg -------------------------------------------------------------------------------- /manuscript/img/vector_approximation.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/manuscript/img/vector_approximation.pdf -------------------------------------------------------------------------------- /manuscript/listings/arap.m: -------------------------------------------------------------------------------- 1 | clear all; close all; clc; 2 | [V,T] = readOBJ(‘diablo.obj’); 3 | nf = size(T,1); 4 | nv = size(V,1); 5 | id_lock = [1176; 1766; 382; 2384; 1779]; 6 | V_lock = V(id_lock,:) + [0,0,-0.5; 0,0,0.5; 0,0,-0.5; 0,0,0.5; 1.5,0,0]; 7 | id_free = setdiff((1:nv)‘, id_lock); 8 | [cotWeight,cotLaplacian] = cotan_laplacian(V, T); 9 | E1 = V(T(:,2),:) - V(T(:,3),:); 10 | E2 = V(T(:,1),:) - V(T(:,3),:); 11 | E3 = V(T(:,1),:) - V(T(:,2),:); 12 | V_prime = V; 13 | Rot = cell(nv,1); 14 | tic; 15 | maxIter = 200; 16 | for i = 1:maxIter 17 | % Now, estimate the rotations 18 | E1new = V_prime(T(:,2),:) - V_prime(T(:,3),:); 19 | E2new = V_prime(T(:,1),:) - V_prime(T(:,3),:); 20 | E3new = V_prime(T(:,1),:) - V_prime(T(:,2),:); 21 | for j = 1:nv 22 | Rot{j} = zeros(3,3); 23 | end 24 | for j = 1:nf 25 | Rot{T(j,3)} = Rot{T(j,3)} + cotWeight(j,1)*E1(j,:)‘*E1new(j,:); 26 | Rot{T(j,2)} = Rot{T(j,2)} + cotWeight(j,1)*E1(j,:)‘*E1new(j,:); 27 | Rot{T(j,3)} = Rot{T(j,3)} + cotWeight(j,2)*E2(j,:)‘*E2new(j,:); 28 | Rot{T(j,1)} = Rot{T(j,1)} + cotWeight(j,2)*E2(j,:)‘*E2new(j,:); 29 | Rot{T(j,2)} = Rot{T(j,2)} + cotWeight(j,3)*E3(j,:)‘*E3new(j,:); 30 | Rot{T(j,1)} = Rot{T(j,1)} + cotWeight(j,3)*E3(j,:)‘*E3new(j,:); 31 | end 32 | for j = 1:nv 33 | [Usvd,~,Vsvd] = svd(Rot{j}); 34 | Rot{j} = Vsvd * Usvd’; 35 | if det(Rot{j}) < 0 36 | Vsvd(:,3)=-Vsvd(:,3); 37 | Rot{j} = Vsvd * Usvd’; 38 | end 39 | end 40 | % Do linear solve for the vertex position 41 | e1Rot = zeros(nf,3); 42 | e2Rot = zeros(nf,3); 43 | e3Rot = zeros(nf,3); 44 | for j = 1:nf 45 | e1Rot(j,:) = 0.5*((Rot{T(j,2)} + Rot{T(j,3)})*E1(j,:)‘)’; 46 | e2Rot(j,:) = 0.5*((Rot{T(j,1)} + Rot{T(j,3)})*E2(j,:)‘)’; 47 | e3Rot(j,:) = 0.5*((Rot{T(j,1)} + Rot{T(j,2)})*E3(j,:)‘)’; 48 | end 49 | e1Rot = bsxfun(@times,e1Rot,cotWeight(:,1)); 50 | e2Rot = bsxfun(@times,e2Rot,cotWeight(:,2)); 51 | e3Rot = bsxfun(@times,e3Rot,cotWeight(:,3)); 52 | b = zeros(nv,3); 53 | o = ones(nf,1); 54 | for dim = 1:3 55 | b(:,dim) = b(:,dim) + accumarray([T(:,2) o], e1Rot(:,dim),[size(b,1) 1]); 56 | b(:,dim) = b(:,dim) + accumarray([T(:,3) o],-e1Rot(:,dim),[size(b,1) 1]); 57 | b(:,dim) = b(:,dim) + accumarray([T(:,1) o], e2Rot(:,dim),[size(b,1) 1]); 58 | b(:,dim) = b(:,dim) + accumarray([T(:,3) o],-e2Rot(:,dim),[size(b,1) 1]); 59 | b(:,dim) = b(:,dim) + accumarray([T(:,1) o], e3Rot(:,dim),[size(b,1) 1]); 60 | b(:,dim) = b(:,dim) + accumarray([T(:,2) o],-e3Rot(:,dim),[size(b,1) 1]); 61 | end 62 | b = 0.5*b; 63 | V_old = V_prime; 64 | V_prime(id_lock,:) = V_lock; 65 | V_prime(id_free,:) = cotLaplacian(id_free,id_free) \ (b(id_free,:) - cotLaplacian(id_free,id_lock)*V_lock); 66 | end 67 | -------------------------------------------------------------------------------- /manuscript/listings/arap.py: -------------------------------------------------------------------------------- 1 | from mesh import Mesh 2 | import numpy as np 3 | from scipy.sparse import lil_matrix 4 | from scipy.sparse.linalg import lsmr 5 | from scipy.linalg import svd 6 | 7 | m = Mesh("diablo.obj") 8 | eij = [np.matrix(m.V[m.dst(c)] - m.V[m.org(c)]).T for c in range(m.ncorners)] # reference for each half-edge 9 | 10 | lock = [1175, 1765, 381, 2383, 1778] # id of the vertices to constrain 11 | disp = [[0,0,-0.5], [0,0,0.5], [0,0,-0.5], [0,0,0.5], [1.5,0,0]] # displacement for the constrained vertices 12 | for v,d in zip(lock, disp): # apply the displacement 13 | m.V[v] = m.V[v] + d 14 | 15 | A = lil_matrix((m.ncorners+len(lock), m.nverts)) 16 | for c in range(m.ncorners): # Least-squares verion of Poisson's problem 17 | A[c, m.dst(c)] = 1 18 | A[c, m.org(c)] = -1 19 | for i,v in enumerate(lock): # the vertices are locked 20 | A[m.ncorners+i, v] = 100 # via quadratic penalty 21 | A = A.tocsr() # convert to compressed sparse row format for faster matrix-vector muliplications 22 | 23 | for _ in range(100): 24 | R = [] # rotation per vertex 25 | for v in range(m.nverts): # solve for rotations 26 | M = np.zeros(3) 27 | c = m.v2c[v] # half-edge departing from v 28 | while True: # iterate through all half-edges departing from v 29 | M = M + np.matrix(m.V[m.dst(c)] - m.V[m.org(c)]).T*eij[c].T 30 | c = m.c2c[c] # next around vertex 31 | if c==m.v2c[v]: break 32 | U, s, VT = svd(M) 33 | R.append(np.dot(U,VT)) # rotation matrix for the neighborhood of vertex v 34 | 35 | for dim in range(3): # the problem is separable in x,y,z 36 | b = [ (R[m.org(c)]*eij[c])[dim,0] for c in range(m.ncorners) ] + \ 37 | [ 100*m.V[v][dim] for v,d in zip(lock, disp) ] 38 | x = lsmr(A, b)[0] # call the least squares solver 39 | for v in range(m.nverts): # apply the computed deformation 40 | m.V[v][dim] = x[v] 41 | print(m) # output the deformed mesh 42 | -------------------------------------------------------------------------------- /manuscript/listings/caricature3d.py: -------------------------------------------------------------------------------- 1 | from mesh import Mesh 2 | from scipy.sparse.linalg import lsmr 3 | from scipy.sparse import lil_matrix 4 | 5 | m = Mesh("input-face.obj") # load mesh 6 | 7 | A = lil_matrix((m.nverts+m.ncorners, m.nverts)) 8 | for v in range(m.nverts): # per-vertex attachment to the original geometry 9 | if m.on_border(v): # hard on the boundary 10 | A[v,v] = 10 11 | else: # light on the interior 12 | A[v,v] = .29 13 | for c in range(m.ncorners): # per-half-edge discretization of the derivative 14 | A[m.nverts+c, m.org(c)] = -1 15 | A[m.nverts+c, m.dst(c)] = 1 16 | A = A.tocsr() # sparse row matrix for fast matrix-vector multiplication 17 | 18 | for dim in range(3): # the problem is separable in x,y,z; the matrix A is the same, the right hand side changes 19 | b = [m.V[v][dim]*10 if m.on_border(v) else m.V[v][dim]*.29 for v in range(m.nverts)] + \ 20 | [2.5*(m.V[m.dst(c)][dim]-m.V[m.org(c)][dim]) for c in range(m.ncorners)] 21 | x = lsmr(A, b)[0] # call the least squares solver 22 | for v in range(m.nverts): # apply the computed distortion 23 | m.V[v][dim] = x[v] 24 | 25 | print(m) # output the deformed mesh 26 | 27 | -------------------------------------------------------------------------------- /manuscript/listings/cubify.cpp: -------------------------------------------------------------------------------- 1 | #include "OpenNL_psm.h" 2 | #include "model.h" 3 | 4 | const vec3 axes[] = {vec3(1,0,0), vec3(-1,0,0), vec3(0,1,0), vec3(0,-1,0), vec3(0,0,1), vec3(0,0,-1)}; 5 | int snap(vec3 n) { // returns 0,1 or 2: the coordinate axis closest to the given normal 6 | double nmin = -2.0; 7 | int imin = -1; 8 | for (int i=0; i<6; i++) { 9 | double t = n*axes[i]; 10 | if (t>nmin) { 11 | nmin = t; 12 | imin = i; 13 | } 14 | } 15 | return imin/2; 16 | } 17 | 18 | int main() { 19 | Model m("../input-face.obj"); 20 | 21 | // for each facet find the coordinate axis (x,y or z) closest to the normal 22 | std::vector nearest_axis(m.nfaces()); 23 | for (int i=0; inmin: 18 | nmin = np.abs(np.dot(n,a)) 19 | imin = i 20 | return imin 21 | 22 | m = Mesh("input-face.obj") # load mesh 23 | 24 | for dim in range(3): # the problem is separable in x,y,z 25 | A = lil_matrix((m.ncorners*2, m.nverts)) 26 | b = [m.V[m.dst(c)][dim]-m.V[m.org(c)][dim] for c in range(m.ncorners)] + [0]*m.ncorners 27 | for c in range(m.ncorners): 28 | A[c, m.org(c)] = -1 # per-half-edge discretization of the derivative 29 | A[c, m.dst(c)] = 1 30 | 31 | t = c//3 # triangle id from halfedge id 32 | n = normalize(cross(m.V[m.T[t][1]]- m.V[m.T[t][0]], m.V[m.T[t][2]]- m.V[m.T[t][0]])) # normal 33 | if nearest_axis(n)==dim: # flatten the right dimension of each half-edge 34 | A[c+m.ncorners, m.org(c)] = -2 35 | A[c+m.ncorners, m.dst(c)] = 2 36 | A = A.tocsr() # sparse row matrix for fast matrix-vector multiplication 37 | x = lsmr(A, b)[0] # call the least squares solver 38 | for v in range(m.nverts): # apply the computed distortion 39 | m.V[v][dim] = x[v] 40 | 41 | print(m) # output the deformed mesh 42 | -------------------------------------------------------------------------------- /manuscript/listings/example_3.1.py: -------------------------------------------------------------------------------- 1 | # initialize the data array 2 | x = [0, .8, 1, .6, .1, .4, .2, .1, .6, .3, 1, .7, .4, 0, .6, 1] 3 | 4 | # smooth the data 5 | for _ in range(512): 6 | x = [ x[0] ] + [ (x[i-1]+x[i+1])/2. for i in range(1, len(x)-1) ] + [ x[-1] ] 7 | -------------------------------------------------------------------------------- /manuscript/listings/example_3.2.py: -------------------------------------------------------------------------------- 1 | x = [0, .8, 1, .6, .1, .4, .2, .1, .6, .3, 1, .7, .4, 0, .6, 1] 2 | 3 | for _ in range(512): 4 | for i in range(1, len(x)-1): 5 | x[i] = ( x[i-1] + x[i+1] )/2. 6 | -------------------------------------------------------------------------------- /manuscript/listings/example_3.3.cpp: -------------------------------------------------------------------------------- 1 | #include "model.h" 2 | 3 | int main(void) { 4 | Model m("../input.obj"); // parse the input mesh 5 | 6 | // smooth the surface through Gauss-Seidel iterations 7 | for (int it=0; it<1000; it++) { 8 | for (int v=0; v 2 | #include "model.h" 3 | 4 | int main(void) { 5 | Model m("input-face.obj"); 6 | 7 | // for each vertex compute the Gaussian curvature 8 | std::vector curv(m.nverts(), vec3(0,0,0)); 9 | for (int v=0; v 1] = 1 36 | x[x < 0] = 0 37 | base[oy:oy+h,ox:ox+w, channel] = x.reshape((h, w)) # glue the football 38 | mpimg.imsave('result.png', base) 39 | -------------------------------------------------------------------------------- /src/ch6/2-poisson/result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssloy/least-squares-course/9cf61055299fe9d24112e5ed52f28aee1ba92e6a/src/ch6/2-poisson/result.png -------------------------------------------------------------------------------- /src/ch6/3-caricature/caricature3d.py: -------------------------------------------------------------------------------- 1 | from mesh import Mesh 2 | from scipy.sparse.linalg import lsmr 3 | from scipy.sparse import lil_matrix 4 | 5 | m = Mesh("input-face.obj") # load mesh 6 | 7 | A = lil_matrix((m.nverts+m.ncorners, m.nverts)) 8 | for v in range(m.nverts): # per-vertex attachment to the original geometry 9 | if m.on_border(v): # hard on the boundary 10 | A[v,v] = 10 11 | else: # light on the interior 12 | A[v,v] = .29 13 | for c in range(m.ncorners): # per-half-edge discretization of the derivative 14 | A[m.nverts+c, m.org(c)] = -1 15 | A[m.nverts+c, m.dst(c)] = 1 16 | A = A.tocsr() # sparse row matrix for fast matrix-vector multiplication 17 | 18 | for dim in range(3): # the problem is separable in x,y,z; the matrix A is the same, the right hand side changes 19 | b = [m.V[v][dim]*10 if m.on_border(v) else m.V[v][dim]*.29 for v in range(m.nverts)] + \ 20 | [2.5*(m.V[m.dst(c)][dim]-m.V[m.org(c)][dim]) for c in range(m.ncorners)] 21 | x = lsmr(A, b)[0] # call the least squares solver 22 | for v in range(m.nverts): # apply the computed distortion 23 | m.V[v][dim] = x[v] 24 | 25 | print(m) # output the deformed mesh 26 | 27 | -------------------------------------------------------------------------------- /src/ch6/3-caricature/mesh.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | class Mesh(): 4 | def __init__(self, filename): 5 | # parse the .obj file 6 | V, T = [], [] 7 | with open(filename) as f: 8 | for line in f.readlines(): 9 | if line.startswith('#'): continue 10 | values = line.split() 11 | if not values: continue 12 | if values[0] == 'v': 13 | V.append([float(x) for x in values[1:4]]) 14 | elif values[0] == 'f': 15 | T.append([int(x) for x in values[1:4]]) 16 | self.V, self.T = np.array(V), np.array(T)-1 17 | 18 | # compute the adjacency 19 | self.v2c = np.array([-1]*self.nverts) # vertex-to-corner map 20 | self.c2c = np.array([-1]*self.ncorners) # corner-to-corner unordered circular lists 21 | for c in range(self.ncorners): 22 | v = self.T[c//3][c%3] 23 | self.v2c[v] = c 24 | for c in range(self.ncorners): 25 | v = self.T[c//3][c%3] 26 | self.c2c[c] = self.v2c[v] 27 | self.v2c[v] = c 28 | 29 | # speed up the computations: precompute the opposites and the boundary flags 30 | self.opp = np.array([-1]*self.ncorners) 31 | for c in range(self.ncorners): 32 | c_org = self.T[c//3][c%3] 33 | c_dst = self.T[c//3][(c+1)%3] 34 | cir = c 35 | opp = -1 36 | while True: 37 | cand = (cir//3)*3 + (cir+2)%3 38 | cand_org = self.T[cand//3][cand%3] 39 | cand_dst = self.T[cand//3][(cand+1)%3] 40 | if (cand_org == c_dst and cand_dst == c_org): 41 | opp = cand # we suppose manifold input 42 | cir = self.c2c[cir] 43 | if (cir==c): break 44 | self.opp[c] = opp 45 | 46 | self.boundary = np.array([False]*self.nverts) 47 | for v in range(self.nverts): 48 | cir = self.v2c[v] 49 | if cir<0: continue 50 | while (True): 51 | if self.opp[cir]<0: 52 | self.boundary[v] = True 53 | break 54 | cir = self.c2c[cir] 55 | if (cir==self.v2c[v]): break 56 | 57 | @property 58 | def nverts(self): 59 | return len(self.V) 60 | 61 | @property 62 | def ntriangles(self): 63 | return len(self.T) 64 | 65 | @property 66 | def ncorners(self): 67 | return self.ntriangles*3; 68 | 69 | def org(self, c): 70 | return self.T[c//3][c%3] 71 | 72 | def dst(self, c): 73 | return self.T[c//3][(c+1)%3] 74 | 75 | def prev(self, c): 76 | return (c//3)*3 + (c+2)%3 77 | 78 | def opposite(self, c): 79 | return self.opp[c] 80 | 81 | def on_border(self, v): 82 | return self.boundary[v] 83 | 84 | def neighbors(self,v): 85 | out = [] 86 | cir = self.v2c[v] 87 | if cir<0: return [] 88 | cnt = 0 89 | while True: 90 | neigh = self.T[cir//3][(cir+1)%3] 91 | out.append(neigh) 92 | cir = self.c2c[cir] 93 | if (cir==self.v2c[v]): break 94 | cnt = cnt + 1 95 | return out 96 | 97 | def __str__(self): 98 | ret = "" 99 | for v in self.V: 100 | ret = ret + ("v %f %f %f\n" % (v[0], v[1], v[2])) 101 | for t in self.T: 102 | ret = ret + ("f %d %d %d\n" % (t[0]+1, t[1]+1, t[2]+1)) 103 | return ret 104 | -------------------------------------------------------------------------------- /src/ch6/3-caricature/silhouette-better.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | 4 | def amplify(x): 5 | n = len(x) 6 | A = np.matrix(np.zeros((2*n,n))) 7 | b = np.matrix(np.zeros((2*n,1))) 8 | for i in range(n): 9 | A[i, i] = 1. # amplify the curvature 10 | A[i, (i+1)%n] = -1. 11 | b[i, 0] = (x[i] - x[(i+1)%n])*1.9 12 | 13 | A[n+i, i] = 1*.3 # light data fitting term 14 | b[n+i, 0] = x[i]*.3 15 | return (np.linalg.inv(A.T*A)*A.T*b).tolist() 16 | 17 | x = [100,100,97,93,91,87,84,83,85,87,88,89,90,90,90,88,87,86,84,82,80, 18 | 77,75,72,69,66,62,58,54,47,42,38,34,32,28,24,22,20,17,15,13,12,9, 19 | 7,8,9,8,6,0,0,2,0,0,2,3,2,0,0,1,4,8,11,14,19,24,27,25,23,21,19] 20 | y = [0,25,27,28,30,34,37,41,44,47,51,54,59,64,66,70,74,78,80,83,86,90,93, 21 | 95,96,98,99,99,100,99,99,99,98,98,96,94,93,91,90,87,85,79,75,70,65, 22 | 62,60,58,52,49,46,44,41,37,34,30,27,20,17,15,16,17,17,19,18,14,11,6,4,1] 23 | 24 | plt.plot(x+[x[0]], y+[y[0]], 'g--') 25 | 26 | x = amplify(x) 27 | y = amplify(y) 28 | 29 | plt.plot(x+[x[0]], y+[y[0]], 'k-', linewidth=3) 30 | plt.axis('off') 31 | plt.gca().set_aspect('equal', adjustable='box') 32 | plt.show() 33 | 34 | -------------------------------------------------------------------------------- /src/ch6/3-caricature/silhouette-naive.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | 4 | x = [100,100,97,93,91,87,84,83,85,87,88,89,90,90,90,88,87,86,84,82,80, 5 | 77,75,72,69,66,62,58,54,47,42,38,34,32,28,24,22,20,17,15,13,12,9, 6 | 7,8,9,8,6,0,0,2,0,0,2,3,2,0,0,1,4,8,11,14,19,24,27,25,23,21,19] 7 | y = [0,25,27,28,30,34,37,41,44,47,51,54,59,64,66,70,74,78,80,83,86,90,93, 8 | 95,96,98,99,99,100,99,99,99,98,98,96,94,93,91,90,87,85,79,75,70,65, 9 | 62,60,58,52,49,46,44,41,37,34,30,27,20,17,15,16,17,17,19,18,14,11,6,4,1] 10 | n = len(x) 11 | 12 | plt.plot(x+[x[0]], y+[y[0]], 'g--') 13 | 14 | cx = [x[i] - (x[(i-1+n)%n]+x[(i+1)%n])/2 for i in range(n)] 15 | cy = [y[i] - (y[(i-1+n)%n]+y[(i+1)%n])/2 for i in range(n)] 16 | 17 | for iter in range(10000): 18 | for i in range(n): 19 | x[i] = (x[(i-1+n)%n]+x[(i+1)%n])/2 + cx[i]*1.9 20 | y[i] = (y[(i-1+n)%n]+y[(i+1)%n])/2 + cy[i]*1.9 21 | 22 | plt.plot(x+[x[0]], y+[y[0]], 'k-', linewidth=3) 23 | plt.axis('off') 24 | plt.gca().set_aspect('equal', adjustable='box') 25 | plt.show() 26 | 27 | -------------------------------------------------------------------------------- /src/ch6/3-caricature/silhouette-winner.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | 4 | x = [100,100,97,93,91,87,84,83,85,87,88,89,90,90,90,88,87,86,84,82,80, 5 | 77,75,72,69,66,62,58,54,47,42,38,34,32,28,24,22,20,17,15,13,12,9, 6 | 7,8,9,8,6,0,0,2,0,0,2,3,2,0,0,1,4,8,11,14,19,24,27,25,23,21,19] 7 | y = [0,25,27,28,30,34,37,41,44,47,51,54,59,64,66,70,74,78,80,83,86,90,93, 8 | 95,96,98,99,99,100,99,99,99,98,98,96,94,93,91,90,87,85,79,75,70,65, 9 | 62,60,58,52,49,46,44,41,37,34,30,27,20,17,15,16,17,17,19,18,14,11,6,4,1] 10 | n = len(x) 11 | 12 | A = np.matrix(np.zeros((4+2*n,2*n))) 13 | b = np.matrix(np.zeros((4+2*n,1))) 14 | for i in range(0, n): 15 | j, k = (i+1)%n, (i+2)%n 16 | PR = [x[k]-x[i], y[k]-y[i]] 17 | PQ = [x[j]-x[i], y[j]-y[i]] 18 | PRperp = [y[i]-y[k], x[k]-x[i]] 19 | c0 = np.dot(PQ, PR )/np.dot(PR, PR) 20 | c1 = np.dot(PQ, PRperp)/np.dot(PR, PR)*1.3 21 | 22 | A[i*2, i*2 ] = 1-c0 23 | A[i*2, j*2 ] = -1 24 | A[i*2, k*2 ] = c0 25 | A[i*2, k*2+1] = -c1 26 | A[i*2, i*2+1] = c1 27 | 28 | A[i*2+1, i*2+1] = 1-c0 29 | A[i*2+1, j*2+1] = -1 30 | A[i*2+1, k*2+1] = c0 31 | A[i*2+1, k*2 ] = c1 32 | A[i*2+1, i*2 ] = -c1 33 | 34 | lock1 = 9123%n # pin two arbitrary points 35 | lock2 = 3478%n 36 | 37 | A[n*2, lock1*2] = A[n*2+1, lock1*2+1] = A[n*2+2, lock2*2] = A[n*2+3, lock2*2+1] = 10. 38 | b[-1] = y[lock2]*10. 39 | b[-2] = x[lock2]*10. 40 | b[-3] = y[lock1]*10. 41 | b[-4] = x[lock1]*10. 42 | 43 | X = (np.linalg.inv(A.T*A)*A.T*b).tolist() 44 | 45 | plt.plot(x+[x[0]], y+[y[0]], 'g--') 46 | plt.plot(X[::2]+[X[0]], X[1::2]+[X[1]], 'k-', linewidth=3) 47 | plt.axis('off') 48 | plt.gca().set_aspect('equal', adjustable='box') 49 | plt.show() 50 | 51 | -------------------------------------------------------------------------------- /src/ch6/4-cubify/cubify.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from mesh import Mesh 3 | from scipy.sparse import lil_matrix 4 | from scipy.sparse.linalg import lsmr 5 | 6 | def nearest_axis(n): 7 | return np.argmax([np.abs(np.dot(n, a)) for a in [[1,0,0],[0,1,0],[0,0,1]]]) 8 | 9 | m = Mesh("input-face.obj") # load mesh 10 | 11 | for dim in range(3): # the problem is separable in x,y,z 12 | A = lil_matrix((m.ncorners*2, m.nverts)) 13 | b = [m.V[m.dst(c)][dim]-m.V[m.org(c)][dim] for c in range(m.ncorners)] + [0]*m.ncorners 14 | for c in range(m.ncorners): 15 | A[c, m.org(c)] = -1 # per-half-edge discretization of the derivative 16 | A[c, m.dst(c)] = 1 17 | 18 | t = c//3 # triangle id from halfedge id 19 | if nearest_axis(m.normal(t))==dim: # flatten the right dimension of each half-edge 20 | A[c+m.ncorners, m.org(c)] = -2 21 | A[c+m.ncorners, m.dst(c)] = 2 22 | A = A.tocsr() # sparse row matrix for fast matrix-vector multiplication 23 | x = lsmr(A, b)[0] # call the least squares solver 24 | for v in range(m.nverts): # apply the computed distortion 25 | m.V[v][dim] = x[v] 26 | 27 | print(m) # output the deformed mesh 28 | -------------------------------------------------------------------------------- /src/ch6/4-cubify/mesh.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | class Mesh(): 4 | def __init__(self, filename): 5 | # parse the .obj file 6 | V, T = [], [] 7 | with open(filename) as f: 8 | for line in f.readlines(): 9 | if line.startswith('#'): continue 10 | values = line.split() 11 | if not values: continue 12 | if values[0] == 'v': 13 | V.append([float(x) for x in values[1:4]]) 14 | elif values[0] == 'f': 15 | T.append([int(x) for x in values[1:4]]) 16 | self.V, self.T = np.array(V), np.array(T)-1 17 | 18 | @property 19 | def nverts(self): 20 | return len(self.V) 21 | 22 | @property 23 | def ntriangles(self): 24 | return len(self.T) 25 | 26 | @property 27 | def ncorners(self): 28 | return self.ntriangles*3; 29 | 30 | def normal(self, t): 31 | n = np.cross(self.V[self.T[t][1]]-self.V[self.T[t][0]], self.V[self.T[t][2]]-self.V[self.T[t][0]]) 32 | return n / np.linalg.norm(n) 33 | 34 | def org(self, c): 35 | return self.T[c//3][c%3] 36 | 37 | def dst(self, c): 38 | return self.T[c//3][(c+1)%3] 39 | 40 | def __str__(self): 41 | ret = "" 42 | for v in self.V: 43 | ret = ret + ("v %f %f %f\n" % (v[0], v[1], v[2])) 44 | for t in self.T: 45 | ret = ret + ("f %d %d %d\n" % (t[0]+1, t[1]+1, t[2]+1)) 46 | return ret 47 | -------------------------------------------------------------------------------- /src/ch6/5-lscm/lscm.py: -------------------------------------------------------------------------------- 1 | import mesh 2 | import numpy as np 3 | import scipy.sparse 4 | from scipy.sparse.linalg import lsmr 5 | 6 | m = mesh.Mesh("input-face.obj") # load mesh 7 | A = scipy.sparse.lil_matrix((2*m.ntriangles+4, 2*m.nverts)) # the variables are packed as u0,v0,u1,v1, ... 8 | lock1, lock2 = 10324%m.nverts, 35492%m.nverts # select two arbitrary vertices to pin 9 | for (t,[i,j,k]) in enumerate(m.T): # for each triangle ijk 10 | [eij, ejk, eki] = mesh.project_triangle(m.V[i], m.V[j], m.V[k]) # project the triangle to a local 2d basis 11 | A[t*2+0, i*2 ] = ejk[0] # (grad u)[0] = (grad v)[1] 12 | A[t*2+0, j*2 ] = eki[0] 13 | A[t*2+0, k*2 ] = eij[0] 14 | A[t*2+0, i*2+1] = ejk[1] 15 | A[t*2+0, j*2+1] = eki[1] 16 | A[t*2+0, k*2+1] = eij[1] 17 | A[t*2+1, i*2 ] = ejk[1] # (grad u)[1] = -(grad v)[0] 18 | A[t*2+1, j*2 ] = eki[1] 19 | A[t*2+1, k*2 ] = eij[1] 20 | A[t*2+1, i*2+1] = -ejk[0] 21 | A[t*2+1, j*2+1] = -eki[0] 22 | A[t*2+1, k*2+1] = -eij[0] 23 | A[-1,lock2*2+1] = A[-2,lock2*2+0] = A[-3,lock1*2+1] = A[-4,lock1*2+0] = 10 # quadratic penalty 24 | A = A.tocsr() # convert to compressed sparse row format for faster matrix-vector muliplications 25 | 26 | b = [0]*(2*m.ntriangles) + [0,0,10,10] # one pinned to (0,0), another to (1,1) 27 | x = lsmr(A, b)[0] # call the least squares solver 28 | 29 | for v in range(m.nverts): # apply the computed flattening 30 | m.V[v] = np.array([x[v*2], x[v*2+1], 0]) 31 | print(m) # output the deformed mesh 32 | -------------------------------------------------------------------------------- /src/ch6/5-lscm/mesh.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | def project_triangle(p0, p1, p2): 4 | X = np.subtract(p1, p0) # construct an orthonormal 3d basis 5 | X = X/np.linalg.norm(X) 6 | Z = np.cross(X, np.subtract(p2, p0)) 7 | Z = Z/np.linalg.norm(Z) 8 | Y = np.cross(Z, X) 9 | z0 = np.array([0,0]) # project the triangle to the 2d basis (X,Y) 10 | z1 = np.array([np.linalg.norm(np.subtract(p1, p0)), 0]) 11 | z2 = np.array([np.dot(np.subtract(p2, p0), X), np.dot(np.subtract(p2, p0), Y)]) 12 | return [z1-z0, z2-z1, z0-z2] 13 | 14 | class Mesh(): 15 | def __init__(self, filename): 16 | # parse the .obj file 17 | V, T = [], [] 18 | with open(filename) as f: 19 | for line in f.readlines(): 20 | if line.startswith('#'): continue 21 | values = line.split() 22 | if not values: continue 23 | if values[0] == 'v': 24 | V.append([float(x) for x in values[1:4]]) 25 | elif values[0] == 'f': 26 | T.append([int(x) for x in values[1:4]]) 27 | self.V, self.T = np.array(V), np.array(T)-1 28 | 29 | @property 30 | def nverts(self): 31 | return len(self.V) 32 | 33 | @property 34 | def ntriangles(self): 35 | return len(self.T) 36 | 37 | def __str__(self): 38 | ret = "" 39 | for v in self.V: 40 | ret = ret + ("v %f %f %f\n" % (v[0], v[1], v[2])) 41 | for t in self.T: 42 | ret = ret + ("f %d %d %d\n" % (t[0]+1, t[1]+1, t[2]+1)) 43 | return ret 44 | -------------------------------------------------------------------------------- /src/ch6/6-arap-matlab/cotan_laplacian.m: -------------------------------------------------------------------------------- 1 | function [cotWeight,cotLaplacian] = cotan_laplacian(V, T) 2 | 3 | nf = size(T,1); 4 | nv = size(V,1); 5 | 6 | normv = @(V) sqrt(sum(V.^2,2)); 7 | E1 = V(T(:,2),:)-V(T(:,3),:); 8 | L1 = normv(E1); 9 | E2 = V(T(:,1),:)-V(T(:,3),:); 10 | L2 = normv(E2); 11 | E3 = V(T(:,1),:)-V(T(:,2),:); 12 | L3 = normv(E3); 13 | 14 | A1 = (L2.^2 + L3.^2 - L1.^2) ./ (2.*L2.*L3); 15 | A2 = (L1.^2 + L3.^2 - L2.^2) ./ (2.*L1.*L3); 16 | A3 = (L1.^2 + L2.^2 - L3.^2) ./ (2.*L1.*L2); 17 | A = [A1,A2,A3]; 18 | A = acos(A); 19 | cotWeight = abs(cot(A)); 20 | 21 | I = [T(:,1);T(:,2);T(:,3)]; 22 | J = [T(:,2);T(:,3);T(:,1)]; 23 | S = 0.5*abs(cot([A(:,3);A(:,1);A(:,2)])); 24 | In = [I;J;I;J]; 25 | Jn = [J;I;I;J]; 26 | Sn = [-S;-S;S;S]; 27 | cotLaplacian = sparse(In,Jn,Sn,nv,nv); -------------------------------------------------------------------------------- /src/ch6/6-arap/arap.py: -------------------------------------------------------------------------------- 1 | from mesh import Mesh 2 | import numpy as np 3 | from scipy.sparse import lil_matrix 4 | from scipy.sparse.linalg import lsmr 5 | from scipy.linalg import svd 6 | 7 | m = Mesh("diablo.obj") 8 | eij = [np.matrix(m.V[m.dst(c)] - m.V[m.org(c)]).T for c in range(m.ncorners)] # reference geometry for each half-edge 9 | 10 | lock = [1175, 1765, 381, 2383, 1778] # id of the vertices to constrain 11 | disp = [[0,0,-0.5], [0,0,0.5], [0,0,-0.5], [0,0,0.5], [1.5,0,0]] # displacement for the constrained vertices 12 | for v,d in zip(lock, disp): # apply the displacement 13 | m.V[v] = m.V[v] + d 14 | 15 | A = lil_matrix((m.ncorners+len(lock), m.nverts)) 16 | for c in range(m.ncorners): # Least-squares verion of Poisson's problem 17 | A[c, m.dst(c)] = 1 18 | A[c, m.org(c)] = -1 19 | for i,v in enumerate(lock): # the vertices are locked 20 | A[m.ncorners+i, v] = 100 # via quadratic penalty 21 | A = A.tocsr() # convert to compressed sparse row format for faster matrix-vector muliplications 22 | 23 | for _ in range(100): 24 | R = [] # rotation per vertex 25 | for v in range(m.nverts): # solve for rotations 26 | M = np.zeros(3) 27 | c = m.v2c[v] # half-edge departing from v 28 | while True: # iterate through all half-edges departing from v 29 | M = M + np.matrix(m.V[m.dst(c)] - m.V[m.org(c)]).T*eij[c].T 30 | c = m.c2c[c] # next around vertex 31 | if c==m.v2c[v]: break 32 | U, s, VT = svd(M) 33 | R.append(np.dot(U,VT)) # rotation matrix for the neighborhood of vertex v 34 | 35 | for dim in range(3): # the problem is separable in x,y,z 36 | b = [ (R[m.org(c)]*eij[c])[dim,0] for c in range(m.ncorners) ] + \ 37 | [ 100*m.V[v][dim] for v,d in zip(lock, disp) ] 38 | x = lsmr(A, b)[0] # call the least squares solver 39 | for v in range(m.nverts): # apply the computed deformation 40 | m.V[v][dim] = x[v] 41 | print(m) # output the deformed mesh 42 | -------------------------------------------------------------------------------- /src/ch6/6-arap/mesh.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | class Mesh(): 4 | def __init__(self, filename): 5 | # parse the .obj file 6 | V, T = [], [] 7 | with open(filename) as f: 8 | for line in f.readlines(): 9 | if line.startswith('#'): continue 10 | values = line.split() 11 | if not values: continue 12 | if values[0] == 'v': 13 | V.append([float(x) for x in values[1:4]]) 14 | elif values[0] == 'f': 15 | T.append([int(x) for x in values[1:4]]) 16 | self.V, self.T = np.array(V), np.array(T)-1 17 | 18 | # compute the adjacency 19 | self.v2c = np.array([-1]*self.nverts) 20 | self.c2c = np.array([-1]*self.ncorners) 21 | for c in range(self.ncorners): 22 | v = self.T[c//3][c%3] 23 | self.v2c[v] = c 24 | for c in range(self.ncorners): 25 | v = self.T[c//3][c%3] 26 | self.c2c[c] = self.v2c[v] 27 | self.v2c[v] = c 28 | 29 | # speed up the computations 30 | self.opp = np.array([-1]*self.ncorners) 31 | for c in range(self.ncorners): 32 | c_org = self.T[c//3][c%3] 33 | c_dst = self.T[c//3][(c+1)%3] 34 | cir = c 35 | opp = -1 36 | while True: 37 | cand = (cir//3)*3 + (cir+2)%3 38 | cand_org = self.T[cand//3][cand%3] 39 | cand_dst = self.T[cand//3][(cand+1)%3] 40 | if (cand_org == c_dst and cand_dst == c_org): 41 | opp = cand # we suppose manifold input 42 | cir = self.c2c[cir] 43 | if (cir==c): break 44 | self.opp[c] = opp 45 | 46 | self.boundary = np.array([False]*self.nverts) 47 | for v in range(self.nverts): 48 | cir = self.v2c[v] 49 | if cir<0: continue 50 | while (True): 51 | if self.opp[cir]<0: 52 | self.boundary[v] = True 53 | break 54 | cir = self.c2c[cir] 55 | if (cir==self.v2c[v]): break 56 | 57 | @property 58 | def nverts(self): 59 | return len(self.V) 60 | 61 | @property 62 | def ntriangles(self): 63 | return len(self.T) 64 | 65 | @property 66 | def ncorners(self): 67 | return len(self.T)*3 68 | 69 | def org(self, c): 70 | return self.T[c//3][c%3] 71 | 72 | def dst(self, c): 73 | return self.T[c//3][(c+1)%3] 74 | 75 | def prev(self, c): 76 | return (c//3)*3 + (c+2)%3 77 | 78 | def opposite(self, c): 79 | return self.opp[c] 80 | 81 | def on_border(self, v): 82 | return self.boundary[v] 83 | 84 | def one_ring_barycenter(self, v): 85 | bary = np.zeros(3) 86 | cnt = 1 87 | cir = self.v2c[v] 88 | if cir<0: return bary 89 | while True: 90 | bary = np.add(bary, self.V[self.T[cir//3][(cir+1)%3]]) 91 | cir = self.c2c[cir] 92 | if (cir==self.v2c[v]): break 93 | cnt = cnt + 1 94 | return bary/cnt 95 | 96 | def __str__(self): 97 | ret = "" 98 | for v in self.V: 99 | ret = ret + ("v %f %f %f\n" % (v[0], v[1], v[2])) 100 | for t in self.T: 101 | ret = ret + ("f %d %d %d\n" % (t[0]+1, t[1]+1, t[2]+1)) 102 | return ret 103 | 104 | -------------------------------------------------------------------------------- /src/ch8/1+3/binary-classifier-1d-linear-vs-logistic.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import numpy as np 3 | 4 | moresamples = True 5 | logistic = True 6 | samples = [[0.47,1],[0.24,1],[0.75,1],[0.00,1],[-0.80,1],[-0.59,1],[1.09,1],[1.34,1], 7 | [1.01,1],[-1.02,1],[0.50,1],[0.64,1],[-1.15,1],[-1.68,1],[-2.21,1],[-0.52,1], 8 | [3.93,1],[4.21,1],[5.18,1],[4.20,1],[4.57,1],[2.63,1],[4.52,1],[3.31,1], 9 | [6.75,1],[3.47,1],[4.32,1],[3.08,1],[4.10,1],[4.00,1],[2.99,1],[3.83,1]] 10 | n = len(samples) 11 | m = len(samples[0]) 12 | labels = [0]*(n//2) + [1]*(n//2) 13 | 14 | if moresamples: 15 | samples += [[16.2,1],[15.7,1],[15.0,1],[16.0,1],[15.4,1],[17.3,1],[15.6,1],[15.8,1],[12.8,1],[16.2,1],[14.8,1],[17.0,1],[16.1,1],[16.0,1],[16.9,1],[15.9,1]] 16 | n = len(samples) 17 | labels += [1]*(n-len(labels)) 18 | 19 | xmin = np.min([x for x,_ in samples]) 20 | xmax = np.max([x for x,_ in samples]) 21 | 22 | if logistic: 23 | U = np.matrix([[1],[0]]) 24 | for _ in range(5): 25 | JR = np.matrix(np.zeros((n+2, 2))) 26 | R = np.matrix(np.zeros((n+2, 1))) 27 | for i in range(n): 28 | ei = np.exp(-U[1,0] - samples[i][0]*U[0,0]) 29 | R[i,0] = -1/(1+ei) + labels[i] 30 | for j in range(3): 31 | JR[i, 0] = samples[i][0]*ei/(1+ei)**2 32 | JR[i, 1] = ei/(1+ei)**2 33 | l = .001 # regularization 34 | JR[n,0] = JR[n+1, 1] = 1.*l 35 | R[n,0] = -U[0]*l 36 | R[n+1,0] = -U[1]*l 37 | U = U + np.linalg.inv(JR.T*JR)*JR.T*R 38 | a,b = U.T.tolist()[0] 39 | print(a,b) 40 | sep = -b/a 41 | xred = np.linspace(xmin, sep, 100) 42 | yred = [1/(1+np.exp(-x*U[0,0] - U[1,0])) for x in xred] 43 | xgrn = np.linspace(sep, xmax, 100) 44 | ygrn = [1/(1+np.exp(-x*U[0,0] - U[1,0])) for x in xgrn] 45 | else: 46 | A = np.matrix(np.zeros((n,m))) 47 | b = np.matrix(np.zeros((n,1))) 48 | for i in range(n): 49 | A[i,:] = samples[i] 50 | b[i,0] = labels[i] 51 | 52 | X = np.linalg.inv(A.transpose()*A)*A.transpose()*b 53 | k,m = X.transpose().tolist()[0] 54 | 55 | sep = (.5-m)/k 56 | xred = np.linspace(xmin, sep, 500) 57 | yred = k*xred + m 58 | xgrn = np.linspace(sep, xmax, 500) 59 | ygrn = k*xgrn + m 60 | 61 | plt.rcParams["font.family"] = "serif" 62 | plt.rcParams["mathtext.fontset"] = "dejavuserif" 63 | plt.rcParams['text.usetex'] = True 64 | plt.rc('font', size=20) 65 | 66 | 67 | if moresamples: 68 | fig, ax = plt.subplots(1, figsize=(6.40*2,2.40),dpi=150) 69 | else: 70 | fig, ax = plt.subplots(1, figsize=(6.40,2.40),dpi=150) 71 | 72 | 73 | plt.axvline(sep, ymin=-0.25, ymax=1.25, color='black', linestyle='--', linewidth=3) 74 | plt.plot(xred, yred, '-r', linewidth=2) 75 | plt.plot(xgrn, ygrn, '-g', linewidth=2) 76 | plt.ylim(-.25, 1.25) 77 | 78 | 79 | for sample, label in zip(samples,labels): 80 | c = 'g' 81 | if (label<.5): c = 'r' 82 | plt.scatter(sample[0], label, color=c, edgecolors='black') 83 | 84 | plt.tight_layout() 85 | if logistic: 86 | if moresamples: 87 | plt.savefig("logistic-1d-b.png", bbox_inches='tight') 88 | else: 89 | plt.savefig("logistic-1d-a.png", bbox_inches='tight') 90 | else: 91 | if moresamples: 92 | plt.savefig("linear-1d-b.png", bbox_inches='tight') 93 | else: 94 | plt.savefig("linear-1d-a.png", bbox_inches='tight') 95 | plt.show() 96 | -------------------------------------------------------------------------------- /src/ch8/1+3/linear-1d.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | samples = [[0.47,1],[0.24,1],[0.75,1],[0.00,1],[-0.80,1],[-0.59,1],[1.09,1],[1.34,1], 3 | [1.01,1],[-1.02,1],[0.50,1],[0.64,1],[-1.15,1],[-1.68,1],[-2.21,1],[-0.52,1], 4 | [3.93,1],[4.21,1],[5.18,1],[4.20,1],[4.57,1],[2.63,1],[4.52,1],[3.31,1], 5 | [6.75,1],[3.47,1],[4.32,1],[3.08,1],[4.10,1],[4.00,1],[2.99,1],[3.83,1]] 6 | n = len(samples) 7 | labels = [0]*(n//2) + [1]*(n-n//2) 8 | 9 | A = np.matrix(samples) 10 | b = np.matrix(labels).transpose() 11 | 12 | print(np.linalg.inv(A.transpose()*A)*A.transpose()*b) 13 | -------------------------------------------------------------------------------- /src/ch8/2/logistic-growth.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | X = [0.2,37.9,32.0,12.7,23.3,8.2,25.2,27.0,40.9,4.7,19.1,50.7,53.2,59.3,15.2,45.5] 4 | Y = [0.04,4.79,4.51,0.30,3.05,0.01,3.61,4.14,4.77,0.01,1.64,4.77,4.56,4.53,0.67,4.61] 5 | n = len(X) 6 | 7 | guess_c = np.max(Y)*1.1 # 1.1 to avoid division by zero 8 | 9 | A = np.matrix(np.zeros((n, 2))) 10 | b = np.matrix(np.zeros((n, 1))) 11 | for i in range(n): 12 | A[i,0] = 1 13 | A[i,1] = X[i] 14 | b[i,0] = np.log(Y[i]/(guess_c - Y[i])) 15 | 16 | guess_w0, guess_w = (np.linalg.inv(A.T*A)*A.T*b).T.tolist()[0] 17 | 18 | 19 | U = np.matrix([[guess_c],[guess_w0],[guess_w]]) 20 | for _ in range(5): 21 | JR = np.matrix(np.zeros((n, 3))) 22 | R = np.matrix(np.zeros((n, 1))) 23 | for i in range(n): 24 | ei = np.exp(-U[1,0] - X[i]*U[2,0]) 25 | R[i,0] = -U[0,0]/(1+ei) + Y[i] 26 | for j in range(3): 27 | JR[i, 0] = 1/(1+ei) 28 | JR[i, 1] = U[0,0]*ei/(1+ei)**2 29 | JR[i, 2] = X[i]*U[0,0]*ei/(1+ei)**2 30 | U = U + np.linalg.inv(JR.T*JR)*JR.T*R 31 | 32 | 33 | import matplotlib.pyplot as plt 34 | plt.scatter(X,Y, color='red', edgecolors='black') 35 | 36 | def sigmoid(x, c,w0,w): 37 | return c/(1+np.exp(-w*x-w0)) 38 | 39 | fit_x = np.linspace(np.min(X), np.max(X), num=100) 40 | fit_y = sigmoid(fit_x, guess_c, guess_w0, guess_w) 41 | #plt.plot(fit_x, fit_y) 42 | fit_y = sigmoid(fit_x, U[0,0], U[1,0], U[2,0]) 43 | plt.plot(fit_x, fit_y) 44 | 45 | plt.show() 46 | 47 | -------------------------------------------------------------------------------- /src/ch8/5/neural.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | samples = [[.5,.7,1.],[.1,.5,1.],[.3,.6,1.],[.2,.8,1.],[.17,.17,1.],[.2,.3,1.], 4 | [.3,.4,1.],[.05,.2,1.], [.2,.3,1.],[.8,.3,1.],[.5,.2,1.],[.7,.2,1.], 5 | [.9,.1,1.],[.8,.4,1.],[.6,.5,1.], [.5,.4,1.], [.9, .5, 1.],[.79, .6, 1.], 6 | [.73, .7, 1.],[.9, .8, 1.],[.95, .4, 1.]] 7 | labels = [0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0] 8 | 9 | def neuron(x, w): 10 | return 1./(1.+np.exp(-np.dot(x,w))) 11 | 12 | u = np.array([0.814, 0.779, 0.103]) # small random values 13 | v = np.array([0.562, 0.310, 0.591]) 14 | w = np.array([0.884, 0.934, 0.649]) 15 | 16 | alpha = 1. # learning rate 17 | for _ in range(0,3000): 18 | E = 0 19 | for x, label in zip(samples,labels): 20 | E += (label - neuron([neuron(x, u), neuron(x, v), 1.],w))**2 21 | print("E =",E) 22 | 23 | for x, label in zip(samples,labels): 24 | out_u = neuron(x, u) 25 | out_v = neuron(x, v) 26 | out_w = neuron([out_u, out_v, 1.], w) 27 | u += alpha*(label-out_w)*out_w*(1.-out_w)*out_u*(1.-out_u)*np.array(x) 28 | v += alpha*(label-out_w)*out_w*(1.-out_w)*out_v*(1.-out_v)*np.array(x) 29 | w += alpha*(label-out_w)*out_w*(1.-out_w)*np.array([out_u, out_v, 1.]) 30 | 31 | #print(u,v,w) 32 | 33 | import matplotlib.pyplot as plt 34 | 35 | fig,ax = plt.subplots(1, figsize=(6.40*1.25,6.40),dpi=150) 36 | 37 | res = 100 38 | x0 = np.arange(0, 1., 1./res) 39 | x1 = np.arange(0, 1., 1./res) 40 | 41 | Y = [[neuron([neuron([a,b,1.], u), neuron([a,b,1],v), 1.], w) for a in x0] for b in x1] 42 | 43 | 44 | X0, X1 = np.meshgrid(x0, x1) 45 | #print(X0, X1, Y) 46 | plt.contourf(X0, X1, Y,100, cmap=plt.cm.RdYlGn) 47 | plt.colorbar() 48 | plt.contour(X0, X1, Y,levels=[.49995, .50005], colors='k', linestyles='--') 49 | 50 | for sample, label in zip(samples,labels): 51 | c = 'lime' 52 | if (label<.5): c = 'tomato' 53 | plt.scatter(sample[0], sample[1], color=c, edgecolors='black',s=200,linewidths=2) 54 | 55 | plt.tight_layout() 56 | plt.gca().axes.get_yaxis().set_visible(False) 57 | plt.gca().axes.get_xaxis().set_visible(False) 58 | plt.show() 59 | 60 | --------------------------------------------------------------------------------