# A. Galligo and M. van Hoeij
#
# Version 0.01,  Jan 2007.

# Weaknesses in current version:
#
#   Program is slow, and if epsilon, the size of the errors in the
#   coefficients, is not small then the result may depend on the
#   projection used (i.e. interchanging x, y may change the result).  A
#   more sophisticated look at the monodromy data would give better
#   quality results even for relatively large epsilon (in particular,
#   if we have 3 nearby branchpoints, the code should consider triples
#   of branchpoints, instead of only pairs which it does at the moment).
#
#   Reconstruction of factors from the monodromy information is not yet
#   implemented, so the only information obtained inside the program is
#   the number of factors and the degree and genus of each factor (and of
#   this information, the only thing returned in the output is whether or
#   not the monodromy was transitive).


# Some macro's needed for the programs below:
macro(
	invperm = group[invperm],
	orbit = group[orbit]
):

mp := proc(a,b)
	options remember;
	if nargs=2 then
		group[mulperms](b,a)
	else
		mp(a,mp(args[2..-1]))
	fi
end:

# Input: M, the output of algcurves[monodromy].
# Note:  M[1] = basepoint.
#        M[2] = fiber above the basepoint
#        M[3] = list of branchpoints with permutations.
#
# p,q: two integers 1 < p < q < nops(M[3]) representing the
# branchpoints M[3][p] and M[3][q].
#
# Return true if the shortest path around p,q has permutation = [].
#
MatchingPermutations := proc(M,p,q)
	local g,i;
	g := [];
	for i in PointsInTriangle(M,p,q) do
		g := mp(M[3,i,2], g)
	od;
	evalb( [] = mp(invperm(g), M[3,q,2], g, M[3,p,2]) )
end:

# Find the points inside the triangle basepoint-p-q
#
PointsInTriangle := proc(M,p,q)
	options remember;
	local L,t,i;
	# The line through p and q:
	L := t * M[3,p,1] + (1-t) * M[3,q,1];
	[seq(`if`(Im(solve(L=M[1],t))*Im(solve(L=M[3,i,1],t)) > 0,
	i, NULL), i=p+1..q-1)]
end:

# M = monodromy
# P = the subset of {1,2,..nops(M[3])} that we keep
# Check if the monodromy is transitive with those points P.
#
TransitiveGroup := proc(M, P)
	local G,i;
	G := permgroup(nops(M[2]), {seq(M[3,i,2], i=P)});
	evalb( nops(orbit(G, 1)) = nops(M[2]) )
end:

ConjugatePerm := proc(s, g)
	mp(invperm(g), s, g)
end:

TransitiveMonodromy := proc(F, x, y)
	local Fr, M, S, p, q, d, P, M_upd, i, TR, per, j, u;
	# Round coefficients to integers.
	Fr := primpart(collect(expand(10^5*F),{x,y},round));

	M := algcurves[monodromy](Fr,x,y);

	# For some reason this goes slow without the line "if d > ..."\
	# even though it should be a trivial computation:
	S := NULL;
	for p to nops(M[3])-1 do for q from p+1 to nops(M[3]) do
		d := abs(M[3,p,1]-M[3,q,1]);
		if d > 0.3 then next fi;
		if MatchingPermutations(M,p,q) then
			S := S, [p,q, d]
		fi
	od od:

	S := sort([S], (i,j) -> i[3]< j[3]);
	nops(S);

	# Now we can start throwing away grouped branchpoints, and we'll
	# stop as soon as the group becomes reducible.

	P := {seq(i,i=1..nops(M[3]))};
	M_upd := M: # M with updated permutations

	for i in S while TransitiveGroup(M_upd,P) do
		if not (member(i[1],P) and member(i[2],P)) then
			# already threw i[1] or i[2] away, can't do it again:
			next
		fi;
		P := P minus {i[1],i[2]};
		TR := PointsInTriangle(M,i[1],i[2]);
		per := M_upd[3,i[1],2];
		for j from i[1]+1 to i[2]-1 do if member(j,P) then
			if member(j, TR) then
				per := ConjugatePerm(per, invperm(M_upd[3,j,2]))
			else
				u := ConjugatePerm( M_upd[3,j,2], per);
				M_upd := subsop(3 = subsop(j =
				  [M_upd[3,j,1], u], M_upd[3]), M_upd)
			fi
		fi od;
		if per <> M_upd[3,i[2],2] then
			error nonmatch
		fi;
	od:

	TransitiveGroup(M_upd,P)
end:
