% pdiag.sty		Style for drawing permutation diagrams
%
% coded by Jason B. Hill (Jason.B.Hill@Colorado.edu)
%
%	This package attempts to provide an environment for drawing permutation diagrams,
%	with no claim that it works well, or works at all. Usage is designed to be as
%	the following example indicates:
%
%	\begin{pdiag}[scale(defauult=1)]{#vertices}{#maps}
%		\pdiagmap{domain vertex}{image vertex}
%		\pdiagendmap
%	\end{pdiag}
%
%	Concrete example:
% 	\begin{pdiag}[1.5]{5}{2}				% Diagram is 5 vertices wide and 2 rows/maps tall
								% - Scale is 1.5 (1.5 times usual scale)
%		\pdiagname{$\alpha$}				% Optional command to name a row (label at left)
								% - \pdiagname[0]{$\alpha$} same as above, but on right
%		\pdiagmap{2}{3}					% First map sends 2 to 3
%		\pdiagmap[0]{3}{2}				% First map sends 3 to 2 (optional [0] draws a line instead of bezier)
%		\pdiagendmap					% End first row/map
%		\pdiagbump{-0.8}{-0.5}\pdiagmap{1}{4}		% Second map sends 1 to 4
								% The optional \pdiagbump command is called before a map to modify the bezier
								% - curves for that map. The first argument controls the bezier as it enters the
								% - domain, while the second argument controls the bezier as it enters the image.
								% - The range of values -1 to 1 correspond to forcing the bezier closer to the
								% - domain and image, repsectively. In this case, -0.8 value will keep the bezier
								% - high as it leaves the domain, the -0.5 value will keep the bezier high again
								% - before it finally drops to the image. 
%		\pdiagmap{2}{3}					% Second map sends 2 to 3 
%		\pdiagmap{3}{1}					% Second map sends 3 to 1
%		\pdiagmap{4}{2}					% Second map sends 4 to 2
%		\pdiagendmap
%	\end{pdiag}
%	
%
\RequirePackage{ifthen,calc,fp} %
\ProvidesPackage{pdiag} %
%
%
%
%
%
\newcommand{\pdiagmap}[3][1] % Draw permutation line between points, create dots at points
{	% A LaTeX Picture bezier is defined on three points, we'll use two beziers here
	%
	% (opional) #1=1 (default) then draw a bezier curve, #1\neq 1 then draw a straight line
	%	The options on how to form the bezier curve are given by the - command
	% #2 is the x-coordinate of the domain for a permutation map
	% #3 is the x-coordinate of the image for a permutation map
	%
	% determine if bezier should be a straight line
	\ifthenelse{\equal{#1}{1}}{}{
		\def\@pdiagbyshift{}\FPset{\pdiagbyshift}{0.1}\def\@pdiagdyshift{}\FPset{\pdiagdyshift}{1.9} %
		\def\@pdiagcyshift{}\FPadd{\pdiagcyshift}{\pdiagbyshift}{\pdiagdyshift}\FPdiv{\pdiagcyshift}{\pdiagcyshift}{2} % 
		\FPclip{\pdiagbyshift}{\pdiagbyshift}\FPclip{\pdiagcyshift}{\pdiagcyshift}\FPclip{\pdiagdyshift}{\pdiagdyshift} % 
	} %
	%
	\def\@pdiagxa{}\FPset{\pdiagxa}{#2} % Set initial x-coord
	\def\@pdiagya{}\FPset{\pdiagya}{\thepdiagthisrow} % Set initial y-coord
	\def\@pdiagxe{}\FPset{\pdiagxe}{#3} % Set terminal x-coord
	\def\@pdiagye{}\FPset{\pdiagye}{\thepdiagnextrow} % Set terminal y-coord
	%
	% count the initial x-coord in the vertex list (unused vertices per row have automatic lines drawn)
	% add a \pdiagxa^{th} power of ten to \pdiagrowassign
	\def\@pdiagtenpow{}\FPset{\pdiagtenpow}{2}\FPpow{\pdiagtenpow}{\pdiagtenpow}{\pdiagxa}\FPclip{\pdiagtenpow}{\pdiagtenpow} %
	\FPround{\pdiagtenpow}{\pdiagtenpow}{\thepdiagcolnum}\FPclip{\pdiagtenpow}{\pdiagtenpow} %
	\FPadd{\pdiagrowassign}{\pdiagrowassign}{\pdiagtenpow}\FPclip{\pdiagrowassign}{\pdiagrowassign} %
	%
	% put a bullet at the endpoints
	\put(\pdiagxa,\pdiagya){\circle*{0.2}}
	\put(\pdiagxe,\pdiagye){\circle{0.2}}
	%
	% calculate other points for use in beziers
	% reset endpoints so they do not overlap dots (only need to change y-coordinate)
	\ifthenelse{\equal{#1}{1}}
	{ % drawing a standard bezier
		\FPsub{\pdiagya}{\pdiagya}{0.1}\FPadd{\pdiagye}{\pdiagye}{0.1} %
	}{} % drawing a line
	% find point b (second point in bezier from top)
	\def\@pdiagxb{}\FPset{\pdiagxb}{\pdiagxa} % x-coord same as with point a
	\def\@pdiagyb{}\FPset{\pdiagyb}{\pdiagya}\FPsub{\pdiagyb}{\pdiagyb}{\pdiagbyshift} %
	% find point d (fourth point in bezier from top)
	\def\@pdiagxd{}\FPset{\pdiagxd}{\pdiagxe} % x-coord same as with point a
	\def\@pdiagyd{}\FPsub{\pdiagyd}{2}{\pdiagdyshift}\FPadd{\pdiagyd}{\pdiagyd}{\pdiagye} %
	% find point c (midpoint in bezier)
	\def\@pdiagxc{}\FPadd{\pdiagxc}{\pdiagxa}{\pdiagxe}\FPdiv{\pdiagxc}{\pdiagxc}{2}\FPclip{\pdiagxc}{\pdiagxc} % x-coord between x-coords for a and e
	\def\@pdiagyc{}\FPadd{\pdiagyc}{\pdiagyb}{\pdiagyd}\FPdiv{\pdiagyc}{\pdiagyc}{2}\FPclip{\pdiagyc}{\pdiagyc} % y-coord between y-coords for b and d
	% draw beziers
	\ifthenelse{\equal{#1}{1}}
	{ % drawing a standard bezier
		\qbezier(\pdiagxa,\pdiagya)(\pdiagxb,\pdiagyb)(\pdiagxc,\pdiagyc) %
		\qbezier(\pdiagxc,\pdiagyc)(\pdiagxd,\pdiagyd)(\pdiagxe,\pdiagye) %
	}{ % drawing a line
		\qbezier(\pdiagxa,\pdiagya)(\pdiagxa,\pdiagya)(\pdiagxc,\pdiagyc) %
		\qbezier(\pdiagxc,\pdiagyc)(\pdiagxe,\pdiagye)(\pdiagxe,\pdiagye) %
	} %
	% reset default bezier shift values
	\def\@pdiagbyshift{}\FPset{\pdiagbyshift}{0.6}\def\@pdiagdyshift{}\FPset{\pdiagdyshift}{1.4} % set default shift values for 2nd and 4th points in bezier curves
	\def\@pdiagcyshift{}\FPadd{\pdiagcyshift}{\pdiagbyshift}{\pdiagdyshift}\FPdiv{\pdiagcyshift}{\pdiagcyshift}{2} % set shift value for middle point in bezier curve
	\FPclip{\pdiagbyshift}{\pdiagbyshift}\FPclip{\pdiagcyshift}{\pdiagcyshift}\FPclip{\pdiagdyshift}{\pdiagdyshift} % make shift values readable
} %
%
%
%
%
%
%% ---------------------------- Command to fill all dots in diagram
% ---------------------------- Command to edit bezier parameters
\newcommand{\pdiagbump}[2] % If called (optional) then drag 2nd and 4th points of bezier curve
{	% Entry values will be integers
	% -1 is as close to the top row as possible
	% 1 is as close to the bottom row as possible
	\def\@pdiagbyshift{}\FPset{\pdiagbyshift}{#1}\def\@pdiagdyshift{}\FPset{\pdiagdyshift}{#2} % set default shift values for 2nd and 4th points in bezier curves
	\FPmul{\pdiagbyshift}{\pdiagbyshift}{0.9}\FPadd{\pdiagbyshift}{\pdiagbyshift}{1} %
	\FPmul{\pdiagdyshift}{\pdiagdyshift}{0.9}\FPadd{\pdiagdyshift}{\pdiagdyshift}{1} %
	\def\@pdiagcyshift{}\FPadd{\pdiagcyshift}{\pdiagbyshift}{\pdiagdyshift}\FPdiv{\pdiagcyshift}{\pdiagcyshift}{2} % set shift value for middle point in bezier curve
	\FPclip{\pdiagbyshift}{\pdiagbyshift}\FPclip{\pdiagcyshift}{\pdiagcyshift}\FPclip{\pdiagdyshift}{\pdiagdyshift} % make shift values readable
} %
% ---------------------------- Command to edit bezier parameters
%
%
%
%
%
% ---------------------------- Command to fill all dots in diagram
\newcommand{\pdiagfill} % If called (optional) then fill all dots in the corresponding diagram
{	%
	\setcounter{pdiagi}{\value{pdiagcolnum}-1} % counter to iterate over columns
	\whiledo{\value{pdiagi}>0} { % iterate from right to left on columns, drawing a bullet at top and bottom rows
		\setcounter{pdiagj}{\value{pdiagrownum}} % counter to iterate over rows
		\whiledo{\value{pdiagj}>-1} {
			\put(\value{pdiagi},\value{pdiagj}){\circle*{0.2}} %
			\setcounter{pdiagj}{\value{pdiagj}-2} %
		} %
		\setcounter{pdiagi}{\value{pdiagi}-1} %
	} %
} %
% ---------------------------- End command to fill all dots in diagram
%
%
%
%
% ---------------------------- Command to end a row and draw lines representing unmapped vertices
\newcommand{\pdiagendmap}
{ %
	\setcounter{pdiagi}{\value{pdiagcolnum}-1} % counter to iterate over columns
	%\FPsub{\pdiagrowassign}{\pdiagrowassign}{1}\FPclip{\pdiagrowassign}{\pdiagrowassign}
	\whiledo{\value{pdiagi}>0} { % iterate from right to left on columns, drawing a bullet at top and bottom rows
		\setcounter{pdiagj}{\value{pdiagi}+1} % set counter for rounding
		\def\@pdiagtens{}\FPpow{\pdiagtens}{2}{\thepdiagi}\FPround{\pdiagtens}{\pdiagtens}{\thepdiagj} %
		\FPsub{\pdiagtens}{\pdiagtens}{1}\FPclip{\pdiagtens}{\pdiagtens} % power of ten to check
		\ifthenelse{\pdiagtens<\pdiagrowassign}
			{ % \pdiagi has a line from it already
				\whiledo{\pdiagtens<\pdiagrowassign}{ % possible that a vertex has more than one map associated with it?
					\FPsub{\pdiagrowassign}{\pdiagrowassign}{\pdiagtens} %
					\FPsub{\pdiagrowassign}{\pdiagrowassign}{1} %
					\FPclip{\pdiagrowassign}{\pdiagrowassign} %
					% do nothing
				} %
			} %
			{ % draw a line from vertex \pdiagi and draw empty dots
				\def\@pdiagxa{}\FPset{\pdiagxa}{\thepdiagi} % Set initial x-coord
				\def\@pdiagya{}\FPset{\pdiagya}{\thepdiagthisrow}
				\put(\pdiagxa,\pdiagya){\circle{0.2}} %
				\FPsub{\pdiagya}{\pdiagya}{0.1} % Set initial y-coord
				\def\@pdiagxe{}\FPset{\pdiagxe}{\thepdiagi} % Set terminal x-coord
				\def\@pdiagye{}\FPset{\pdiagye}{\thepdiagnextrow}
				\put(\pdiagxe,\pdiagye){\circle{0.2}} %
				\FPadd{\pdiagye}{\pdiagye}{0.1} % Set terminal y-coord
				\qbezier(\pdiagxa,\pdiagya)(\pdiagxa,\pdiagya)(\pdiagxe,\pdiagye) %
			} %
		\setcounter{pdiagi}{\value{pdiagi}-1} %
	} %
	\setcounter{pdiagthisrow}{\value{pdiagthisrow}-2} %
	\setcounter{pdiagnextrow}{\value{pdiagnextrow}-2} %
	\FPset{\pdiagrowassign}{0} % reset count to zero for vertices
}%
% ---------------------------- End command to end a row and draw lines representing unmapped vertices
%
%
%
%
% ---------------------------- Command to label a permutation
\newcommand{\pdiagname}[2][1] % If called (optional), puts the name #2 at the side of the row
{	% if #1=1 then place label #2 at left side, otherwise at right side
	\setcounter{pdiagk}{\value{pdiagthisrow}-1} %
	% \put(0,\value{pdiagk}){\footnotesize{#2}} %
	\ifthenelse{\equal{#1}{1}}{\put(0,\value{pdiagk}){#2}}{\put(\value{pdiagcolnum},\value{pdiagk}){\hspace{-5pt}#2}} %

} %
% ---------------------------- End command to label a permutation
%
%
%
%
% ---------------------------- Main Environment Definition
\newenvironment{pdiag}[3][1]
{	% Creates a picture environment with scale #1*1cm
	% #2 is the width of the diagram (add a column on each side for labels, etc.)
	% #3 is the height of the diagram (given in number of permutations, add empty rows between rows for readability)
	\@ifundefined{c@pdiagi}{\newcounter{pdiagi}\newcounter{pdiagj}\newcounter{pdiagk}}{} % supply generic counters
	\@ifundefined{c@pdiagcolnum}{\newcounter{pdiagcolnum}\newcounter{pdiagrownum}}{} %
	\@ifundefined{c@pdiagthisrow}{\newcounter{pdiagthisrow}\newcounter{pdiagnextrow}}{} % Define a counter to keep track of iteration dimensions
	\setcounter{pdiagcolnum}{#2+1} % Define a counter to keep track of overall column dimension 
	\setcounter{pdiagrownum}{#3*\real{2}} % Define a counter to keep track of overall row dimension	
	\setcounter{pdiagthisrow}{#3*\real{2}} % initial count for thisrow
	\setcounter{pdiagnextrow}{#3*\real{2}-2} % initial count for nextrow skip rows
	\def\@pdiagbyshift{}\FPset{\pdiagbyshift}{0.6}\def\@pdiagdyshift{}\FPset{\pdiagdyshift}{1.4} % set default shift values for 2nd and 4th points in bezier curves
	\def\@pdiagcyshift{}\FPadd{\pdiagcyshift}{\pdiagbyshift}{\pdiagdyshift}\FPdiv{\pdiagcyshift}{\pdiagcyshift}{2} % set shift value for middle point in bezier curve
	\FPclip{\pdiagbyshift}{\pdiagbyshift}\FPclip{\pdiagcyshift}{\pdiagcyshift}\FPclip{\pdiagdyshift}{\pdiagdyshift} % make shift values readable
	\def\@pdiagrowassign{}\FPset{\pdiagrowassign}{0} % for each row, keep track of vertices used
\setlength{\unitlength}{0.5cm*\real{#1}} %
\begin{array}{c}\begin{picture}(\thepdiagcolnum,\thepdiagrownum) %
	% start by drawing the initial dots at the top/bottom of the diagram
	\setcounter{pdiagi}{\value{pdiagcolnum}-1} %
	\whiledo{\value{pdiagi}>0} { % iterate from right to left on columns, drawing an empty bullet at top and bottom rows
			\put(\value{pdiagi},\value{pdiagrownum}){\circle{0.2}} %
			\put(\value{pdiagi},0){\circle{0.2}} %
			\setcounter{pdiagi}{\value{pdiagi}-1} %
		} %
}{\end{picture}\end{array}} %
% ---------------------------- End Main Environment Definition