Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ require (

require (
git.sr.ht/~sbinet/gg v0.5.0 // indirect
github.com/Knetic/govaluate v3.0.0+incompatible // indirect
github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b // indirect
github.com/campoy/embedmd v1.0.0 // indirect
github.com/ebitengine/purego v0.5.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ git.sr.ht/~sbinet/cmpimg v0.1.0/go.mod h1:FU12psLbF4TfNXkKH2ZZQ29crIqoiqTZmeQ7dk
git.sr.ht/~sbinet/gg v0.5.0 h1:6V43j30HM623V329xA9Ntq+WJrMjDxRjuAB1LFWF5m8=
git.sr.ht/~sbinet/gg v0.5.0/go.mod h1:G2C0eRESqlKhS7ErsNey6HHrqU1PwsnCQlekFi9Q2Oo=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/Knetic/govaluate v3.0.0+incompatible h1:7o6+MAPhYTCF0+fdvoz1xDedhRb4f6s9Tn1Tt7/WTEg=
github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY=
github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk=
github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b h1:slYM766cy2nI3BwyRiyQj/Ud48djTMtMebDqepE95rw=
Expand Down
41 changes: 35 additions & 6 deletions main.go
Original file line number Diff line number Diff line change
@@ -1,28 +1,57 @@
package main

import (
"fmt"
"image"
"log"
"math"
"time"

"github.com/hajimehoshi/ebiten/v2"
)

func f(x float64) float64 { return x*x + 5*x - 3 }
func df(x float64) float64 { return 2*x + 5 }
func f(x float64) float64 { return math.Cos(x*x + 3*x + 97) } // FUCTION CONTROL

// TODO: use govaluate to get function as user input
// i can get string from user, parse it to function, but then what?

func derivative(f func(float64) float64) func(float64) float64 {
return func(x float64) float64 {
dx := 0.00000000005 // dx -> 0
return (f(x+dx) - f(x)) / dx //literally todays math lesson.
}
}
func GradientDescent(f func(float64) float64, x0, alpha float64) float64 {
x := x0
var stop bool
for !stop {
x -= alpha * derivative(f)(x)
if derivative(f)(x) == 0 || math.Abs(derivative(f)(x)) < 0.00001 {
stop = true
}
}
return x
}

func main() {
ebiten.SetWindowSize(640, 480)
ebiten.SetWindowTitle("Gradient descent")

fmt.Println(GradientDescent(f, -math.Pi/6, 0.01)) //CONTROL X0 AND ALPHA HERE FOR PRINTLN OUTPUT

img := make(chan *image.RGBA, 1)
go func() {
p := Plot(-5, 0, 0.1, f)
x := 0.0
p := Plot(-math.Pi, math.Pi/3, 0.01, f) //CONTROL RANGE AND STEP HERE
x := -math.Pi / 6 //CONTROL X0 HERE FOR GRAPHICS
img <- p(x)
for i := 0; i < 50; i++ {
var stop bool
for !stop {
time.Sleep(30 * time.Millisecond)
x -= df(x) * 0.1
x -= 0.1 * derivative(f)(x) // CONTROL ALPHA HERE FOR GRAPHICS
// if you put alpha = 0.9, you wil get badly animated film about snake :)
if derivative(f)(x) == 0 || math.Abs(derivative(f)(x)) < 0.00001 {
stop = true
}
img <- p(x)
}
}()
Expand Down
62 changes: 62 additions & 0 deletions main_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package main

import (
"math"
"testing"
)

func TestDerivative(t *testing.T) {
for _, tc := range []struct {
name string
f func(float64) float64
x float64
want float64
}{
{name: "constant", f: func(x float64) float64 { return 5 }, x: 0.0, want: 0.0},
{name: "linear", f: func(x float64) float64 { return 2*x + 5 }, x: 0.0, want: 2.0},
{name: "simple square", f: func(x float64) float64 { return x * x }, x: 2.0, want: 4.0},
{name: "not so simple square", f: func(x float64) float64 { return x*x + 5*x - 3 }, x: 1.0, want: 7.0},
{name: "hyperbola", f: func(x float64) float64 { return 1 / x }, x: 2.0, want: -0.25},
{name: "diff.135 lpp. N18 a)", f: func(x float64) float64 { return 2*x*x - 3*x }, x: 3, want: 9},
{name: "diff.135 lpp. N18 b)", f: func(x float64) float64 { return x*x - x + 2 }, x: 0, want: -1},
{name: "diff.135 lpp. N18 c)", f: func(x float64) float64 { return 4 - 5*x - x*x }, x: 1, want: -7},
{"diff.135 lpp. N18 d)", func(x float64) float64 { return -3 / x }, 3, 0.3333333}, //1/3
{"diff.135 lpp. N18 e)", func(x float64) float64 { return 4 / x * x }, -2, 0},
{"diff.135 lpp. N18 f)", func(x float64) float64 { return 4/x + 1 }, -2, -1},
{"diff.135 lpp. N18 g)", func(x float64) float64 { return 6/2 - x }, -1, -1},
{"diff.135 lpp. N18 h)", func(x float64) float64 { return 1 / math.Sqrt(x) }, 4, -0.062499},
{"diff.135 lpp. N18 i)", func(x float64) float64 { return 2 * math.Sqrt(1-x) }, 0, -1},
{"diff.135 lpp. N18 j)", func(x float64) float64 { return math.Sqrt(1 + 2*x) }, 4, 0.3333333},
} {
t.Run("", func(t *testing.T) {
d := derivative(tc.f)
got := d(tc.x)
if math.Abs(got-tc.want) > 0.0001 {
t.Errorf("Expected derivative(%f) to be %f, but got %f", tc.x, tc.want, got)
}
})
}
}

func TestGradientDescend(t *testing.T) {
for _, tc := range []struct {
name string
f func(float64) float64
x0 float64
alpha float64
want float64
}{
{name: "constant", f: func(x float64) float64 { return 5 }, x0: 0.0, alpha: 0.01, want: 0.0},
{name: "simple square", f: func(x float64) float64 { return x * x }, x0: 2.0, alpha: 0.01, want: 0.0},
{name: "not so simple square", f: func(x float64) float64 { return x*x + 5*x - 3 }, x0: 1.0, alpha: 0.01, want: -2.5},
{name: "diff.135 lpp. N18 a)", f: func(x float64) float64 { return 2*x*x - 3*x }, x0: 3, alpha: 0.01, want: 0.75},
{name: "diff.135 lpp. N18 b)", f: func(x float64) float64 { return x*x - x + 2 }, x0: 0, alpha: 0.01, want: 0.5},
} {
t.Run("", func(t *testing.T) {
got := GradientDescent(tc.f, tc.x0, tc.alpha)
if math.Abs(got-tc.want) > 0.0001 {
t.Errorf("Expected GradientDescent(%f, %f) to be %f, but got %f", tc.x0, tc.alpha, tc.want, got)
}
})
}
}