I am using gonum to perform a few linear algebra calculations. After extending the original mat.VecDense
struct I am getting a "bad region: identical" panic when applying a method on itself. This error does not occur when I am using the original setup gonum provides.
Here is my implementation:
type Vector struct {
mat.VecDense
}
func NewVector(n int, data []float64) *Vector {
return &Vector{*mat.NewVecDense(n, data)}
}
I am testing it using the following snippet:
func main() {
u, v := mat.NewVecDense(3, []float64{1, 2, 3}), mat.NewVecDense(3, []float64{4, 5, 6})
fmt.Printf("[U - NewVecDense]\tADDRESS: %v, VALUE: %v\n", &u, u)
fmt.Printf("[V - NewVecDense]\tADDRESS: %v, VALUE: %v\n", &v, v)
u.AddVec(u, v)
fmt.Println("-------------------------")
x, y := NewVector(3, []float64{1, 2, 3}), NewVector(3, []float64{4, 5, 6})
fmt.Printf("[X - NewVector]\tADDRESS: %v, VALUE: %v\n", &x, x)
fmt.Printf("[Y - NewVector]\tADDRESS: %v, VALUE: %v\n", &y, y)
x.AddVec(x, y)
fmt.Println(x)
}
While the first addition executes fine, the second fails:
[U - NewVecDense] ADDRESS: 0xc42000c028, VALUE: &{{[1 2 3] 1} 3}
[V - NewVecDense] ADDRESS: 0xc42000c030, VALUE: &{{[4 5 6] 1} 3}
-------------------------
[X - NewVector] ADDRESS: 0xc42000c040, VALUE: &{{{[1 2 3] 1} 3}}
[Y - NewVector] ADDRESS: 0xc42000c048, VALUE: &{{{[4 5 6] 1} 3}}
panic: mat: bad region: identical
AddVec
is a method implemented by gonum:
func (v *VecDense) AddVec(a, b Vector)
Why is this happening, hand what is the right way of implementing this?
Edit:
Thanks to @Himanshu I managed to solve the problem.
I created pass-through methods for each method I am using, passing the right level of the struct through:
type Vector struct {
*mat.VecDense
}
func NewVector(n int, data []float64) Vector {
return Vector{mat.NewVecDense(n, data)}
}
func (v *Vector) AddVec(a, b Vector) {
v.VecDense.AddVec(a.VecDense, b.VecDense)
}
func (v *Vector) SubVec(a, b Vector) {
v.VecDense.SubVec(a.VecDense, b.VecDense)
}
func (v *Vector) ScaleVec(alpha float64, a Vector) {
v.VecDense.ScaleVec(alpha, a.VecDense)
}
func (v *Vector) AddScaledVec(a Vector, alpha float64, b Vector) {
v.VecDense.AddScaledVec(a.VecDense, alpha, b.VecDense)
}
In addition - I am not sure if this is the right approach or not - I have also changed the return type for NewVector
from pointer to value, since it holds a pointer to the mat.VecDense
anyway. Note that *mat.VecDense
satisfies the Vector
interface from gonum, so passing this internal field on to the methods worked fine, as the example above shows.
In Golang it is described for promoted methods as
Promoted fields act like ordinary fields of a struct except that they cannot be used as field names in composite literals of the struct.
Given a struct type S and a defined type T, promoted methods are included in the method set of the struct as follows:
The problem is that you are passing pointer type arguments to AddVec
function. But you are using pointer type fields in second case.
func (v *VecDense) AddVec(a, b Vector)
One more thing to notice is that AddVec
has value type arguments of Vector
struct but you are passing pointer to Vector
fields as
x, y := NewVector(3, []float64{1, 2, 3}), NewVector(3, []float64{4, 5, 6})
In above code x,y
are pointer type returned from NewVector
x.AddVec(x, y)