From 2e111b2ac8e3a88a8157d0badd17d6e554a3ea98 Mon Sep 17 00:00:00 2001 From: Hayden McAlister Date: Sun, 4 Jun 2023 14:54:06 +1200 Subject: [PATCH 01/25] Move state generator into subfolder --- .../states/stategenerator/StateGenerator.go | 75 ++++++++++ .../stategenerator/StateGeneratorBuilder.go | 130 ++++++++++++++++++ 2 files changed, 205 insertions(+) create mode 100644 hopfieldnetwork/states/stategenerator/StateGenerator.go create mode 100644 hopfieldnetwork/states/stategenerator/StateGeneratorBuilder.go diff --git a/hopfieldnetwork/states/stategenerator/StateGenerator.go b/hopfieldnetwork/states/stategenerator/StateGenerator.go new file mode 100644 index 0000000..a815b17 --- /dev/null +++ b/hopfieldnetwork/states/stategenerator/StateGenerator.go @@ -0,0 +1,75 @@ +// A package to handle generating states for the Hopfield Network +package states + +import ( + "hmcalister/hopfield/hopfieldnetwork/activationfunction" + "hmcalister/hopfield/hopfieldnetwork/domain" + + "gonum.org/v1/gonum/mat" + "gonum.org/v1/gonum/stat/distuv" +) + +// Define a struct that can generate new states. +// +// Note this struct should be initialized using the StateGeneratorBuilder from [hmcalister/hopfield/hopfieldnetwork/states]. +type StateGenerator struct { + domain domain.DomainEnum + rng distuv.Uniform + dimension int +} + +// Creates and returns a fresh array that can store a state. +// +// This is implemented for cleaner, more explicit code. Rather than calling NextState once to get memory, +// this method will create the memory independently. For example, calling AllocStateMemory before a loop and passing +// the result to NextState within the loop looks a lot nicer than some messy, potentially nil value being passed about. +// +// # Returns +// +// A new slice of float64 with enough memory to store once VecDense (state). +func (gen *StateGenerator) AllocStateMemory() []float64 { + return make([]float64, gen.dimension) +} + +// Create a new random state, using dataArray to store intermediate random values. +// +// Note this function require an array to be allocated already. Don't panic! Use AllocDataArray to get this memory! +// +// # Arguments +// +// dataArray: A slice of float64 with enough memory to store a VecDense. Should be created with AllocStateMemory. +// +// # Returns +// +// A new state, with backing memory equal to the passed dataArray +func (gen *StateGenerator) NextState(dataArray []float64) *mat.VecDense { + for i := 0; i < gen.dimension; i++ { + dataArray[i] = gen.rng.Rand() + } + + state := mat.NewVecDense(gen.dimension, dataArray) + activationfunction.GetActivationFunction(gen.domain)(state) + return state +} + +// Creates a set of new states, returning the new states as a pointer to a slice of VecDense. +// +// Note this function does NOT require new memory to be allocated - it is allocated in the method. +// +// # Arguments +// +// numStates: The number of states to generate. +// +// # Returns +// +// A slice of new states. +func (gen *StateGenerator) CreateStateCollection(numStates int) []*mat.VecDense { + states := make([]*mat.VecDense, numStates) + + var backingMem []float64 + for i := range states { + backingMem = gen.AllocStateMemory() + states[i] = gen.NextState(backingMem) + } + return states +} diff --git a/hopfieldnetwork/states/stategenerator/StateGeneratorBuilder.go b/hopfieldnetwork/states/stategenerator/StateGeneratorBuilder.go new file mode 100644 index 0000000..c1c34c3 --- /dev/null +++ b/hopfieldnetwork/states/stategenerator/StateGeneratorBuilder.go @@ -0,0 +1,130 @@ +package states + +import ( + "hmcalister/hopfield/hopfieldnetwork/domain" + "time" + + "golang.org/x/exp/rand" + + "gonum.org/v1/gonum/stat/distuv" +) + +// Define a builder for a new state generator. +// +// rand_min defines the lower bound on the uniform distribution to use for state generation. +// +// rand_max defines the upper bound on the uniform distribution to use for state generation. +// +// Seed defines the seed to use for the new uniform distribution. The default value is 0. +// If seed is 0 build time then a random seed is selected. This is useful for having different threads use different seeds. +// +// Dimension defines the length of the vector to be generated. +type StateGeneratorBuilder struct { + randMin float64 + randMax float64 + seed uint64 + seedGenerator *rand.Rand + domain domain.DomainEnum + dimension int +} + +func NewStateGeneratorBuilder() *StateGeneratorBuilder { + seedGenSrc := rand.NewSource(uint64(time.Now().Nanosecond())) + seedGen := rand.New(seedGenSrc) + return &StateGeneratorBuilder{ + randMin: -1, + randMax: 1, + seed: 0, + seedGenerator: seedGen, + domain: 0, + dimension: 0, + } +} + +// Set the lower bound of the uniform distribution to use for state generation +// +// Be aware that rand_min must be strictly less than rand_max to build. +// +// Note a reference to the builder is returned to allow for chaining. +func (builder *StateGeneratorBuilder) SetRandMin(randMin float64) *StateGeneratorBuilder { + builder.randMin = randMin + return builder +} + +// Set the upper bound of the uniform distribution to use for state generation +// +// Be aware that rand_max must be strictly greater than rand_min to build. +// +// Note a reference to the builder is returned to allow for chaining. +func (builder *StateGeneratorBuilder) SetRandMax(randMax float64) *StateGeneratorBuilder { + builder.randMax = randMax + return builder +} + +// Set the random seed for the uniform distribution used for state generation. +// +// If the seed is left at the default value (0) then a random seed is created. +// +// Note a reference to the builder is returned to allow for chaining. +func (builder *StateGeneratorBuilder) SetSeed(seed uint64) *StateGeneratorBuilder { + builder.seed = seed + return builder +} + +// Sets the domain of the state generator +func (builder *StateGeneratorBuilder) SetGeneratorDomain(domain domain.DomainEnum) *StateGeneratorBuilder { + builder.domain = domain + return builder +} + +// Set the dimension of the vectors to be produced, i.e. the length of the vector. +// +// Dimension must be a strictly positive integer and match the Hopfield Network dimension. +// +// Note a reference to the builder is returned to allow for chaining. +func (builder *StateGeneratorBuilder) SetGeneratorDimension(dimension int) *StateGeneratorBuilder { + builder.dimension = dimension + return builder +} + +// Perform final checks on the builder - to be run right before constructing the StateGenerator struct. +// +// Note this function panics if builder is invalid - perhaps instead an error could be bubbled up? This is probably okay though. +func (builder *StateGeneratorBuilder) checkValid() { + if builder.randMin >= builder.randMax { + panic("StateGeneratorBuilder encountered an error during build! rand_min must be strictly smaller than rand_max!") + } + + if builder.dimension <= 0 { + panic("StateGeneratorBuilder encountered an error during build! Dimension must be strictly positive!") + } +} + +// Builds the StateGenerator. +// +// Note this function will panic if invalid options are given to the builder. +// +// RngDistribution must be a valid distribution from the [gonum.org/v1/gonum/stat/distuv] package. +// +// Dimension must be a strictly positive integer and match the Hopfield Network dimension. +func (builder *StateGeneratorBuilder) Build() *StateGenerator { + builder.checkValid() + + var seed uint64 + if builder.seed == 0 { + seed = builder.seedGenerator.Uint64() + } else { + seed = builder.seed + } + + rand_dist := distuv.Uniform{ + Min: builder.randMin, + Max: builder.randMax, + Src: rand.NewSource(seed), + } + + return &StateGenerator{ + rng: rand_dist, + dimension: builder.dimension, + } +} From d6ad98672c86a157b8353f38bf417b3407af48e4 Mon Sep 17 00:00:00 2001 From: Hayden McAlister Date: Sun, 4 Jun 2023 14:54:11 +1200 Subject: [PATCH 02/25] Add state manager interface --- hopfieldnetwork/states/statemanager/StateManager.go | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 hopfieldnetwork/states/statemanager/StateManager.go diff --git a/hopfieldnetwork/states/statemanager/StateManager.go b/hopfieldnetwork/states/statemanager/StateManager.go new file mode 100644 index 0000000..e95e48e --- /dev/null +++ b/hopfieldnetwork/states/statemanager/StateManager.go @@ -0,0 +1,11 @@ +package statemanager + +import "gonum.org/v1/gonum/mat" + +type StateManager interface { + ActivationFunction(*mat.VecDense) + InvertState(*mat.VecDense) + UnitEnergy(*mat.Dense, *mat.VecDense, int) float64 + AllUnitEnergies(*mat.Dense, *mat.VecDense) *mat.VecDense + StateEnergy(*mat.Dense, *mat.VecDense) float64 +} From dae290c2f8851edef2cfe3c129d81547ac246df5 Mon Sep 17 00:00:00 2001 From: Hayden McAlister Date: Sun, 4 Jun 2023 14:54:21 +1200 Subject: [PATCH 03/25] Add bipolar state manager implementation --- .../statemanager/BipolarStateManager.go | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 hopfieldnetwork/states/statemanager/BipolarStateManager.go diff --git a/hopfieldnetwork/states/statemanager/BipolarStateManager.go b/hopfieldnetwork/states/statemanager/BipolarStateManager.go new file mode 100644 index 0000000..5e14dde --- /dev/null +++ b/hopfieldnetwork/states/statemanager/BipolarStateManager.go @@ -0,0 +1,47 @@ +package statemanager + +import "gonum.org/v1/gonum/mat" + +type BipolarStateManager struct { +} + +func (manager *BipolarStateManager) ActivationFunction(vector *mat.VecDense) { + for n := 0; n < vector.Len(); n++ { + if vector.AtVec(n) < 0.0 { + vector.SetVec(n, -1.0) + } else { + vector.SetVec(n, 1.0) + } + } +} + +func (manager *BipolarStateManager) InvertState(vector *mat.VecDense) { + vector.ScaleVec(-1.0, vector) + manager.ActivationFunction(vector) +} + +func (manager *BipolarStateManager) UnitEnergy(matrix *mat.Dense, vector *mat.VecDense, i int) float64 { + dimension, _ := vector.Dims() + energy := 0.0 + for j := 0; j < dimension; j++ { + energy += -1 * matrix.At(i, j) * vector.AtVec(i) * vector.AtVec(j) + } + return energy +} + +func (manager *BipolarStateManager) AllUnitEnergies(matrix *mat.Dense, vector *mat.VecDense) *mat.VecDense { + energyVector := mat.NewVecDense(vector.Len(), nil) + energyVector.MulVec(matrix, vector) + energyVector.MulElemVec(energyVector, vector) + energyVector.ScaleVec(-1, energyVector) + return energyVector +} + +func (manager *BipolarStateManager) StateEnergy(matrix *mat.Dense, vector *mat.VecDense) float64 { + energyVector := manager.AllUnitEnergies(matrix, vector) + energy := 0.0 + for i := 0; i < energyVector.Len(); i++ { + energy += energyVector.AtVec(i) + } + return energy +} From d6df8818be926e0f0da7dfe21ef4acef9d084acf Mon Sep 17 00:00:00 2001 From: Hayden McAlister Date: Sun, 4 Jun 2023 14:54:29 +1200 Subject: [PATCH 04/25] Add binary state manager implementation --- .../states/statemanager/BinaryStateManager.go | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 hopfieldnetwork/states/statemanager/BinaryStateManager.go diff --git a/hopfieldnetwork/states/statemanager/BinaryStateManager.go b/hopfieldnetwork/states/statemanager/BinaryStateManager.go new file mode 100644 index 0000000..44861f0 --- /dev/null +++ b/hopfieldnetwork/states/statemanager/BinaryStateManager.go @@ -0,0 +1,53 @@ +package statemanager + +import "gonum.org/v1/gonum/mat" + +type BinaryStateManager struct { +} + +func (manager *BinaryStateManager) ActivationFunction(vector *mat.VecDense) { + for n := 0; n < vector.Len(); n++ { + if vector.AtVec(n) < 0.0 { + vector.SetVec(n, 0.0) + } else { + vector.SetVec(n, 1.0) + } + } +} + +func (manager *BinaryStateManager) InvertState(vector *mat.VecDense) { + onesVector := mat.NewVecDense(vector.Len(), nil) + for i := 0; i < onesVector.Len(); i++ { + onesVector.SetVec(i, 1.0) + } + vector.AddScaledVec(onesVector, -1.0, vector) + manager.ActivationFunction(vector) +} + +// TODO: ENERGIES + +func (manager *BinaryStateManager) UnitEnergy(matrix *mat.Dense, vector *mat.VecDense, i int) float64 { + dimension, _ := vector.Dims() + energy := 0.0 + for j := 0; j < dimension; j++ { + energy += -1 * matrix.At(i, j) * vector.AtVec(i) * vector.AtVec(j) + } + return energy +} + +func (manager *BinaryStateManager) AllUnitEnergies(matrix *mat.Dense, vector *mat.VecDense) *mat.VecDense { + energyVector := mat.NewVecDense(vector.Len(), nil) + energyVector.MulVec(matrix, vector) + energyVector.MulElemVec(energyVector, vector) + energyVector.ScaleVec(-1, energyVector) + return energyVector +} + +func (manager *BinaryStateManager) StateEnergy(matrix *mat.Dense, vector *mat.VecDense) float64 { + energyVector := manager.AllUnitEnergies(matrix, vector) + energy := 0.0 + for i := 0; i < energyVector.Len(); i++ { + energy += energyVector.AtVec(i) + } + return energy +} From 93a03cec8f7d40892ba0ba012eef7a6c86a78efe Mon Sep 17 00:00:00 2001 From: Hayden McAlister Date: Sun, 4 Jun 2023 14:54:34 +1200 Subject: [PATCH 05/25] Remove old state generator --- hopfieldnetwork/states/StateGenerator.go | 75 ------------------------ 1 file changed, 75 deletions(-) delete mode 100644 hopfieldnetwork/states/StateGenerator.go diff --git a/hopfieldnetwork/states/StateGenerator.go b/hopfieldnetwork/states/StateGenerator.go deleted file mode 100644 index a815b17..0000000 --- a/hopfieldnetwork/states/StateGenerator.go +++ /dev/null @@ -1,75 +0,0 @@ -// A package to handle generating states for the Hopfield Network -package states - -import ( - "hmcalister/hopfield/hopfieldnetwork/activationfunction" - "hmcalister/hopfield/hopfieldnetwork/domain" - - "gonum.org/v1/gonum/mat" - "gonum.org/v1/gonum/stat/distuv" -) - -// Define a struct that can generate new states. -// -// Note this struct should be initialized using the StateGeneratorBuilder from [hmcalister/hopfield/hopfieldnetwork/states]. -type StateGenerator struct { - domain domain.DomainEnum - rng distuv.Uniform - dimension int -} - -// Creates and returns a fresh array that can store a state. -// -// This is implemented for cleaner, more explicit code. Rather than calling NextState once to get memory, -// this method will create the memory independently. For example, calling AllocStateMemory before a loop and passing -// the result to NextState within the loop looks a lot nicer than some messy, potentially nil value being passed about. -// -// # Returns -// -// A new slice of float64 with enough memory to store once VecDense (state). -func (gen *StateGenerator) AllocStateMemory() []float64 { - return make([]float64, gen.dimension) -} - -// Create a new random state, using dataArray to store intermediate random values. -// -// Note this function require an array to be allocated already. Don't panic! Use AllocDataArray to get this memory! -// -// # Arguments -// -// dataArray: A slice of float64 with enough memory to store a VecDense. Should be created with AllocStateMemory. -// -// # Returns -// -// A new state, with backing memory equal to the passed dataArray -func (gen *StateGenerator) NextState(dataArray []float64) *mat.VecDense { - for i := 0; i < gen.dimension; i++ { - dataArray[i] = gen.rng.Rand() - } - - state := mat.NewVecDense(gen.dimension, dataArray) - activationfunction.GetActivationFunction(gen.domain)(state) - return state -} - -// Creates a set of new states, returning the new states as a pointer to a slice of VecDense. -// -// Note this function does NOT require new memory to be allocated - it is allocated in the method. -// -// # Arguments -// -// numStates: The number of states to generate. -// -// # Returns -// -// A slice of new states. -func (gen *StateGenerator) CreateStateCollection(numStates int) []*mat.VecDense { - states := make([]*mat.VecDense, numStates) - - var backingMem []float64 - for i := range states { - backingMem = gen.AllocStateMemory() - states[i] = gen.NextState(backingMem) - } - return states -} From 0544dd40e69d7f7df3de40927ea6a48a42bf1731 Mon Sep 17 00:00:00 2001 From: Hayden McAlister Date: Sun, 4 Jun 2023 14:54:40 +1200 Subject: [PATCH 06/25] Remove old state generator builder --- .../states/StateGeneratorBuilder.go | 130 ------------------ 1 file changed, 130 deletions(-) delete mode 100644 hopfieldnetwork/states/StateGeneratorBuilder.go diff --git a/hopfieldnetwork/states/StateGeneratorBuilder.go b/hopfieldnetwork/states/StateGeneratorBuilder.go deleted file mode 100644 index c1c34c3..0000000 --- a/hopfieldnetwork/states/StateGeneratorBuilder.go +++ /dev/null @@ -1,130 +0,0 @@ -package states - -import ( - "hmcalister/hopfield/hopfieldnetwork/domain" - "time" - - "golang.org/x/exp/rand" - - "gonum.org/v1/gonum/stat/distuv" -) - -// Define a builder for a new state generator. -// -// rand_min defines the lower bound on the uniform distribution to use for state generation. -// -// rand_max defines the upper bound on the uniform distribution to use for state generation. -// -// Seed defines the seed to use for the new uniform distribution. The default value is 0. -// If seed is 0 build time then a random seed is selected. This is useful for having different threads use different seeds. -// -// Dimension defines the length of the vector to be generated. -type StateGeneratorBuilder struct { - randMin float64 - randMax float64 - seed uint64 - seedGenerator *rand.Rand - domain domain.DomainEnum - dimension int -} - -func NewStateGeneratorBuilder() *StateGeneratorBuilder { - seedGenSrc := rand.NewSource(uint64(time.Now().Nanosecond())) - seedGen := rand.New(seedGenSrc) - return &StateGeneratorBuilder{ - randMin: -1, - randMax: 1, - seed: 0, - seedGenerator: seedGen, - domain: 0, - dimension: 0, - } -} - -// Set the lower bound of the uniform distribution to use for state generation -// -// Be aware that rand_min must be strictly less than rand_max to build. -// -// Note a reference to the builder is returned to allow for chaining. -func (builder *StateGeneratorBuilder) SetRandMin(randMin float64) *StateGeneratorBuilder { - builder.randMin = randMin - return builder -} - -// Set the upper bound of the uniform distribution to use for state generation -// -// Be aware that rand_max must be strictly greater than rand_min to build. -// -// Note a reference to the builder is returned to allow for chaining. -func (builder *StateGeneratorBuilder) SetRandMax(randMax float64) *StateGeneratorBuilder { - builder.randMax = randMax - return builder -} - -// Set the random seed for the uniform distribution used for state generation. -// -// If the seed is left at the default value (0) then a random seed is created. -// -// Note a reference to the builder is returned to allow for chaining. -func (builder *StateGeneratorBuilder) SetSeed(seed uint64) *StateGeneratorBuilder { - builder.seed = seed - return builder -} - -// Sets the domain of the state generator -func (builder *StateGeneratorBuilder) SetGeneratorDomain(domain domain.DomainEnum) *StateGeneratorBuilder { - builder.domain = domain - return builder -} - -// Set the dimension of the vectors to be produced, i.e. the length of the vector. -// -// Dimension must be a strictly positive integer and match the Hopfield Network dimension. -// -// Note a reference to the builder is returned to allow for chaining. -func (builder *StateGeneratorBuilder) SetGeneratorDimension(dimension int) *StateGeneratorBuilder { - builder.dimension = dimension - return builder -} - -// Perform final checks on the builder - to be run right before constructing the StateGenerator struct. -// -// Note this function panics if builder is invalid - perhaps instead an error could be bubbled up? This is probably okay though. -func (builder *StateGeneratorBuilder) checkValid() { - if builder.randMin >= builder.randMax { - panic("StateGeneratorBuilder encountered an error during build! rand_min must be strictly smaller than rand_max!") - } - - if builder.dimension <= 0 { - panic("StateGeneratorBuilder encountered an error during build! Dimension must be strictly positive!") - } -} - -// Builds the StateGenerator. -// -// Note this function will panic if invalid options are given to the builder. -// -// RngDistribution must be a valid distribution from the [gonum.org/v1/gonum/stat/distuv] package. -// -// Dimension must be a strictly positive integer and match the Hopfield Network dimension. -func (builder *StateGeneratorBuilder) Build() *StateGenerator { - builder.checkValid() - - var seed uint64 - if builder.seed == 0 { - seed = builder.seedGenerator.Uint64() - } else { - seed = builder.seed - } - - rand_dist := distuv.Uniform{ - Min: builder.randMin, - Max: builder.randMax, - Src: rand.NewSource(seed), - } - - return &StateGenerator{ - rng: rand_dist, - dimension: builder.dimension, - } -} From d3eb3fe58d75cb8f5e73016e1d0c6b34ab5fb036 Mon Sep 17 00:00:00 2001 From: Hayden McAlister Date: Sun, 4 Jun 2023 14:54:56 +1200 Subject: [PATCH 07/25] Update energy function for consistency of 0.0 --- hopfieldnetwork/energyfunction/EnergyFunction.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hopfieldnetwork/energyfunction/EnergyFunction.go b/hopfieldnetwork/energyfunction/EnergyFunction.go index 9c7b6b5..9cff1bc 100644 --- a/hopfieldnetwork/energyfunction/EnergyFunction.go +++ b/hopfieldnetwork/energyfunction/EnergyFunction.go @@ -17,7 +17,7 @@ func UnitEnergy(matrix *mat.Dense, vector *mat.VecDense, i int) float64 { // Defines the overall energy for a state with respect to a matrix. func StateEnergy(matrix *mat.Dense, vector *mat.VecDense) float64 { energyVector := AllUnitEnergies(matrix, vector) - energy := 0. + energy := 0.0 for i := 0; i < energyVector.Len(); i++ { energy += energyVector.AtVec(i) } From 8424416627026d6303407885737038906b41135f Mon Sep 17 00:00:00 2001 From: Hayden McAlister Date: Sun, 4 Jun 2023 14:58:24 +1200 Subject: [PATCH 08/25] Remove now incorrect comment on function of domain enum --- hopfieldnetwork/domain/DomainEnum.go | 1 - 1 file changed, 1 deletion(-) diff --git a/hopfieldnetwork/domain/DomainEnum.go b/hopfieldnetwork/domain/DomainEnum.go index 3310c90..f9c2674 100644 --- a/hopfieldnetwork/domain/DomainEnum.go +++ b/hopfieldnetwork/domain/DomainEnum.go @@ -1,7 +1,6 @@ package domain // An enum to note the domain of the network. -// This determines the learning mapping function to use. type DomainEnum int const ( From d76815c949507d21f22dee90e140095181911e33 Mon Sep 17 00:00:00 2001 From: Hayden McAlister Date: Sun, 4 Jun 2023 14:58:34 +1200 Subject: [PATCH 09/25] Add GetDomainStateManager pattern --- .../states/statemanager/StateManager.go | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/hopfieldnetwork/states/statemanager/StateManager.go b/hopfieldnetwork/states/statemanager/StateManager.go index e95e48e..8b41194 100644 --- a/hopfieldnetwork/states/statemanager/StateManager.go +++ b/hopfieldnetwork/states/statemanager/StateManager.go @@ -1,6 +1,10 @@ package statemanager -import "gonum.org/v1/gonum/mat" +import ( + "hmcalister/hopfield/hopfieldnetwork/domain" + + "gonum.org/v1/gonum/mat" +) type StateManager interface { ActivationFunction(*mat.VecDense) @@ -9,3 +13,12 @@ type StateManager interface { AllUnitEnergies(*mat.Dense, *mat.VecDense) *mat.VecDense StateEnergy(*mat.Dense, *mat.VecDense) float64 } + +func GetDomainStateManager(targetDomain domain.DomainEnum) StateManager { + domainStateManagerMap := map[domain.DomainEnum]StateManager{ + domain.BipolarDomain: &BipolarStateManager{}, + domain.BinaryDomain: &BinaryStateManager{}, + } + + return domainStateManagerMap[targetDomain] +} From b62000d9e3151bfc59c37c5643ff552ac09b9462 Mon Sep 17 00:00:00 2001 From: Hayden McAlister Date: Sun, 4 Jun 2023 15:28:11 +1200 Subject: [PATCH 10/25] Pass state manager to state generator struct --- .../states/stategenerator/StateGeneratorBuilder.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hopfieldnetwork/states/stategenerator/StateGeneratorBuilder.go b/hopfieldnetwork/states/stategenerator/StateGeneratorBuilder.go index c1c34c3..cffdf28 100644 --- a/hopfieldnetwork/states/stategenerator/StateGeneratorBuilder.go +++ b/hopfieldnetwork/states/stategenerator/StateGeneratorBuilder.go @@ -2,6 +2,7 @@ package states import ( "hmcalister/hopfield/hopfieldnetwork/domain" + "hmcalister/hopfield/hopfieldnetwork/states/statemanager" "time" "golang.org/x/exp/rand" @@ -124,7 +125,8 @@ func (builder *StateGeneratorBuilder) Build() *StateGenerator { } return &StateGenerator{ - rng: rand_dist, - dimension: builder.dimension, + domainStateManager: statemanager.GetDomainStateManager(builder.domain), + rng: rand_dist, + dimension: builder.dimension, } } From 19a271c9dc1cb19ef00d7c1931b75d3d6be96ce8 Mon Sep 17 00:00:00 2001 From: Hayden McAlister Date: Sun, 4 Jun 2023 15:28:26 +1200 Subject: [PATCH 11/25] Update generator struct to use state manager over domain --- hopfieldnetwork/states/stategenerator/StateGenerator.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hopfieldnetwork/states/stategenerator/StateGenerator.go b/hopfieldnetwork/states/stategenerator/StateGenerator.go index a815b17..540908e 100644 --- a/hopfieldnetwork/states/stategenerator/StateGenerator.go +++ b/hopfieldnetwork/states/stategenerator/StateGenerator.go @@ -48,7 +48,7 @@ func (gen *StateGenerator) NextState(dataArray []float64) *mat.VecDense { } state := mat.NewVecDense(gen.dimension, dataArray) - activationfunction.GetActivationFunction(gen.domain)(state) + gen.domainStateManager.ActivationFunction(state) return state } From e8db148d389885e94f51c199858e0f7eeb311193 Mon Sep 17 00:00:00 2001 From: Hayden McAlister Date: Sun, 4 Jun 2023 15:28:56 +1200 Subject: [PATCH 12/25] Update generator to use new stateManager directly --- hopfieldnetwork/states/stategenerator/StateGenerator.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/hopfieldnetwork/states/stategenerator/StateGenerator.go b/hopfieldnetwork/states/stategenerator/StateGenerator.go index 540908e..4195921 100644 --- a/hopfieldnetwork/states/stategenerator/StateGenerator.go +++ b/hopfieldnetwork/states/stategenerator/StateGenerator.go @@ -2,8 +2,7 @@ package states import ( - "hmcalister/hopfield/hopfieldnetwork/activationfunction" - "hmcalister/hopfield/hopfieldnetwork/domain" + "hmcalister/hopfield/hopfieldnetwork/states/statemanager" "gonum.org/v1/gonum/mat" "gonum.org/v1/gonum/stat/distuv" @@ -13,9 +12,9 @@ import ( // // Note this struct should be initialized using the StateGeneratorBuilder from [hmcalister/hopfield/hopfieldnetwork/states]. type StateGenerator struct { - domain domain.DomainEnum - rng distuv.Uniform - dimension int + domainStateManager statemanager.StateManager + rng distuv.Uniform + dimension int } // Creates and returns a fresh array that can store a state. From 51269ac98585e9f6d84f42bb640e94fde322b689 Mon Sep 17 00:00:00 2001 From: Hayden McAlister Date: Sun, 4 Jun 2023 15:37:45 +1200 Subject: [PATCH 13/25] Update AllUnitEnergies to return []float64 --- hopfieldnetwork/states/statemanager/StateManager.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hopfieldnetwork/states/statemanager/StateManager.go b/hopfieldnetwork/states/statemanager/StateManager.go index 8b41194..a9b0518 100644 --- a/hopfieldnetwork/states/statemanager/StateManager.go +++ b/hopfieldnetwork/states/statemanager/StateManager.go @@ -10,7 +10,7 @@ type StateManager interface { ActivationFunction(*mat.VecDense) InvertState(*mat.VecDense) UnitEnergy(*mat.Dense, *mat.VecDense, int) float64 - AllUnitEnergies(*mat.Dense, *mat.VecDense) *mat.VecDense + AllUnitEnergies(*mat.Dense, *mat.VecDense) []float64 StateEnergy(*mat.Dense, *mat.VecDense) float64 } From f9d2ee2df77951a35b80cec632e6395462eba05f Mon Sep 17 00:00:00 2001 From: Hayden McAlister Date: Sun, 4 Jun 2023 15:37:53 +1200 Subject: [PATCH 14/25] Update binary state manager to conform to interface change --- hopfieldnetwork/states/statemanager/BinaryStateManager.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hopfieldnetwork/states/statemanager/BinaryStateManager.go b/hopfieldnetwork/states/statemanager/BinaryStateManager.go index 44861f0..e2c1802 100644 --- a/hopfieldnetwork/states/statemanager/BinaryStateManager.go +++ b/hopfieldnetwork/states/statemanager/BinaryStateManager.go @@ -35,19 +35,19 @@ func (manager *BinaryStateManager) UnitEnergy(matrix *mat.Dense, vector *mat.Vec return energy } -func (manager *BinaryStateManager) AllUnitEnergies(matrix *mat.Dense, vector *mat.VecDense) *mat.VecDense { +func (manager *BinaryStateManager) AllUnitEnergies(matrix *mat.Dense, vector *mat.VecDense) []float64 { energyVector := mat.NewVecDense(vector.Len(), nil) energyVector.MulVec(matrix, vector) energyVector.MulElemVec(energyVector, vector) energyVector.ScaleVec(-1, energyVector) - return energyVector + return energyVector.RawVector().Data } func (manager *BinaryStateManager) StateEnergy(matrix *mat.Dense, vector *mat.VecDense) float64 { energyVector := manager.AllUnitEnergies(matrix, vector) energy := 0.0 - for i := 0; i < energyVector.Len(); i++ { - energy += energyVector.AtVec(i) + for _, unitEnergy := range energyVector { + energy += unitEnergy } return energy } From 93c87b6c22bc49cbc5ac1ed417c08133eac2ba21 Mon Sep 17 00:00:00 2001 From: Hayden McAlister Date: Sun, 4 Jun 2023 15:37:59 +1200 Subject: [PATCH 15/25] Update bipolar state manager to conform to interface change --- .../states/statemanager/BipolarStateManager.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hopfieldnetwork/states/statemanager/BipolarStateManager.go b/hopfieldnetwork/states/statemanager/BipolarStateManager.go index 5e14dde..e74f73a 100644 --- a/hopfieldnetwork/states/statemanager/BipolarStateManager.go +++ b/hopfieldnetwork/states/statemanager/BipolarStateManager.go @@ -29,19 +29,19 @@ func (manager *BipolarStateManager) UnitEnergy(matrix *mat.Dense, vector *mat.Ve return energy } -func (manager *BipolarStateManager) AllUnitEnergies(matrix *mat.Dense, vector *mat.VecDense) *mat.VecDense { +func (manager *BipolarStateManager) AllUnitEnergies(matrix *mat.Dense, vector *mat.VecDense) []float64 { energyVector := mat.NewVecDense(vector.Len(), nil) energyVector.MulVec(matrix, vector) energyVector.MulElemVec(energyVector, vector) energyVector.ScaleVec(-1, energyVector) - return energyVector + return energyVector.RawVector().Data } func (manager *BipolarStateManager) StateEnergy(matrix *mat.Dense, vector *mat.VecDense) float64 { energyVector := manager.AllUnitEnergies(matrix, vector) energy := 0.0 - for i := 0; i < energyVector.Len(); i++ { - energy += energyVector.AtVec(i) + for _, unitEnergy := range energyVector { + energy += unitEnergy } return energy } From b374aa5dda6789adaa4297b81ce6ca7a50e038b1 Mon Sep 17 00:00:00 2001 From: Hayden McAlister Date: Sun, 4 Jun 2023 16:10:16 +1200 Subject: [PATCH 16/25] Remove activation function - now present in statemanager --- .../activationfunction/ActivationFunction.go | 65 ------------------- 1 file changed, 65 deletions(-) delete mode 100644 hopfieldnetwork/activationfunction/ActivationFunction.go diff --git a/hopfieldnetwork/activationfunction/ActivationFunction.go b/hopfieldnetwork/activationfunction/ActivationFunction.go deleted file mode 100644 index a4be47d..0000000 --- a/hopfieldnetwork/activationfunction/ActivationFunction.go +++ /dev/null @@ -1,65 +0,0 @@ -// Definitions of activation functions for the Hopfield Network -// -// Includes map from network domain to activation function -package activationfunction - -import ( - "hmcalister/hopfield/hopfieldnetwork/domain" - - "gonum.org/v1/gonum/mat" -) - -// Defines the activation function as a mapping that alters a vector in place -type ActivationFunction = func(*mat.VecDense) - -func GetActivationFunction(domainEnum domain.DomainEnum) ActivationFunction { - activationFunctionMap := map[domain.DomainEnum]ActivationFunction{ - domain.BipolarDomain: bipolarActivationFunction, - domain.BinaryDomain: binaryActivationFunction, - } - - return activationFunctionMap[domainEnum] -} - -// Apply a binary mapping to the given vector. The vector is modified in place. -// Elements of the vector set according to sign. -// -// # Arguments -// -// - vector *mat.VecDense: The vector to apply a binary mapping to. -func binaryActivationFunction(vector *mat.VecDense) { - for n := 0; n < vector.Len(); n++ { - if vector.AtVec(n) <= 0.0 { - vector.SetVec(n, 0.0) - } else { - vector.SetVec(n, 1.0) - } - } -} - -// Apply a bipolar mapping to the given vector. The vector is modified in place. -// Elements of the vector have their values set to their sign. (0 is mapped to 1.0). -// -// # Arguments -// -// - vector *mat.VecDense: The vector to apply a bipolar mapping to. -func bipolarActivationFunction(vector *mat.VecDense) { - for n := 0; n < vector.Len(); n++ { - if vector.AtVec(n) <= 0.0 { - vector.SetVec(n, -1.0) - } else { - vector.SetVec(n, 1.0) - } - } -} - -func continuousBipolarActivationFunction(vector *mat.VecDense) { - for n := 0; n < vector.Len(); n++ { - if vector.AtVec(n) < -1.0 { - vector.SetVec(n, -1.0) - } - if vector.AtVec(n) > 1.0 { - vector.SetVec(n, 1.0) - } - } -} From 032169f1d7dee7a780701680e444e086697c2714 Mon Sep 17 00:00:00 2001 From: Hayden McAlister Date: Sun, 4 Jun 2023 16:10:24 +1200 Subject: [PATCH 17/25] Remove energy function - now present in statemanager --- .../energyfunction/EnergyFunction.go | 34 ------------------- 1 file changed, 34 deletions(-) delete mode 100644 hopfieldnetwork/energyfunction/EnergyFunction.go diff --git a/hopfieldnetwork/energyfunction/EnergyFunction.go b/hopfieldnetwork/energyfunction/EnergyFunction.go deleted file mode 100644 index 9cff1bc..0000000 --- a/hopfieldnetwork/energyfunction/EnergyFunction.go +++ /dev/null @@ -1,34 +0,0 @@ -package energyfunction - -import ( - "gonum.org/v1/gonum/mat" -) - -// Defines the energy of a single unit in a vector with respect to a matrix. -func UnitEnergy(matrix *mat.Dense, vector *mat.VecDense, i int) float64 { - dimension, _ := vector.Dims() - energy := 0.0 - for j := 0; j < dimension; j++ { - energy += -1 * matrix.At(i, j) * vector.AtVec(i) * vector.AtVec(j) - } - return energy -} - -// Defines the overall energy for a state with respect to a matrix. -func StateEnergy(matrix *mat.Dense, vector *mat.VecDense) float64 { - energyVector := AllUnitEnergies(matrix, vector) - energy := 0.0 - for i := 0; i < energyVector.Len(); i++ { - energy += energyVector.AtVec(i) - } - return energy -} - -// Gets all the unit energies of a given vector with respect to a matrix. -func AllUnitEnergies(matrix *mat.Dense, vector *mat.VecDense) *mat.VecDense { - energyVector := mat.NewVecDense(vector.Len(), nil) - energyVector.MulVec(matrix, vector) - energyVector.MulElemVec(energyVector, vector) - energyVector.ScaleVec(-1, energyVector) - return energyVector -} From afab6b0f33dee2b283d1f96f83967c85f10796f3 Mon Sep 17 00:00:00 2001 From: Hayden McAlister Date: Sun, 4 Jun 2023 16:10:32 +1200 Subject: [PATCH 18/25] Remove learning mapping function - now present in statemanager --- .../LearningMappingFunction.go | 36 ------------------- 1 file changed, 36 deletions(-) delete mode 100644 hopfieldnetwork/learningmappingfunction/LearningMappingFunction.go diff --git a/hopfieldnetwork/learningmappingfunction/LearningMappingFunction.go b/hopfieldnetwork/learningmappingfunction/LearningMappingFunction.go deleted file mode 100644 index a522deb..0000000 --- a/hopfieldnetwork/learningmappingfunction/LearningMappingFunction.go +++ /dev/null @@ -1,36 +0,0 @@ -package learningmappingfunction - -import ( - "hmcalister/hopfield/hopfieldnetwork/domain" - - "gonum.org/v1/gonum/mat" -) - -// A learningMappingFunction is a map taking a state vector -// (specifically a target state vector) and maps it into a domain -// that the learning rule can be applied to. For example, the -// bipolar domain requires no mapping as the learning rules already -// support this directly, while the binary domain needs to be mapped -// into the bipolar domain. -type LearningMappingFunction func(*mat.VecDense) - -func GetLearningMappingFunction(domainEnum domain.DomainEnum) LearningMappingFunction { - learningMappingFunctionMap := map[domain.DomainEnum]LearningMappingFunction{ - domain.BipolarDomain: bipolarLearningMappingFunction, - domain.BinaryDomain: binaryLearningMappingFunction, - } - - return learningMappingFunctionMap[domainEnum] -} - -func binaryLearningMappingFunction(vector *mat.VecDense) { - negativeOneVector := mat.NewVecDense(vector.Len(), nil) - for i := 0; i < negativeOneVector.Len(); i++ { - negativeOneVector.SetVec(i, -1.0) - } - vector.AddScaledVec(negativeOneVector, 2, vector) -} - -func bipolarLearningMappingFunction(vector *mat.VecDense) { - -} From fdde3246e82ceef24569813af33ddc2add38e374 Mon Sep 17 00:00:00 2001 From: Hayden McAlister Date: Sun, 4 Jun 2023 16:10:53 +1200 Subject: [PATCH 19/25] Update binary mapping to change activation function to be idempotent --- hopfieldnetwork/states/statemanager/BinaryStateManager.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hopfieldnetwork/states/statemanager/BinaryStateManager.go b/hopfieldnetwork/states/statemanager/BinaryStateManager.go index e2c1802..0d0335b 100644 --- a/hopfieldnetwork/states/statemanager/BinaryStateManager.go +++ b/hopfieldnetwork/states/statemanager/BinaryStateManager.go @@ -7,7 +7,7 @@ type BinaryStateManager struct { func (manager *BinaryStateManager) ActivationFunction(vector *mat.VecDense) { for n := 0; n < vector.Len(); n++ { - if vector.AtVec(n) < 0.0 { + if vector.AtVec(n) <= 0.0 { vector.SetVec(n, 0.0) } else { vector.SetVec(n, 1.0) From 8dd100598006cd270518d77410b286e08f1952bf Mon Sep 17 00:00:00 2001 From: Hayden McAlister Date: Sun, 4 Jun 2023 16:11:12 +1200 Subject: [PATCH 20/25] Update bipolar manager to change activation function to be idempotent --- hopfieldnetwork/states/statemanager/BipolarStateManager.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hopfieldnetwork/states/statemanager/BipolarStateManager.go b/hopfieldnetwork/states/statemanager/BipolarStateManager.go index e74f73a..f3de58b 100644 --- a/hopfieldnetwork/states/statemanager/BipolarStateManager.go +++ b/hopfieldnetwork/states/statemanager/BipolarStateManager.go @@ -7,7 +7,7 @@ type BipolarStateManager struct { func (manager *BipolarStateManager) ActivationFunction(vector *mat.VecDense) { for n := 0; n < vector.Len(); n++ { - if vector.AtVec(n) < 0.0 { + if vector.AtVec(n) <= 0.0 { vector.SetVec(n, -1.0) } else { vector.SetVec(n, 1.0) From 64ba6c40bf2f3531969ad46a917dab8bc8a9d8c1 Mon Sep 17 00:00:00 2001 From: Hayden McAlister Date: Sun, 4 Jun 2023 16:11:47 +1200 Subject: [PATCH 21/25] Update hebbian learning rule to be more general --- hopfieldnetwork/LearningRule.go | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/hopfieldnetwork/LearningRule.go b/hopfieldnetwork/LearningRule.go index 94eea11..8a40b44 100644 --- a/hopfieldnetwork/LearningRule.go +++ b/hopfieldnetwork/LearningRule.go @@ -1,10 +1,6 @@ package hopfieldnetwork import ( - "fmt" - "hmcalister/hopfield/hopfieldnetwork/activationfunction" - "hmcalister/hopfield/hopfieldnetwork/learningmappingfunction" - "gonum.org/v1/gonum/mat" ) @@ -69,17 +65,18 @@ func getLearningRule(learningRule LearningRuleEnum) LearningRule { // // A pointer to a new matrix that stabilizes the given states as much as possible. func hebbian(network *HopfieldNetwork, states []*mat.VecDense) *mat.Dense { + var instanceContribution float64 updatedMatrix := mat.DenseCopyOf(network.GetMatrix()) updatedMatrix.Zero() for _, state := range states { - stateCopy := mat.VecDenseCopyOf(state) - learningmappingfunction.GetLearningMappingFunction(network.domain)(stateCopy) - fmt.Printf("%v\n", stateCopy) for i := 0; i < network.GetDimension(); i++ { for j := 0; j < network.GetDimension(); j++ { - val := stateCopy.AtVec(i) * stateCopy.AtVec(j) - val += updatedMatrix.At(i, j) - updatedMatrix.Set(i, j, val) + if state.AtVec(i) == state.AtVec(j) { + instanceContribution = 1.0 + } else { + instanceContribution = -1.0 + } + updatedMatrix.Set(i, j, updatedMatrix.At(i, j)+instanceContribution) } } } From 8e639356cb11246eabf20648c624ee12e7eaea98 Mon Sep 17 00:00:00 2001 From: Hayden McAlister Date: Sun, 4 Jun 2023 16:11:55 +1200 Subject: [PATCH 22/25] Update delta rule to be more general --- hopfieldnetwork/LearningRule.go | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/hopfieldnetwork/LearningRule.go b/hopfieldnetwork/LearningRule.go index 8a40b44..241a524 100644 --- a/hopfieldnetwork/LearningRule.go +++ b/hopfieldnetwork/LearningRule.go @@ -109,7 +109,7 @@ func delta(network *HopfieldNetwork, states []*mat.VecDense) *mat.Dense { relaxedStates[stateIndex] = mat.VecDenseCopyOf(states[stateIndex]) // We also apply some noise to the state to aide in learning network.learningNoiseMethod(network.randomGenerator, relaxedStates[stateIndex], network.learningNoiseScale) - activationfunction.GetActivationFunction(network.domain)(relaxedStates[stateIndex]) + network.domainStateManager.ActivationFunction(relaxedStates[stateIndex]) } // This is the most important call - relax all the states! @@ -121,16 +121,11 @@ func delta(network *HopfieldNetwork, states []*mat.VecDense) *mat.Dense { stateHistory := relaxationResults[stateIndex].StateHistory relaxedState := stateHistory[len(stateHistory)-1] - stateCopy := mat.VecDenseCopyOf(state) - learningmappingfunction.GetLearningMappingFunction(network.domain)(stateCopy) - relaxedCopy := mat.VecDenseCopyOf(relaxedState) - learningmappingfunction.GetLearningMappingFunction(network.domain)(relaxedCopy) - relaxationDifference.Zero() - relaxationDifference.SubVec(stateCopy, relaxedCopy) + relaxationDifference.SubVec(state, relaxedState) stateContribution.Zero() - stateContribution.Outer(0.5, relaxationDifference, stateCopy) + stateContribution.Outer(0.5, relaxationDifference, state) updatedMatrix.Add(updatedMatrix, stateContribution) } From 4f422c466e0c5490d8df0794111c1ef1c48487ef Mon Sep 17 00:00:00 2001 From: Hayden McAlister Date: Sun, 4 Jun 2023 16:12:05 +1200 Subject: [PATCH 23/25] Update network builder to use new domain managers --- hopfieldnetwork/HopfieldNetworkBuilder.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hopfieldnetwork/HopfieldNetworkBuilder.go b/hopfieldnetwork/HopfieldNetworkBuilder.go index 19ce741..45fac96 100644 --- a/hopfieldnetwork/HopfieldNetworkBuilder.go +++ b/hopfieldnetwork/HopfieldNetworkBuilder.go @@ -4,6 +4,7 @@ import ( "hmcalister/hopfield/hopfieldnetwork/datacollector" "hmcalister/hopfield/hopfieldnetwork/domain" "hmcalister/hopfield/hopfieldnetwork/noiseapplication" + "hmcalister/hopfield/hopfieldnetwork/states/statemanager" "log" "time" @@ -239,6 +240,7 @@ func (networkBuilder *HopfieldNetworkBuilder) Build() *HopfieldNetwork { matrix: matrix, dimension: networkBuilder.dimension, domain: networkBuilder.domain, + domainStateManager: statemanager.GetDomainStateManager(networkBuilder.domain), forceSymmetric: networkBuilder.forceSymmetric, forceZeroDiagonal: networkBuilder.forceZeroDiagonal, learningMethod: networkBuilder.learningMethod, From 669c5cfd0345095ad049e309bb468d482b604b9b Mon Sep 17 00:00:00 2001 From: Hayden McAlister Date: Sun, 4 Jun 2023 16:12:17 +1200 Subject: [PATCH 24/25] Update hopfield network to use new domain state manager --- hopfieldnetwork/HopfieldNetwork.go | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/hopfieldnetwork/HopfieldNetwork.go b/hopfieldnetwork/HopfieldNetwork.go index 04514c6..72590e8 100644 --- a/hopfieldnetwork/HopfieldNetwork.go +++ b/hopfieldnetwork/HopfieldNetwork.go @@ -3,12 +3,10 @@ package hopfieldnetwork import ( "fmt" - "hmcalister/hopfield/hopfieldnetwork/activationfunction" "hmcalister/hopfield/hopfieldnetwork/datacollector" "hmcalister/hopfield/hopfieldnetwork/domain" - "hmcalister/hopfield/hopfieldnetwork/energyfunction" - "hmcalister/hopfield/hopfieldnetwork/learningmappingfunction" "hmcalister/hopfield/hopfieldnetwork/noiseapplication" + "hmcalister/hopfield/hopfieldnetwork/states/statemanager" "hmcalister/hopfield/hopfieldutils" "log" @@ -27,6 +25,7 @@ type HopfieldNetwork struct { matrix *mat.Dense dimension int domain domain.DomainEnum + domainStateManager statemanager.StateManager forceSymmetric bool forceZeroDiagonal bool learningMethod LearningMethod @@ -168,9 +167,7 @@ func (network *HopfieldNetwork) String() string { // A float64 representing the energy of the given state with respect to the network. // Note a lower energy is more stable - but a negative state energy may still be unstable! func (network *HopfieldNetwork) StateEnergy(state *mat.VecDense) float64 { - stateCopy := mat.VecDenseCopyOf(state) - learningmappingfunction.GetLearningMappingFunction(network.domain)(stateCopy) - return energyfunction.StateEnergy(network.matrix, stateCopy) + return network.domainStateManager.StateEnergy(network.matrix, state) } // Get the energy of a given unit (indexed by i) in the state with respect to the network matrix. @@ -184,9 +181,7 @@ func (network *HopfieldNetwork) StateEnergy(state *mat.VecDense) float64 { // // A float64 representing the energy of the given unit within the state. func (network *HopfieldNetwork) UnitEnergy(state *mat.VecDense, unitIndex int) float64 { - stateCopy := mat.VecDenseCopyOf(state) - learningmappingfunction.GetLearningMappingFunction(network.domain)(stateCopy) - return energyfunction.UnitEnergy(network.matrix, stateCopy, unitIndex) + return network.domainStateManager.UnitEnergy(network.matrix, state, unitIndex) } // Get the energy of a each unit within a state with respect to the network matrix. @@ -199,10 +194,7 @@ func (network *HopfieldNetwork) UnitEnergy(state *mat.VecDense, unitIndex int) f // // A slice of float64 representing the energy of the given state's units with respect to the network. func (network *HopfieldNetwork) AllUnitEnergies(state *mat.VecDense) []float64 { - stateCopy := mat.VecDenseCopyOf(state) - learningmappingfunction.GetLearningMappingFunction(network.domain)(stateCopy) - unitEnergies := energyfunction.AllUnitEnergies(network.matrix, stateCopy) - return unitEnergies.RawVector().Data + return network.domainStateManager.AllUnitEnergies(network.matrix, state) } // Determine if a given state is unstable. @@ -262,7 +254,7 @@ func (network *HopfieldNetwork) AllStatesAreStable(states []*mat.VecDense) bool // states []*mat.VecDense: A collection of states to learn func (network *HopfieldNetwork) LearnStates(states []*mat.VecDense) []*datacollector.LearnStateData { for _, state := range states { - activationfunction.GetActivationFunction(network.domain)(state) + network.domainStateManager.ActivationFunction(state) } network.targetStates = append(network.targetStates, states...) @@ -298,7 +290,7 @@ func (network *HopfieldNetwork) UpdateState(state *mat.VecDense) { for _, unitIndex := range chunk { state.SetVec(unitIndex, newState.AtVec(unitIndex)) } - activationfunction.GetActivationFunction(network.domain)(state) + network.domainStateManager.ActivationFunction(state) } } @@ -334,7 +326,7 @@ func (network *HopfieldNetwork) RelaxState(state *mat.VecDense) *RelaxationResul for _, unitIndex := range chunk { state.SetVec(unitIndex, newState.AtVec(unitIndex)) } - activationfunction.GetActivationFunction(network.domain)(state) + network.domainStateManager.ActivationFunction(state) } // Collect the current history item if requested @@ -412,7 +404,7 @@ StateRecvLoop: for _, unitIndex := range chunk { state.SetVec(unitIndex, newState.AtVec(unitIndex)) } - activationfunction.GetActivationFunction(network.domain)(state) + network.domainStateManager.ActivationFunction(state) } // Collect the current history item if requested From 2d9ad350f34c4de7fa0d9bf1d8848841b69376ff Mon Sep 17 00:00:00 2001 From: Hayden McAlister Date: Sun, 4 Jun 2023 16:12:29 +1200 Subject: [PATCH 25/25] Update main to remove use of old energy, activation functions --- main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.go b/main.go index 16fafe8..56358ac 100644 --- a/main.go +++ b/main.go @@ -15,7 +15,7 @@ import ( "hmcalister/hopfield/hopfieldnetwork/datacollector" "hmcalister/hopfield/hopfieldnetwork/domain" "hmcalister/hopfield/hopfieldnetwork/noiseapplication" - "hmcalister/hopfield/hopfieldnetwork/states" + states "hmcalister/hopfield/hopfieldnetwork/states/stategenerator" "hmcalister/hopfield/hopfieldutils" )