Example #1
0
func TestTanhKernelShouldPass1(t *testing.T) {
	k := TanhKernel(1)

	// test different dot products which
	// should be valid

	// when constant is 0, default to -1.0

	assert.InDelta(t, math.Tanh(1.0-1.0), k([]float64{
		0.0, 1.0, 1.0, 0.0,
	}, []float64{
		0.0, 1.0, 0.0, 0.0,
	}), 5e-4, "Dot product should be valid")

	assert.InDelta(t, math.Tanh(6.0-1.0), k([]float64{
		15.0, 1.0, -1.0, 0.0,
	}, []float64{
		1.0, 1.0, 10.0, 0.0,
	}), 5e-4, "Dot product should be valid")

	assert.InDelta(t, math.Tanh(-84.0-1.0), k([]float64{
		15.0, 1.0, -1.0, 0.0,
	}, []float64{
		1.0, 1.0, 100.0, 0.0,
	}), 5e-4, "Dot product should be valid")
}
Example #2
0
// Evaluate the anomalous retarded pair Green's function,
// Pi^A(k, omega)_{xx, xy, yy}. k must be a two-dimensional vector.
func PiAnom(env *tempAll.Environment, k vec.Vector, omega float64) vec.Vector {
	piInner := func(q vec.Vector, out *vec.Vector) {
		// Do vector operations on out to avoid allocation:
		//  first case, out = k/2 + q
		(*out)[0] = k[0]/2.0 + q[0]
		(*out)[1] = k[1]/2.0 + q[1]
		Delta1 := env.Delta_h(*out)
		E1 := env.BogoEnergy(*out)
		//  second case, out = k/2 - q
		(*out)[0] = k[0]/2.0 - q[0]
		(*out)[1] = k[1]/2.0 - q[1]
		Delta2 := env.Delta_h(*out)
		E2 := env.BogoEnergy(*out)
		// Get part of result that's the same for all (xx, xy, yy):
		t1 := math.Tanh(env.Beta * E1 / 2.0)
		t2 := math.Tanh(env.Beta * E2 / 2.0)
		common := -Delta1 * Delta2 / (4.0 * E1 * E2) * ((t1+t2)*(1.0/(omega+E1+E2)-1.0/(omega-E1-E2)) + (t1-t2)*(1.0/(omega-E1+E2)-1.0/(omega+E1-E2)))
		// Set out = result:
		sx := math.Sin(q[0])
		sy := math.Sin(q[1])
		(*out)[0] = sx * sx * common
		(*out)[1] = sx * sy * common
		(*out)[2] = sy * sy * common
	}
	return bzone.VectorAvg(env.PointsPerSide, 2, 3, piInner)
}
Example #3
0
// Evaluate the retarded pair Green's function Pi_R(k, omega)_{xx, xy, yy}.
// k must be a two-dimensional vector.
func Pi(env *tempAll.Environment, k vec.Vector, omega float64) vec.Vector {
	var piInner func(k vec.Vector, out *vec.Vector)
	// TODO: should this comparison be math.Abs(env.F0)? Not using that to
	// avoid going to finite F0 procedure when F0 < 0 (since F0 is
	// positive by choice of gauge). Also - would it be better to just
	// test if F0 == 0.0? Would prefer to avoid equality comparison
	// on float.
	if math.Abs(env.F0) < 1e-9 {
		piInner = func(q vec.Vector, out *vec.Vector) {
			// do vector operations on out to avoid allocation:
			// out = k/2 + q
			(*out)[0] = k[0]/2.0 + q[0]
			(*out)[1] = k[1]/2.0 + q[1]
			xp := env.Xi_h(*out)
			// out = k/2 - q
			(*out)[0] = k[0]/2.0 - q[0]
			(*out)[1] = k[1]/2.0 - q[1]
			xm := env.Xi_h(*out)

			tp := math.Tanh(env.Beta * xp / 2.0)
			tm := math.Tanh(env.Beta * xm / 2.0)
			common := -(tp + tm) / (omega - xp - xm)
			sx := math.Sin(q[0])
			sy := math.Sin(q[1])
			// out = result
			(*out)[0] = sx * sx * common
			(*out)[1] = sx * sy * common
			(*out)[2] = sy * sy * common
		}
	} else {
		piInner = func(q vec.Vector, out *vec.Vector) {
			// out = k/2 + q
			(*out)[0] = k[0]/2.0 + q[0]
			(*out)[1] = k[1]/2.0 + q[1]
			xi1 := env.Xi_h(*out)
			E1 := env.BogoEnergy(*out)
			// out = k/2 - q
			(*out)[0] = k[0]/2.0 - q[0]
			(*out)[1] = k[1]/2.0 - q[1]
			xi2 := env.Xi_h(*out)
			E2 := env.BogoEnergy(*out)

			A1 := 0.5 * (1.0 + xi1/E1)
			A2 := 0.5 * (1.0 + xi2/E2)
			B1 := 0.5 * (1.0 - xi1/E1)
			B2 := 0.5 * (1.0 - xi2/E2)
			t1 := math.Tanh(env.Beta * E1 / 2.0)
			t2 := math.Tanh(env.Beta * E2 / 2.0)
			common := -(t1+t2)*(A1*A2/(omega-E1-E2)-B1*B2/(omega+E1+E2)) - (t1-t2)*(A1*B2/(omega-E1+E2)-B1*A2/(omega+E1-E2))
			sx := math.Sin(q[0])
			sy := math.Sin(q[1])
			// out = result
			(*out)[0] = sx * sx * common
			(*out)[1] = sx * sy * common
			(*out)[2] = sy * sy * common
		}
	}
	return bzone.VectorAvg(env.PointsPerSide, 2, 3, piInner)
}
func NewActivationFunction(name ActivationName) ActivationFunction {
	switch name {
	case ActivationName_LINEAR:
		return func(x mat64.Matrix, y *mat64.Dense) { y.Clone(x) }
	case ActivationName_LOGISTIC:
		return func(x mat64.Matrix, y *mat64.Dense) {
			y.Apply(func(r, c int, v float64) float64 {
				return 1 / (1 + math.Exp(-v))
			}, x)
		}
	case ActivationName_RELU:
		return func(x mat64.Matrix, y *mat64.Dense) {
			y.Apply(func(r, c int, v float64) float64 { return math.Max(0, v) }, x)
		}
	case ActivationName_TANH:
		return func(x mat64.Matrix, y *mat64.Dense) {
			y.Apply(func(r, c int, v float64) float64 { return math.Tanh(v) }, x)
		}
	case ActivationName_SOFTMAX:
		return func(x mat64.Matrix, y *mat64.Dense) {
			r, c := x.Dims()
			for i := 0; i < r; i++ {
				exp_sum := 0.0
				for j := 0; j < c; j++ {
					exp_sum = exp_sum + math.Exp(x.At(i, j))
				}
				for j := 0; j < c; j++ {
					y.Set(i, j, math.Exp(x.At(i, j))/exp_sum)
				}
			}
		}
	}
	return nil
}
Example #5
0
func innerMu_h(env *tempAll.Environment, k vec.Vector) float64 {
	sxy := math.Sin(k[0]) - math.Sin(k[1])
	numer := sxy * sxy * math.Tanh(env.Beta*env.Xi_h(k)/2.0)
	denom := env.Mu_b + 2.0*env.Xi_h(k)
	//denom := env.Mu_b - 2.0*env.Be_field*env.A + 2.0*env.Xi_h(k)
	return numer / denom
}
Example #6
0
// TanhKernel takes in a required Kappa modifier
// parameter (defaults to 1.0 if 0.0 given,) and
// optional float64 args afterwords which will be
// added together to create a constant term (general
// reccomended use is to just pass one arg as the
// constant if you need it.)
//
//     K(x, x`) = tanh(κx*x` + c)
//
// https://en.wikipedia.org/wiki/Hyperbolic_function
// https://en.wikipedia.org/wiki/Support_vector_machine#Nonlinear_classification
//
// Note that c must be less than 0 (if >= 0 default
// to -1.0) and κ (for most cases, but not all -
// hence no default) must be greater than 0
func TanhKernel(k float64, constants ...float64) func([]float64, []float64) float64 {
	if k == 0.0 {
		k = 1.0
	}

	var c float64
	if len(constants) != 0 {
		for _, val := range constants {
			c += val
		}
	}

	if c >= 0.0 {
		c = -1.0
	}

	return func(X []float64, x []float64) float64 {
		// don't throw error but fail peacefully
		//
		// returning "not at all similar", basically
		if len(X) != len(x) {
			return 0.0
		}

		var dot float64

		for i := range X {
			dot += k * X[i] * x[i]
		}

		return math.Tanh(dot + c)
	}
}
Example #7
0
func Tanh(x2 Audio) (x Audio) {
	var v Audio
	var v2 Audio
	var v3 Audio
	var v4 int
	v2 = x2
	v3 = x2
	x22 := len(v2)
	v4 = x22
	x3 := make(Audio, v4)
	x = x3
	v = x3
	for k := range v {
		var v5 = &v[k]
		var v6 *float64
		var v7 int
		var v8 float64
		var v9 float64
		v7 = k
		v6 = v5
		x4 := &v3[v7]
		v8 = *x4
		x5 := math.Tanh(v8)
		v9 = x5
		*v6 = v9
	}
	return
}
Example #8
0
func innerMu_h(env *tempAll.Environment, k vec.Vector) float64 {
	sxy := math.Sin(k[0]) - math.Sin(k[1])
	E := env.BogoEnergy(k)
	xi := env.Xi_h(k)
	delta := env.Delta_h(k)
	return sxy * sxy * math.Tanh(env.Beta*E/2.0) * (2.0*xi*xi + delta*delta) / (E * E * E)
}
func Expit(x float64) (out float64) {
	//return 1.0 / (1.0 + math.Exp(-1.0*x))
	out = 0.5 * x
	out = math.Tanh(out)
	out += 1.0
	out *= 0.5
	return out
}
Example #10
0
func (k *pluckedKey) release(loc geom.Point) {
	amp := math.Max(-6, math.Log2(math.Tanh(dist(loc, k.pressLoc)/64)))

	updateKeys(k.ratio)
	v := newPluckedTone(amp, math.Exp2(k.pitch))
	tones.Add(v)
	k.keyBase.voice = v
}
Example #11
0
func (Tanh) D2ActivateDCombination(sum, output float64) float64 {
	// http://www.wolframalpha.com/input/?i=1.14393+Sech[%282+x%29%2F3]^2
	// -1.52524 tanh(2/3 * x) * sech2(2/3 * x)
	// tanh^2 = 1 - sech^2
	tanh := math.Tanh(twoThirds * sum)
	sec2 := 1 - tanh*tanh
	return tanhHessConst * tanh * sec2
}
Example #12
0
// AddTagScore should be called for every tag occurrence in the database. The
// 'dist' argument refers to the number of days between the date that
// suggestions are being generated for and the date of the closest serving of
// the meal the tag is associated with.
func (s *Scorer) AddTagScore(tag string, dist int) {
	score, ok := s.tagScores[tag]
	if !ok {
		score = 1.0 // the default
	}

	score *= 0.1 + float32(math.Tanh(float64(dist)*0.2))
	s.tagScores[tag] = score
}
Example #13
0
func (k *bowedKey) move(loc geom.Point) {
	dx := dist(loc, k.moveLoc)
	dt := time.Now().Sub(k.moveTime).Seconds()
	amp := math.Max(-12, math.Log2(math.Tanh(dx/dt/128)))
	a := math.Pow(.999, 1/dt)
	k.amp = a*amp + (1-a)*k.amp
	k.voice.attack(k.amp)

	k.moveLoc = loc
	k.moveTime = time.Now()
}
Example #14
0
func TestMathTanh(t *testing.T) {
	// This is just an interface to Go's function, so just a quick simple test
	ctx := runtime.NewCtx(nil, nil)
	mm := new(MathMod)
	mm.SetCtx(ctx)
	val := 1.12
	ret := mm.math_Tanh(runtime.Number(val))
	exp := math.Tanh(val)
	if ret.Float() != exp {
		t.Errorf("expected %f, got %f", exp, ret.Float())
	}
}
Example #15
0
func (v *bowedTone) Sing() float64 {
	select {
	case targetAmp := <-v.ampChan:
		v.targetAmp = math.Max(v.targetAmp, targetAmp)
	default:
	}
	decay := 3.0 / 48000
	v.targetAmp -= decay
	da := 16.0 / 48000
	v.amp_ += math.Min(da, math.Max(-da, v.targetAmp-v.amp_))
	return math.Exp2(v.amp_) * math.Tanh(2*v.Osc.Sine())
}
Example #16
0
// Apply a forward pass with the identity activation function
// g(x) = tanh(x).
func (l TanhLayer) Forward(x []float32) ([]float32, error) {
	outputs, err := l.IdentityLayer.Forward(x)
	if err != nil {
		return nil, err
	}

	for idx, val := range outputs {
		outputs[idx] = float32(math.Tanh(float64(val)))
	}

	return outputs, nil
}
Example #17
0
func HyperTanFunction(x float64) float64 {

	// This function is used in neural network programming
	// as an activation function. Use this for neural nets
	// with range from -1 to 1

	if x < -20.0 {
		return -1.0 // approximation is correct to 30 decimals
	} else if x > 20.0 {
		return 1.0
	}

	return math.Tanh(x)
}
Example #18
0
func TestTanhKernelShouldPass3(t *testing.T) {
	k := TanhKernel(3, -16.0)

	// test different dot products which
	// should be valid

	assert.InDelta(t, math.Tanh(3.0-16.0), k([]float64{
		0.0, 1.0, 1.0, 0.0,
	}, []float64{
		0.0, 1.0, 0.0, 0.0,
	}), 5e-4, "Dot product should be valid")

	assert.InDelta(t, math.Tanh(18.0-16.0), k([]float64{
		15.0, 1.0, -1.0, 0.0,
	}, []float64{
		1.0, 1.0, 10.0, 0.0,
	}), 5e-4, "Dot product should be valid")

	assert.InDelta(t, math.Tanh(-252.0-16.0), k([]float64{
		15.0, 1.0, -1.0, 0.0,
	}, []float64{
		1.0, 1.0, 100.0, 0.0,
	}), 5e-4, "Dot product should be valid")
}
func NewDActivationFunction(name ActivationName) DActivationFunction {
	switch name {
	case ActivationName_LINEAR:
		return func(y mat64.Matrix, x *mat64.Dense) {
			x.Apply(func(r, c int, v float64) float64 { return 1 }, y)
		}
	case ActivationName_RELU:
		return func(y mat64.Matrix, x *mat64.Dense) {
			x.Apply(func(r, c int, v float64) float64 {
				if v <= 0 {
					return 0
				}
				return 1
			}, y)
		}
	case ActivationName_LOGISTIC:
		return func(y mat64.Matrix, x *mat64.Dense) {
			x.Apply(func(r, c int, v float64) float64 {
				logistic := 1 / (1 + math.Exp(-v))
				return logistic * (1 - logistic)
			}, y)
		}
	case ActivationName_TANH:
		return func(y mat64.Matrix, x *mat64.Dense) {
			x.Apply(func(r, c int, v float64) float64 {
				tanh := math.Tanh(v)
				return 1 - tanh*tanh
			}, y)
		}
	case ActivationName_SOFTMAX:
		return func(y mat64.Matrix, x *mat64.Dense) {
			// TODO(ariw): Finish this.
			r, c := y.Dims()
			for i := 0; i < r; i++ {
				exp_sum := 0.0
				for j := 0; j < c; j++ {
					exp_sum = exp_sum + math.Exp(y.At(i, j))
				}
				for j := 0; j < c; j++ {
					x.Set(i, j, math.Exp(y.At(i, j))/exp_sum)
				}
			}
		}
	}
	return nil
}
Example #20
0
func computeKernelValue(px, py []snode, param *Parameter) float64 {
	switch param.KernelType {
	case LINEAR:
		return dot(px, py)
	case RBF:
		q := dot(px, px) + dot(py, py) - 2*dot(px, py)
		return math.Exp(-param.Gamma * q)
	case POLY:
		q := param.Gamma*dot(px, py) + param.Coef0
		return math.Pow(q, float64(param.Degree))
	case SIGMOID:
		q := param.Gamma*dot(px, py) + param.Coef0
		return math.Tanh(q)
	case PRECOMPUTED:
		var idx_j int = int(py[0].value)
		return px[idx_j].value
	}

	return 0
}
Example #21
0
func (x Audio) Tanh(x2 Audio) (x3 Audio) {
	var v Audio
	var v2 Audio
	v2 = x2
	v = x
	x3 = x
	for k := range v2 {
		var v3 = &v2[k]
		var v4 int
		var v5 float64
		var v6 *float64
		var v7 float64
		v5 = *v3
		v4 = k
		x22 := &v[v4]
		v6 = x22
		x32 := math.Tanh(v5)
		v7 = x32
		*v6 = v7
	}
	return
}
Example #22
0
//Gives all particles magnetisation specified by the moment superposition model
func M_MSM(tmag, field float64) {
	r := rand.New(rand.NewSource(99))
	magnetisationcalled = true
	for i := range universe.lijst {
		volume := cube(universe.lijst[i].r) * 4. / 3. * math.Pi
		gprime := Alpha * gamma0 * mu0 / (1. + (Alpha * Alpha))
		delta := Ku1 * volume / (kb * Temp)
		msat := universe.lijst[i].msat
		hk := 2. * Ku1 / (msat * mu0)
		tau0 := gprime * hk * math.Sqrt(delta/math.Pi)
		tauN := 1. / tau0 * math.Exp(Ku1*volume/(kb*Temp)*(1.-0.82*msat*field*mu0/Ku1))
		x := volume * field * msat * mu0 / (kb * Temp)

		langevin := 1./math.Tanh(x) - 1./x

		M := langevin * (1. - math.Exp(-tmag/tauN))
		up := (2.*M + 1.) / (2.) //2.M because of random anisotropy axes
		if r.Float64() < up {
			universe.lijst[i].m = universe.lijst[i].u_anis
		} else {
			universe.lijst[i].m = universe.lijst[i].u_anis.times(-1.)
		}
	}
}
Example #23
0
func (self Tanh) Deriv(x float64) float64 {
	// 1 - Math.pow(Math.tanh(x),2)
	return 1 - math.Pow(math.Tanh(x), 2)
}
Example #24
0
// Logistic function: 1/(1+exp(-x)).
func Logistic(x float64) float64 {
	return .5 * (1 + math.Tanh(.5*x))
}
Example #25
0
func (v *pluckedTone) Sing() float64 {
	return math.Exp2(v.Amp.Sing()) * math.Tanh(2*v.Osc.Sine())
}
Example #26
0
func (t *Tones) Sing() float64 { return math.Tanh(t.MultiVoice.Sing() / 4) }
Example #27
0
func (p *Pane) update(dt float64) {
	for i := range p.droplets {
		d := &p.droplets[i]
		if d.x+d.r < 0 || d.x-d.r > p.fw || d.y+d.r < -0.4*p.fh || d.y-d.r > p.fh {
			d.init()
			d.x = rand.Float64() * p.fw
			d.y = (1.5*rand.Float64() - 0.4) * p.fh
		}
	}
	for i := range p.droplets {
		d := &p.droplets[i]
		d.lifetime += dt
		fx := 0.0
		fy := d.mass() * g

		cfx, cfy := p.coatForce(d.x/dx, d.y/dx, d.r/dx, d.h/dx)
		fx += cfx
		fy += cfy

		d.vx += dt * fx / d.mass()
		d.vy += dt * fy / d.mass()
		d.vx *= 1 - γ*dt
		d.vy *= 1 - γ*dt

		if v2 := d.vx*d.vx + d.vy*d.vy; v2 > maxv*maxv {
			v := maxv / math.Sqrt(v2)
			d.vx *= v
			d.vy *= v
		}

	}
	for i := range p.droplets {
		d := &p.droplets[i]
		d.x += dt * d.vx
		d.y += dt * d.vy
	}
	for i := range p.droplets {
		d := &p.droplets[i]
		for j := 0; j < i; j++ {
			d2 := &p.droplets[j]
			maxr := d.r
			if d2.r > maxr {
				maxr = d2.r
			}
			ddx := d2.x - d.x
			ddy := d2.y - d.y
			if math.Abs(ddx) > 0.5*maxr || math.Abs(ddy) > 0.5*maxr {
				continue
			}
			if ddx*ddx+ddy*ddy > 0.5*0.5*maxr*maxr {
				continue
			}

			dm := d.mass()
			d2m := d2.mass()
			d.x = (d.x*dm + d2.x*d2m) / (dm + d2m)
			d.y = (d.y*dm + d2.y*d2m) / (dm + d2m)
			maxh := d.h
			if d2.h > maxh {
				maxh = d2.h
			}
			d.r = math.Sqrt(d.r*d.r*d.h/maxh + d2.r*d2.r*d2.h/maxh)
			d.h = maxh

			if d2.vx*d2.vx+d2.vy*d2.vy >= d.vx*d.vx+d.vy*d.vy {
				d.lifetime = d2.lifetime
			}

			d2.init()
		}
	}
	for i, _ := range p.droplets {
		d := &p.droplets[i]
		spent := p.drawCoating(d.x/dx, d.y/dx, d.r/dx*0.7*math.Tanh(d.lifetime), d.h/dx)
		fac := math.Sqrt(d.vx*d.vx + d.vy*d.vy)
		d.h -= 0.04 * fac * spent / d.r / d.r / 2
		if d.h < d.r/10 {
			//oldh := d.h
			d.h = d.r / 10
		}
	}

	for i := range p.coat {
		p.coat[i] -= dissipation * dt * p.dirt[i]
		if p.coat[i] < 0 {
			p.coat[i] = 0
		}
	}

}
Example #28
0
func Tanh(x float64) float64 {
	return math.Tanh(x)
}
Example #29
0
func (self Tanh) Eval(x float64) float64 {
	return math.Tanh(x)
}
Example #30
0
// Inverse transverse mercator projection: Projection of an cylinder onto the surface of
// of an ellipsoid. Also known as reverse Gauss-Krüger projection. Input parameters:
//
//	pt *GeoPoint: Easting(Y) and Northing(X) of map point to be projected; in meters
//	latO, longO: Shifted origin of latitude and longitude in decimal degrees
//	fe, fn: False easting and northing respectively in meters
//	scale: Projection scaling; Dimensionless, typically 1 or little bellow
//
// This algorithm uses the algorithm described by Redfearn
// http://en.wikipedia.org/wiki/Transverse_Mercator:_Redfearn_series
//
// Taken from "OGP Publication 373-7-2 – Surveying and Positioning Guidance Note number 7, part 2 – November 2010",
// pp. 48 - 51
//
// More accurate, iterative but slower algorithmic implementation
func InverseTransverseMercator(pt *GeoPoint, latO, longO, scale, fe, fn float64) *PolarCoord {

	var gc PolarCoord

	el := pt.El

	latOrad := degtorad(latO)
	longOrad := degtorad(longO)

	f := 1 - el.b/el.a
	esq := math.Sqrt(2.0*f - f*f)

	n := f / (2.0 - f)
	B := (el.a / (1 + n)) * (1 + n*n/4.0 + n*n*n*n/64.0)

	var SO float64

	if latOrad != 0.0 {

		h1 := n/2.0 - (2.0/3.0)*n*n + (5.0/16.0)*n*n*n + (41.0/180.0)*n*n*n*n
		h2 := (13.0/48.0)*n*n - (3.0/5.0)*n*n*n + (557.0/1440.0)*n*n*n*n
		h3 := (61.0/240.0)*n*n*n - (103.0/140.0)*n*n*n*n
		h4 := (49561.0 / 161280.0) * n * n * n * n

		QO := math.Asinh(math.Tan(latOrad)) - (esq * math.Atanh(esq*math.Sin(latOrad)))
		bO := math.Atan(math.Sinh(QO))
		xiO0 := bO // math.Asin(math.Sin(bO))

		xiO1 := h1 * math.Sin(2.0*xiO0)
		xiO2 := h2 * math.Sin(4.0*xiO0)
		xiO3 := h3 * math.Sin(6.0*xiO0)
		xiO4 := h4 * math.Sin(8.0*xiO0)

		xiO := xiO0 + xiO1 + xiO2 + xiO3 + xiO4

		SO = B * xiO
	}

	h1i := n/2.0 - (2.0/3.0)*n*n + (37.0/96.0)*n*n*n - (1.0/360.0)*n*n*n*n
	h2i := (1.0/48.0)*n*n + (1.0/15.0)*n*n*n - (437.0/1440.0)*n*n*n*n
	h3i := (17.0/480.0)*n*n*n - (37.0/840.0)*n*n*n*n
	h4i := (4397.0 / 161280.0) * n * n * n * n

	etai := (pt.X - fe) / (B * scale)
	xii := ((pt.Y - fn) + scale*SO) / (B * scale)

	xi1i := h1i * math.Sin(2*xii) * math.Cosh(2*etai)
	xi2i := h2i * math.Sin(4*xii) * math.Cosh(4*etai)
	xi3i := h3i * math.Sin(6*xii) * math.Cosh(6*etai)
	xi4i := h4i * math.Sin(8*xii) * math.Cosh(8*etai)

	eta1i := h1i * math.Cos(2*xii) * math.Sinh(2*etai)
	eta2i := h2i * math.Cos(4*xii) * math.Sinh(4*etai)
	eta3i := h3i * math.Cos(6*xii) * math.Sinh(6*etai)
	eta4i := h4i * math.Cos(8*xii) * math.Sinh(8*etai)

	xi0i := xii - (xi1i + xi2i + xi3i + xi4i)
	eta0i := etai - (eta1i + eta2i + eta3i + eta4i)

	bi := math.Asin(math.Sin(xi0i) / math.Cosh(eta0i))

	Qi := math.Asinh(math.Tan(bi))
	Qiiold := Qi + (esq * math.Atanh(esq*math.Tanh(Qi)))
	Qii := Qi + (esq * math.Atanh(esq*math.Tanh(Qiiold)))

	for math.Abs(Qiiold-Qii) > 1e-12 {
		Qiiold = Qii
		Qii = Qi + (esq * math.Atanh(esq*math.Tanh(Qiiold)))
	}

	gc.Latitude = radtodeg(math.Atan(math.Sinh(Qii)))
	gc.Longitude = radtodeg(longOrad + math.Asin(math.Tanh(eta0i)/math.Cos(bi)))

	gc.El = el

	return &gc
}