(*  :Title:	Supporting Routines  *)

(*  :Authors:	Brian Evans, James McClellan  *)

(*
    :Summary:	To provide routines that Mathematica should have.
		Many are borrowed from Lisp.
 *)

(*  :Context:	SignalProcessing`Support`SupCode`  *)

(*  :PackageVersion:  2.6	*)

(*
    :Copyright:	Copyright 1989-1991 by Brian L. Evans
		Georgia Tech Research Corporation

	Permission to use, copy, modify, and distribute this software
	and its documentation for any purpose and without fee is
	hereby granted, provided that the above copyright notice
	appear in all copies and that both that copyright notice and
	this permission notice appear in supporting documentation,
	and that the name of the Georgia Tech Research Corporation,
	Georgia Tech, or Georgia Institute of Technology not be used
	in advertising or publicity pertaining to distribution of the
	software without specific, written prior permission.  Georgia
	Tech makes no representations about the suitability of this
	software for any purpose.  It is provided "as is" without
	express or implied warranty.
 *)

(*  :History:	*)

(*  :Keywords:	list processing, sequences, number theory, set theory	*)

(*  :Source:	*)

(*  :Warning:	*)

(*  :Mathematica Version:  1.2 or 2.0  *)

(*  :Limitation:  *)

(*
    :Functions:	AllSubsets
		Arrow2D
		AssociateItem
		Assuming
		CirclePS
		Combine
		ComplexQ
		ComplexTo2DCoord
		ComplexTo2DCoordList
		ConstantQ
		ConstantTerm
		Dialogue
		Element
		EmptyQ
		GenerateCode
		GeneratePattern
		GenerateSymbol
		GetAllExponents
		GetAllFactors
		GetArgs
		GetRoot
		GetRootList
		GetShiftFactor
		GetStateField
		GetVariables
		GetValue
		HasAttributes
		ImaginaryQ
		InRange
		InfinityQ
		InformUserQ
		ListQ
		MixedPolynomialQ
		MyApart
		MyCollectAll
		MyFreeQ
		MyMessage
		MyTogether
		NegExponent
		NormalizedQ
		PatternQ
		PointwisePlot
		PrintIt
		ProtectIt
		RationalQ
		RationalFunctionQ
		RationalPolynomialQ
		RealQ
		RealValuedQ
		RemoveOptions
		ReplaceWith
		RuleAppliesQ
		SameFormQ
		Second
		SetExclusion
		SetStateField
		StripPackage
		SubsetQ
		TableLookup
		Third
		ToCollection
		ToList
		UnprotectIt
		VariableQ
		ZeroQ
		ZPolynomial
 *)



If [ ! TrueQ[ $VersionNumber >= 2.0 ],
     $notloaded = ! MemberQ[$ContextPath, "SignalProcessing`Support`SupCode`"],

     $notloaded = ! MemberQ[$Packages, "SignalProcessing`Support`SupCode`"];
     Unprotect[ ListQ ];
     Clear[ ListQ ];
     $NewMessage[General, "spell"];
     $NewMessage[General, "spell1"];
     Off[ General::spell ];
     Off[ General::spell1 ];
     $NewMessage[Set, "write"];
     $NewMessage[Set, "wrsym"];
     $NewMessage[SetDelayed, "write"];
     Off[ SetDelayed::write ];
     Off[ Set::write ];
     Off[ Set::wrsym ] ]


(*  B E G I N     P A C K A G E  *)

BeginPackage[ "SignalProcessing`Support`SupCode`" ]


(*  U S A G E     I N F O R M A T I O N  *)

AllSubsets::usage =
	"AllSubsets[set] returns a list of all subsets of set, \
	including the null set {}. \
	The original set must be a lis."

Arrow2D::usage =
	"Arrow2D[tail, plotwidth, plotheight] returns a graphics object \
	that is an arrow starting at tail, pointing upwards, of \
	length plotheight. \
	The length of the tail can be controlled by an optional \
	fourth parameter."

AssociateItem::usage =
	"AssociateItem[item, lookuplist, newlist] finds the location of \
	item in the lookuplist and returns the element of newlist in \
	that position. \
	If item is not is lookup list, Null is returned. \
	If item is a list, then a list of associations is returned."

Assuming::usage =
	"Assuming[condition] keeps track of assumptions made during \
	a calculation. \
	Assuming[All] gives all of the current assumptions. \
	Assuming[condition, True] prints the condition if it is not True. \
	Assuming[] removes all current assumptions."

CirclePS::usage =
	"CirclePS[r] and CirclePS[r, p] will return a graphics object, \
	a circle of radius r with plotstyle p. \
	CirclePS makes use of the Circle primitive."

Combine::usage =
	"Combine[object, joindata] sets the value of object to the \
	joining of object with joindata; however, if object has no \
	value, then object is set to joindata."

ComplexQ::usage =
	"ComplexQ[z] returns True if z is a complex number, False otherwise."

ComplexTo2DCoord::usage =
	"ComplexTo2DCoord[x] returns the two-dimensional coordinate \
	corresponding to the complex form of x. \
	That is, a pair of values in the form { Re[x], Im[x] } is returned."

ComplexTo2DCoordList::usage =
	"ComplexTo2DCoordList[zlist] returns a list of coordinates \
	corresponding to the complex form of each element in zlist. \
	That is, zlist is mapped through ComplexTo2DCoord."

ConstantQ::usage =
	"ConstantQ[x] returns True if x is always constant. \
	If x is an atom, then x is constant it is a number or it x has \
	a Constant attribute. \
	If x is a function of the form f[arg1, arg2, ...], then x is \
	considered to be constant if arg1, arg2, ..., are constant."

ConstantTerm::usage =
	"ConstantTerm[expr, x] returns the constant term of the \
	expression expr."

Dialogue::usage =
	"Dialogue is an option for all of the symbolic transforms, the \
	differential/difference equations solvers, and more. \
	Possible settings are False, True, or All, for no, partial, or \
	full justification. \
	In the case of symbolic transforms, a setting of True or All will \
	cause the rule base to describe strategies being applied to compute \
	the transform as well as the functions (if any) which it could not \
	transform. \
	If it set to All, then the rule base will also display each step \
	of the transform reasoning."

Element::usage =
	"Element[list, n] returns the nth element of list. \
	Also, Element[l1, l2, ..., n] returns ln."

EmptyQ::usage =
	"EmptyQ[packet] returns True the packet of data is empty."

GenerateCode::usage =
	"GenerateCode[object] converts object to a string (if necessary) \
	and then evaluates it (translates it to Mathematica code)."

