#@###########################################################################
#
# mtex:                      MAPLE ===> TeX
#      ___________________________________________________________________
#
#	     Copyright (c) 1993 by Yunliang Yu. All rights reserved.
#
#	This package may be freely distributed for non-profit purposes 
#	only. It may be modified as long as no modified version is
#	distributed and the copyright notice is retained. The author 
#	is not responsible for any damage caused by using this package.
#
#	This package is revised in Maple V release 2 and it requires maple 4.2 
#	or higher; the procedure "clct" does not work under maple 4.2 because 
#	of the definition of "collect".
#
#	Please send bug reports, comments and ideas to yu@math.duke.edu
#      ___________________________________________________________________
#
# Main Features:
# -------------
#	1). typesetting in AmS-TeX, LaTeX or Plain TeX,
#	2). automatic line-breaking,
#	3). multi-level sorting,
#	4). name and index substitutions.
#
# Deficiencies:
# ------------
#       1). no automatic line-breaking for matrices or quotients
#       2). general tables are not implemented yet
#
# Procedures Available:
# -------------------
#	The user-level procedures are: 
#		
#		mtex, stex, tex, rlms, clct, test
#
# For Help:
# --------
# 	See ?TeX, ?TeX[usage] and ?TeX[example].
#@###########################################################################
tex_file:=`mtex: 3/19/91, mtex5 8/20/91, 10/19/91, mtex, 6/7/93,8/10/93`:
tex_date:=`$Id: mtex,v 1.22 1993/08/11 13:10:38 yu Exp yu $`:
`help/text/TeX` := TEXT(
`   `,
`mtex:                       MAPLE ===> TeX`,
`      ___________________________________________________________________`,
`   `,
`            Copyright (c) 1993 by Yunliang Yu. All rights reserved.`,
`   `,
`        Please send bug reports, comments and ideas to yu@math.duke.edu`,
`   `,
`Main Features:`,
`=============`,
`       1). typesetting in AmS-TeX, LaTeX or Plain TeX,`,
`       2). automatic line-breaking,`,
`       3). multi-level sorting,`,
`       4). name and index substitutions.`,
`   `,
`Main Deficiencies:`,
`=================`,
`       1). no automatic line-breaking for matrices or quotients`,
`       2). general tables are not implemented yet`,
`   `,
`Procedures Available:`,
`====================`,
`   `,
`               mtex, stex, tex, rlms, clct, test`,
`   `,
`SEE ALSO: ?TeX[usage], ?TeX[example].`,
`  `,
`VERSION: $Id: mtex,v 1.22 1993/08/11 13:10:38 yu Exp yu $`,
`   `
):
`help/TeX/text/usage` := TEXT(
`   `,
`Usages of User-level Procedures in the TeX Package:`,
`==================================================`,
`   `,
` mtex(expr,<options>);`,
` --------------------`,
`       This procedure is used to typeset a Maple expression in TeX.`,
`   `,
`       <options> can be any of the following in any order:`,
`               1). One of the names {amstex,latex,plain}.`,
`                       It tells the program to typeset expr in the format `,
`                   of AmS-TeX, LaTeX or Plain TeX. `,
`                       The main purpose of this option is to let one switch `,
`                   from one format to another. One does not need to call `,
`                   this option in subsequent usages of the same format.`,
`                       The default is LaTeX if one never uses this option.`,
`               2). A string, which tells mtex to save the output to a file `,
`                   named after this string, string.tex.`,
`               3). A negative number to turn off the `,
`                   auto-line-breaking.`,
`   `,
`       There are some environment variables which affect the behavior of `,
`       this procedure, see tex() below.`,
`   `,
` stex(expr,<options>);`,
` --------------------`,
`       This procedure is used to sort and typeset an expression.`,
`   `,
`       In this procedure, we use multi-level sorting which means that we`,
`       first sort an expression by an ordering in one set of variables,`,
`       then we sort the result by another ordering in a different set of`,
`       variables and so on. For a general idea of sorting, try out the `,
`       procedure "sort" on polynomials.`,
`   `,
`       An ordering here is given by a sequence of lists of the form:`,
`               [x1,x2,...,xn,order1],[y1,...,ym,order2],...`,
`       where order.i can be any of {plex,rlex,tdeg,rdeg}; the default`,
`       ordering on any list of variables is tdeg if order.i is missing.`,
`   `,
`       Its <options> are:`,
`               1). The <options> of mtex().`,
`               1). Any number of lists for the ordering.`,
`   `,
` tex(expr);`,
` ---------   `,
`       This is the core of this package. It does all the basic typesetting `,
`       and computes the 'length' of expr.`,
`   `,
`       One does NOT call this procedure directly. It is needed only in the`,
`       subprocedures for typesetting maple expressions.`,
`   `,
`       A user can tell tex how to format a particular function by`,
`       defining a procedure 'tex/<func>' where <func> is the`,
`       function name to be formatted. This procedure needs to`,
`       return the TeXed sequence and also inform the TeX package`,
`       the TeXed length. See the procedure ``tex/SetOps`` for an example.`,
`   `,
`       Environmental variables for this package:`,
`               1). texwid:=60:`,
`                       texwid is the maximum 'length' of a TeXed line. It is`,
`                       used to determine where to break a long line.`,
`                       The default is 60. One can assign it to any value.`,
`               2). texsub:={n1=e1,n2=e2,....}:`,
`                       texsub is a set to hold all the name substitutions.`,
`                       The default is texsub:={}.`,
`               3). texidx:={n1=e1,n2=e2,....}:`,
`                       This is a set to hold the index substitutions.`,
`                       The default is texidx:={}.`,
`               4). texvar:=[x1,x2,...,xn,order1],[y1,...,ym,order2],...:`,
`                       texvar holds the orderings one has given in stex().`,
`   `,
` rlms(expr);`,
` ----------`,
`       This one is simple; its function is to remove the leading ``-`` sign`,
`       in any subexpression of type ``+`` to make things look good in TeX.`,
`   `,
` clct(expr,<option>);`,
` -------------------`,
`       This is a multilevel collect procedure.`,
`   `,
`       <option> can be a sequence of lists as in stex(). If <option> is not`,
`       given, it uses the lists one has used in stex(). This function is `,
`       called in stex().`,
`   `,
` test(file,<option>);`,
` -------------------`,
`       It generates a complete TeX file file.tex for testing purposes.`,
`   `,
`       file is the name of the output file, if ommitted, it uses the`,
`       standard output. <option> can be: plain, latex or amstex`,
`   `,
`       After invoking it, you type all the stuff you want and type exit; to`,
`       quit.   `,
`   `,
`SEE ALSO: ?TeX, ?TeX[example].`,
`   `
):
`help/TeX/text/example` := TEXT(
`   `,
`Some Examples of the TeX Package:`,
`================================`,
`   `,
`> mtex((-5*a^3*b*(4*c-d*(e-f)))-sin(x)^5-9*(m[p,q]-n[5])^6+15+(-1)^g,latex);`,
`$ -5\\,a^3\\,b\\left(4\\,c-d\\,(e-f)\\right) - \\sin(x)^5 - 9\\,(m_{p,q}-n_{5}`,
`)^6 + 15 + (-1)^{g} $`,
`> expand((3*a^3-m*sin(x)-sqrt(d))^5):`,
`> mtex(");   `,
`\\begin{eqnarray*} && 15\\,m^4\\,\\sin(x)^4\\,a^3 + 270\\,m^2\\,\\sin(x)^2\\,a^`,
`9 - 90\\,m^3\\,\\sin(x)^3\\,a^6 \\\\ &&\\quad\\mbox{} - 5\\,m^4\\,\\sin(x)^4\\,`,
`\\sqrt{d} - 10\\,m^3\\,\\sin(x)^3\\,d - 10\\,m^2\\,\\sin(x)^2\\,d^{3/2}`,
` \\\\ &&\\quad\\mbox{} - 405\\,m\\,\\sin(x)\\,a^{12} - 5\\,m\\,\\sin(x)\\,d^2 - d`,
`^{5/2} + 15\\,a^3\\,d^2 \\\\ &&\\quad\\mbox{} - 405\\,a^{12}\\,\\sqrt{d} + 270`,
`\\,a^9\\,d - 90\\,a^6\\,d^{3/2} - m^5\\,\\sin(x)^5 + 243\\,a^{15}`,
` \\\\ &&\\quad\\mbox{} + 540\\,m\\,\\sin(x)\\,a^9\\,\\sqrt{d} - 270\\,m\\,\\sin(x)`,
`\\,a^6\\,d \\\\ &&\\quad\\mbox{} + 60\\,m\\,\\sin(x)\\,a^3\\,d^{3/2} - 270\\,m^2\\,`,
`\\sin(x)^2\\,a^6\\,\\sqrt{d} \\\\ &&\\quad\\mbox{} + 60\\,m^3\\,\\sin(x)^3\\,a^3\\,`,
`\\sqrt{d} + 90\\,m^2\\,\\sin(x)^2\\,a^3\\,d \\end{eqnarray*}`,
`> stex(",[m,a,plex],[sin(x)]);`,
`\\begin{eqnarray*} && -\\sin(x)^5\\,m^5 + 15\\,\\sin(x)^4\\,m^4\\,a^3 - 5\\,`,
`\\sqrt{d}\\,\\sin(x)^4\\,m^4 - 90\\,\\sin(x)^3\\,m^3\\,a^6 \\\\ &&\\quad\\mbox{}`,
` + 60\\,\\sqrt{d}\\,\\sin(x)^3\\,m^3\\,a^3 - 10\\,d\\,\\sin(x)^3\\,m^3 + 270\\,`,
`\\sin(x)^2\\,m^2\\,a^9 \\\\ &&\\quad\\mbox{} - 270\\,\\sqrt{d}\\,\\sin(x)^2\\,m^2`,
`\\,a^6 + 90\\,d\\,\\sin(x)^2\\,m^2\\,a^3 \\\\ &&\\quad\\mbox{} - 10\\,d^{3/2}\\,`,
`\\sin(x)^2\\,m^2 - 405\\,\\sin(x)\\,m\\,a^{12} + 540\\,\\sqrt{d}\\,\\sin(x)\\,m\\,`,
`a^9 \\\\ &&\\quad\\mbox{} - 270\\,d\\,\\sin(x)\\,m\\,a^6 + 60\\,d^{3/2}\\,\\sin(x)`,
`\\,m\\,a^3 - 5\\,d^2\\,\\sin(x)\\,m \\\\ &&\\quad\\mbox{} + 243\\,a^{15} - 405\\,`,
`\\sqrt{d}\\,a^{12} + 270\\,d\\,a^9 - 90\\,d^{3/2}\\,a^6 + 15\\,d^2\\,a^3`,
` \\\\ &&\\quad\\mbox{} - d^{5/2} \\end{eqnarray*}`,
`> texsub:={w=omega,x=chi,v=lambda}:`,
`> mtex(2*w^2*x5^3-2/3*v1^3+w*x*v);`,
`$ 2\\,\\omega^2\\,{\\chi_5}^3 - 2/3\\,{\\lambda_1}^3 + \\omega\\,\\chi\\,\\lambda $`,
`> t[3,5]:=x3: t[1,2]:=v1: mtex(t);`,
`$$ \\left( \\begin{array}{cccc} \\lambda_1 & t_{1,3} & t_{1,4} & t_{1,5}`,
` \\cr t_{2,2} & t_{2,3} & t_{2,4} & t_{2,5} \\cr t_{3,2} & t_{3,3} & t_{`,
`3,4} & \\chi_3 \\end{array} \\right) $$`,
`> A:=array(1..50): mtex(A);`,
`\\begin{eqnarray*} && \\bigl[\\, A_{1},\\, A_{2},\\, A_{3},\\, A_{4},\\, A_{5`,
`},\\, A_{6},\\, A_{7},\\, A_{8},\\, A_{9},\\, A_{10},\\, A_{11},\\, A_{12}`,
`,\\, A_{13},\\, A_{14},\\, A_{15},\\, A_{16},\\, A_{17},\\, A_{18},\\, `,
`\\\\ &&\\quad\\mbox{} A_{19},\\, A_{20},\\, A_{21},\\, A_{22},\\, A_{23},\\, A`,
`_{24},\\, A_{25},\\, A_{26},\\, A_{27},\\, A_{28},\\, A_{29},\\, A_{30},\\, A`,
`_{31},\\, A_{32},\\, A_{33},\\, A_{34},\\, \\\\ &&\\quad\\mbox{} A_{35},\\, A_{`,
`36},\\, A_{37},\\, A_{38},\\, A_{39},\\, A_{40},\\, A_{41},\\, A_{42},\\, A_{`,
`43},\\, A_{44},\\, A_{45},\\, A_{46},\\, A_{47},\\, A_{48},\\, A_{49},\\, A_{`,
`50} \\,\\bigr] \\end{eqnarray*}`,
`> texidx:={``1``=i}:`,
`> mtex(t1); `,
`$ t_i $   `,
`> mtex(set1 intersect set2 union set3 minus set4);`,
`$ \\left(set_3\\cup \\left(set_i\\cap set_2\\right)\\right)\\setminus set_4 $`,
`> mtex(proc(x) sin(x) end);`,
`\\begin{verbatim}`,
`   `,
`proc(x) sin(x) end`,
`   `,
`\\end{verbatim}`,
`   `,
`> rlms(a*(-b-c)^3);`,
`                             3`,
`                  - a (b + c)`,
`   `,
`SEE ALSO: ?TeX, ?TeX[usage].`,
`   `
):
`help/tex/text/example` := `help/TeX/text/example`:
`help/tex/text/usage` := `help/TeX/text/usage`:
`help/text/tex`:=`help/text/TeX`:
`help/text/mtex`:=`help/text/TeX`:
tex:=proc(e)
	local sq,b,tmp,ee,aa,a,t0,t1,c, i,n, j,k,nm:
        global tex_lt, texsub, texidx, tex_space;
	options `Copyright (c) 1991 by Yunliang Yu`;
	if nargs=0 then  RETURN(NULL) fi;
	nm:=NULL;
	if nargs>1 then
		nm:=NULL: b:=nargs:
		if args[b]=name then nm:=name: b:=b-1: fi:
		if b>1 then
			sq:=NULL:
			tex_lt:=tex_lt+(b-1)*1/2:
			for i to b-1 do sq:=sq,tex(args[i],nm),`,`: od:
			sq:=sq,tex(args[b],nm):
			RETURN(sq):
		fi:
	fi:
	if type(e,table) and nm<>name then
		if type(e,array) then
			if not type(e,name) then tmp:=[op(2,e)]:
			else tmp:=[op(2,eval(e))]: fi:
			if   tmp=[] then RETURN(`(`,`) `):
			elif nops(tmp)=1 then
				t0:=NULL:
				t1:=op(1,tmp[1]): ee:=op(2,tmp[1]):
				RETURN( tex([seq(e[i],i=t1..ee)]) );
			elif nops(tmp)=2 then
				t0:=op(1,tmp[1]): aa:=op(2,tmp[1]):
				t1:=op(1,tmp[2]): ee:=op(2,tmp[2]):
			else
				ERROR(`cannot format arrays of dimension > 2`);
			fi:
		else	tmp:={indices(e)}:
			if not type(tmp,{set([integer]),set([integer,integer])})
			then ERROR(`unable to format table`) fi;
			if   tmp={} then RETURN(`(`,`) `):
			elif nops(tmp[1])=1 then
				t0:=NULL:
				tmp:=op(map(proc(x) op(x) end,tmp)):
				t1:=min(tmp): ee:=max(tmp):
				if t1=ee then t1:=1: fi:
			else
				aa:=seq(a[1],a=tmp); t0:=min(aa): aa:=max(aa):
				ee:=seq(a[2],a=tmp); t1:=min(ee): ee:=max(ee):
			fi:
		fi:
		if   tex_caller=amstex then
			sq:=`\\pmatrix `:
		elif tex_caller=latex then
			sq:=`\\left( \\begin{array}{`.(cat(`c`$(ee-t1+1))).`} `:
		else	sq:=`\\pmatrix{ `: fi:
		if tex_caller<>amstex then tmp:=` \\cr ` else tmp:=` \\\\ ` fi:
		a:=t0:
		do
			sq:=sq,tex(e[a,t1],name):
			for b from t1+1 to ee do
				sq:=sq,` & `,tex(e[a,b],name):
			od:
			if a=NULL or a+1>aa then break: fi:
			if a<aa then sq:=sq,tmp: fi:
			a:=a+1:
		od:
		if   tex_caller=amstex then
			sq:=sq,` \\endpmatrix `:
		elif tex_caller=latex then
			sq:=sq,` \\end{array} \\right) `:
		else	sq:=sq,` \\cr} `: fi:
	elif type(e,name) then
		if not type(texsub,{list,set}) then
			texsub:={}:
		fi:
		if not type(texidx,{list,set}) then
			texidx:={}:
		fi:
		ee:=subs(texsub,e):
		if ee<>e then
			a:=ee: b:=NULL:
		else
			if type(e,indexed) then
				b:=op(e): a:=op(0,e):
				do
					if not type('"',name) then
						a:=`?`: break:
					elif type('"',indexed) then
						b:=op(a),b: a:=op(0,a):
					else	break: fi:
				od:
				if b<>NULL then
					b:=subs(texidx,[b]):
					t0:=tex_lt:
					b:=`_{`,tex(op(b),nm),`}`:
					tex_lt:=tex_lt-(tex_lt-t0)/3:
				else b:=`_{}`; tex_lt:=tex_lt+1/5;
				fi:
			else
				c:=length(e):
				for n from c by -1 to 1 do
					if member(substring(e,n..n),
				     {`0`,`1`,`2`,`3`,`4`,`5`,`6`,`7`,`8`,`9`})
					then else break fi:
				od:
				if n=0 or c-n=0 then a:=e: b:=NULL:
				else	a:=substring(e,1..n):
					b:=substring(e,n+1..c):
					b:=subs(texidx,b):
					c:=c-n:
					if c=1 then
						tex_lt:=tex_lt+  2/3:
						b:=`_`,b:
					else
						tex_lt:=tex_lt+c*2/3:
						b:=`_{`,b,`}`:
					fi:
				fi:
			fi:
			a:=subs(texsub,a):
		fi:
		if   a=infinity then sq:=`\\infty`,b: tex_lt:=tex_lt+1:
		elif a=Beta     then sq:=`\\beta`,b: tex_lt:=tex_lt+1:
		elif a=GAMMA    then sq:=`\\Gamma`,b: tex_lt:=tex_lt+1:
		elif a=Zeta     then sq:=`\\zeta`,b: tex_lt:=tex_lt+1:
		elif a=Pi       then sq:=`\\pi`,b: tex_lt:=tex_lt+1:
		elif a=E        then sq:=proc() local e;e end(),b: tex_lt:=tex_lt+1:
		elif member(a,tex_greek_) then
			sq:=`\\`.a,b: tex_lt:=tex_lt+1:
		elif member(a,tex_math_func_) then
			sq:=`\\`.a,b: tex_lt:=tex_lt+length(a):
		elif type(a,string) then
			sq:=a,b: tex_lt:=tex_lt+length(a):
		else
			sq:=`{`,tex(a,nm),`}`,b:
		fi:
	elif type(e,`^`) then
		a:=op(1,e): b:=op(2,e):
		if   b= 1/2 then tex_lt:=tex_lt+3/2:
				RETURN( `\\sqrt{`,tex(a,nm),`}`  ):
		elif b=-1/2 then tex_lt:=tex_lt+3/2:
			if tex_caller=plain then
				RETURN( `{1\\over\\sqrt{`,tex(a,nm),`}}` ):
			else	RETURN( `\\frac1{\\sqrt{`,tex(a,nm),`}}` ): fi:
		elif type(b,integer) and b<0 then
			if tex_caller=plain then
				RETURN( `{1\\over `,tex(a^(-b),nm),`}` ):
			else	RETURN( `\\frac1{`,tex(a^(-b),nm),`}`  ): fi:
		elif type(b*t0,`*`) and numer(b*t0)=t0 then
			t0:=tex_lt: tmp:=tex(denom(b),nm):
			tex_lt:=tex_lt-(tex_lt-t0)*3/4 + 3/2:
			if tex_caller=latex then
				RETURN(`\\sqrt[`,tmp,`]{`,tex(a,nm),`}`):
			else
			  RETURN( `\\root{`,tmp,`}\\of{`,tex(a,nm),`}` ):
			fi:
		fi:
		if   type(b,integer) and b>=0 and b<=9 then
			tmp:=`^`,b: tex_lt:=tex_lt+2/3:
		else	t0:=tex_lt: c:=tex(b,nm):
			tex_lt:=tex_lt-(tex_lt-t0)/3:
			tmp:=`^{`,c,`}`:
		fi:
		if   type(a,{`+`,`*`,`^`,fraction}) or
			(type(a,numeric) and a<0) then
			if tex_tall(a) then
				tex_lt:=tex_lt+3:
	           		sq:=`\\left(`,tex(a,nm),`\\right)`,tmp:
				tex_space:=0:
			else	tex_lt:=tex_lt+2:
				sq:=`(`,tex(a,nm),`)`,tmp:
			fi:
		elif type(a,numeric) or type(a,function)
			or ( type(a,string) and
			not member(substring(a,length(a)..length(a)),
			{`0`,`1`,`2`,`3`,`4`,`5`,`6`,`7`,`8`,`9`}) ) then
			sq:=tex(a,nm),tmp:
		else
			sq:=`{`,tex(a,nm),`}`,tmp:
		fi:
	elif type(e,fraction) then
		b:=NULL: tmp:=e: if e<0 then b:=`-`: tmp:=-e: fi:
		ee:=op(1,tmp): aa:=op(2,tmp): a:=length(aa): c:=length(ee):
		if not tex_tall(tmp) then
			sq:=b,ee,`/`,aa:
			tex_lt:=tex_lt + a + 1 + c:
		else
			tex_lt:=tex_lt + max( a, c ):
			if tex_caller=plain then
				RETURN( b,`{`,ee,`\\over `,aa,`}` ):
			fi:
			if ee<10 then
				sq:=b,`\\frac`, ee, `{`,aa,`}`:
			else	sq:=b,`\\frac{`,ee,`}{`,aa,`}`: fi:
		fi:
	elif type(e,integer)  then
		if   e=0   then tex_lt:=tex_lt+1:
		elif e<>-1 then tex_lt:=tex_lt+length(e):fi:
		if e>=0 then sq:=e: else sq:=`-`,-e:fi:
	elif type(e,numeric) then
		c:=NULL: ee:=e: if e<0 then c:=`-`: ee:=-e: fi:
			a:=[op(ee)]:     b:=-op(2,a):
			a:=``.(op(1,a)): i:=length(a):
 			if i>b then
				tmp:=``.(substring(a,1..i-b)).`.`.
					(substring(a,i-b+1..i)):
			else	tmp:=`0.`.(cat(`0`$(b-i))).a: fi:
		tex_lt:=tex_lt+length(tmp)-1/2:
		sq:=c,tmp:
	elif type(e,function) then
		a:=op(0,e):
		if type(a,string) and assigned(`tex/`.a) then
			sq:=`tex/`.a(op(e));
		elif type(a,string) and assigned(`latex/`.a) then
			sq:=`latex/`.a(op(e));
		else
			if tex_tall({op(e)}) then
				tex_lt:=tex_lt+3-1/3:
				b:=`\\!\\left(`,tex(op(e),nm),`\\right)`:
				tex_space:=2:
			else	tex_lt:=tex_lt+2:
				b:=`(`,tex(op(e),nm),`)`:
			fi:
			if member(a,tex_math_func_) or
				( type(a,string) and substring(a,1..1)=`&` )
				 then
				sq:=`\\`.a,b:
				tex_lt:=tex_lt+length(a):
			elif type(a,{`*`,`+`}) then
				sq:=`(`,tex(a,nm),`)`,b:
				tex_lt:=tex_lt+2;
			else	sq:=tex(a,nm),b: fi:
		fi:
	elif type(e,`*`) then
		tmp:=[op(e)]:
		a:=tmp[1]:
		b:=NULL: ee:=NULL: aa:=NULL:
		if type(a,numeric) then
			tmp:=subsop(1=NULL,tmp):
			if a<0 then b:=`-`: a:=-a: fi:
		else	a:=1: fi:
		for i in tmp do
			if type(i,`^`) and type(op(2,i),numeric) and
				op(2,i)<0 then aa:=aa,1/i:
			else	ee:=ee,i: fi:
		od:
		ee:=tex_sort([ee],1): aa:=tex_sort([aa],1):
		if ee=[] then
			if type(a,fraction) then
				ee:=[op(1,a),op(ee)]:
				aa:=[op(2,a),op(aa)]:
			else	ee:=[a,op(ee)]: fi:
		elif aa=[]  and type(a,fraction) and op(1,a)=1 then
			aa:=[op(2,a),op(aa)]:
		elif aa<>[] and type(a,fraction) then
			if op(1,a)<>1 then ee:=[op(1,a),op(ee)]: fi:
			aa:=[op(2,a),op(aa)]:
		elif a<>1 then
			b:=b,tex(a,nm),`\\,`: tex_lt:=tex_lt+2/3:
		fi:
		t0:=tex_lt:
		ee:=tex_pdt(ee,nm):
		t1:=tex_lt:
		tmp:=tex_pdt(aa,nm):
		if   aa=[] then sq:=b,ee:
		elif tex_caller=plain then
			sq:=b,`{`,ee,`\\over `,tmp,`}`:
		else	sq:=b,`\\frac{`,ee,`}{`,tmp,`}`: fi:
		tex_lt:=t0+max(t1-t0,tex_lt-t1):
	elif type(e,`+`) then
		sq:=NULL: b:=tex_sort([op(e)]):
		c:=nops(b):
		for i to c do	a:=1:
			if type(b[i],{numeric,`*`}) then a:=op(1,b[i]): fi:
			if i=1 then ee:=tex(b[i],nm):
			elif type(a,numeric) and a<0 then
				ee:=`-`,tex(-b[i],nm):
			else	ee:=`+`,tex( b[i],nm): fi:
			sq:=sq,ee:
		od:
		tex_lt:=tex_lt+3*(c-1):
	elif type(e,set) then
		tmp:=tex_sort([op(e)]):
		if tex_tall(e) then
			tex_lt:=tex_lt+3:
			sq:=`\\left\\{\\,`,tex(op(tmp),nm),`\\,\\right\\}`:
		else	tex_lt:=tex_lt+2:
			sq:=`\\{\\,`,tex(op(e),nm),`\\,\\}`:
		fi:
	elif type(e,list) then
		if tex_tall(e) then
			tex_lt:=tex_lt+3:
			sq:=`\\left[\\,`,tex(op(e),nm),`\\,\\right]`:
		else	tex_lt:=tex_lt+2:
			sq:=`[\\,`,tex(op(e),nm),`\\,]`:
		fi:
	elif type(e,relation) then
		if   whattype(e) = `<=` then ee:=`\\leq `:
		elif whattype(e) = `>=` then ee:=`\\geq `:
		elif whattype(e) = `<>` then
			if tex_caller=plain then ee:=`\\not= `:
			else ee:=`\\neq `: fi:
		else	ee:=whattype( e ): fi:
		tex_lt:=tex_lt+3:
		sq:=tex(op(1,e),nm),ee,tex(op(2,e),nm):
	elif type(e,{taylor,series}) then
		sq:=tex( convert(e,`+`) ,nm):
	elif type(e,range) then
		tex_lt:=tex_lt+3:
		sq:=tex(op(1,e),nm),`\\ldots `,tex(op(2,e),nm):
	else	ERROR(`cases haven't defined yet.`):
	fi:
	RETURN(sq):
end:
tex_pdt:=proc(ee)
	local sq,n,i,s,t,nm:
        global tex_lt, tex_space;
	options `Copyright (c) 1991 by Yunliang Yu`;
	if nargs=1 then nm:=NULL else nm:=args[2] fi:
	if   ee=[] then RETURN( tex(1) ):
	elif nops(ee)=1 then
		RETURN( tex(op(ee),nm) ):
	fi:
	sq:=NULL: n:=nops(ee):
	for i to n do
		if type(ee[i],`+`) then
	  		if tex_tall(ee[i]) then
				tex_lt:=tex_lt+3:
		   		sq:=sq,`\\left(`,tex(ee[i],nm),`\\right)`:
				tex_space:=0:
			else 	tex_lt:=tex_lt+2:
				if tex_space=1 and i>1 then
					sq:=sq,`\\,`,`(`,tex(ee[i],nm),`)`:
					tex_lt:=tex_lt+2/3:
				else	sq:=sq,`(`,tex(ee[i],nm),`)`: fi:
				tex_space:=1:
			fi:
		else
			t:=tex_space:
			tex_space:=1:
			s:=tex(ee[i],nm):
			if t=1 and tex_space<>0 and i>1 then
				sq:=sq,`\\,`,s:
				tex_lt:=tex_lt+2/3:
			else	sq:=sq,s: fi:
		fi:
	od:	RETURN(sq):
