Skip to content

Commit

Permalink
parallelize
Browse files Browse the repository at this point in the history
  • Loading branch information
fogleman committed Sep 23, 2016
1 parent 264a7e9 commit ccd3490
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 78 deletions.
34 changes: 18 additions & 16 deletions primitive/ellipse.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,22 @@ type Ellipse struct {
X, Y int
Rx, Ry int
Circle bool
rnd *rand.Rand
}

func NewRandomEllipse(w, h int) *Ellipse {
x := rand.Intn(w)
y := rand.Intn(h)
rx := rand.Intn(w / 2)
ry := rand.Intn(h / 2)
return &Ellipse{w, h, x, y, rx, ry, false}
func NewRandomEllipse(w, h int, rnd *rand.Rand) *Ellipse {
x := rnd.Intn(w)
y := rnd.Intn(h)
rx := rnd.Intn(w / 2)
ry := rnd.Intn(h / 2)
return &Ellipse{w, h, x, y, rx, ry, false, rnd}
}

func NewRandomCircle(w, h int) *Ellipse {
x := rand.Intn(w)
y := rand.Intn(h)
r := rand.Intn(w / 4)
return &Ellipse{w, h, x, y, r, r, true}
func NewRandomCircle(w, h int, rnd *rand.Rand) *Ellipse {
x := rnd.Intn(w)
y := rnd.Intn(h)
r := rnd.Intn(w / 4)
return &Ellipse{w, h, x, y, r, r, true, rnd}
}

func (c *Ellipse) Draw(dc *gg.Context) {
Expand All @@ -46,17 +47,18 @@ func (c *Ellipse) Copy() Shape {
}

func (c *Ellipse) Mutate() {
switch rand.Intn(3) {
rnd := c.rnd
switch rnd.Intn(3) {
case 0:
c.X = clampInt(c.X+rand.Intn(21)-10, 0, c.W-1)
c.Y = clampInt(c.Y+rand.Intn(21)-10, 0, c.H-1)
c.X = clampInt(c.X+rnd.Intn(21)-10, 0, c.W-1)
c.Y = clampInt(c.Y+rnd.Intn(21)-10, 0, c.H-1)
case 1:
c.Rx = clampInt(c.Rx+rand.Intn(21)-10, 0, c.W-1)
c.Rx = clampInt(c.Rx+rnd.Intn(21)-10, 0, c.W-1)
if c.Circle {
c.Ry = c.Rx
}
case 2:
c.Ry = clampInt(c.Ry+rand.Intn(21)-10, 0, c.W-1)
c.Ry = clampInt(c.Ry+rnd.Intn(21)-10, 0, c.W-1)
if c.Circle {
c.Rx = c.Ry
}
Expand Down
60 changes: 45 additions & 15 deletions primitive/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"image"
"math/rand"
"strings"
"time"

"github.com/fogleman/gg"
)
Expand Down Expand Up @@ -119,18 +120,47 @@ func (model *Model) Add(shape Shape) {
}

func (model *Model) Step() {
state := model.BestHillClimbState(model.Buffer, model.Mode, 100, 100, 10)
// state := model.BestRandomState(model.Buffer, model.Mode, 1000)
// state = Anneal(state, 0.1, 0.00001, 25000).(*State)
state = HillClimb(state, 1000).(*State)
state := model.runWorkers(model.Mode, 100, 100, 10)
// state := model.BestHillClimbState(model.Buffer, model.Mode, 100, 100, 20)
// state = HillClimb(state, 1000).(*State)
model.Add(state.Shape)
}

func (model *Model) BestHillClimbState(buffer *image.RGBA, t Mode, n, age, m int) *State {
func (model *Model) runWorkers(t Mode, n, age, m int) *State {
wn := 1 //runtime.GOMAXPROCS(0)
ch := make(chan *State, wn)
wm := m / wn
if m%wn != 0 {
wm++
}
for i := 0; i < wn; i++ {
go model.runWorker(t, n, age, wm, ch)
}
var bestEnergy float64
var bestState *State
for i := 0; i < wn; i++ {
state := <-ch
energy := state.Energy()
if i == 0 || energy < bestEnergy {
bestEnergy = energy
bestState = state
}
}
return HillClimb(bestState, 1000).(*State)
}

func (model *Model) runWorker(t Mode, n, age, m int, ch chan *State) {
buffer := image.NewRGBA(model.Target.Bounds())
rnd := rand.New(rand.NewSource(time.Now().UnixNano()))
state := model.BestHillClimbState(buffer, t, n, age, m, rnd)
ch <- state
}

func (model *Model) BestHillClimbState(buffer *image.RGBA, t Mode, n, age, m int, rnd *rand.Rand) *State {
var bestEnergy float64
var bestState *State
for i := 0; i < m; i++ {
state := model.BestRandomState(buffer, t, n)
state := model.BestRandomState(buffer, t, n, rnd)
before := state.Energy()
state = HillClimb(state, age).(*State)
energy := state.Energy()
Expand All @@ -143,11 +173,11 @@ func (model *Model) BestHillClimbState(buffer *image.RGBA, t Mode, n, age, m int
return bestState
}

func (model *Model) BestRandomState(buffer *image.RGBA, t Mode, n int) *State {
func (model *Model) BestRandomState(buffer *image.RGBA, t Mode, n int, rnd *rand.Rand) *State {
var bestEnergy float64
var bestState *State
for i := 0; i < n; i++ {
state := model.RandomState(buffer, t)
state := model.RandomState(buffer, t, rnd)
energy := state.Energy()
if i == 0 || energy < bestEnergy {
bestEnergy = energy
Expand All @@ -157,20 +187,20 @@ func (model *Model) BestRandomState(buffer *image.RGBA, t Mode, n int) *State {
return bestState
}

func (model *Model) RandomState(buffer *image.RGBA, t Mode) *State {
func (model *Model) RandomState(buffer *image.RGBA, t Mode, rnd *rand.Rand) *State {
switch t {
default:
return model.RandomState(buffer, Mode(rand.Intn(5)+1))
return model.RandomState(buffer, Mode(rnd.Intn(5)+1), rnd)
case ModeTriangle:
return NewState(model, buffer, NewRandomTriangle(model.W, model.H))
return NewState(model, buffer, NewRandomTriangle(model.W, model.H, rnd))
case ModeRectangle:
return NewState(model, buffer, NewRandomRectangle(model.W, model.H))
return NewState(model, buffer, NewRandomRectangle(model.W, model.H, rnd))
case ModeEllipse:
return NewState(model, buffer, NewRandomEllipse(model.W, model.H))
return NewState(model, buffer, NewRandomEllipse(model.W, model.H, rnd))
case ModeCircle:
return NewState(model, buffer, NewRandomCircle(model.W, model.H))
return NewState(model, buffer, NewRandomCircle(model.W, model.H, rnd))
case ModeRotatedRectangle:
return NewState(model, buffer, NewRandomRotatedRectangle(model.W, model.H))
return NewState(model, buffer, NewRandomRotatedRectangle(model.W, model.H, rnd))
}
}

Expand Down
56 changes: 30 additions & 26 deletions primitive/rectangle.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@ type Rectangle struct {
W, H int
X1, Y1 int
X2, Y2 int
rnd *rand.Rand
}

func NewRandomRectangle(w, h int) *Rectangle {
x1 := rand.Intn(w)
y1 := rand.Intn(h)
x2 := rand.Intn(w)
y2 := rand.Intn(h)
return &Rectangle{w, h, x1, y1, x2, y2}
func NewRandomRectangle(w, h int, rnd *rand.Rand) *Rectangle {
x1 := rnd.Intn(w)
y1 := rnd.Intn(h)
x2 := rnd.Intn(w)
y2 := rnd.Intn(h)
return &Rectangle{w, h, x1, y1, x2, y2, rnd}
}

func (r *Rectangle) bounds() (x1, y1, x2, y2 int) {
Expand Down Expand Up @@ -54,13 +55,14 @@ func (r *Rectangle) Copy() Shape {
}

func (r *Rectangle) Mutate() {
switch rand.Intn(2) {
rnd := r.rnd
switch rnd.Intn(2) {
case 0:
r.X1 = clampInt(r.X1+rand.Intn(21)-10, 0, r.W-1)
r.Y1 = clampInt(r.Y1+rand.Intn(21)-10, 0, r.H-1)
r.X1 = clampInt(r.X1+rnd.Intn(21)-10, 0, r.W-1)
r.Y1 = clampInt(r.Y1+rnd.Intn(21)-10, 0, r.H-1)
case 1:
r.X2 = clampInt(r.X2+rand.Intn(21)-10, 0, r.W-1)
r.Y2 = clampInt(r.Y2+rand.Intn(21)-10, 0, r.H-1)
r.X2 = clampInt(r.X2+rnd.Intn(21)-10, 0, r.W-1)
r.Y2 = clampInt(r.Y2+rnd.Intn(21)-10, 0, r.H-1)
}
}

Expand All @@ -80,15 +82,16 @@ type RotatedRectangle struct {
X, Y int
Sx, Sy int
Angle int
rnd *rand.Rand
}

func NewRandomRotatedRectangle(w, h int) *RotatedRectangle {
x := rand.Intn(w)
y := rand.Intn(h)
sx := rand.Intn(w / 2)
sy := rand.Intn(h / 2)
a := rand.Intn(360)
r := &RotatedRectangle{w, h, x, y, sx, sy, a}
func NewRandomRotatedRectangle(w, h int, rnd *rand.Rand) *RotatedRectangle {
x := rnd.Intn(w)
y := rnd.Intn(h)
sx := rnd.Intn(w / 2)
sy := rnd.Intn(h / 2)
a := rnd.Intn(360)
r := &RotatedRectangle{w, h, x, y, sx, sy, a, rnd}
r.Mutate()
return r
}
Expand All @@ -114,19 +117,20 @@ func (r *RotatedRectangle) Copy() Shape {
}

func (r *RotatedRectangle) Mutate() {
switch rand.Intn(3) {
rnd := r.rnd
switch rnd.Intn(3) {
case 0:
r.X = clampInt(r.X+rand.Intn(21)-10, 0, r.W-1)
r.Y = clampInt(r.Y+rand.Intn(21)-10, 0, r.H-1)
r.X = clampInt(r.X+rnd.Intn(21)-10, 0, r.W-1)
r.Y = clampInt(r.Y+rnd.Intn(21)-10, 0, r.H-1)
case 1:
r.Sx = clampInt(r.Sx+rand.Intn(21)-10, 0, r.W-1)
r.Sy = clampInt(r.Sy+rand.Intn(21)-10, 0, r.H-1)
r.Sx = clampInt(r.Sx+rnd.Intn(21)-10, 0, r.W-1)
r.Sy = clampInt(r.Sy+rnd.Intn(21)-10, 0, r.H-1)
case 2:
r.Angle = r.Angle + rand.Intn(41) - 20
r.Angle = r.Angle + rnd.Intn(41) - 20
}
for !r.Valid() {
r.Sx = clampInt(r.Sx+rand.Intn(21)-10, 0, r.W-1)
r.Sy = clampInt(r.Sy+rand.Intn(21)-10, 0, r.H-1)
r.Sx = clampInt(r.Sx+rnd.Intn(21)-10, 0, r.W-1)
r.Sy = clampInt(r.Sy+rnd.Intn(21)-10, 0, r.H-1)
}
}

Expand Down
19 changes: 13 additions & 6 deletions primitive/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,33 @@ type State struct {
Model *Model
Buffer *image.RGBA
Shape Shape
Score float64
}

func NewState(model *Model, buffer *image.RGBA, shape Shape) *State {
return &State{model, buffer, shape}
return &State{model, buffer, shape, -1}
}

func (state *State) Energy() float64 {
return state.Model.Energy(state.Shape, state.Buffer)
if state.Score < 0 {
state.Score = state.Model.Energy(state.Shape, state.Buffer)
}
return state.Score
}

func (state *State) DoMove() interface{} {
oldShape := state.Shape.Copy()
oldState := state.Copy()
state.Shape.Mutate()
return oldShape
state.Score = -1
return oldState
}

func (state *State) UndoMove(undo interface{}) {
state.Shape = undo.(Shape)
oldState := undo.(*State)
state.Shape = oldState.Shape
state.Score = oldState.Score
}

func (state *State) Copy() Annealable {
return &State{state.Model, state.Buffer, state.Shape.Copy()}
return &State{state.Model, state.Buffer, state.Shape.Copy(), state.Score}
}
32 changes: 17 additions & 15 deletions primitive/triangle.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,17 @@ type Triangle struct {
X1, Y1 int
X2, Y2 int
X3, Y3 int
rnd *rand.Rand
}

func NewRandomTriangle(w, h int) *Triangle {
x1 := rand.Intn(w)
y1 := rand.Intn(h)
x2 := rand.Intn(w)
y2 := rand.Intn(h)
x3 := rand.Intn(w)
y3 := rand.Intn(h)
t := &Triangle{w, h, x1, y1, x2, y2, x3, y3}
func NewRandomTriangle(w, h int, rnd *rand.Rand) *Triangle {
x1 := rnd.Intn(w)
y1 := rnd.Intn(h)
x2 := rnd.Intn(w)
y2 := rnd.Intn(h)
x3 := rnd.Intn(w)
y3 := rnd.Intn(h)
t := &Triangle{w, h, x1, y1, x2, y2, x3, y3, rnd}
t.Mutate()
return t
}
Expand All @@ -46,17 +47,18 @@ func (t *Triangle) Copy() Shape {
}

func (t *Triangle) Mutate() {
rnd := t.rnd
for {
switch rand.Intn(3) {
switch rnd.Intn(3) {
case 0:
t.X1 = clampInt(t.X1+rand.Intn(21)-10, 0, t.W-1)
t.Y1 = clampInt(t.Y1+rand.Intn(21)-10, 0, t.H-1)
t.X1 = clampInt(t.X1+rnd.Intn(21)-10, 0, t.W-1)
t.Y1 = clampInt(t.Y1+rnd.Intn(21)-10, 0, t.H-1)
case 1:
t.X2 = clampInt(t.X2+rand.Intn(21)-10, 0, t.W-1)
t.Y2 = clampInt(t.Y2+rand.Intn(21)-10, 0, t.H-1)
t.X2 = clampInt(t.X2+rnd.Intn(21)-10, 0, t.W-1)
t.Y2 = clampInt(t.Y2+rnd.Intn(21)-10, 0, t.H-1)
case 2:
t.X3 = clampInt(t.X3+rand.Intn(21)-10, 0, t.W-1)
t.Y3 = clampInt(t.Y3+rand.Intn(21)-10, 0, t.H-1)
t.X3 = clampInt(t.X3+rnd.Intn(21)-10, 0, t.W-1)
t.Y3 = clampInt(t.Y3+rnd.Intn(21)-10, 0, t.H-1)
}
if t.Valid() {
break
Expand Down

0 comments on commit ccd3490

Please sign in to comment.