GeneratePattern::usage =
	"GeneratePattern[namestring] generates a symbol with the name \
	equal to namestring followed by an underscore, which makes the \
	object be a pattern which can be used for pattern matching. \
	For example, GeneratePattern[\"a\"] yields the pattern (a_)."

GenerateSymbol::usage =
	"GenerateSymbol[namestring], GenerateSymbol[namestring, trailer], \
	and GenerateSymbol[namestring, trailer, header], generate a \
	symbol by concatenating header, namestring, and trailer."

GetAllExponents::usage =
	"GetAllExponents[expr, x] returns all exponents of the \
	term x in the expression expr. \
	GetAllExponents[z^3 + 2 z^6, z] returns {6, 3}."

GetAllFactors::usage =
	"GetAllFactors[expr, x] returns all factors of the \
	term x in the expression expr. \
	GetAllFactors[z^3 + 2 z^6, z] returns {1, 2}. \
	GetAllFactors[z^-3 + 2 z^-6, z] returns {1/2, 1}."

GetArgs::usage =
	"GetArgs[function] returns the argument(s) of the function. \
	For example, GetArgs[ Bogus[1,2,3] ] would return 1,2,3. \
	If the programmer only wishes to replace the head of a function \
	with another, then use Apply instead of GetArgs. \
	This function is similar to ToCollection."

GetOperatorVariables::usage =
	"GetOperatorVariables[op] returns the variable(s) in the \
	parameterized operator op. \
	By default, GetOperatorVariables[ op[par1, par2, ...] ] \
	returns the first parameter, par1."

GetRoot::usage =
	"GetRoot[rule] extracts the value from an expression like \
	{z -> 0.}, which is 0. in this case."

GetRootList::usage =
	"GetRootList[p, x] returns a list of the approximate numerical roots \
	of expression p, a function of x, with infinite roots removed. \ 
	GetRootList[p, x, filter] applies filter to the list of roots \
	returned by the Solve function (defaults to N)."

GetShiftFactor::usage =
	"GetShiftFactor[expr, x] returns a list containing the common
	shift factor in the variable x and a normalized version of expr. \
	For example, GetShiftFactor[ (2 s + 2 b + c) Exp[s + b + Pi], s] \
	returns {b, 2 Exp[Pi + b + s] (b + c/2 + s)}."

GetStateField::usage =
	"GetStateField[state, field] returns the value of the slot \
	field n the list state."

GetVariables::usage =
	"GetVariables[expr] returns a list of all of the variables in \
	the expression expr. \
	See VariableQ for the definition of a variable."

GetValue::usage =
	"GetValue[f[n], n, n0] finds the numeric value of f[n] at n = n0 \
	and GetValue[f[n1,n2], {n1,n2}, {n01, n02}] finds the numeric \
	value of f[n1,n2] at n1 = n01 and n2 = n02. \
	When the first argument has the variables embedded in it, \
	two arguments are sometimes enough:  GetValue[ object, n0 ]. \
	This is true when the object is an abstract signal."

HasAttributes::usage =
	"HasAttributes[symbol, attribute1, attribute2, ...] returns True \
	if the evaluation of symbol is another symbol and the attributes \
	to be checked are a subset of the attributes of this other symbol. \
	HasAttributes[Plus, {Listable, Orderless}] would return True."

ImaginaryQ::usage =
	"ImaginaryQ[z] returns True if z is a number whose real part is zero."

InRange::usage =
	"InRange[a, b, c, amin, cmax, leftcompare, rightcompare] returns \
	True if b in between a and c. \
	The inclusiveness of the interval a to c is determined by the \
	arguments leftcompare and rightcompare, each of which defaults to \
	LessEqual. \
	So, InRange[a, b, c] returns True if a <= b <= c. \
	Non-numeric values, like Infinity, can be used for amin and cmax, \
	which default to -Infinity and +Infinity, respectively."

InfinityQ::usage =
	"InfinityQ[a] will return True if a is Infinity, -Infinity, \
	ComplexInfinity, DirectedInfinity[], or DirectedInfinity[r]."

InformUserQ::usage =
	"InformUserQ[x] returns True if the options in object x contain \
	Dialogue -> All or Dialogue -> True. \
	It also returns True if x is All or True."

ListQ::usage =
	"ListQ[expr] gives True if expr is a List, and False otherwise."

MixedPolynomialQ::usage =
	"MixedPolynomialQ[p] and MixedPolynomialQ[p,x] return \
	return True if p is a polynomial in negative and positive \
	(mixed) powers of x.  \
	Note that rational numbers like 5/6 and 1 are polynomials. \
	MixedPolynomialQ[x + x^-1, x] is True."

MyApart::usage =
	"MyApart[ rational_polynomial, x ] decomposes the rational \
	polynomial into a sum of fractions whose numerators are of \
	the form (x + b)^n where b is a constant and n is an integer. \
	MyApart[rational_polynomial, x, filter] specifies a filter to be \
	placed on the output of the Solve command used to root the \
	denominator:  Identity for rational and N for real-valued roots. \
	The default is Identity. \
	In Mathematica 1.2, MyApart is about 25 times slower than Apart."

MyCollectAll::usage =
	"MyCollectAll[ expression, var ] attempts to collect all \
	subexpressions of expression in terms of var."

MyFreeQ::usage =
	"MyFreeQ[expr, form], when form is not a list, yields True if no \
	subexpression in expr matches form. \
	If form is a list, then True is returned if expr is free of \
	each element of form. \
	This is similar to MyFreeQ[expr, form1, form2, ...] which expands to \
	MyFreeQ[expr, form1] and MyFreeQ[expr, form2] and ...."

MyMessage::usage =
	"MyMessage[message-label, return-value, arg1, arg2, ...] first calls \
	Message[message-label, arg1, arg2, ...] and then returns return-value."

MyTogether::usage =
	"MyTogether[x] puts the expression x over a common denominator. \
	This is the same as Together[x] without the effect of Cancel. \
	This function is compatible with DFT expressions."

NegExponent::usage =
	"NegExponent[poly, x] returns the maximum exponent of x^-1."

NormalizedQ::usage =
	"NormalizedQ[e,x] gives True if the constant term is one \
	or zero, and gives False otherwise."

NullPlot::usage =
	"NullPlot is a 2-d graphics object which only contains the origin."

PatternQ::usage =
	"PatternQ[expr] returns True if the head of expr is Pattern."

PointwisePlot::usage =
	"PointwisePlot[coordlist, text] and \
	PointwisePlot[coordlist, text, multiplicitytext] \
	will plot the coordinates in coordlist as text \
	for 2-D and 3-D graphics. \
	An optional fourth argument specifies the size of the font to use. \
	For multiple occurrences of the same coordinate,\
	the object multiplicitytext is displayed. \
	The last two arguments are usually symbols, numbers, or \
	FontForm objects."