end:
tex_tall:=proc(e)
	local x,i:
	options `Copyright (c) 1991 by Yunliang Yu`;
	if   hastype(e,`^`) or  hastype(e,function) then RETURN(true):
	elif type(e,{set,list,`+`}) then
		for x in e do if tex_tall(x) then RETURN(true) fi: od:
	elif hastype(e,`+`) then RETURN(true):
	elif hastype(e,fraction) then
		x:=indets(e,fraction):
		for i in x do
			if min( length(op(1,i)),length(op(2,i)) )>1 then
				RETURN(true):
			fi:
		od:
	fi:
	false:
end:
tex_split:=proc(e,sp)
	local a,sq,i,ict,e1,ee,ct:
        global texwid, tex_lt;
	options `Copyright (c) 1991 by Yunliang Yu`;
	if not type(texwid,numeric) then texwid:=60: fi:
	if nargs>2 then
		a:=args[nargs]: sq:=NULL:
		for i to nargs-2 do
			sq:=sq,tex_split(args[i],a),`,\\, `:
			tex_lt:=tex_lt+1/2+2/3:
		od:	sq:=sq,tex_split(args[nargs-1],a):
		RETURN(sq):
	fi:
	if   type(e,{set,list}) then
		if type(e,set) then
			a:=`\\{\\, `: 	i:=`\\}`:
		else	a:=`[\\, `: 	i:=`]`: fi:
		tex_lt:=tex_lt+2+1:
		if nops(e)=0 then RETURN(a,i) fi:
		if type(e,set) then
			sq:=tex_split(op( tex_sort([op(e)]) ),sp):
		else	sq:=tex_split(op(e),sp): fi:
		if member(sp,{sq}) then
			if tex_tall(e) then
				sq:=`\\Bigl`.a,sq,` \\,\\Bigr`.i:
			else	sq:=`\\bigl`.a,sq,` \\,\\bigr`.i: fi:
		else
			if tex_tall(e) then
				sq:=`\\left`.a,sq,` \\,\\right`.i:
			else	sq:=         a,sq,       ` \\,`.i: fi:
		fi:
	elif type(e,`+`) then
		ee:=tex_sort([op(e)]):  sq:=NULL:
		ict:=tex_lt:
		for i to nops(ee) do ct:=tex_lt: a:=1:
			if type(ee[i],{numeric,`*`}) then
				a:=op(1,ee[i]): fi:
			if   i=1 then
				e1:=tex(ee[i]):
			elif type(a,numeric) and a<0 then
				e1:=` - `,tex(-ee[i]):
				tex_lt:=tex_lt+3:
			else	e1:=` + `,tex(ee[i]):
				tex_lt:=tex_lt+3:
			fi:
			if tex_lt>texwid and ct<>0 then
				sq:=sq, sp, e1:
				tex_lt:=3 + (tex_lt-ct):
			else	sq:=sq,e1:fi:
		od:
		sq:=[sq]:
		if ict=0 and tex_caller=amstex and member(sp,sq) and
			sq[1]=`-` then
			sq:=subsop(1=`{-}`,sq):
		fi:	sq:=op(sq):
	elif type(e,relation) then
		if   whattype(e) = `<=` then ee:=`\\leq `:
		elif whattype(e) = `>=` then ee:=`\\geq `:
		elif whattype(e) = `<>` then
			if tex_caller=plain then ee:=`\\not= `:
			else ee:=`\\neq `: fi:
		else	ee:=whattype( e ): fi:
		sq:=tex_split(op(1,e),sp): tex_lt:=tex_lt+3:
		sq:=sq,ee,tex_split(op(2,e),sp):
	elif type(e,{taylor,series}) then sq:=tex_split( convert(e,`+`) ,sp):
	else
		ct:=tex_lt: sq:=tex(e):
		if tex_lt>texwid and ct<>0 then
			sq:=sp,sq: tex_lt:=(tex_lt-ct)+3:
		fi:
	fi:	RETURN(sq);
