summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--autoart/autoaudio.go64
-rw-r--r--autoart/autoimages.go265
-rw-r--r--autoart/autovideos.go174
-rw-r--r--autoutils/audio.go99
-rw-r--r--autoutils/batches.go49
-rw-r--r--autoutils/colorconversion.go65
-rw-r--r--autoutils/functiongenerator.go264
7 files changed, 504 insertions, 476 deletions
diff --git a/autoart/autoaudio.go b/autoart/autoaudio.go
index 05a91d4..cc5965e 100644
--- a/autoart/autoaudio.go
+++ b/autoart/autoaudio.go
@@ -20,37 +20,39 @@ along with AutoArt. If not, see <https://www.gnu.org/licenses/>.
package autoart
import (
- "github.com/pommicket/autoart/autoutils"
- "io"
+ "github.com/pommicket/autoart/autoutils"
+ "io"
)
func GenerateAudio(output io.Writer, duration float64, sampleRate int32,
- functionLength int, rectifier int) error {
- samples := int64(duration * float64(sampleRate))
- err := autoutils.WriteAudioHeader(output, samples, 1, sampleRate)
- if err != nil { return err }
-
- vars := make([]float64, 1)
- const sampleBufferSize = 4096
- sampleBuffer := make([]uint8, sampleBufferSize)
- sampleBufferIndex := 0
-
- var function autoutils.Function
- function.Generate(1, functionLength)
-
- for s := int64(0); s < samples; s++ {
- t := float64(s) / float64(sampleRate)
- vars[0] = t
- value := rectify(function.Evaluate(vars), rectifier)
- sampleBuffer[sampleBufferIndex] = uint8(255 * value)
- sampleBufferIndex++
- if sampleBufferIndex == sampleBufferSize {
- err = autoutils.WriteAudioSamples(output, sampleBuffer)
- if err != nil {
- return err
- }
- sampleBufferIndex = 0
- }
- }
- return autoutils.WriteAudioSamples(output, sampleBuffer[:sampleBufferIndex])
-} \ No newline at end of file
+ functionLength int, rectifier int) error {
+ samples := int64(duration * float64(sampleRate))
+ err := autoutils.WriteAudioHeader(output, samples, 1, sampleRate)
+ if err != nil {
+ return err
+ }
+
+ vars := make([]float64, 1)
+ const sampleBufferSize = 4096
+ sampleBuffer := make([]uint8, sampleBufferSize)
+ sampleBufferIndex := 0
+
+ var function autoutils.Function
+ function.Generate(1, functionLength)
+
+ for s := int64(0); s < samples; s++ {
+ t := float64(s) / float64(sampleRate)
+ vars[0] = t
+ value := rectify(function.Evaluate(vars), rectifier)
+ sampleBuffer[sampleBufferIndex] = uint8(255 * value)
+ sampleBufferIndex++
+ if sampleBufferIndex == sampleBufferSize {
+ err = autoutils.WriteAudioSamples(output, sampleBuffer)
+ if err != nil {
+ return err
+ }
+ sampleBufferIndex = 0
+ }
+ }
+ return autoutils.WriteAudioSamples(output, sampleBuffer[:sampleBufferIndex])
+}
diff --git a/autoart/autoimages.go b/autoart/autoimages.go
index 53eea18..df0a3fd 100644
--- a/autoart/autoimages.go
+++ b/autoart/autoimages.go
@@ -20,185 +20,186 @@ along with AutoArt. If not, see <https://www.gnu.org/licenses/>.
package autoart
import (
- "image"
- "image/color"
- "math"
- "math/rand"
"fmt"
- "github.com/pommicket/autoart/autoutils"
+ "github.com/pommicket/autoart/autoutils"
+ "image"
+ "image/color"
+ "math"
+ "math/rand"
)
const (
- XY = iota
- RTHETA
+ XY = iota
+ RTHETA
)
const (
- RGB = iota
- GRAYSCALE
- CMYK
- HSV
- YCbCr
+ RGB = iota
+ GRAYSCALE
+ CMYK
+ HSV
+ YCbCr
)
const (
- MOD = iota
- CLAMP
- SIGMOID
+ MOD = iota
+ CLAMP
+ SIGMOID
)
type Config struct {
- FunctionLength int
- ColorSpace int
- CoordinateSys int
- Alpha bool
- Rectifier int // What to do with out-of-bounds values
+ FunctionLength int
+ ColorSpace int
+ CoordinateSys int
+ Alpha bool
+ Rectifier int // What to do with out-of-bounds values
}
func sigmoid(x float64) float64 {
- return 1 / (1 + math.Exp(-x))
+ return 1 / (1 + math.Exp(-x))
}
func rectify(x float64, rectifier int) float64 {
- switch rectifier {
- case MOD:
- return math.Mod(x, 1)
- case CLAMP:
- if x > 1 {
- return 1
- } else if x < 0 {
- return 0
- }
- case SIGMOID:
- return sigmoid(x)
- }
- return 0
+ switch rectifier {
+ case MOD:
+ return math.Mod(x, 1)
+ case CLAMP:
+ if x > 1 {
+ return 1
+ } else if x < 0 {
+ return 0
+ }
+ case SIGMOID:
+ return sigmoid(x)
+ }
+ return 0
}
func (conf *Config) nFunctions() int {
- a := 0
- if conf.Alpha { a = 1 }
- switch conf.ColorSpace {
- case GRAYSCALE:
- return a + 1
- case RGB, HSV, YCbCr:
- return a + 3
- case CMYK:
- return a + 4
- }
- panic("Invalid color space!")
- return a
+ a := 0
+ if conf.Alpha {
+ a = 1
+ }
+ switch conf.ColorSpace {
+ case GRAYSCALE:
+ return a + 1
+ case RGB, HSV, YCbCr:
+ return a + 3
+ case CMYK:
+ return a + 4
+ }
+ panic("Invalid color space!")
+ return a
}
const defaultFunctionLength = 40
func GenerateImageFromFunctions(width int, height int, config Config,
- functions []autoutils.Function,
- vars []float64) image.Image {
- var rect = image.Rectangle{image.Point{0, 0}, image.Point{width, height}}
- img := image.NewRGBA(rect)
- colorSpace := config.ColorSpace
- alpha := config.Alpha
- rectifier := config.Rectifier
- nfunctions := len(functions)
- rets := make([]uint8, nfunctions)
- fwidth, fheight := float64(width), float64(height)
- for y := 0; y < height; y++ {
- for x := 0; x < width; x++ {
- switch config.CoordinateSys {
- case XY:
- vars[0], vars[1] = float64(x)/fwidth, float64(y)/fheight
- case RTHETA:
- dx, dy := float64(x - width/2), float64(y - height/2)
- vars[0] = math.Sqrt(dx * dx + dy * dy) / ((fwidth+fheight)/2) // r
- vars[1] = math.Atan2(dy, dx) // theta
- }
- for i := range rets {
- ret := rectify(functions[i].Evaluate(vars), rectifier)
- rets[i] = uint8(255 * ret)
- }
- var r, g, b, a uint8
- a = 255
- switch (colorSpace) {
- case RGB:
- r, g, b = rets[0], rets[1], rets[2]
- case GRAYSCALE:
- r, g, b = rets[0], rets[0], rets[0]
- case CMYK:
- r, g, b = color.CMYKToRGB(rets[0], rets[1], rets[2], rets[3])
- case HSV:
- r, g, b = autoutils.HSVToRGB(rets[0], rets[1], rets[2])
- case YCbCr:
- r, g, b = color.YCbCrToRGB(rets[0], rets[1], rets[2])
- }
- if (alpha) {
- a = rets[nfunctions-1]
- }
- img.Set(x, y, color.RGBA{r, g, b, a})
- }
- }
- return img
+ functions []autoutils.Function,
+ vars []float64) image.Image {
+ var rect = image.Rectangle{image.Point{0, 0}, image.Point{width, height}}
+ img := image.NewRGBA(rect)
+ colorSpace := config.ColorSpace
+ alpha := config.Alpha
+ rectifier := config.Rectifier
+ nfunctions := len(functions)
+ rets := make([]uint8, nfunctions)
+ fwidth, fheight := float64(width), float64(height)
+ for y := 0; y < height; y++ {
+ for x := 0; x < width; x++ {
+ switch config.CoordinateSys {
+ case XY:
+ vars[0], vars[1] = float64(x)/fwidth, float64(y)/fheight
+ case RTHETA:
+ dx, dy := float64(x-width/2), float64(y-height/2)
+ vars[0] = math.Sqrt(dx*dx+dy*dy) / ((fwidth + fheight) / 2) // r
+ vars[1] = math.Atan2(dy, dx) // theta
+ }
+ for i := range rets {
+ ret := rectify(functions[i].Evaluate(vars), rectifier)
+ rets[i] = uint8(255 * ret)
+ }
+ var r, g, b, a uint8
+ a = 255
+ switch colorSpace {
+ case RGB:
+ r, g, b = rets[0], rets[1], rets[2]
+ case GRAYSCALE:
+ r, g, b = rets[0], rets[0], rets[0]
+ case CMYK:
+ r, g, b = color.CMYKToRGB(rets[0], rets[1], rets[2], rets[3])
+ case HSV:
+ r, g, b = autoutils.HSVToRGB(rets[0], rets[1], rets[2])
+ case YCbCr:
+ r, g, b = color.YCbCrToRGB(rets[0], rets[1], rets[2])
+ }
+ if alpha {
+ a = rets[nfunctions-1]
+ }
+ img.Set(x, y, color.RGBA{r, g, b, a})
+ }
+ }
+ return img
}
func GenerateImage(width int, height int, config Config) image.Image {
- if config.FunctionLength == 0 {
- // 0 value of config shouldn't have empty functions
- config.FunctionLength = defaultFunctionLength
- }
+ if config.FunctionLength == 0 {
+ // 0 value of config shouldn't have empty functions
+ config.FunctionLength = defaultFunctionLength
+ }
- functionLength := config.FunctionLength
+ functionLength := config.FunctionLength
- nfunctions := config.nFunctions()
- functions := make([]autoutils.Function, nfunctions)
- for i := range functions {
- functions[i].Generate(2, functionLength)
- }
- vars := []float64{0, 0}
- return GenerateImageFromFunctions(width, height, config, functions, vars)
+ nfunctions := config.nFunctions()
+ functions := make([]autoutils.Function, nfunctions)
+ for i := range functions {
+ functions[i].Generate(2, functionLength)
+ }
+ vars := []float64{0, 0}
+ return GenerateImageFromFunctions(width, height, config, functions, vars)
}
-
func GenerateImages(width int, height int, config Config, number int, verbose bool) []image.Image {
- c := make(chan image.Image)
- for i := 0; i < number; i++ {
- go func () {
- c <- GenerateImage(width, height, config)
- }()
- }
- imgs := make([]image.Image, number)
- for i := range imgs {
- imgs[i] = <-c
+ c := make(chan image.Image)
+ for i := 0; i < number; i++ {
+ go func() {
+ c <- GenerateImage(width, height, config)
+ }()
+ }
+ imgs := make([]image.Image, number)
+ for i := range imgs {
+ imgs[i] = <-c
if verbose {
fmt.Println("Generating images...", i+1, "/", number)
}
- }
- return imgs
+ }
+ return imgs
}
type PaletteConfig struct {
- NColors int
- Alpha bool
+ NColors int
+ Alpha bool
FunctionLength int
- CoordinateSys int
+ CoordinateSys int
}
func GenerateImagePaletteFrom(width int, height int, conf PaletteConfig,
- funcs []autoutils.Function, vars []float64,
- palette []color.RGBA) image.Image {
- img := image.NewRGBA(image.Rectangle{image.Point{0,0}, image.Point{width, height}})
- fwidth, fheight := float64(width), float64(height)
+ funcs []autoutils.Function, vars []float64,
+ palette []color.RGBA) image.Image {
+ img := image.NewRGBA(image.Rectangle{image.Point{0, 0}, image.Point{width, height}})
+ fwidth, fheight := float64(width), float64(height)
for y := 0; y < height; y++ {
for x := 0; x < width; x++ {
- switch conf.CoordinateSys {
- case XY:
- vars[0], vars[1] = float64(x)/fwidth, float64(y)/fheight
- case RTHETA:
- dx, dy := float64(x - width/2), float64(y - height/2)
- vars[0] = math.Sqrt(dx * dx + dy * dy) / ((fwidth+fheight)/2) // r
- vars[1] = math.Atan2(dy, dx) // theta
- }
+ switch conf.CoordinateSys {
+ case XY:
+ vars[0], vars[1] = float64(x)/fwidth, float64(y)/fheight
+ case RTHETA:
+ dx, dy := float64(x-width/2), float64(y-height/2)
+ vars[0] = math.Sqrt(dx*dx+dy*dy) / ((fwidth + fheight) / 2) // r
+ vars[1] = math.Atan2(dy, dx) // theta
+ }
for i := range palette {
- if i == conf.NColors - 1 {
+ if i == conf.NColors-1 {
// Background color
img.Set(x, y, palette[i])
} else if funcs[i].Evaluate(vars) < 0 {
@@ -216,7 +217,7 @@ func GenerateImagePalette(width int, height int, conf PaletteConfig) image.Image
alpha := conf.Alpha
functionLength := conf.FunctionLength
- funcs := make([]autoutils.Function, nColors - 1)
+ funcs := make([]autoutils.Function, nColors-1)
palette := make([]color.RGBA, nColors)
// Choose palette
diff --git a/autoart/autovideos.go b/autoart/autovideos.go
index 4a51d1f..82c2747 100644
--- a/autoart/autovideos.go
+++ b/autoart/autovideos.go
@@ -24,103 +24,103 @@ NOTE: AutoVideos requires Go 1.11 or newer (for temp file patterns).
package autoart
import (
+ "fmt"
"github.com/pommicket/autoart/autoutils"
+ "image"
+ "image/color"
+ "image/png"
"io"
"io/ioutil"
- "image"
- "image/png"
- "image/color"
- "math/rand"
- "fmt"
- "os/exec"
+ "math/rand"
"os"
+ "os/exec"
)
func generateFrame(width int, height int, paletted bool, config Config,
- pconfig PaletteConfig, palette []color.RGBA,
- functions []autoutils.Function, time float64,
- frameNumber int64, file *os.File) error { // NOTE: file is closed by this function
+ pconfig PaletteConfig, palette []color.RGBA,
+ functions []autoutils.Function, time float64,
+ frameNumber int64, file *os.File) error { // NOTE: file is closed by this function
vars := []float64{0, 0, time}
- var img image.Image
- if paletted {
- img = GenerateImagePaletteFrom(width, height, pconfig, functions, vars, palette)
- } else {
- img = GenerateImageFromFunctions(width, height, config, functions, vars)
- }
+ var img image.Image
+ if paletted {
+ img = GenerateImagePaletteFrom(width, height, pconfig, functions, vars, palette)
+ } else {
+ img = GenerateImageFromFunctions(width, height, config, functions, vars)
+ }
if err := png.Encode(file, img); err != nil {
- file.Close()
+ file.Close()
return err
}
- return file.Close()
+ return file.Close()
}
func generateVideo(width int, height int, paletted bool, config Config,
- pconfig PaletteConfig, time float64,
- framerate int, filename string, verbose bool) error {
-
- var palette []color.RGBA
- if paletted {
- // Generate palette
- palette = make([]color.RGBA, pconfig.NColors)
- for i := range palette {
- r := uint8(rand.Intn(256))
- g := uint8(rand.Intn(256))
- b := uint8(rand.Intn(256))
- a := uint8(255)
- if pconfig.Alpha {
- a = uint8(rand.Intn(256))
- }
- palette[i] = color.RGBA{r, g, b, a}
- }
- }
-
- if config.FunctionLength == 0 {
+ pconfig PaletteConfig, time float64,
+ framerate int, filename string, verbose bool) error {
+
+ var palette []color.RGBA
+ if paletted {
+ // Generate palette
+ palette = make([]color.RGBA, pconfig.NColors)
+ for i := range palette {
+ r := uint8(rand.Intn(256))
+ g := uint8(rand.Intn(256))
+ b := uint8(rand.Intn(256))
+ a := uint8(255)
+ if pconfig.Alpha {
+ a = uint8(rand.Intn(256))
+ }
+ palette[i] = color.RGBA{r, g, b, a}
+ }
+ }
+
+ if config.FunctionLength == 0 {
// 0 value of config shouldn't have empty functions
config.FunctionLength = defaultFunctionLength
- }
-
- var functionLength int
- if paletted {
- functionLength = pconfig.FunctionLength
- } else {
- functionLength = config.FunctionLength
- }
-
- var nfunctions int
- if paletted {
- nfunctions = pconfig.NColors
- } else {
- nfunctions = config.nFunctions()
- }
+ }
+
+ var functionLength int
+ if paletted {
+ functionLength = pconfig.FunctionLength
+ } else {
+ functionLength = config.FunctionLength
+ }
+
+ var nfunctions int
+ if paletted {
+ nfunctions = pconfig.NColors
+ } else {
+ nfunctions = config.nFunctions()
+ }
functions := make([]autoutils.Function, nfunctions)
- for i := range functions {
- functions[i].Generate(3, functionLength)
- }
-
- frames := int64(time * float64(framerate))
-
- files := make([]*os.File, frames)
- defer func() {
- // Delete all temporary files
- for _, file := range files {
- if file != nil {
- os.Remove(file.Name())
- }
- }
- }()
- // Create temporary frame files
- for i := range files {
- var err error
- files[i], err = ioutil.TempFile("", "frame*.png")
- if err != nil {
- return err
- }
- }
-
- autoutils.RunInBatches(frames, "Generating video...", func (n int64, errs chan<- error) {
- t := float64(n)/float64(framerate)
- errs <- generateFrame(width, height, paletted, config, pconfig, palette, functions, t, n, files[n])
- })
+ for i := range functions {
+ functions[i].Generate(3, functionLength)
+ }
+
+ frames := int64(time * float64(framerate))
+
+ files := make([]*os.File, frames)
+ defer func() {
+ // Delete all temporary files
+ for _, file := range files {
+ if file != nil {
+ os.Remove(file.Name())
+ }
+ }
+ }()
+ // Create temporary frame files
+ for i := range files {
+ var err error
+ files[i], err = ioutil.TempFile("", "frame*.png")
+ if err != nil {
+ return err
+ }
+ }
+
+ autoutils.RunInBatches(frames, "Generating video...", func(n int64, errs chan<- error) {
+ t := float64(n) / float64(framerate)
+ errs <- generateFrame(width, height, paletted, config, pconfig, palette, functions, t, n, files[n])
+ })
ffmpegInputFile, err := ioutil.TempFile("", "input*.txt")
if err != nil {
@@ -129,7 +129,7 @@ func generateVideo(width int, height int, paletted bool, config Config,
defer os.Remove(ffmpegInputFile.Name())
for _, file := range files {
- name := file.Name()
+ name := file.Name()
info := fmt.Sprintf("file '%v'\nduration %v\n", name, 1/float64(framerate))
if _, err = io.WriteString(ffmpegInputFile, info); err != nil {
return err
@@ -159,13 +159,13 @@ func generateVideo(width int, height int, paletted bool, config Config,
}
func GenerateVideo(width int, height int, config Config, time float64,
- framerate int, filename string, verbose bool) error {
- var pconfig PaletteConfig
- return generateVideo(width, height, false, config, pconfig, time, framerate, filename, verbose)
+ framerate int, filename string, verbose bool) error {
+ var pconfig PaletteConfig
+ return generateVideo(width, height, false, config, pconfig, time, framerate, filename, verbose)
}
func GenerateVideoPalette(width int, height int, pconfig PaletteConfig,
- time float64, framerate int, filename string, verbose bool) error {
- var config Config
- return generateVideo(width, height, true, config, pconfig, time, framerate, filename, verbose)
+ time float64, framerate int, filename string, verbose bool) error {
+ var config Config
+ return generateVideo(width, height, true, config, pconfig, time, framerate, filename, verbose)
}
diff --git a/autoutils/audio.go b/autoutils/audio.go
index 19ae5f3..67fe923 100644
--- a/autoutils/audio.go
+++ b/autoutils/audio.go
@@ -20,46 +20,69 @@ along with AutoArt. If not, see <https://www.gnu.org/licenses/>.
package autoutils
import (
- "io"
- "encoding/binary"
+ "encoding/binary"
+ "io"
)
// Write a header to writer. You need to decide ahead of time how many samples
// you want.
func WriteAudioHeader(writer io.Writer, nSamples int64, channels, sampleRate int32) error {
- w := func (data interface{}) error {
- return binary.Write(writer, binary.LittleEndian, data)
- }
- var err error
- if err = w([]byte("RIFF")); err != nil { return err }
- var chunkSize1 uint32 = 36 + uint32(nSamples)
- if err = w(chunkSize1); err != nil { return err }
- if err = w([]byte("WAVEfmt ")); err != nil { return err }
- var subchunk1size uint32 = 16
- if err = w(subchunk1size); err != nil { return err }
- var audioFormat uint16 = 1
- if err = w(audioFormat); err != nil { return err }
- var nChannels uint16 = uint16(channels)
- if err = w(nChannels); err != nil { return err }
- var srate uint32 = uint32(sampleRate)
- if err = w(srate); err != nil { return err }
- var byteRate uint32 = srate * uint32(nChannels)
- if err = w(byteRate); err != nil { return err }
- var blockAlign uint16 = nChannels
- if err = w(blockAlign); err != nil { return err }
- var bitsPerSample uint16 = 8
- if err = w(bitsPerSample); err != nil { return err }
- if err = w([]byte("data")); err != nil { return err }
- var chunkSize2 uint32 = uint32(nSamples) * uint32(nChannels)
- if err = w(chunkSize2); err != nil { return err }
- return nil
+ w := func(data interface{}) error {
+ return binary.Write(writer, binary.LittleEndian, data)
+ }
+ var err error
+ if err = w([]byte("RIFF")); err != nil {
+ return err
+ }
+ var chunkSize1 uint32 = 36 + uint32(nSamples)
+ if err = w(chunkSize1); err != nil {
+ return err
+ }
+ if err = w([]byte("WAVEfmt ")); err != nil {
+ return err
+ }
+ var subchunk1size uint32 = 16
+ if err = w(subchunk1size); err != nil {
+ return err
+ }
+ var audioFormat uint16 = 1
+ if err = w(audioFormat); err != nil {
+ return err
+ }
+ var nChannels uint16 = uint16(channels)
+ if err = w(nChannels); err != nil {
+ return err
+ }
+ var srate uint32 = uint32(sampleRate)
+ if err = w(srate); err != nil {
+ return err
+ }
+ var byteRate uint32 = srate * uint32(nChannels)
+ if err = w(byteRate); err != nil {
+ return err
+ }
+ var blockAlign uint16 = nChannels
+ if err = w(blockAlign); err != nil {
+ return err
+ }
+ var bitsPerSample uint16 = 8
+ if err = w(bitsPerSample); err != nil {
+ return err
+ }
+ if err = w([]byte("data")); err != nil {
+ return err
+ }
+ var chunkSize2 uint32 = uint32(nSamples) * uint32(nChannels)
+ if err = w(chunkSize2); err != nil {
+ return err
+ }
+ return nil
}
-
// Writes some samples to the writer. You will need to write a header before
// any samples.
func WriteAudioSamples(writer io.Writer, samples []uint8) error {
- return binary.Write(writer, binary.LittleEndian, samples)
+ return binary.Write(writer, binary.LittleEndian, samples)
}
/*
@@ -72,12 +95,12 @@ you're using that many?!)
*/
func WriteAudio(writer io.Writer, audio []uint8, channels, sampleRate int32) error {
- err := WriteAudioHeader(writer, int64(len(audio)), channels, sampleRate)
- if err != nil {
- return err
- }
- if err = WriteAudioSamples(writer, audio); err != nil {
- return err
- }
- return nil
+ err := WriteAudioHeader(writer, int64(len(audio)), channels, sampleRate)
+ if err != nil {
+ return err
+ }
+ if err = WriteAudioSamples(writer, audio); err != nil {
+ return err
+ }
+ return nil
}
diff --git a/autoutils/batches.go b/autoutils/batches.go
index fb39fc1..7e27473 100644
--- a/autoutils/batches.go
+++ b/autoutils/batches.go
@@ -20,7 +20,7 @@ along with AutoArt. If not, see <https://www.gnu.org/licenses/>.
package autoutils
import (
- "fmt"
+ "fmt"
)
/*
@@ -31,26 +31,27 @@ a message will be printed, starting with progress, and showing how many batches
have been completed so far out of the total number of batches.
*/
const batchSize = 32
-func RunInBatches(number int64, progress string, f func (n int64, errs chan<- error)) error {
- nBatches := number / batchSize
- errs := make(chan error)
- for batch := int64(0); batch <= nBatches; batch++ {
- fmt.Println(progress, batch+1, "/", nBatches+1)
- thisBatchSize := batchSize
- if batch == nBatches {
- // Deal with case of last batch
- thisBatchSize = int(number - nBatches * batchSize)
- }
- for task := 0; task < thisBatchSize; task++ {
- go f(int64(task) + batchSize * batch, errs)
- }
-
- for completed := 0; completed < thisBatchSize; completed++ {
- err := <-errs
- if err != nil {
- return err
- }
- }
- }
- return nil
-} \ No newline at end of file
+
+func RunInBatches(number int64, progress string, f func(n int64, errs chan<- error)) error {
+ nBatches := number / batchSize
+ errs := make(chan error)
+ for batch := int64(0); batch <= nBatches; batch++ {
+ fmt.Println(progress, batch+1, "/", nBatches+1)
+ thisBatchSize := batchSize
+ if batch == nBatches {
+ // Deal with case of last batch
+ thisBatchSize = int(number - nBatches*batchSize)
+ }
+ for task := 0; task < thisBatchSize; task++ {
+ go f(int64(task)+batchSize*batch, errs)
+ }
+
+ for completed := 0; completed < thisBatchSize; completed++ {
+ err := <-errs
+ if err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+}
diff --git a/autoutils/colorconversion.go b/autoutils/colorconversion.go
index af21668..6128e39 100644
--- a/autoutils/colorconversion.go
+++ b/autoutils/colorconversion.go
@@ -18,40 +18,41 @@ along with AutoArt. If not, see <https://www.gnu.org/licenses/>.
*/
package autoutils
+
import (
- "math"
+ "math"
)
func HSVToRGB(h uint8, s uint8, v uint8) (uint8, uint8, uint8) {
- // https://en.wikipedia.org/wiki/HSL_and_HSV#HSV_to_RGB
- V := float64(v) / 256
- S := float64(s) / 256
- C := V * S
- H := float64(h) / (256/6)
- X := float64(C) * (1 - math.Abs(math.Mod(H, 2) - 1))
- var r, g, b float64
- switch true {
- case s == 0:
- r, g, b = 0, 0, 0
- case H <= 1:
- r, g, b = C, X, 0
- case H <= 2:
- r, g, b = X, C, 0
- case H <= 3:
- r, g, b = 0, C, X
- case H <= 4:
- r, g, b = 0, X, C
- case H <= 5:
- r, g, b = X, 0, C
- default:
- r, g, b = C, 0, X
- }
- m := V - C
- r += m
- g += m
- b += m
- r *= 255
- g *= 255
- b *= 255
- return uint8(r), uint8(g), uint8(b)
+ // https://en.wikipedia.org/wiki/HSL_and_HSV#HSV_to_RGB
+ V := float64(v) / 256
+ S := float64(s) / 256
+ C := V * S
+ H := float64(h) / (256 / 6)
+ X := float64(C) * (1 - math.Abs(math.Mod(H, 2)-1))
+ var r, g, b float64
+ switch true {
+ case s == 0:
+ r, g, b = 0, 0, 0
+ case H <= 1:
+ r, g, b = C, X, 0
+ case H <= 2:
+ r, g, b = X, C, 0
+ case H <= 3:
+ r, g, b = 0, C, X
+ case H <= 4:
+ r, g, b = 0, X, C
+ case H <= 5:
+ r, g, b = X, 0, C
+ default:
+ r, g, b = C, 0, X
+ }
+ m := V - C
+ r += m
+ g += m
+ b += m
+ r *= 255
+ g *= 255
+ b *= 255
+ return uint8(r), uint8(g), uint8(b)
}
diff --git a/autoutils/functiongenerator.go b/autoutils/functiongenerator.go
index 7acb680..20ab0e0 100644
--- a/autoutils/functiongenerator.go
+++ b/autoutils/functiongenerator.go
@@ -20,27 +20,27 @@ along with AutoArt. If not, see <https://www.gnu.org/licenses/>.
package autoutils
import (
- "math"
- "math/rand"
- "fmt"
+ "fmt"
+ "math"
+ "math/rand"
)
// Operators
const (
- CONST = iota
- ADD
- SUB
- MUL
- DIV
+ CONST = iota
+ ADD
+ SUB
+ MUL
+ DIV
MIN
MAX
- SQRT
- SIN
- COS
- TAN
+ SQRT
+ SIN
+ COS
+ TAN
LOG
EXP
- OPERATOR_COUNT
+ OPERATOR_COUNT
)
const FIRST_BINARY = ADD
const FIRST_UNARY = SQRT
@@ -49,147 +49,147 @@ const UNARY_COUNT = OPERATOR_COUNT - FIRST_UNARY
const FIRST_VAR = OPERATOR_COUNT
type Operator struct {
- op int // Operator number. If operator is a variable, v, it is equal to FIRST_VAR + v
- constant float64 // Constant (if op = CONST)
+ op int // Operator number. If operator is a variable, v, it is equal to FIRST_VAR + v
+ constant float64 // Constant (if op = CONST)
}
type Function struct {
- nvars int
- operators []Operator
+ nvars int
+ operators []Operator
}
// Generate a random function f with the given length (i.e. len(f.operators))
// and the given number of variables
func (f *Function) Generate(nvars int, length int) {
- f.nvars = nvars
- f.operators = make([]Operator, length)
- nsOnStack := 0
- i := 0
- for nsOnStack + i < length {
- var operator Operator
- var optype int
- if nsOnStack == 0 {
- // Pick a random variable
- optype = 0
- } else if nsOnStack == 1 {
- // Pick a constant/variable/unary operator
- optype = rand.Intn(3)
- } else {
- // Pick a constant/variable/unary/binary operator
- optype = rand.Intn(4)
- }
- switch optype {
- case 0:
- // variable
- operator.op = FIRST_VAR + rand.Intn(nvars)
- nsOnStack++
- case 1:
- // Constant
- operator.op = CONST
- operator.constant = rand.Float64()
- nsOnStack++
- case 2:
- // unary
- operator.op = rand.Intn(UNARY_COUNT) + FIRST_UNARY
- case 3:
- // binary
- operator.op = rand.Intn(BINARY_COUNT) + FIRST_BINARY
- nsOnStack--
- }
- f.operators[i] = operator
- i++
- }
-
- if nsOnStack + i == length {
- // Add a unary operator
- f.operators[i].op = rand.Intn(UNARY_COUNT) + FIRST_UNARY
- i++
- }
-
- // Keep adding binary operators until nsOnStack == 1
- for nsOnStack > 1 {
- f.operators[i].op = rand.Intn(BINARY_COUNT) + FIRST_BINARY
- nsOnStack--
- i++
- }
+ f.nvars = nvars
+ f.operators = make([]Operator, length)
+ nsOnStack := 0
+ i := 0
+ for nsOnStack+i < length {
+ var operator Operator
+ var optype int
+ if nsOnStack == 0 {
+ // Pick a random variable
+ optype = 0
+ } else if nsOnStack == 1 {
+ // Pick a constant/variable/unary operator
+ optype = rand.Intn(3)
+ } else {
+ // Pick a constant/variable/unary/binary operator
+ optype = rand.Intn(4)
+ }
+ switch optype {
+ case 0:
+ // variable
+ operator.op = FIRST_VAR + rand.Intn(nvars)
+ nsOnStack++
+ case 1:
+ // Constant
+ operator.op = CONST
+ operator.constant = rand.Float64()
+ nsOnStack++
+ case 2:
+ // unary
+ operator.op = rand.Intn(UNARY_COUNT) + FIRST_UNARY
+ case 3:
+ // binary
+ operator.op = rand.Intn(BINARY_COUNT) + FIRST_BINARY
+ nsOnStack--
+ }
+ f.operators[i] = operator
+ i++
+ }
+
+ if nsOnStack+i == length {
+ // Add a unary operator
+ f.operators[i].op = rand.Intn(UNARY_COUNT) + FIRST_UNARY
+ i++
+ }
+
+ // Keep adding binary operators until nsOnStack == 1
+ for nsOnStack > 1 {
+ f.operators[i].op = rand.Intn(BINARY_COUNT) + FIRST_BINARY
+ nsOnStack--
+ i++
+ }
}
func (f *Function) Evaluate(vars []float64) float64 {
- var stack []float64
- for _, op := range f.operators {
- l := len(stack)
- switch (op.op) {
- case CONST:
- stack = append(stack, op.constant)
- case ADD:
- stack[l-2] += stack[l-1]
- stack = stack[:l-1]
- case SUB:
- stack[l-2] -= stack[l-1]
- stack = stack[:l-1]
- case MUL:
- stack[l-2] *= stack[l-1]
- stack = stack[:l-1]
- case DIV:
- if stack[l-1] == 0 { // Check for division by 0
- stack[l-1] = 0.01
- }
- stack[l-2] /= stack[l-1]
- stack = stack[:l-1]
+ var stack []float64
+ for _, op := range f.operators {
+ l := len(stack)
+ switch op.op {
+ case CONST:
+ stack = append(stack, op.constant)
+ case ADD:
+ stack[l-2] += stack[l-1]
+ stack = stack[:l-1]
+ case SUB:
+ stack[l-2] -= stack[l-1]
+ stack = stack[:l-1]
+ case MUL:
+ stack[l-2] *= stack[l-1]
+ stack = stack[:l-1]
+ case DIV:
+ if stack[l-1] == 0 { // Check for division by 0
+ stack[l-1] = 0.01
+ }
+ stack[l-2] /= stack[l-1]
+ stack = stack[:l-1]
case MIN:
stack[l-2] = math.Min(stack[l-2], stack[l-1])
stack = stack[:l-1]
case MAX:
stack[l-2] = math.Max(stack[l-2], stack[l-1])
stack = stack[:l-1]
- case SQRT:
- stack[l-1] = math.Sqrt(math.Abs(stack[l-1]))
- case SIN:
- stack[l-1] = math.Sin(stack[l-1])
- case COS:
- stack[l-1] = math.Cos(stack[l-1])
- case TAN:
- stack[l-1] = math.Tan(stack[l-1])
+ case SQRT:
+ stack[l-1] = math.Sqrt(math.Abs(stack[l-1]))
+ case SIN:
+ stack[l-1] = math.Sin(stack[l-1])
+ case COS:
+ stack[l-1] = math.Cos(stack[l-1])
+ case TAN:
+ stack[l-1] = math.Tan(stack[l-1])
case LOG:
stack[l-1] = math.Log(math.Abs(stack[l-1]))
case EXP:
stack[l-1] = math.Exp(stack[l-1])
- default:
- stack = append(stack, vars[op.op - FIRST_VAR])
- }
- }
- return stack[0]
+ default:
+ stack = append(stack, vars[op.op-FIRST_VAR])
+ }
+ }
+ return stack[0]
}
func (f *Function) String() string {
- var str string
- for _, op := range f.operators {
- switch (op.op) {
- case CONST:
- str += fmt.Sprintf("%v",op.constant)
- case ADD:
- str += "+"
- case SUB:
- str += "-"
- case MUL:
- str += "*"
- case DIV:
- str += "/"
- case SQRT:
- str += "sqrt"
- case SIN:
- str += "sin"
- case COS:
- str += "cos"
- case TAN:
- str += "tan"
- default:
- str += fmt.Sprintf("v%v", op.op - FIRST_VAR)
- }
- str += " "
- }
- return str
+ var str string
+ for _, op := range f.operators {
+ switch op.op {
+ case CONST:
+ str += fmt.Sprintf("%v", op.constant)
+ case ADD:
+ str += "+"
+ case SUB:
+ str += "-"
+ case MUL:
+ str += "*"
+ case DIV:
+ str += "/"
+ case SQRT:
+ str += "sqrt"
+ case SIN:
+ str += "sin"
+ case COS:
+ str += "cos"
+ case TAN:
+ str += "tan"
+ default:
+ str += fmt.Sprintf("v%v", op.op-FIRST_VAR)
+ }
+ str += " "
+ }
+ return str
}
const mutationRate = 0.01
@@ -202,14 +202,14 @@ func (f *Function) Mutate() {
}
}
-func (f *Function) Breed(f1* Function, f2 *Function) {
+func (f *Function) Breed(f1 *Function, f2 *Function) {
// f(x) = (f1(x) + f2(x)) / 2
- f.operators = make([]Operator, len(f1.operators) + len(f2.operators) + 3)
+ f.operators = make([]Operator, len(f1.operators)+len(f2.operators)+3)
for i, o := range f1.operators {
f.operators[i] = o
}
for i, o := range f2.operators {
- f.operators[i + len(f1.operators)] = o
+ f.operators[i+len(f1.operators)] = o
}
i := len(f1.operators) + len(f2.operators)
f.operators[i].op = ADD