PrintIt::usage =
	"PrintIt[graphics, printer] will print out graphics on a printer. \
	If the printer is not specified, the default printer is used."

ProtectIt::usage =
	"ProtectIt[expr] evaluates expr. \
	If it evaluates to a symbol, that symbol will be write protected. \
	Rules can be written for that symbol, \
	but values can no longer be assigned to it."

RationalQ::usage =
	"RationalQ[m] returns True if m is a rational number. \
	If m is an integer, then this function also return True, \
	since the set of integers are a subset of rationals."

RationalFunctionQ::usage =
	"RationalFunctionQ[f,x] returns True if expression f is of the form \
	f = g(x) / h(x), where h(x) depends on x but g(x) does not have \
	to depend on x. \
	For example, 1 / ( x + 1 ) is a rational function \
	in x but x^3 + x^2 + x / ( x + 1) is not."

RationalPolynomialQ::usage =
	"RationalPolynomialQ[p] and RationalPolynomialQ[p,x] return \
	True if p is a rational polynomial in x. \
	Note that rational numbers like 5/6 and 1 are also \
	rational polynomials."

RealQ::usage =
	"RealQ[z] returns True if z is a floating-point number \
	(has a head of Real), False otherwise.  See RealValuedQ."

RealValuedQ::usage =
	"RealValuedQ[z] gives True if z is a number whose imaginary \
	component is 0, and gives False otherwise.  See RealQ."

RemoveOptions::usage =
	"RemoveOptions[optionlist, options] removes the options \
	from optionlist."

ReplaceWith::usage =
	"ReplaceWith[oldexpr, newexpr] is a generalized way to specify \
	a substitution when the substitution may be either atomic \
	and a list of substitutions."

RuleAppliesQ::usage =
	"RuleAppliesQ[expr, rule] returns True if rule applies to expr. \
	RuleAppliesQ[head[expr1, expr2, ..., exprn], rule, head] returns \
	True if the rule applies to each expression expr1, expr2, ..., \
	exprn."

SameFormQ::usage =
	"SameFormQ[pattern, expr1, expr2, ...] returns True if every \
	expression matches pattern via MatchQ. \
	Once an expression does not match, \
	this function immediately returns False."

Second::usage =
	"Second[list] returns the second element of list."

SetExclusion::usage =
	"SetExclusion[set1, set2, ...] returns a set equal to the union \
	of the sets minus the intersection of the sets."

SetStateField::usage =
	"SetStateField[state, field, value] will return a new state, \
	which is a copy of the list state except that the value of \
	the slot field will be equal to value."

SPfunctions::usage =
	"SPfunctions maintains a current list of those new routines \
	that have been loaded from the signal processing packages."

SPLessGreaterRules::usage =
	"SPLessGreaterRules are a collection of rules for simplifying \
	expressions involving inequalities."

SPoperators::usage =
	"SPoperators maintains a current list of the new mathematical \
	operators that have been loaded from the signal processing packages."

SPsignals::usage =
	"SPsignals maintains a current list of those new signals \
	(mathematical functions) that have been loaded from the \
	signal processing packages."

SPSimplificationRules::usage =
	"SPSimplificationRules are a collection of simplification rules \
	that are not carried out by Simplify. \
	These rules require too much overhead to encode them directly \
	into Mathematica. \
	See also SPSimplify."

StripPackage::usage =
	"StripPackage[symbol] returns the symbol (as a string) after its \
	context has been removed. \
	To remove the package definition from every symbol in expression, \
	use MapAll[StripPackaage, expression]."

SubsetQ::usage =
	"SubsetQ[set1, set2, set3,  ...] returns True if set1 is a subset \
	of set2 and set2 is a subset of set3, etc."

TableLookup::usage =
	"TableLookup[index, hlist, len, val] returns hlist[[index]] \
	if index is between 1 and len, inclusive; otherwise, val is \
	returned."

Third::usage =
	"Third[list] returns the third element of list."

ToCollection::usage =
	"ToCollection[expr] strips the head off of arg and returns \
	the argument of expr as a collection. \
	ToCollection returns an object that is a sequence, \
	which is represented in Mathematica 1.2 as (a1, a2, ...) \
	and in Mathematica 2.0 as Sequence[a1, a2, ...]. \
	So, it provides a unified way of generating collections (sequences)."

ToList::usage =
	"ToList[arg] returns arg if arg is a list. \
	Otherwise, List[arg] is returned. \
	ToList[arg1, arg2, ...] returns List[arg1, arg2, ...]."

UnprotectIt::usage =
	"UnprotectIt[expr] evaluates expr. \
	If it evaluates to a symbol, \
	write protection will be removed for that symbol."

VariableQ::usage =
	"VariableQ[x] returns True if x is a symbol that \
	(1) does not have a numerical value associated with it and
	(2) does not have its Constant attribute enabled. \
	Pi fails the first test, so it is not considered a variable. \
	A variable can also have the form of C[n] where n is an integer \
	and C is a symbol whose Constant attribute is enabled."

ZeroQ::usage =
	"ZeroQ[x] returns True if x is 0 or 0.0"

ZPolynomial::usage =
	"ZPolynomial[m, n] is an mth order polynomial in the discrete \
	variable n defined by the product of (-n - k) for k = 0 ... m-1. \
	The z-transform of the product of this polynomial and some function \
	f[n] gives z^m times the mth derivative of F(z)."

(*  E N D     U S A G E     I N F O R M A T I O N  *)


Begin["`Private`"]


(*  A L T E R     E X I S T I N G    F U N C T I O N S  *)

(*  And     *)
Unprotect[And]
And/: Simplify[And[a1_, args__]] := Apply[And, Union[{a1, args}]]
Protect[And]

(*  ClearAttributes  *)
Unprotect[ClearAttributes]
SetAttributes[ClearAttributes, HoldFirst]
Protect[ClearAttributes]

(*  Det     *)
Unprotect[Det]
Det[x_?NumberQ] := x
Protect[Det]

(*  Dot     *)
Unprotect[Dot]
Dot[x_?NumberQ, y_?NumberQ] := x y
Protect[Dot]

(*  Limit  *)
If [ TrueQ[ $VersionNumber >= 2.0 ],
     Unprotect[ Limit ];
     Limit/: Options[Limit] := { Analytic -> True, Direction -> Automatic };
     Protect[ Limit ] ]

(*  SetAttributes  *)
Unprotect[SetAttributes]
SetAttributes[SetAttributes, HoldFirst]
Protect[SetAttributes]