end:
tex_print:=proc(e)
	local sq,ls,x,lx:
	options `Copyright (c) 1991 by Yunliang Yu`;
	if not type(e,list) then ERROR(`argument has to be a list`): fi:
	if e=[] then RETURN(NULL) fi:
	sq:=``; ls:=0:
	for x in e do
		if x=0 then lx:=1 else lx:=length(x) fi:
    		if ls+lx>70 then
			lprint(sq): sq:=x; ls:=lx:
		else 	sq:=``.sq.x: ls:=ls+lx:	fi:
	od:	lprint(sq):
end:
mtex:=proc(e)
	local sp,sq,hd,tr,i,file,ee,oldqt:
        global tex_caller, tex_lt, first_verbatim;
	options `Copyright (c) 1991 by Yunliang Yu`;
	if nargs=0 then RETURN(NULL): fi:
	oldqt:=interface(quiet,quiet=true);
	for i from 2 to nargs do
		if   member(args[i],{amstex,latex,plain}) then
			tex_caller:=args[i]:
		elif type(args[i],string) then
			writeto(cat(args[i],`.tex`)): file:=1:
		elif type(args[i],numeric) then tex_lt:=args[i]:
		fi:
	od:
	if type(tex_lt,numeric) and tex_lt<0 then
		tex_lt:=-1000000;
	else
		tex_lt:=0:
	fi:
	if not member(tex_caller,{amstex,latex,plain}) then
		tex_caller:=latex:
	fi:
	if   type(e,{array,table}) then
		if type(e,vector) then
			if not type(e,name) then ee:=op(2,e):
			else ee:=op(2,eval(e)): fi:
			mtex([seq(e[i],i=1..op(2,ee))]);
		else
			sq:=traperror(tex(e)):
			if sq=lasterror then lprint(sq)
			else
				tex_print([`$$ `,sq,`$$`]):
			fi:
		fi
	elif type(e,relation) then
		if   tex_caller=amstex then
			hd:=`$$ \\align `:
			tr:=` \\endalign $$`:
			sp:=` \\\\&\\qquad`:
		elif tex_caller=latex then
			hd:=`\\begin{eqnarray*} `:
			tr:=` \\end{eqnarray*}`:
			sp:=` \\\\ &&\\quad\\mbox{}`:
		elif tex_caller=plain then
			hd:=`$$ \\eqalign{ `:
			tr:=` \\cr} $$`:
			sp:=` \\cr&\\qquad`:
		fi:
		if   whattype(e) = `<=` then ee:=`\\leq`:
		elif whattype(e) = `>=` then ee:=`\\geq`:
		elif whattype(e) = `<>` then
			if tex_caller=plain then ee:=`\\not=`:
			else ee:=`\\neq`: fi:
		else	ee:=whattype( e ):
		fi:
		sq:=traperror(tex_split(op(1,e),sp)):
		if sq=lasterror then lprint(sq)
		else 	tex_lt:=tex_lt+3:
			i:=traperror(tex_split(op(2,e),sp)):
			if i=lasterror then 	lprint(i)
			else  	sq:=sq,ee,i:
				if member(sp,{sq}) then
					if tex_caller=latex then
					 sq:=op(subs(ee=` &`.(ee).`& `,[sq])):
					else
					 sq:=op(subs(ee=` &`.(ee).` `,[sq])):
					fi:
					tex_print([hd,sq,tr]):
				else	sq:=op(subs(ee=` `.(ee).` `,[sq])):
					tex_print([`$ `,sq,` $`]):
				fi:
			fi:
		fi:
	elif type(e,procedure) and
		not member(e,tex_math_func_) then
		if tex_caller=latex then
			lprint(`\\begin{verbatim}`);
			lprint();
			print(e);
			lprint(`\\end{verbatim}`);
		else
			if first_verbatim<>0 then
				first_verbatim:=0;
				for i in [
`%%%%%%% verbtim2.tex from ymir.claremont.edu by Tim Morgan <morgan@uci-icsa>`,
`\\def\\uncatcodespecials{\\def\\do##1{\\catcode``##1=12 } \\dospecials}`,
`\\def\\setupverbatim{\\par \\tt \\spaceskip=0pt`,
`        \\obeylines\\uncatcodespecials\\obeyspaces\\verbatimdefs}`,
`\\def\\verbatim{\\begingroup \\setupverbatim`,
`     \\parskip=0pt plus .05\\baselineskip \\parindent=0pt`,
`      \\catcode``\\ =13 \\catcode``\\^^M=13 \\catcode``\\?=0\\verbatimgobble}`,
`{\\catcode``\\^^M=13{\\catcode``\\ =13\\gdef\\verbatimdefs{\\def^^M{\\ \\par}\\let =\\ }}`,
`  \\gdef\\verbatimgobble#1^^M{}}`,
`\\let\\endverbatim=\\endgroup`,
`%%%%%%%   `] 			do lprint(i); od:
			fi;
			lprint(`\\verbatim`);
			lprint();
			print(e);
			lprint(`?endverbatim`);
		fi;
	else
		if   tex_caller=amstex then
			hd:=`$$ \\align & `:
			tr:=` \\endalign $$`:
			sp:=` \\\\&\\qquad`:
		elif tex_caller=latex then
			hd:=`\\begin{eqnarray*} && `:
			tr:=` \\end{eqnarray*}`:
			sp:=` \\\\ &&\\quad\\mbox{}`:
		elif tex_caller=plain then
			hd:=`$$ \\eqalign{& `:
			tr:=` \\cr} $$`:
			sp:=` \\cr&\\qquad`:
		fi:
		if type(e,{set,list}) then
			sp:=cat(substring(sp,2..length(sp)),` `);
		fi:
		sq:=traperror(tex_split(e,sp)):
		if sq=lasterror then lprint(sq) else
			if member(sp,{sq}) then
				tex_print([hd,sq,tr]):
			else	tex_print([`$ `,sq,` $`]):
			fi:
		fi:
	fi:
	if file=1 then writeto(terminal) fi:
	interface(quiet = oldqt); 	NULL:
end:
tex_lead:=proc(a,b)
	local da,db,i, X, k, pt, p, HAS,DEG, nt:
	options `Copyright (c) 1991 by Yunliang Yu`;
	if args[nargs]=1 then p:=1: else p:=0: fi:
	HAS:=proc(x,y) frontend(has,[x,y],[{`+`,`*`,list,set},{}]) end:
	DEG:=proc(x,y) frontend(degree,[x,y],[{`+`,`*`,list,set},{}]) end:
	for i from 3 to nargs-p do
		if not HAS(a,args[i]) and not HAS(b,args[i]) then next fi:
		if p=1 then
			da:=HAS(a,args[i]): db:=HAS(b,args[i]):
			if   da and not db then RETURN(false):
			elif not da and db then RETURN(true): fi:
			k:=proc(a) if type(a,`+`) or ( type(a,`^`) and
			       type(op(1,a),`+`) ) then true else false fi end;
			da:=k(a): db:=k(b):
			if   not da and db then RETURN(true):
			elif da and not db then RETURN(false):fi:
		fi:
		nt:=nops(args[i]): X:=subsop(nt=NULL,args[i]): pt:=args[i][nt]:
		if pt=plex then
			for k in X do
				da:=DEG(a,k): db:=DEG(b,k):
				if   db=FAIL then RETURN(true):
				elif da=FAIL then RETURN(false):
				elif da>db then RETURN(true):
				elif da<db then RETURN(false): fi:
			od:
		elif pt=rlex then
			for k from nops(X) by -1 to 1 do
				da:=DEG(a,X[k]): db:=DEG(b,X[k]):
				if   db=FAIL then RETURN(true):
				elif da=FAIL then RETURN(false):
				elif da<db then RETURN(true):
				elif da>db then RETURN(false): fi:
			od:
		elif pt=tdeg then
			da:=DEG(a,{op(X)}): db:=DEG(b,{op(X)}):
			if   db=FAIL then RETURN(true):
			elif da=FAIL then RETURN(false):
			elif da>db then RETURN(true):
			elif da<db then RETURN(false): fi:
			RETURN(tex_lead(a,b,[op(X),rlex],args[i+1..nargs])):
		elif pt=rdeg then
			da:=DEG(a,{op(X)}): db:=DEG(b,{op(X)}):
			if   db=FAIL then RETURN(true):
			elif da=FAIL then RETURN(false):
			elif da<db then RETURN(true):
			elif da>db then RETURN(false): fi:
			RETURN(tex_lead(a,b,[op(X),plex],args[i+1..nargs])):
		fi:
	od:
	true:
end:
rlms:=proc(e)
	local ee,sg,i,e1,e2,a,s:
	options `Copyright (c) 1991 by Yunliang Yu`;
	if   type(e,`+`) then map(rlms,e):
	elif type(e,`*`) then
		ee:=[op(e)]: sg:=1:
		for i to nops(ee) do
			e1:=rlms(ee[i]):
			if type(e1,`+`) then
				a:=tex_sort([op(e1)]):
				a:=op(1,a): s:=1:
				if type(a,{numeric,`*`}) then s:=op(1,a): fi:
				if type(s,numeric) and s<0 then
					sg:=-sg: e1:=-e1:
				fi:
			fi:
			ee:=subsop(i=e1,ee):
		od:
		sg*convert(ee,`*`):
	elif type(e,`^`) then
		e1:=rlms(op(1,e)): e2:=op(2,e):
		if not type(e1,`+`) then e1^e2:
		else 	a:=tex_sort([op(e1)]):
			a:=op(1,a): s:=1:
			if type(a,{numeric,`*`}) then s:=op(1,a): fi:
			if type(s,numeric) and s<0 then
				(-1)^e2*(-e1)^e2:
			else 	e1^e2: fi:
		fi:
	elif type(e,{function, set,list, relation, taylor,series, range}) then
		map(rlms,e):
	else	e:
	fi:
