diff --git a/examples/metrics/metrics.go b/examples/metrics/metrics.go index a1befd9..c8bc5f8 100644 --- a/examples/metrics/metrics.go +++ b/examples/metrics/metrics.go @@ -4,23 +4,27 @@ import ( "fmt" pariwiseMetrics "github.com/sjwhitworth/golearn/metrics/pairwise" - "github.com/sjwhitworth/golearn/utilities" mat "github.com/skelterjohn/go.matrix" ) func main() { - randArray := utilities.RandomArray(3, 7) - vectorX := mat.MakeDenseMatrix(randArray, 1, 3) - randArray = utilities.RandomArray(3, 7) - vectorY := mat.MakeDenseMatrix(randArray, 1, 3) + vectorX := mat.MakeDenseMatrix([]float64{1, 2, 3}, 3, 1) + vectorY := mat.MakeDenseMatrix([]float64{3, 4, 5}, 3, 1) - distance, err := pariwiseMetrics.Euclidean(vectorX, vectorY) + euclidean := pariwiseMetrics.NewEuclidean() + polyKernel := pariwiseMetrics.NewPolyKernel(3) + euclideanDistance, err := euclidean.Distance(vectorX, vectorY) + polyKernelDistance, err := polyKernel.Distance(vectorX, vectorY) if err != nil { fmt.Println(err) return } - fmt.Println("Euclidean distance of " + vectorX.String() + " and " + vectorY.String() + " is: ") - fmt.Println(distance) + fmt.Println("Vector X:") + fmt.Println(vectorX.String()) + fmt.Println("Vector Y: ") + fmt.Println(vectorY.String()) + fmt.Println("Euclidean : ", euclideanDistance) + fmt.Println("PolyKernel(degree 3): ", polyKernelDistance) } diff --git a/metrics/pairwise/euclidean.go b/metrics/pairwise/euclidean.go index cb594d1..bd8eddd 100644 --- a/metrics/pairwise/euclidean.go +++ b/metrics/pairwise/euclidean.go @@ -1,30 +1,32 @@ package pairwise import ( - "fmt" + "errors" "math" mat "github.com/skelterjohn/go.matrix" ) -// We may need to create Metrics / Vector interface for this -func Euclidean(vectorX *mat.DenseMatrix, vectorY *mat.DenseMatrix) (float64, error) { - var sum float64 +type Euclidean struct{} - difference, err := vectorY.MinusDense(vectorX) - - flat := difference.Array() - - if err != nil { - fmt.Println(err) - return -1, err - } - - for _, i := range flat { - squared := math.Pow(i, 2) - sum += squared - } - - distance := math.Sqrt(sum) - return distance, nil +func NewEuclidean() *Euclidean { + return &Euclidean{} +} + +func (self *Euclidean) InnerProduct(vectorX *mat.DenseMatrix, vectorY *mat.DenseMatrix) (float64, error) { + if !CheckDimMatch(vectorX, vectorY) { + return 0, errors.New("Dimension mismatch") + } + + result := mat.Product(mat.Transpose(vectorX), vectorY).Get(0, 0) + + return result, nil +} + +// We may need to create Metrics / Vector interface for this +func (self *Euclidean) Distance(vectorX *mat.DenseMatrix, vectorY *mat.DenseMatrix) (float64, error) { + difference, err := vectorY.MinusDense(vectorX) + result, err := self.InnerProduct(difference, difference) + + return math.Sqrt(result), err } diff --git a/metrics/pairwise/pairwise.go b/metrics/pairwise/pairwise.go new file mode 100644 index 0000000..a256038 --- /dev/null +++ b/metrics/pairwise/pairwise.go @@ -0,0 +1,20 @@ +package pairwise + +import ( + mat "github.com/skelterjohn/go.matrix" +) + +type Metric interface { + InnerProduct(vectorX *mat.DenseMatrix, vectorY *mat.DenseMatrix) + Distance(vectorX *mat.DenseMatrix, vectorY *mat.DenseMatrix) +} + +func CheckDimMatch(vectorX *mat.DenseMatrix, vectorY *mat.DenseMatrix) bool { + if vectorX.Cols() != 1 || + vectorY.Cols() != 1 || + vectorX.Rows() != vectorY.Rows() { + return false + } else { + return true + } +} diff --git a/metrics/pairwise/poly_kernel.go b/metrics/pairwise/poly_kernel.go new file mode 100644 index 0000000..2ed44da --- /dev/null +++ b/metrics/pairwise/poly_kernel.go @@ -0,0 +1,34 @@ +package pairwise + +import ( + "errors" + "math" + + mat "github.com/skelterjohn/go.matrix" +) + +type PolyKernel struct { + degree int +} + +func NewPolyKernel(degree int) *PolyKernel { + return &PolyKernel{degree: degree} +} + +func (self *PolyKernel) InnerProduct(vectorX *mat.DenseMatrix, vectorY *mat.DenseMatrix) (float64, error) { + if !CheckDimMatch(vectorX, vectorY) { + return 0, errors.New("Dimension mismatch") + } + + result := mat.Product(mat.Transpose(vectorX), vectorY).Get(0, 0) + result = math.Pow(result+1, float64(self.degree)) + + return result, nil +} + +func (self *PolyKernel) Distance(vectorX *mat.DenseMatrix, vectorY *mat.DenseMatrix) (float64, error) { + difference, err := vectorY.MinusDense(vectorX) + result, err := self.InnerProduct(difference, difference) + + return math.Sqrt(result), err +}