(*  TeXForm  *)
Unprotect[Re, Im]
Im/: Format[ Im[x_], TeXForm ] := StringForm["\\Im{m}(``)", x]
Re/: Format[ Re[x_], TeXForm ] := StringForm["\\Re{e}(``)", x]
Protect[Re, Im]



(*  S I M P L I F I C A T I O N     R U L E S  *)

(*  PositiveOrNegative  *)
PositiveOrNegative[a_] := SameQ[Head[N[a]], Real]

(*  For minimum/maximum operations  *)
MinMaxRules = {
	Min[t1_, t2_] :> t1 /; N[t1 < t2],
	Min[t1_, t2_] :> t2 /; N[t1 > t2],
	Max[t1_, t2_] :> t1 /; N[t1 > t2],
	Max[t1_, t2_] :> t2 /; N[t1 < t2],

	Min[a_ + b_, b_] :> a + b /; Negative[a],
	Min[a_ + b_, b_] :> b /; Positive[a],
	Max[a_ + b_, b_] :> b /; Negative[a],
	Max[a_ + b_, b_] :> a + b /; Positive[a]
}
 
If [ ! TrueQ[ $VersionNumber >= 2.0 ],		(* built into 2.0's Simplify *)
     MinMaxRules = MinMaxRules ~Join~ {
	Min[a_, a_] :> a,
	Max[a_, a_] :> a
	} ]

(*  For the less than operation  *)
LessRules = {
	Less[Max[a_, b__], a_] :> Less[Max[b], a],
	LessEqual[Max[a_, b__], a_] :> LessEqual[Max[b], a],
	Less[Times[-1, b_], 0] :> Greater[b, 0],
	LessEqual[Times[-1, b_], 0] :> GreaterEqual[b, 0]
}

(*  For the greater than operation  *)
GreaterRules = {
	Greater[Min[a_, b__], a_] :> Greater[Min[b], a],
	GreaterEqual[Min[a_, b__], a_] :> GreaterEqual[Min[b], a],
	Greater[Times[-1, b_], 0] :> Less[b, 0],
	GreaterEqual[Times[-1, b_], 0] :> LessEqual[b, 0]
}

(*  For the absolute value operation  *)
AbsRules = {
	Abs[- a_] :> Abs[a],
	Abs[x_?PositiveOrNegative y_] :> Abs[x] Abs[y]
}

If [ ! TrueQ[ $VersionNumber >= 2.0 ],		(* built into 2.0's Simplify *)
     AbsRules = AbsRules ~Join~ {
	Re[Abs[a_]] :> Abs[a],
	Im[Abs[a_]] :> 0,
	Abs[Abs[a_]] :> Abs[a],
	Abs[r_. Exp[ Complex[0, b_] a_. ] ] :> r /; PositiveOrNegative[a b r],
	Abs[a_] :> a /; Positive[a],
	Abs[a_] :> -a /; Negative[a]
	} ]

(*  For the real and imaginary operations  *)
ReImRules = {
	Re[- a_] :> - Re[a],
	Im[- a_] :> - Im[a],
	Conjugate[ Exp[ Complex[0, b_] a_. ] ] :> Exp[ Complex[0, -b] a ] /;
		PositiveOrNegative[a b],
        Conjugate[ ( a_. Conjugate[z_]^r_. + b_. )^s_. ] :>
		( a z^r + b )^s /;
		((r == 1) || (r == -1)) && ((s == 1) || (s == -1)) &&
		PositiveOrNegative[a] && PositiveOrNegative[b],
        Conjugate[a_ b_] :> Conjugate[a] Conjugate[b]
}

If [ ! TrueQ[ $VersionNumber >= 2.0 ],		(* built into 2.0's Simplify *)
     ReImRules = ReImRules ~Join~ {
	Re[a_] :> a /; PositiveOrNegative[a],
	Im[a_] :> 0 /; PositiveOrNegative[a],

	Re[r_. Exp[ Complex[0, b_] a_. ] ] :> r Cos[b a] /;
		PositiveOrNegative[a b r],
	Im[r_. Exp[ Complex[0, b_] a_. ] ] :> r Sin[b a] /;
		PositiveOrNegative[a b r],

	Re[Im[a_]] :> Im[a],
	Im[Re[a_]] :> 0,
	Re[Re[a_]] :> Re[a],
	Im[Im[a_]] :> 0,

	Conjugate[Conjugate[x_]] :> x,
	Conjugate[Re[x]] :> Re[x],
	Conjugate[Im[x]] :> Im[x],
	Conjugate[x_] :> x /; PositiveOrNegative[x]
	} ]

(*  For products of exponentials  *)
TimesRules = {
	a_^k_ b_^k_ :> 1 /; ( a == 1/b ) && PositiveOrNegative[k]
}

(*  For exponential and logarithmic functions  *)
ExpLogRules = {
	base_^(c_. Log[base_, b_]) :> b^c,
	Log[c_. Exp[b_]] :> Log[c] + b,
	Log[base_, c_. base_^b_] :> Log[base, c] + b
}

If [ ! TrueQ[ $VersionNumber >= 2.0 ],		(* built into 2.0's Simplify *)
     ExpLogRules = ExpLogRules ~Join~ {
	Exp[c_. Log[b_]] :> b^c,
	Erf[-a_] :> -Erf[a],
	Exp[ a_. Complex[0, b_] Pi ] :> Exp[ Mod[a b, 2] I Pi ] /;
		RationalQ[a b] && ( (a b < 0) || (a b >= 2) )
	} ]

(*  Evenness and oddness of functions  *)
EvenOddRules = {
	Sign[-x_] :> -Sign[x],
	BesselI[n_Integer, -x_] :> (-1)^n BesselI[n, x],
	BesselJ[n_Integer, -x_] :> (-1)^n BesselJ[n, x]
}
If [ ! TrueQ[ $VersionNumber >= 2.0 ],
     EvenOddRules = EvenOddRules ~Join~ {
	Sin[-x_]  :> -Sin[x],
	Cos[-x_]  :>  Cos[x],
	Tan[-x_]  :> -Tan[x] } ]

(*  For other simplifications  *)
If [ TrueQ[ $VersionNumber >= 2.0 ],
     OtherRules = {
	( ((x_^l_.) t_)^k_ :> x^(l k) t^k /;
	    PositiveOrNegative[x] && PositiveOrNegative[l] &&
	    PositiveOrNegative[k] ) },
     OtherRules = {
	Sqrt[x_] :> I Sqrt[-x] /; x < 0,
	Tan[Complex[0, b_] w_.] :> I Tanh[b w],
	Sin[Complex[0, b_] w_.] :> I Sinh[b w],
	Cos[Complex[0, b_] w_.] :> Cosh[b w] } ]


SPSimplificationRules =
    Join[MinMaxRules, AbsRules, TimesRules, ReImRules,
         ExpLogRules, OtherRules, EvenOddRules]

SPLessGreaterRules = Join[LessRules, GreaterRules]


(*  M E S S A G E S  *)

PointwisePlot::invalid = "Null coordinate list passed."

Dialogue::notvalid =
	"The Dialogue option must be True, False, or All: `` is not valid."


(*  G L O B A L S  *)

NullPlot := Graphics [ PointSize[0.007] ]
(*  NullPlot := Graphics [ Point[{0, 0}], DisplayFunction -> Identity ]  *)


(*  F U N C T I O N S  *)

(*  AllSubsets  *)
AllSubsets[x_List] :=
	Sort[ Map[Flatten, Distribute[Map[{{},{#1}}&, x], List]] ]

(*  Arrow2D  *)
Arrow2D[tail_, plotwidth_, plotheight_:1] :=
	Arrow2D[tail, plotwidth, plotheight, plotheight]

Arrow2D[tail_, plotwidth_, plotheight_, length_] :=
	Block [	{arrowleft, arrowright, head, xoffset, yoffset},
		xoffset = 0.1 plotheight;
		yoffset = 0.3 plotheight;
		head = tail + { 0, length };
		arrowleft = head - { xoffset, yoffset };
		arrowright = head + { xoffset, - yoffset };
		Graphics[ Line[{tail, head, arrowleft, arrowright, head}] ] ]

(*  AssociateItem  *)
AssociateItem[item_, lookuptable_, assoctable_] :=
	Map[Function[var, AssociateItem[var, lookuptable, assoctable]], item] /;
	ListQ[item]
AssociateItem[item_, lookuptable_, assoctable_] :=
	If [ MemberQ[lookuptable, item],
	     assoctable [[ ToCollection[ToCollection[Position[lookuptable, item] ]] ]] ] /;
	! ListQ[item]

(*  Assuming  *)
AssumingList = {}

Assuming[] := AssumingList = {}
Assuming[All] := Apply[And, AssumingList]
Assuming[True] := Null
Assuming[True, x_] := Null
Assuming[cond_] := AppendTo[AssumingList, cond]
Assuming[cond_, op_List] := Assuming[cond, SameQ[Replace[Dialogue, op], All]]
Assuming[cond_, True] :=
	Block [	{},
		Print[ "assuming ", cond ]; 
		Assuming[cond] ]
Assuming[cond_, x_] := Assuming[cond]

(*  CirclePS  *)
CirclePS[r_] := Graphics[ Circle[{0, 0}, r] ]
CirclePS[r_, p_] := Graphics[ { p, Circle[{0, 0}, r] } ]

(*  Combine  *)
SetAttributes[Combine, {HoldFirst}]
Combine[object_, joindata_] :=
	If [ ValueQ[object],
	     object = Sort[object ~Join~ joindata],
	     object = joindata ]

(*  ComplexQ  *)
ComplexQ[z_] := NumberQ[z] && SameQ[Head[z], Complex]

(*  ComplexTo2DCoord and ComplexTo2DCoordList  *)
ComplexTo2DCoord[z_] := { Re[z], Im[z] }
  
ComplexTo2DCoordList[zlist_] := Map[ ComplexTo2DCoord, zlist ]

(*  ConstantQ  *)
ConstantQ[x_?AtomQ] := NumberQ[x] || HasAttributes[x, Constant]
ConstantQ[f_[x__]] := Apply[And, Map[ConstantQ, List[x]]]

(*  ConstantTerm  *)
ConstantTerm[expr_, z_:Global`x] :=
	Block [ {nonpropterms},
		keepconstants[e_] := If [ MyFreeQ[e,z], e, 0 ];
		nonpropterms = Coefficient[expr, z, 0];
		If [ MyFreeQ[nonpropterms, z],
		     nonpropterms,
		     Map[keepconstants, nonpropterms] ] ]

(*  Element  *)
Element[h_[args__], i_?IntegerQ] := h[args] [[i]]
Element[x_?AtomQ, i_] := x
Element[x__, i_?IntegerQ] := ToList[x] [[i]]

(*  EmptyQ  *)
EmptyQ[x_?AtomQ] := False
EmptyQ[h_[]] := True
EmptyQ[h_[values__]] := False

(*  GenerateCode  *)
GenerateCode[code_] := ToExpression[ToString[code]]

(*  GeneratePattern  *)
GeneratePattern[name_] := GenerateSymbol[name, "_"]

(*  GenerateSymbol  *)
GenerateSymbol[name_] := GenerateCode[name]
GenerateSymbol[name_, trailer_] :=
	GenerateCode[StringForm["````", name, trailer]]
GenerateSymbol[name_, trailer_, header_] :=
	GenerateCode[StringForm["``````", header, name, trailer]]

(*  GetArgs  *)
GetArgs[h_[]] := Null
GetArgs[h_[x__][d__]] := d
GetArgs[h_[x__]] := x

GetArgs[e1_, e__] := ToCollection[ GetArgs[e1], GetArgs[e] ]

(*  GetAllExponents and GetAllFactors  *)
depthfirstsearch[expr_, lhs_, rule_] :=
	Block [ {cur, i, len},

		If [ AtomQ[expr],
		     If [ MatchQ[expr, lhs],
			  PrependTo[list, Replace[expr, rule]] ],

		     len = Length[expr];
		     For [ i = 1, i <= len, i++,
			   cur = expr[[i]];
			   If [ MatchQ[cur, lhs],
				PrependTo[list, Replace[cur, rule]],
				depthfirstsearch[cur, lhs, rule] ] ] ];

		Null ]

depthdriver[expr_, lhs_, rule_] :=
	Block [	{},
		list = {};
		depthfirstsearch[expr, lhs, rule];
		list ]

GetAllExponents[ expr_, z_ ] :=
	depthdriver[expr, (c_. z^n_.), (c_. z^n_. :> n) ]

GetAllFactors[ a_ + b_, z_ ] :=
	Join[ GetAllFactors[a, z], GetAllFactors[b, z] ]
GetAllFactors[ c_ z_^n_. expr_, z_ ] :=
	Prepend[ GetAllFactors[expr, z], c^Sign[n] /. Sign[x_] :> 1 ]
GetAllFactors[ expr_, z_ ] :=
	depthdriver[expr, (c_. z^n_.), (c_. z^n_. :> c^Sign[n]) ] /.
	( Sign[x_] :> 1 )

(*  GetOperatorVariables  *)
GetOperatorVariables[ h_[var_, rest___] ] := var

(*  GetRoot  *)
GetRoot[{}] := {}				(* no roots *)
GetRoot[rule_] := Second[First[rule]]

(*  GetRootList  *)
goodroot[r_] := ! MatchQ[r, DirectedInfinity[___]]

GetRootList[p_, x_, filter_:N] :=
	Select[ Map[ GetRoot, filter[ Solve[ p == 0, x ] ] ], goodroot ]

(*  GetShiftFactor  *)
commonFactor = 0

myMin[ x1_?RealValuedQ, x2_?RealValuedQ ] :=
	Min[x1, x2]
myMin[ x1_?RealValuedQ, Complex[re2_,im2_] ] :=
	Complex[myMin[x1, re2], im2]
myMin[ Complex[re1_,im1_], Complex[re2_,im2_] ] :=
	Complex[myMin[re1,re2], myMin[im1,im2] ]

reduce[ 0, x_, term_ ] := term		(* stopping conditions  *)
reduce[ x_, 0, term_ ] := term

reduce[ x1_?NumberQ + rest1_., x2_?NumberQ + rest2_., term_ ] :=
	reduce[ rest1, rest2, term + myMin[x1,x2] ]
reduce[ x1_. y_ + rest1_., x2_. y_ + rest2_., term_ ] :=
	reduce[ rest1, rest2, term + myMin[x1,x2] y ] /;
	NumberQ[x1] && NumberQ[x2] && ! NumberQ[y]

reduce[ a_, b_, term_ ] := term		(* incomplete reduction *)

extractShift[ a_, b_, s_ ] :=
	Block [ {shift},
		shift = Expand[b/a];
		If [ ValueQ[commonFactor],
		     commonFactor = reduce[shift, commonFactor, 0],
		     commonFactor = shift ];
		a ( s + shift ) ]

GetShiftFactor[expr_, s_] :=
	Block [	{normexpr, rules},
		Clear[commonFactor];
		rules = (a_. s + b_. :> extractShift[a, b, s]);
		If [ ! TrueQ[ $VersionNumber >= 2.0 ],
		     rules = { (a_. s + b__) :> extractShift[a, Plus[b], s],
			       rules,
			       s :> extractShift[1, 0, s] } ];
		normexpr = expr /. rules;
		If [ ! ValueQ[commonFactor], commonFactor = 0 ];
		{ commonFactor, normexpr } ]

(*  GetStateField  *)
GetStateField[state_List, field_] := state[[field]]

(*  GetVariables  *)
extractrules = { f_[x__][y__][z__] :> bogus[x, y, z],
		 f_[x__][y__] :> bogus[x, y],
		 (x_ -> y_) :> {},
		 (x_ :> y_) :> {} }

GetVariables[x_] :=
	Union[ Select[ Level[x /. extractrules, Infinity], VariableQ ] ]

(*  GetValue  *)
GetValue[f_, n_Symbol, n0_] :=
	Block [	{value},
		value = N [ f /. n -> n0 ];
		If [ NumberQ[value],
		     value,
		     N [ Limit[f, n -> n0] ] ] ]

GetValue[f_, {n1_Symbol, n2_Symbol}, {n01_, n02_}] :=
	Block [	{value},
		value = N [ f /. { n1 -> n01, n2 -> n02 } ];
		If [ NumberQ[value],
		     value,
		     N[ Limit[ Limit[f, n1 -> n01], n2 -> n02] ] ] ]

(*  HasAttributes  *)
HasAttributes[symbol_, attrib1_, attribs__] :=
	HasAttributes[symbol, {attrib1, attribs}]

HasAttributes[symbol_Symbol, attrib_] :=
	Block [	{attributes, protected},
		attributes = Attributes[Attributes];
		Unprotect[Attributes];
		ClearAttributes[Attributes, {HoldFirst, HoldAll, HoldRest}];
		protected = If [ AtomQ[attrib],
				 MemberQ[Attributes[symbol], attrib],
				 SubsetQ[attrib, Attributes[symbol]] ];
		SetAttributes[Attributes, attributes];
		protected ]

(*  ImaginaryQ  *)
ImaginaryQ[z_] := NumberQ[z] && ZeroQ[Re[z]]

(*  InRange, function will be automatically threaded if a,b,c are not atoms  *)
SetAttributes[MyInRange, Listable]

InRange[a_, b_, c_, amin_:-Infinity, cmax_:Infinity, leftcompare_:LessEqual, rightcompare_:LessEqual ] :=
	Apply[And,
	      ToList[MyInRange[a, b, c, amin, cmax, leftcompare, rightcompare]]]

MyInRange[a_, b_, c_, amin_, cmax_, leftcompare_, rightcompare_] :=
	Which [ SameQ[a, amin] && SameQ[c, cmax],
		  True,
		SameQ[a, amin],
		  SameQ[b, amin] || rightcompare[b, c],
		SameQ[c, cmax],
		  SameQ[b, cmax] || leftcompare[a, b],
		True,
		  leftcompare[a, b] && rightcompare[b, c] ]


(*  InfinityQ  *)
InfinityQ[e_List] := Apply[And, Map[InfinityQ, e]]
InfinityQ[DirectedInfinity[]] := True 
InfinityQ[DirectedInfinity[r_]] := True
InfinityQ[a_] := False

(*  InformUserQ  *)
informuser[All] := True
informuser[True] := True
informuser[False] := False
informuser[x_] := False

InformUserQ[x_List] := informuser[Replace[Dialogue, x]]
InformUserQ[x_] := informuser[x]

(*  ListQ--  it is an undocumented primitive in Mma 2.0+	*)
(*           in 2.0, it does not always return True or False	*)
ListQ[object_] := SameQ[Head[object], List]

(*  MixedPolynomialQ  *)
twosided[ c_. z_^r_., z_ ] := FreeQ[c, z] && IntegerQ[r]
twosided[ c_, z_ ] := FreeQ[c, z]

MixedPolynomialQ[c_] := MixedPolynomialQ[c, Global`x]

MixedPolynomialQ[x_?AtomQ, z_] := True
MixedPolynomialQ[Plus[a_, b__], z_] := Apply[And, Map[twosided[#1, z]&, {a, b}]]
MixedPolynomialQ[x_, z_] := twosided[x, z]

(*  MyApart --  kludge around the way Apart does partial fractions *)
(*		Root denominator and replace roots with symbols	   *)
MyApart[ratpoly_, x_, filter_:Identity] :=
	Block [	{apart, denom, denomfactored, normfact, numer,
		 partfrac, rootlist, rootmult, rules},

		numer = Numerator[ratpoly];
		denom = Denominator[ratpoly];
		normfact = Last[ CoefficientList[denom, x] ];
		numer /= normfact;
		denom /= normfact;
		rootlist = Sort[ GetRootList[denom, x, filter] ];
		{ denomfactored, rules } = multiplicityform[rootlist, x];
		apart = Apart[numer / denomfactored, x];

		partfrac = apart /. rules;
		partfrac /. ( a_. / (b_ c_) :> a / ( Together[b] c ) /;
				FreeQ[b, x] &&  ! FreeQ[c, x] ) ]

multiplicityform[ roots_, x_ ] :=
	Block [	{count = 1, cur, denom = 1, i, last,
		 length, sublist = {}, sym = 1},
		Clear[localvar];	(* localvar is global to package *)
		length = Length[roots];
		last = First[roots];
		For [ i = 2, i <= length, i++,
		      cur = roots[[i]];
		      If [ SameQ[ cur, last ],
			   count++,
			   denom *= (x - localvar[sym])^count;
			     PrependTo[ sublist, localvar[sym] -> last ];
			     sym++;
			     count = 1 ];
		      last = cur ];

		denom *= (x - localvar[sym])^count;
		PrependTo[ sublist, localvar[sym] -> last ];

		{ denom, sublist } ]

(*  MyCollectAll  *)
MyCollectAll[ Plus[term1_, terms__], x_ ] := Collect[ Plus[term1, terms], x ]
MyCollectAll[ h_[a_], x_ ] := h[ MyCollectAll[a,x] ]
MyCollectAll[ h_[a_, b__], x_ ] := Apply[h, Map[MyCollectAll[#1, x]&, {a, b}]]
MyCollectAll[ a_, x_ ] := a

(*  MyFreeQ  *)
MyFreeQ[expr_, {form_}] := FreeQ[expr, form]
MyFreeQ[expr_, {form1_, forms__}] := FreeQ[expr, form1] && MyFreeQ[expr, forms]
MyFreeQ[expr_, form_] := FreeQ[expr, form]
MyFreeQ[expr_, form1_, forms__] := FreeQ[expr, form1] && MyFreeQ[expr, forms]

(*  MyMessage  *)
SetAttributes[MyMessage, HoldFirst]
MyMessage[message_, return_] :=
	Block [	{},
		Message[message];
		return ]
MyMessage[message_, return_, args__] :=
	Block [	{},
		Message[message, args];
		return ]

(*  MyTogether  *)
MyTogether[ Plus[a_, b_, c__] ] := MyTogether[ Plus[MyTogether[Plus[a, b]], c] ]
MyTogether[ Plus[a_, b_] ] := MyTogether[ Numerator[a], Denominator[a], Numerator[b], Denominator[b] ]
MyTogether[ a_ ] := a

MyTogether[ a_, b_, c_, b_ ] := ( a + c ) / b
MyTogether[ a_, b_, c_, b_ d_ ] := ( a d + c ) / ( b d )
MyTogether[ a_, b_ d_, c_, d_ ] := ( a + b c ) / ( b d )
MyTogether[ a_, b_, c_, d_ ] := ( a d + b c ) / ( b d )

(*  NegExponent  *)
NegExponent[p_, x_:Global`x] := Exponent[p /. x -> x^-1, x]

(*  NormalizedQ  *)
NormalizedQ[e_, z_] :=
	Block [	{leadingcoef},
		leadingcoef = ConstantTerm[Expand[e], z];
		TrueQ[( leadingcoef == 0 ) || ( leadingcoef == 1 )] ]

(*  PatternQ  *)
PatternQ[expr_] := SameQ[Head[expr], Pattern]

(*  PointwisePlot  *)

PointwisePlot[coordlist_, singtext_] :=
	PointwisePlot[coordlist, singtext, singtext]

(*  plots each unique set of coordinates.  multiple occurrences of the   *)
(*    same coordinate are plotted as <text>(n), where n is the number of *)
(*    occurrences.  First, the coordinate list is sorted.  A Null is     *)
(*    appended because the scanning function compares the current        *)
(*    coordinate with the last, so that Null forces the last coordinate  *)
(*    to be processed.  After the pointwiseplot graphics commands are    *)
(*    built up, the resulting plot is returned as a graphics object.     *)
(*    The point size of the text defaults to 18.  Supported font sizes   *)
(*    are 10, 12, 14, 18, 20, 24, ...					 *)

PointwisePlot[coordlist_, singtext_, multtext_, fontsize_:18] :=
	Block [	{counter = 1, text, lastcoord = Null,
		 pointwiseplot = {}, ptsize, str},
		ptsize = Round[fontsize];
		Scan [ Function[ coord,
			 Which [ SameQ[lastcoord, Null],   (* initial cond.   *)
				   counter = 1;
				   lastcoord = coord,
				 SameQ[coord, lastcoord],  (* multiple occur. *)
				   ++counter,
				 True,				   (* plot it *)
				   str = If [ SameQ[counter, 1],
				   	      singtext,
					      multtext ];
				   text = If [ TrueQ[$VersionNumber >= 2.0],
					       FontForm[str, {"Bold", ptsize}],
					       FontForm[str, "Bold", ptsize] ];
				   AppendTo[ pointwiseplot,
					     Text[text, lastcoord] ];
				   counter = 1;
				   lastcoord = coord ] ],
		       Append[Sort[coordlist], Null] ];
		Graphics[pointwiseplot] ] /;
	! EmptyQ[coordlist]

PointwisePlot[coordlist_, singtext_, multtext_] :=
	MyMessage[PointwisePlot::invalid, NullPlot] /;
	EmptyQ[coordlist] 

(*  PrintIt  *)
PrintIt[graphics_] :=
	Display["!psfix | lpr", graphics]

PrintIt[graphics_, printer_] :=
	Display[ToString[StringForm["!psfix | lpr -P``", printer]], graphics]

(*  ProtectIt  *)
ProtectIt[symbol_Symbol] := Apply[Protect, {symbol}]

(*  RationalQ  *)
RationalQ[z_Integer] := True
RationalQ[z_Rational] := True
RationalQ[z_] := False

(*  RationalFunctionQ  *)
RationalFunctionQ[f_, x_:Global`x] :=
	( ! SameQ[Head[f], Plus] ) && ( ! MyFreeQ[Denominator[f], x] )

(*  RationalPolynomialQ  *)
RationalPolynomialQ[p_] :=
	PolynomialQ[Numerator[p]] && PolynomialQ[Denominator[p]]
RationalPolynomialQ[p_, x_] :=
	PolynomialQ[Numerator[p], x] && PolynomialQ[Denominator[p], x]

(*  RealQ  *)
RealQ[z_] := SameQ[Head[z], Real]

(*  RealValuedQ  *)
RealValuedQ[z_] := NumberQ[z] && ZeroQ[Im[z]]

(*  RemoveOptions  *)
badOptionList = {}
goodOptionQ[ a_ -> b_ ] := ! MemberQ[badOptionList, a]
goodOptionQ[ a_ :> b_ ] := ! MemberQ[badOptionList, a]
goodOptionQ[ x_ ] := False

RemoveOptions[ oplist_List, badoplist_List ] :=
	Block [ {},
		badOptionList = badoplist;
		Select[ oplist, goodOptionQ ] ]


(*  ReplaceWith  *)
SetAttributes[ReplaceWith, {Listable}]
ReplaceWith[org_, val_] := org -> val

(*  RuleAppliesQ  *)
(*  Yes, I tried the "efficient" way of separating the lhs	*)
(*  and rhs to see if the lhs applies to an expression;		*)
(*  The would avoid the evaluation of the right-hand side.	*)
(*  The main problem is that we are not guaranteed to run	*)
(*  through all possible pattern matches since this separation	*)
(*  only considers one pattern match.  Therefore, I had to	*)
(*  encode this by evaluating the rule using Replace.		*)

RuleAppliesQ[expr_, rule_] := ! SameQ[expr, Replace[expr, rule]]
RuleAppliesQ[expr_, rule_, True] :=
	Apply[ And, Map[ RuleAppliesQ[#, rule]&, Apply[List, expr] ] ]

(*  SameFormQ  *)
SameFormQ[form_, expr_] := MatchQ[expr, form]
SameFormQ[form_, expr1_, expr__] :=
	SameFormQ[form, expr1] && SameFormQ[form, expr]

(*  Second  *)
Unprotect[Second]
Second[x_] := x[[2]]
Protect[Second]

(*  SetExclusion  *)
SetExclusion[sets__] := Complement[Union[sets], Intersection[sets]]

(*  SetStateField  *)
SetStateField[state_List, field_, value_] :=
	Block [ {newstate},
		newstate = state;
		newstate[[field]] = value;
		newstate ]

(*  StripPackage  *)
StripPackage[symbol_Symbol] := StripPackage[ ToString[symbol] ]

StripPackage[symbol_String] :=
	Block [	{expandedstring, pos},
		expandedstring = Characters[symbol];
		pos = Position[expandedstring, "`"];
		If [ SameQ[pos, {}],
		     symbol,
		     Apply[ StringJoin,
			    Drop[expandedstring, Last[Last[pos]]] ] ] ]

StripPackage[x_] := x

(*  SubsetQ  *)
SubsetQ[x1_] := True
SubsetQ[x1_, x2_] :=
	Block [	{x1sorted},
		x1sorted = Sort[x1];
		SameQ[x1sorted, Intersection[x1sorted, x2]] ]
SubsetQ[x1_, x2_, x__] := SubsetQ[x1, x2] && SubsetQ[x2, x]

(*  TableLookup  *)
TableLookup[index_, table_, len_, val_] :=		(* multidimensional *)
	Which [ TrueQ[ Apply[Or, Map[InfinityQ, index]] ],
		  val,
		TrueQ[ InRange[1, index, len] ],
		  Apply[Part, {table} ~Join~ index],
		True,
		  val ] /;
	ListQ[index]

TableLookup[index_, table_, len_, val_] :=		(* one-dimensional  *)
	Which [ InfinityQ[index],
		  val,
		TrueQ[ 1 <= index <= len ],
		  table[[index]],
		True,
		  val ] /;
	( InfinityQ[index] || IntegerQ[index] ) && IntegerQ[len]

(*  Third  *)
Third[x_] := x[[3]]

(*  ToCollection  *)
ToCollection[x_?AtomQ] := x
ToCollection[h_[args___]] := args
ToCollection[a__] := a

(*  ToList  *)
ToList[] := {}
ToList[arg_List] := arg
ToList[arg_] := List[arg] /; ! SameQ[Head[arg], List]
ToList[arg1_, args__] := List[arg1, args]

(*  UnprotectIt  *)
UnprotectIt[symbol_Symbol] :=
	Block [	{attributes},
		attributes = Attributes[Unprotect];
		Unprotect[Unprotect];
		ClearAttributes[Unprotect, {HoldFirst, HoldAll, HoldRest}];
		Unprotect[symbol];
		SetAttributes[Unprotect, attributes] ]

(*  VariableQ  *)
VariableQ[x_Symbol] := ! ConstantQ[x]
VariableQ[x_[n_Integer]] := HasAttributes[x, Constant]
VariableQ[x_] := False

(*  ZeroQ  *)
ZeroQ[x_] := SameQ[x, 0] || SameQ[x, 0.0]

(*  ZPolynomial  *)
ZPolynomial[m_Integer, n_] :=
	(-1)^m Expand[ Product[n + k, {k, 0, m-1}] ] /; ( m > 0 )


(*  E N D     P A C K A G E *)

End[]
EndPackage[]


If [ TrueQ[ $VersionNumber >= 2.0 ],
     On[ General::spell ];
     On[ General::spell1 ];
     On[ SetDelayed::write ];
     On[ Set::write ];
     On[ Set::wrsym ] ]


(*  H E L P     I N F O R M A T I O N  *)

Block [	{newfuns},
	newfuns =
	{ AllSubsets,		Assuming,		CirclePS,
	  Combine,		ComplexQ,		ComplexTo2DCoord,
	  ComplexTo2DCoordList,	ConstantQ,		ConstantTerm,
	  Element,		GenerateCode,
	  GenerateSymbol,	GetAllExponents,	GetAllFactors,
	  GetArgs,		GetRoot,		GetRootList,
	  GetShiftFactor,	GetStateField,		GetValue,
	  GetVariables,		ImaginaryQ,		InRange,
	  InfinityQ,		InformUserQ,
	  ListQ,		MixedPolynomialQ,	MyApart,
	  MyCollectAll,		MyFreeQ,		MyMessage,
	  MyTogether,		NegExponent,		NormalizedQ,
	  PointwisePlot,	PrintIt,		RationalFunctionQ,
	  RationalPolynomialQ,	RationalQ,		RealQ,
	  RealValuedQ,		RemoveOptions,		ReplaceWith,
	  RuleAppliesQ,		SameFormQ,		Second,
	  SetExclusion,		SetStateField,		StripPackage,
	  SubsetQ,		TableLookup,		Third,
	  ToCollection,		ToList,			VariableQ,
	  ZeroQ,		ZPolynomial };
	SPfunctions = Combine[SPfunctions, newfuns];	
	Apply[Protect, newfuns];
	Protect[Dialogue] ]

Protect[ SPSimplificationRules ]


(*  E N D I N G     M E S S A G E  *)

If [ $notloaded, Print["Support module has been loaded."] ]
Remove[ $notloaded ]