end:
clct:=proc(e)
	local var,i,v,vv,dum:
	options `Copyright (c) 1991 by Yunliang Yu`;
	var:=NULL:
	for i from 2 to nargs do
		if type(args[i],list) and args[i]<>[] then
			var:=var,args[i]:
		fi:
	od:
	if var=NULL then
		if assigned(texvar) and texvar<>NULL then
			RETURN(clct(e,texvar)):
		else	RETURN(e):	fi:
	elif nops([var])=1 then
		collect(e,var,distributed):
	else	var:=[var]: v:=var[1]: vv:=var[2..nops(var)]:
		dum:=subs({'Y'=vv},proc() clct(args[1],Y) end):
		collect(e,v,distributed,dum):
	fi:
end:
stex:=proc(e)
	local tmp,var,file,i,nt:
	global tex_caller, tex_lt, texvar, tex_sort;
	options `Copyright (c) 1991 by Yunliang Yu`;
	if nargs=0 then RETURN(NULL) fi:
	file:=NULL: var:=NULL:
	for i from 2 to nargs do
		if   type(args[i],list) then
			tmp:=map(proc(x) if type(x,{name,function}) then x fi
				end, args[i]):
			if tmp=[] then next fi: nt:=nops(tmp):
			if member(tmp[nt],{tdeg,rdeg,plex,rlex}) then
				if nt=1 then next: fi:
			else	tmp:=[op(tmp),tdeg]: fi:
			var:=var,tmp:
		elif member(args[i],{amstex,latex,plain}) then
			tex_caller:=args[i]:
		elif type(args[i],string) then
			file:=args[i]:
		elif type(args[i],numeric) then tex_lt:=args[i]:
		fi:
	od:
	if not member(tex_caller,{amstex,latex,plain}) then
		tex_caller:=latex:
	fi:
	if var<>NULL then texvar:=var:
	elif assigned(texvar) then
		var:=NULL:
		for i in [texvar] do
			if not type(i,list) or i=[] then next fi:
			tmp:=map(proc(x) if type(x,{name,function}) then x fi
				end, i):
			if tmp=[] then next fi: nt:=nops(tmp):
			if member(tmp[nt],{tdeg,rdeg,plex,rlex}) then
				if nt=1 then next: fi:
			else	tmp:=[op(tmp),tdeg]: fi:
			var:=var,tmp:
		od:	texvar:=var:
	fi:
	if var=NULL then
		if type(e,{table,array}) then
			tmp:=traperror(indets({entries(e)})):
		else 	tmp:=traperror(indets(e)): fi:
		if tmp=lasterror then tmp:={}: fi:
		if tmp<>{} then
			i:=proc(a,b)
				if   not type(a,string) then true
				elif not type(b,string) then false
				else lexorder(a,b) fi: end:
			var:=[op(sort([op(tmp)],i)),tdeg]:
		fi:
	fi:
	if var<>NULL then
		tex_sort:=subs('Y'=var,
			proc() local tmp:
			if nargs=2 then
			     tmp:=proc() tex_lead(args[1],args[2],Y,1) end:
			else tmp:=proc() tex_lead(args[1],args[2],Y) end:
			fi:  sort(args[1],tmp)
			end  ):
	fi:
	tmp:=traperror( rlms(e) ):
	if tmp=lasterror then tmp:=e: fi:
	if type(e,{table,array}) then
		tmp:=traperror( mtex(e, tex_caller,file) ):
	else 	tmp:=traperror( mtex(tmp,tex_caller,file) ): fi:
	if tmp=lasterror then lprint(tmp) fi:
	tex_sort:=proc() args[1] end:
	NULL:
