"""A partially successful attempt at a multidimensional scaling routine."""

import Numeric as Num
import nice_hash
import sys
import math
import RandomArray
import random
import die


N = 4
NP = 5
c = None
SIGMA = 0.1


try:
	enumerate([])
except NameError:
	from g_enumerate import enumerate



_h = nice_hash.nice_hash(lambda x:x)
_rmap = None
_dbar = None

def init(arglist):
	while len(arglist)>0 and arglist[0].startswith('-'):
		arg = arglist.pop(0)
		if arg == '-sigma':
			sig = arglist.pop(0)
			if sig is None or sig=='':
				SIGMA = None
			else:
				SIGMA = float(sig)
		elif arg == '-n':
			N = int(arglist.pop(0))
			NP = 2*N-3
		elif arg == '--':
			break
		else:
			die.die('Unrecognized flag: %s' % arg)

	tmp = []
	for l in sys.stdin.readlines():
		if l.startswith('#'):
			continue
		if l.strip() == '':
			continue
		a = l.strip().split()
		if len(a) != 3:
			die.die('Need three fields per line')
		tmp.append( a )
	tmp.sort()
	global c
	c = []
	ds = 0.0
	nd = 0
	for a in tmp:
		i = _h.add(a[0].strip())
		j = _h.add(a[1].strip())
		d = float(a[2])
		c.append( (i, j, d) )
		ds += d
		nd += 1
	global _rmap, _dbar
	_rmap = _h.classmap()
	# print 'RMAP', _rmap
	_dbar = ds/nd
	sys.stdout.write('# iteration point_id point x y\n')
	return sys.stdout
	


def log(logptr, i, p, wt):
	sigma, swapper, pts = unpack(p)
	# print 'LOG', sigma, swapper
	for (j, (x, y)) in enumerate(pts):
		logptr.write('%d %d %s %f %f\n' % ( i, j, _rmap[j], x, y ))
	logptr.write('# sigma= %g\n' % sigma)
	logptr.flush()



def start(arglist):
	NS = 30
	o = []
	mu = Num.zeros((NP,), Num.Float)
	sig = Num.identity(NP) * _dbar
	for i in range(NS):
		rp = RandomArray.multivariate_normal(mu, sig)
		if SIGMA is None:
			o.append( Num.concatenate( ([random.expovariate(5.0/_dbar),
							random.uniform(-1.0, 1.0)
							],
							rp) ) )
		else:
			o.append( Num.concatenate( ([ random.uniform(-1.0, 1.0) ],
						rp
						) ) )
	# print '# LEN(o)=', len(o)
	# for t in o:
		# print 'o:', t
	return o



def V(st):
	if SIGMA is None:
		tmp =  _dbar*Num.identity(NP+2)
		tmp[1,1] = 1.0
		return tmp
	tmp = _dbar*Num.identity(NP+1)
	tmp[0,0] = 1.0
	return tmp



def unpack_guts(p, swap):
	assert N == 4
	tmp = [ Num.array((0.0, p[0])),
		Num.array((p[3], p[4])),
		Num.array((p[1], p[2])),
		Num.array((0.0, -p[0]))
		]
	if swap:
		tt = tmp[1]
		tmp[1] = tmp[2]
		tmp[2] = tt

	sum = Num.array((0.0, 0.0), Num.Float)
	for t in tmp:
		sum += t
	sum /= len(tmp)
	for i in range(N):
		tmp[i] -= sum

	flipy = p[0] < 0
	flipx = p[1]+p[3] > 0
	flip = 1-2*Num.array((flipx, flipy), Num.Int)

	# print 'UP', tmp
	# print 'UPF', flipx, flipy, flip
	# print 'UPf', [t*flip for t in tmp]

	return [ t * flip for t in tmp ]



def unpack(p):
	if SIGMA is None:
		assert len(p) == NP+2
		return (p[0],
			p[1],
			unpack_guts(p[2:], p[1]>0.0)
			)
	assert len(p) == NP+1
	return (SIGMA*_dbar,
		p[0],
		unpack_guts(p[1:], p[0]>0.0)
		)
	





def logp(p, c):
	"""c = [ (i, j, dij), ... ]"""
	sigma, swapper, coord = unpack(p)
	# print 'LOGP', sigma, swapper
	if sigma <= 0.0:
		# print 'NEG SIG', p
		return None
	model = []
	for (i, j, dij) in c:
		dc = math.sqrt(Num.sum((coord[i]-coord[j])**2))
		model.append( (i, j, dc) )
	mlogp = 0.0
	for ((i, j, dij), (ii, jj, dc)) in zip(c, model):
		assert i==ii and j==jj
		# print 'Ci', coord[i]
		# print 'Cj', coord[j]
		# print 'd', i, j, dc, dij, 'sigma:', sigma
		# print 'Ch', (dc - dij)**2, (2*sigma**2), math.log(sigma)
		# print 'dmlogp', (dc - dij)**2/(2*sigma**2) + math.log(sigma)
		# mlogp += ((dc - dij)**2)/(2*(sigma**2)) + math.log(sigma)
		mlogp += (abs(dc - dij))/sigma + math.log(sigma)
	# print 'mlogp', -mlogp, swapper, swapper**2
	mlogp += swapper**2
	return -mlogp


NI = 1000

STARTLOW = 1

def finish(p, v, stdout):
	pass
