mirror of
https://github.com/gonum/gonum.git
synced 2025-12-24 13:47:56 +08:00
mat: add Kronecker product function
This commit is contained in:
@@ -673,6 +673,20 @@ func (m *Dense) Pow(a Matrix, n int) {
|
||||
putWorkspace(x)
|
||||
}
|
||||
|
||||
// Kronecker calculates the Kronecker product of a and b, placing the result in
|
||||
// the receiver.
|
||||
func (m *Dense) Kronecker(a, b Matrix) {
|
||||
ra, ca := a.Dims()
|
||||
rb, cb := b.Dims()
|
||||
|
||||
m.reuseAsNonZeroed(ra*rb, ca*cb)
|
||||
for i := 0; i < ra; i++ {
|
||||
for j := 0; j < ca; j++ {
|
||||
m.Slice(i*rb, (i+1)*rb, j*cb, (j+1)*cb).(*Dense).Scale(a.At(i, j), b)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Scale multiplies the elements of a by f, placing the result in the receiver.
|
||||
//
|
||||
// See the Scaler interface for more information.
|
||||
|
||||
@@ -1087,6 +1087,106 @@ func TestDensePow(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDenseKronecker(t *testing.T) {
|
||||
for i, test := range []struct {
|
||||
a, b Matrix
|
||||
want *Dense
|
||||
}{
|
||||
{
|
||||
a: NewDense(1, 3, []float64{1, 2, 3}),
|
||||
b: NewDense(3, 1, []float64{1, 2, 3}),
|
||||
want: NewDense(3, 3, []float64{
|
||||
1, 2, 3,
|
||||
2, 4, 6,
|
||||
3, 6, 9,
|
||||
}),
|
||||
},
|
||||
{
|
||||
a: NewDense(3, 1, []float64{1, 2, 3}),
|
||||
b: NewDense(1, 3, []float64{1, 2, 3}),
|
||||
want: NewDense(3, 3, []float64{
|
||||
1, 2, 3,
|
||||
2, 4, 6,
|
||||
3, 6, 9,
|
||||
}),
|
||||
},
|
||||
{
|
||||
a: NewDense(1, 3, []float64{1, 2, 3}),
|
||||
b: NewDense(2, 1, []float64{1, 2}),
|
||||
want: NewDense(2, 3, []float64{
|
||||
1, 2, 3,
|
||||
2, 4, 6,
|
||||
}),
|
||||
},
|
||||
{
|
||||
a: NewDense(2, 1, []float64{1, 2}),
|
||||
b: NewDense(1, 3, []float64{1, 2, 3}),
|
||||
want: NewDense(2, 3, []float64{
|
||||
1, 2, 3,
|
||||
2, 4, 6,
|
||||
}),
|
||||
},
|
||||
{
|
||||
a: NewDense(1, 2, []float64{1, 2}),
|
||||
b: NewDense(3, 1, []float64{1, 2, 3}),
|
||||
want: NewDense(3, 2, []float64{
|
||||
1, 2,
|
||||
2, 4,
|
||||
3, 6,
|
||||
}),
|
||||
},
|
||||
{
|
||||
a: NewDense(3, 1, []float64{1, 2, 3}),
|
||||
b: NewDense(1, 2, []float64{1, 2}),
|
||||
want: NewDense(3, 2, []float64{
|
||||
1, 2,
|
||||
2, 4,
|
||||
3, 6,
|
||||
}),
|
||||
},
|
||||
|
||||
// Examples from https://en.wikipedia.org/wiki/Kronecker_product.
|
||||
{
|
||||
a: NewDense(2, 2, []float64{1, 2, 3, 4}),
|
||||
b: NewDense(2, 2, []float64{0, 5, 6, 7}),
|
||||
want: NewDense(4, 4, []float64{
|
||||
0, 5, 0, 10,
|
||||
6, 7, 12, 14,
|
||||
0, 15, 0, 20,
|
||||
18, 21, 24, 28,
|
||||
}),
|
||||
},
|
||||
{
|
||||
a: NewDense(2, 3, []float64{
|
||||
1, -4, 7,
|
||||
-2, 3, 3,
|
||||
}),
|
||||
b: NewDense(4, 4, []float64{
|
||||
8, -9, -6, 5,
|
||||
1, -3, -4, 7,
|
||||
2, 8, -8, -3,
|
||||
1, 2, -5, -1,
|
||||
}),
|
||||
want: NewDense(8, 12, []float64{
|
||||
8, -9, -6, 5, -32, 36, 24, -20, 56, -63, -42, 35,
|
||||
1, -3, -4, 7, -4, 12, 16, -28, 7, -21, -28, 49,
|
||||
2, 8, -8, -3, -8, -32, 32, 12, 14, 56, -56, -21,
|
||||
1, 2, -5, -1, -4, -8, 20, 4, 7, 14, -35, -7,
|
||||
-16, 18, 12, -10, 24, -27, -18, 15, 24, -27, -18, 15,
|
||||
-2, 6, 8, -14, 3, -9, -12, 21, 3, -9, -12, 21,
|
||||
-4, -16, 16, 6, 6, 24, -24, -9, 6, 24, -24, -9,
|
||||
-2, -4, 10, 2, 3, 6, -15, -3, 3, 6, -15, -3,
|
||||
}),
|
||||
},
|
||||
} {
|
||||
var got Dense
|
||||
got.Kronecker(test.a, test.b)
|
||||
if !Equal(&got, test.want) {
|
||||
t.Errorf("unexpected result for test %d\ngot:%#v want:%#v", i, &got, test.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDenseScale(t *testing.T) {
|
||||
for _, f := range []float64{0.5, 1, 3} {
|
||||
method := func(receiver, a Matrix) {
|
||||
|
||||
Reference in New Issue
Block a user