end:
test:=proc()
	local tmp,file;
	global tex_date, first_verbatim, tex_caller, tex_lt;
	options `Copyright (c) 1991 by Yunliang Yu`;
	file:=NULL: tex_date:=evaln(tex_date):
	first_verbatim:=1;
	for tmp in [args[1..nargs]] do
		if member(tmp,{amstex,latex,plain}) then tex_caller:=tmp:
		elif type(tmp,string) then file:=tmp: fi:
	od:
	if not member(tex_caller,{amstex,latex,plain}) then
		tex_caller:=latex;
	fi:
        print(`--------- Do your stuff now, ending it with exit; -----------`);
	if file<>NULL then
		interface(quiet=true);
		writeto(``.file.`.tex`);
	fi;
	lprint(``);
	lprint(`%%%%%%% test file for TeX package generated by test() `.
	`%%%%%%%%%%`);
	lprint(``);
	if tex_caller=amstex then
		lprint(`\\input amstex`);
		lprint(`\\documentstyle{amsppt}`);
		lprint(`\\magnification=\\magstep1`);
		lprint(`\\document`);
	elif tex_caller=latex then
		lprint(`\\documentstyle [12pt]{article}`);
		lprint(`\\begin{document}`);
	else
		lprint(`\\magnification=\\magstep1`);
	fi:	lprint(``);	0:
	do
		traperror(readstat(`% `)):
		if "=exit then
			lprint(``);
			if   tex_caller=amstex then
				lprint(`\\enddocument`);
			elif tex_caller=latex then
				lprint(`\\end{document}`);
			else
				lprint(`\\bye`);
			fi:
			writeto(terminal);
			interface(quiet=false);
			break;
		else	lprint(``);
		fi;
	od:	NULL:
end:
tex_greek_:='{alpha,beta,gamma,delta,epsilon,varepsilon,zeta,eta,theta,
      	vartheta,iota,kappa,lambda,mu,nu,xi,pi,varpi,rho,varrho,
      	sigma,varsigma,tau,upsilon,phi,varphi,chi,psi,omega,
      	Gamma,Delta,Theta,Lambda,Xi,Sigma,Upsilon,Phi,Pi,Psi,
     	Omega}':
tex_math_func_:='{arccos,arcsin,arctan,arg,cos,cosh,cot,coth,csc,
      deg,det,dim, exp,gcd, hom, inf, ker, lg, lim,
      liminf,limsup,ln,log,max,min, Pr, sec, sin, sinh,
      sup,tan,tanh}':
`tex/SetOps`:=proc()
	local sq,op,i;
	global tex_lt;
	sq:=NULL; op:=args[nargs];
	for i to nargs-1 do
		if type(args[i],{name,set}) then
			sq:=sq,tex(args[i]);
		else
			sq:=sq,`\\left(`,tex(args[i]),`\\right)`;
			tex_lt:=tex_lt+1;
		fi;
		if i<nargs-1 then
			sq:=sq,op; tex_lt:=tex_lt+3/2;
		fi;
	od;
	RETURN(sq);
end:
`tex/union`:=proc() `tex/SetOps`(args,`\\cup `) end:
`tex/minus`:=proc() `tex/SetOps`(args,`\\setminus `) end:
`tex/intersect`:=proc() `tex/SetOps`(args,`\\cap `) end:
tex_sort:=proc() args[1] end:
tex_lt:=0:
#print(`Save to the file ./tex.m...`);
#save `tex.m`;
#quit
