You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: level3cmplx128.go
    path of file: ./repos/hoverfly/vendor/gonum.org/v1/gonum/blas/gonum
    
    the code of the file until where you have to start completion: // Copyright ©2019 The Gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package gonum

import (
	"math/cmplx"

	"gonum.org/v1/gonum/blas"
	"gonum.org/v1/gonum/internal/asm/c128"
)

var _ blas.Complex128Level3 = Implementation{}

// Zgemm performs one of the matrix-matrix operations
//  C = alpha * op(A) * op(B) + beta * C
// where op(X) is one of
//  op(X) = X  or  op(X) = Xᵀ  or  op(X) = Xᴴ,
// alpha and beta are scalars, and A, B and C are matrices, with op(A) an m×k matrix,
// op(B) a k×n matrix and C an m×n matrix.
func (Implementation) Zgemm(tA, tB blas.Transpose, m, n, k int, alpha complex128, a []complex128, lda int, b []complex128, ldb int, beta complex128, c []complex128, ldc int) {
	switch tA {
	default:
		panic(badTranspose)
	case blas.NoTrans, blas.Trans, blas.ConjTrans:
	}
	switch tB {
	default:
		panic(badTranspose)
	case blas.NoTrans, blas.Trans, blas.ConjTrans:
	}
	switch {
	case m < 0:
		panic(mLT0)
	case n < 0:
		panic(nLT0)
	case k < 0:
		panic(kLT0)
	}
	rowA, colA := m, k
	if tA != blas.NoTrans {
		rowA, colA = k, m
	}
	if lda < max(1, colA) {
		panic(badLdA)
	}
	rowB, colB := k, n
	if tB != blas.NoTrans {
		rowB, colB = n, k
	}
	if ldb < max(1, colB) {
		panic(badLdB)
	}
	if ldc < max(1, n) {
		panic(badLdC)
	}

	// Quick return if possible.
	if m == 0 || n == 0 {
		return
	}

	// For zero matrix size the following slice length checks are trivially satisfied.
	if len(a) < (rowA-1)*lda+colA {
		panic(shortA)
	}
	if len(b) < (rowB-1)*ldb+colB {
		panic(shortB)
	}
	if len(c) < (m-1)*ldc+n {
		panic(shortC)
	}

	// Quick return if possible.
	if (alpha == 0 || k == 0) && beta == 1 {
		return
	}

	if alpha == 0 {
		if beta == 0 {
			for i := 0; i < m; i++ {
				for j := 0; j < n; j++ {
					c[i*ldc+j] = 0
				}
			}
		} else {
			for i := 0; i < m; i++ {
				for j := 0; j < n; j++ {
					c[i*ldc+j] *= beta
				}
			}
		}
		return
	}

	switch tA {
	case blas.NoTrans:
		switch tB {
		case blas.NoTrans:
			// Form  C = alpha * A * B + beta * C.
			for i := 0; i < m; i++ {
				switch {
				case beta == 0:
					for j := 0; j < n; j++ {
						c[i*ldc+j] = 0
					}
				case beta != 1:
					for j := 0; j < n; j++ {
						c[i*ldc+j] *= beta
					}
				}
				for l := 0; l < k; l++ {
					tmp := alpha * a[i*lda+l]
					for j := 0; j < n; j++ {
						c[i*ldc+j] += tmp * b[l*ldb+j]
					}
				}
			}
		case blas.Trans:
			// Form  C = alpha * A * Bᵀ + beta * C.
			for i := 0; i < m; i++ {
				switch {
				case beta == 0:
					for j := 0; j < n; j++ {
						c[i*ldc+j] = 0
					}
				case beta != 1:

    
func (Implementation) Zsymm(side blas.Side, uplo blas.Uplo, m, n int, alpha complex128, a []complex128, lda int, b []complex128, ldb int, beta complex128, c []complex128, ldc int) {
	na := m
	if side == blas.Right {
		na = n
	}
	switch {
	case side != blas.Left && side != blas.Right:
		panic(badSide)
	case uplo != blas.Lower && uplo != blas.Upper:
		panic(badUplo)
	case m < 0:
		panic(mLT0)
	case n < 0:
		panic(nLT0)
	case lda < max(1, na):
		panic(badLdA)
	case ldb < max(1, n):
		panic(badLdB)
	case ldc < max(1, n):
		panic(badLdC)
	}

	// Quick return if possible.
	if m == 0 || n == 0 {
		return
	}

	// For zero matrix size the following slice length checks are trivially satisfied.
	if len(a) < lda*(na-1)+na {
		panic(shortA)
	}
	if len(b) < ldb*(m-1)+n {
		panic(shortB)
	}
	if len(c) < ldc*(m-1)+n {
		panic(shortC)
	}

	// Quick return if possible.
	if alpha == 0 && beta == 1 {
		return
	}

	if alpha == 0 {
		if beta == 0 {
			for i := 0; i < m; i++ {
				ci := c[i*ldc : i*ldc+n]
				for j := range ci {
					ci[j] = 0
				}
			}
		} else {
			for i := 0; i < m; i++ {
				ci := c[i*ldc : i*ldc+n]
				c128.ScalUnitary(beta, ci)
			}
		}
		return
	}

	if side == blas.Left {
		// Form  C = alpha*A*B + beta*C.
		for i := 0; i < m; i++ {
			atmp := alpha * a[i*lda+i]
			bi := b[i*ldb : i*ldb+n]
			ci := c[i*ldc : i*ldc+n]
			if beta == 0 {
				for j, bij := range bi {
					ci[j] = atmp * bij
				}
			} else {
				for j, bij := range bi {
					ci[j] = atmp*bij + beta*ci[j]
				}
			}
			if uplo == blas.Upper {
				for k := 0; k < i; k++ {
					atmp = alpha * a[k*lda+i]
					c128.AxpyUnitary(atmp, b[k*ldb:k*ldb+n], ci)
				}
				for k := i + 1; k < m; k++ {
					atmp = alpha * a[i*lda+k]
					c128.AxpyUnitary(atmp, b[k*ldb:k*ldb+n], ci)
				}
			} else {
				for k := 0; k < i; k++ {
					atmp = alpha * a[i*lda+k]
					c128.AxpyUnitary(atmp, b[k*ldb:k*ldb+n], ci)
				}
				for k := i + 1; k < m; k++ {
					atmp = alpha * a[k*lda+i]
					c128.AxpyUnitary(atmp, b[k*ldb:k*ldb+n], ci)
				}
			}
		}
	} else {
		// Form  C = alpha*B*A + beta*C.
		if uplo == blas.Upper {
			for i := 0; i < m; i++ {
				for j := n - 1; j >= 0; j-- {
					abij := alpha * b[i*ldb+j]
					aj := a[j*lda+j+1 : j*lda+n]
					bi := b[i*ldb+j+1 : i*ldb+n]
					ci := c[i*ldc+j+1 : i*ldc+n]
					var tmp complex128
					for k, ajk := range aj {
						ci[k] += abij * ajk
						tmp += bi[k] * ajk
					}
					if beta == 0 {
						c[i*ldc+j] = abij*a[j*lda+j] + alpha*tmp
					} else {
						c[i*ldc+j] = abij*a[j*lda+j] + alpha*tmp + beta*c[i*ldc+j]
					}
				}
			}
		} else {
			for i := 0; i < m; i++ {
				for j := 0; j < n; j++ {
					abij := alpha * b[i*ldb+j]
					aj := a[j*lda : j*lda+j]
					bi := b[i*ldb : i*ldb+j]
					ci := c[i*ldc : i*ldc+j]
					var tmp complex128
					for k, ajk := range aj {
						ci[k] += abij * ajk
						tmp += bi[k] * ajk
					}
					if beta == 0 {
						c[i*ldc+j] = abij*a[j*lda+j] + alpha*tmp
					} else {
						c[i*ldc+j] = abij*a[j*lda+j] + alpha*tmp + beta*c[i*ldc+j]
					}
				}
			}
		}
	}
}