(* ::Package:: *)

(* ::Chapter:: *)
(*prolog*)


Asymptotes::usage= "Compute the asymptotes to a plane curves";
asymptotesOfImplicitEquations::usage= "Compute the asymptotes to a plane curves";
horizontalAsymptotes::usage= "Compute the asymptotes to a plane curves";
verticalAsymptotes::usage= "Compute the asymptotes to a plane curves";


Needs["AlphaScannerFunctions`CommonFunctions`"]


Begin["`Private`"]


(* ::Chapter::Closed:: *)
(*main code*)


ClearAll[Asymptotes, asymptotesOfImplicitEquations, horizontalAsymptotes, verticalAsymptotes]
Asymptotes::usage = "Scanner for computing and graphing horizontal, vertical, oblique(slant or skew) and parabolic asymptotes.";


(* ::Subsection::Closed:: *)
(*Asymptotes*)


Asymptotes[___] = {};
Asymptotes[_, Hold[CalculateAsymptotes[expr:Equal[lhs_, rhs_]]], _, OptionsPattern[]] /; 
	!(Head[lhs] === Symbol && Length[VarList[{lhs, rhs}]] == 1) && !MatchQ[lhs, _?usersymbolQ[_]] := Module[
	{vars, x, y, asym, display, asymFnX, asymFnY},

	vars = VarList[expr];
	If[Length[vars] != 2, 
		Return[],
		{x, y} = vars
	];
	
	asymFnX = TimeConstrained[
		asymptotesOfImplicitEquations[expr, {x, y}], (* y[x] = <fn of x> *)
		5 $singlesteptimelimit,
		{}
	];

	asymFnY = TimeConstrained[
		asymptotesOfImplicitEquations[expr, {y, x}], (* x[y] = <fn of y> *)
		5 $singlesteptimelimit,
		{}
	];
	
	asym = DeleteCases[Flatten[{asymFnX, asymFnY}, 1], $Failed];
	asym = DeleteDuplicates[asym, TrueQ[#1 === #2 || Eliminate[{#1, #2}, x]]&];
 
	If[asym === {}, 
		Return @ SowResult[
			$CaptionResult, 
			GrayComment[Localize["no asymptotes found",474]], 
			10, 
			"PodIdentifier" -> "Result",
			"Buttons" -> {"ReplacePod", "Identity", Identity},
			"Dependencies" -> {"UpdateFrequency" -> "Weekly"},
			"PrimaryResult" -> True
		]
	];
	display = asym /. {s1___, v_ == a_, s2___, v_ == b_, s3___} /; Cancel[a + b] == 0 :> 
		{s1, s2, v == PlusMinus[selectBestForm[a, b]], s3};
	
	SowResult[
		$CaptionResult,
		RowTemplate[Localize["`1`<GrayText> is asymptotic to </GrayText>`2`",1172],{originalform[expr],#}]& /@ display,
		10,
		"Buttons" -> {"ReplacePod", "ListOfResultsToSubPods", Identity},
		"PodIdentifier" -> "Result",
		"Dependencies" -> {"UpdateFrequency" -> "Weekly"},
		"PrimaryResult" -> True
	];
	
	plotImplicitAsymptotes[expr, asym, {x, y}]
]


Asymptotes[_, Hold[CalculateAsymptotes[exp_]], _, OptionsPattern[]] := Module[
	{expr, vars, x, horiz, vert, pmHoriz, pmVert, parabolic, caption},

	SuppressResult[$CaptionResult];

	expr = preprocessUserInput[exp];
	vars = VarList[expr];
	If[Length[vars] =!= 1, 
		Return[],
		x = First @ vars
	];

	horiz = horizontalAsymptotes[expr, x];
	pmHoriz = combinePlusMinus[horiz];
	If[horiz =!= $Failed,
			SowResult[
				Localize["Horizontal asymptote",476],
				formatAsymptote[expr, x, #]& /@ pmHoriz,
				10,
				"MInput" -> Hold[{Limit[#1, #2 -> -Infinity], Limit[#1, #2 -> Infinity]}]& [expr, x],
				"Buttons" -> {"ReplacePod", "ListOfResultsToSubPods", Identity},
				"PodIdentifier" -> "Horizontal asymptote",
				"Dependencies" -> {"UpdateFrequency" -> "Weekly"}
			]
	];
	
	vert = verticalAsymptotes[expr, x];
	pmVert = combinePlusMinus[vert];
	If[vert =!= $Failed,
		SowResult[
			Localize["Vertical asymptote",477],
			formatAsymptote[expr, x, #]& /@ pmVert,
			11,
			"MInput" -> Hold[Reduce[1/#1 == 0, #2, Reals]]& [expr, x],
			"Buttons" -> {"ReplacePod", "ListOfResultsToSubPods", Identity},
			"PodIdentifier" -> "Vertical asymptote",
			"Dependencies" -> {"UpdateFrequency" -> "Weekly"}
		]
	];
	
	parabolic = parabolicAsymptotes[expr, x];
	If[parabolic =!= $Failed && VarList[parabolic] =!= {} && parabolic =!= expr,
		{caption, podid} = Which[
			PolynomialQ[parabolic, x] && Exponent[parabolic, x] === 1,
				{Localize["Oblique asymptote",478], "PodIdentifier" -> "Oblique asymptote"},
			PolynomialQ[parabolic, x] && Exponent[parabolic, x] === 2,
				{Localize["Parabolic asymptote",479], "PodIdentifier" -> "Parabolic asymptote"},
			PolynomialQ[parabolic, x],
				{Localize["Polynomial asymptote",480], "PodIdentifier" -> "Polynomial asymptote"},
			True,
				{Localize["Asymptote",481], "PodIdentifier"->"Asymptote"}
		];
		SowResult[
			caption,
			RowTemplate[Localize["`1`<GrayText> is asymptotic to </GrayText>`2`",1173],{originalform[exp],parabolic}],
			12,
			"MInput" -> Hold[PolynomialQuotient[Numerator[Together[#1]], Denominator[Together[#1]], #2]]& [expr, x],
			"MOutput" -> parabolic,
			"PodIdentifier" -> DynamicPodIdentifier[podid],
			"Dependencies" -> {"UpdateFrequency" -> "Weekly"} 		
		]
	];
	
	If[MatchQ[DeleteDuplicates[{horiz, vert, parabolic}], {($Failed|{}|expr)..}],
		SowResult[
			Localize["No asymptotes found",482], 
			GrayComment[Localize["no asymptotes found",483]], 
			10, 
			"PodIdentifier" -> "no asymptotes found",
			"SubstituteCaption" -> $CaptionResult,
			"Buttons" -> {"ReplacePod", "Identity", Identity},
			"Dependencies" -> {"UpdateFrequency" -> "Weekly"}
		]
	];
	
	Apply[plotAsymptotes, {expr, horiz, vert, parabolic, x} /. $Failed -> Automatic]
]

Asymptotes[_, Hold[CalculateAsymptotes[exp_, "Type" -> "Horizontal"]], _, OptionsPattern[]] := Module[
	{expr, vars, x, horiz, pmHoriz},

	expr = preprocessUserInput[exp];
	vars = VarList[expr];
	If[Length[vars] =!= 1, 
		Return[],
		x = First @ vars
	];

	horiz = horizontalAsymptotes[expr, x];
	pmHoriz = combinePlusMinus[horiz];
	If[!MatchQ[horiz, {}|$Failed],
			SowResult[
				$CaptionResult,
				formatAsymptote[expr, x, #]& /@ pmHoriz,
				10,
				"MInput" -> Hold[{Limit[#1, #2 -> -Infinity], Limit[#1, #2 -> Infinity]}]& [expr, x],
				"PodIdentifier" -> "Result",
				"Buttons" -> {"ReplacePod", "ListOfResultsToSubPods", Identity},
				"Dependencies" -> {"UpdateFrequency" -> "Weekly"},
				"PrimaryResult" -> True
			];
			plotAsymptotes[expr, horiz, Automatic, Automatic, x],
			SowResult[
				$CaptionResult,
				GrayComment[Localize["no horizontal asymptotes found",487]],
				10,
				"PodIdentifier" -> "Result",
				"Buttons" -> {"ReplacePod", "Identity", Identity},
				"Dependencies" -> {"UpdateFrequency" -> "Weekly"},
				"PrimaryResult" -> True
			];
			PlotScanner["", Hold @@ {expr}, expr, "PlotUnivariate" -> True];
	]
]

Asymptotes[_, Hold[CalculateAsymptotes[exp_, "Type" -> "Vertical"]], _, OptionsPattern[]] := Module[
	{expr, vars, x, vert, pmVert},

	expr = preprocessUserInput[exp];
	vars = VarList[expr];
	If[Length[vars] =!= 1, 
		Return[],
		x = First @ vars
	];

	vert = verticalAsymptotes[expr, x];
	pmVert = combinePlusMinus[vert];
	Print[vert];
	If[!MatchQ[vert, {}|$Failed],
		SowResult[
			$CaptionResult,
			formatAsymptote[expr, x, #]& /@ pmVert,
			10,
			"MInput" -> Hold[Reduce[1/#1 == 0, #2, Reals]]& [expr, x],
			"PodIdentifier" -> "Result",
			"Buttons" -> {"ReplacePod", "ListOfResultsToSubPods", Identity},
			"Dependencies" -> {"UpdateFrequency" -> "Weekly"},
			"PrimaryResult" -> True
		];
		plotAsymptotes[expr, Automatic, vert, Automatic, x],
		SowResult[
			$CaptionResult,
			GrayComment[Localize["no vertical asymptotes found",490]],
			10,
			"PodIdentifier" -> "Result",
			"Buttons" -> {"ReplacePod", "Identity", Identity},
			"Dependencies" -> {"UpdateFrequency" -> "Weekly"},
			"PrimaryResult" -> True
		];
		PlotScanner["", Hold @@ {expr}, expr, "PlotUnivariate" -> True];
	]
]

Asymptotes[_, Hold[CalculateAsymptotes[exp_, "Type" -> "Oblique"]], _, OptionsPattern[]] := Module[
	{expr, vars, x, parabolic},

	expr = preprocessUserInput[exp];
	vars = VarList[expr];
	If[Length[vars] =!= 1, 
		Return[],
		x = First @ vars
	];

	parabolic = parabolicAsymptotes[expr, x];
	If[!MatchQ[parabolic, {}|$Failed] && (Head[parabolic] === Piecewise || (PolynomialQ[parabolic, x] && Exponent[parabolic, x] === 1)),
		SowResult[
			$CaptionResult,
			RowTemplate[Localize["`1`<GrayText> is asymptotic to </GrayText>`2`",1174],{originalform[exp],parabolic}],
			10,
			"MInput" -> Hold[PolynomialQuotient[Numerator[Together[#1]], Denominator[Together[#1]], #2]]& [expr, x],
			"MOutput" -> parabolic,
			"PodIdentifier" -> "Result",
			"Dependencies" -> {"UpdateFrequency" -> "Weekly"},
			"PrimaryResult" -> True
		];
		plotAsymptotes[expr, Automatic, Automatic, parabolic, x],
		SowResult[
			$CaptionResult,
			GrayComment[Localize["no oblique asymptotes found",493]],
			10,
			"PodIdentifier" -> "Result",
			"Buttons" -> {"ReplacePod", "Identity", Identity},
			"Dependencies" -> {"UpdateFrequency" -> "Weekly"},
			"PrimaryResult" -> True	
		];
		PlotScanner["", Hold @@ {expr}, expr, "PlotUnivariate" -> True];		
	]
]

Asymptotes[_, Hold[CalculateAsymptotes[exp_, "Type" -> "Parabolic"]], _, OptionsPattern[]] := Module[
	{expr, vars, x, parabolic},

	expr = preprocessUserInput[exp];
	vars = VarList[expr];
	If[Length[vars] =!= 1, 
		Return[],
		x = First @ vars
	];

	parabolic = parabolicAsymptotes[expr, x];
	If[!MatchQ[parabolic, {}|$Failed] && Exponent[parabolic, x] === 2,
		SowResult[
			$CaptionResult,
			RowTemplate[Localize["`1`<GrayText> is asymptotic to </GrayText>`2`",1175],{originalform[exp],parabolic}],
			10,
			"MInput" -> Hold[PolynomialQuotient[Numerator[Together[#1]], Denominator[Together[#1]], #2]]& [expr, x],
			"MOutput" -> parabolic,
			"PodIdentifier" -> "Result",
			"Dependencies" -> {"UpdateFrequency" -> "Weekly"},
			"PrimaryResult" -> True
		];
		plotAsymptotes[expr, Automatic, Automatic, parabolic, x],
		SowResult[
			$CaptionResult,
			GrayComment[Localize["no parabolic asymptotes found",496]],
			10,
			"PodIdentifier" -> "Result",
			"Buttons" -> {"ReplacePod", "Identity", Identity},
			"Dependencies" -> {"UpdateFrequency" -> "Weekly"},
			"PrimaryResult" -> True
		];
		PlotScanner["", Hold @@ {expr}, expr, "PlotUnivariate" -> True];		
	]
]


Asymptotes[_, Hold[CalculateAsymptotes[exp_, "Type" -> "Polynomial"]], _, OptionsPattern[]] := Module[
	{expr, vars, x, polynomial},

	expr = preprocessUserInput[exp];
	vars = VarList[expr];
	If[Length[vars] =!= 1, 
		Return[],
		x = First @ vars
	];

	polynomial = parabolicAsymptotes[expr, x];
	If[!MatchQ[polynomial, {}|$Failed],
		SowResult[
			$CaptionResult,
			RowTemplate[Localize["`1`<GrayText> is asymptotic to </GrayText>`2`",1176],{originalform[exp],polynomial}],
			10,
			"MInput" -> Hold[PolynomialQuotient[Numerator[Together[#1]], Denominator[Together[#1]], #2]]& [expr, x],
			"MOutput" -> polynomial,
			"PodIdentifier" -> "Result",
			"Dependencies" -> {"UpdateFrequency" -> "Weekly"},
			"PrimaryResult" -> True
		];
		plotAsymptotes[expr, Automatic, Automatic, polynomial, x],
		SowResult[
			$CaptionResult,
			GrayComment[Localize["no polynomial asymptotes found",499]],
			10,
			"PodIdentifier" -> "Result",
			"Buttons" -> {"ReplacePod", "Identity", Identity},
			"Dependencies" -> {"UpdateFrequency" -> "Weekly"},
			"PrimaryResult" -> True
		];
		PlotScanner["", Hold @@ {expr}, expr, "PlotUnivariate" -> True];		
	]
]


(* ::Subsection::Closed:: *)
(*selectBestForm, combinePlusMinus, formatAsymptote *)


selectBestForm[a_, b : Times[-1, _]] := a

selectBestForm[a : Times[-1, _], b_] := b

selectBestForm[a_, b_] := If[LeafCount[a] < LeafCount[b], a, b]

combinePlusMinus[l_List] := Quiet[l //. {a___, {as_, x_ -> la_}, b___, {as_, x_ -> lb_}, c___} :> 
		{a, b, c, {as, h_[x, PlusMinus[Abs[lb]]]}} 
			/; (PossibleZeroQ[la + lb] || (la === Infinity && lb === -Infinity) || (la === -Infinity && lb === Infinity))]

formatAsymptote[expr_, x_, asym_] := RowTemplate[Localize["`1`<GrayText>   as   </GrayText>`2`",1177],{expr->First[asym],x->asym[[-1,-1]]}]
formatAsymptote[expr_, x_, asym_] /; ContainsQ[asym, C[_]] := RowTemplate[Localize["`1`<GrayText>   as   </GrayText>`2`<GrayText BaseStyle=\"Serif\">  for integer </GrayText>`3`",3392],
	{expr->First[asym],x->asym[[-1,-1]]/. C[_]->CalculateSymbol["n"],GrayText[CalculateSymbol["n"]]}]


(* ::Subsection::Closed:: *)
(*horizontalAsymptote*)


horizontalAsymptotes[expr_, x_] := Block[{right, left, asym},
  	asym = Flatten[Reap[
    	left = Limit[expr, x -> -Infinity];
     	If[FreeQ[left, DirectedInfinity] && NumericQ[left] && Element[left, Reals],
      		Sow[{left, x -> -Infinity}]
      	];
     	right = Limit[expr, x -> Infinity];
     	If[FreeQ[right, DirectedInfinity] && NumericQ[right] && Element[right, Reals],
      		Sow[{right, x -> Infinity}]
      	]
	][[-1]], 1];
	If[asym === {}, $Failed, asym]
]

(*
In[87]:= horizontalAsymptotes[1/x, x]
Out[87]= {{0, x -> -Infinity}, {0, x -> Infinity}}

In[88]:= horizontalAsymptotes[(2*x^2 + 3*x + 1)/x^2, x]
Out[88]= {{2, x -> -Infinity}, {2, x -> Infinity}}

In[89]:= horizontalAsymptotes[(x^2 + 3*x + 1)/(4*x^2 - 9), x]
Out[89]= {{1/4, x -> -Infinity}, {1/4, x -> Infinity}}

In[90]:= horizontalAsymptotes[(x + 3)/(x^2 + 9), x]
Out[90]= {{0, x -> -Infinity}, {0, x -> Infinity}}

In[91]:= horizontalAsymptotes[1 - Exp[-2*x], x]
Out[91]= {{1, x -> Infinity}}

In[92]:= horizontalAsymptotes[ArcTan[x], x]
Out[92]= {{-(Pi/2), x -> -Infinity}, {Pi/2, x -> Infinity}}

In[93]:= horizontalAsymptotes[(5 - 3*x^2)/(1 - x^2), x]
Out[93]= {{3, x -> -Infinity}, {3, x -> Infinity}}

In[94]:= horizontalAsymptotes[200/(1 + x)^2, x]
Out[94]= {{0, x -> -Infinity}, {0, x -> Infinity}}
*)



(* ::Subsection::Closed:: *)
(*processInfinities, infinityRules*)


processInfinities[expr_] := Block[{lims},
	lims = Select[expr, FreeQ[#, Complex]&];
	Which[
		lims === {},
			Return[{}],
		MatchQ[lims, {Infinity} | {-Infinity}],
			First @ lims,
		True,
			(lims /. C[_] -> 1) //. infinityRules
	]
]

infinityRules = {
					{-Infinity, Infinity} -> PlusMinus[Infinity], 
					{Infinity, -Infinity} -> PlusMinus[Infinity],
					{Infinity, Infinity} -> Infinity,
					{-Infinity, -Infinity} -> -Infinity,
					{a_, b_} /; MatchQ[a, Infinity] || MatchQ[b, Infinity] :> Infinity,
					{a_, b_} /; MatchQ[a, -Infinity] || MatchQ[b, -Infinity] :> -Infinity
				};


(* ::Subsection:: *)
(*verticalAsymptotes, checkVerticalAsymptotes*)


checkVerticalAsymptotes[expr_, x_ -> p_] := 
	ContainsQ[{
		Assuming[Element[C[1], Integers], Limit[expr, x -> p, Direction -> -1]], 
		Assuming[Element[C[1], Integers], Limit[expr, x -> p, Direction -> 1]]
		}, DirectedInfinity]

verticalAsymptotes[expr_, x_] := Block[{pts, otherPoints, res},
  	pts = Quiet @ TimeConstrained[Reduce[1/expr == 0, x, Reals], 2 $singlesteptimelimit];
  	otherPoints = Quiet @ DeleteCases[TimeConstrained[Reduce[# == 0, x], $singlesteptimelimit/5, False]& /@ Level[expr, {0, Infinity}], False]; 
  	If[pts === $Aborted && otherPoints === {}, Return[$Failed]];
  	pts = Cases[{pts, otherPoints}, _?usersymbolQ == _, {0, Infinity}];
  	If[pts === {}, Return[$Failed]];
  	pts = DeleteDuplicates[Rule @@@ pts];
  	(* Check the points are really vertical asymptotes. SamB 0510 *)
  	pts = Cases[pts, pt_ /; checkVerticalAsymptotes[expr, pt]];
  	res = {
  		processInfinities[{
  			Assuming[Element[C[1], Integers], Limit[expr, #, Direction -> -1]], 
  			Assuming[Element[C[1], Integers], Limit[expr, #, Direction -> 1]]
  		}], #} & /@ pts;
  	DeleteCases[res, l_ /; ListQ[First[l]] || ContainsQ[l, _Complex]]
]

(*
In[97]:= verticalAsymptotes[(x^2 + 3*x + 1)/(4*x^2 - 9), x]
Out[97]= {{Infinity, x -> -(3/2)}, {Infinity, x -> 3/2}}

In[98]:= verticalAsymptotes[Tan[t], t]
Out[98]= {{-Cot[Pi*C[1]], t -> Pi/2 + Pi*C[1]}}

In[99]:= verticalAsymptotes[2*x + 3/x, x]
Out[99]= {{Infinity, x -> 0}}

In[100]:= verticalAsymptotes[(3*x + 6)/((x + 2)*(x - 4)), x]
Out[100]= {{Infinity, x -> 4}}

In[101]:= verticalAsymptotes[(5 - 3*x^2)/(1 - x^2), x]
Out[101]= {{Infinity, x -> -1}, {-Infinity, x -> 1}}

In[103]:= verticalAsymptotes[(x^2 - 5 x + 6)/(x^3 - 3 x^2 + 2 x), x]
Out[103]= {{Infinity, x -> 0}, {-Infinity, x -> 1}}

In[397]:= verticalAsymptotes[x*Csc[x], x]
Out[397]= {{\[PlusMinus]Infinity, x -> 2*Pi*C[1]}, {\[PlusMinus]Infinity, x -> Pi + 2*Pi*C[1]}}
*)


(* ::Subsection::Closed:: *)
(*univariateRationalQ*)


univariateRationalQ[Power[expr_, _Integer]] := univariateRationalQ[expr]
univariateRationalQ[expr_Plus] := VectorQ[List @@ expr, univariateRationalQ]
univariateRationalQ[expr_Times] := VectorQ[List @@ expr, univariateRationalQ]
univariateRationalQ[expr_] := With[{vars = VarList[expr]}, Length[vars] <= 1 && PolynomialQ[expr, vars]]
univariateRationalQ[n_] /; NumericQ[n] = True;
univariateRationalQ[__] = False;

(*
In[88]:= univariateRationalQ[Pi/E/Sqrt[x] - (1 + 4 Pi)^(3/2) x^2]
Out[88]= False

In[89]:= univariateRationalQ[Pi/E /x - (1 + 4 Pi)^(3/2) x^2]
Out[89]= True
*)


(* ::Subsection::Closed:: *)
(*parabolicAsymptotes*)


Clear[parabolicAsymptotes];

parabolicAsymptotes[expr_, x_] /; univariateRationalQ[expr] := Block[{rat, num, den},
  	rat = Together[expr];
  	num = Numerator[rat];
  	den = Denominator[rat];
  	If[Exponent[num, x] - Exponent[den, x] >= 1,
   		PolynomialQuotient[num, den, x],
   		$Failed
   	]
]

(*
In[158]:= parabolicAsymptotes[(x^2 + x + 1)/(x + 1), x]
Out[158]= x

In[159]:= parabolicAsymptotes[(2 x^3 + 4 x^2 - 9)/(3 - x^2), x]
Out[159]= -4 - 2 x

In[160]:= parabolicAsymptotes[(x^3 + 2 x^2 + 3 x + 4)/x, x]
Out[160]= 3 + 2 x + x^2

In[161]:= parabolicAsymptotes[(37 x^5 + 2 x^2 + 3 x + 4)/(x^2 - x - 1), x]
Out[161]= 113 + 74 x + 37 x^2 + 37 x^3

In[174]:= parabolicAsymptotes[(x^4 - 2 x^3 + 1)/x^2, x]
Out[174]= -2 x + x^2

In[175]:= parabolicAsymptotes[(1 - x)^3/x^2, x]
Out[175]= 3 - x
*)

parabolicAsymptotes[c_. (a_. x_^n_Integer + k_.)^m_., x_] /; n == 1/m && FreeQ[{a, k, c}, x] && Im[a] == 0 && a > 0 := c Sqrt[a] Abs[x]

(*
In[902]:= parabolicAsymptotes[Sqrt[x^2 + 1], x]
Out[902]= Abs[x]

In[907]:= parabolicAsymptotes[7 Power[x^4 + 8, (4)^-1], x]
Out[907]= 7 Abs[x]
*)

parabolicAsymptotes[c_. (x_^n_ + k_.)^m_., x_] /; FreeQ[{k, c}, x] := c x^(m n)

(*
In[200]:= parabolicAsymptotes[Sqrt[1 + x^3], x]
Out[200]= x^(3/2)
*)

parabolicAsymptotes[Sqrt[a_. x_^2 + b_. ] + c_. x_, x_] /; FreeQ[{a, b, c}, x] && c < 0 && Sqrt[a] == -c := 
	Piecewise[{{-2 Sqrt[a] x, x < 0}}, 0]

(*
In[211]:= Table[Limit[(Sqrt[k x^2 + 1] - Sqrt[k] x) - (-2 Sqrt[k] x), x -> -Infinity], {k, 5}]
Out[211]= {0, 0, 0, 0, 0}
*)

parabolicAsymptotes[expr_, x_] /; !PolynomialQ[expr, x] := Block[{series, seriesData, rat, poly, limit, nlimit},
	If[FreeQ[expr, x], Return[$Failed]];
  	series = Quiet @ Series[ToRadicals[expr], {x, Infinity, 1}];
  	seriesData = Cases[series, HoldPattern @ SeriesData[_, _, {__?NumericQ}, ___], {0, Infinity}];

  	If[seriesData === {},
   		$Failed,
   		rat = Together[Plus @@ Normal /@ seriesData];
   		If[PolynomialQ[Numerator[rat], x] && PolynomialQ[Denominator[rat], x],
    		poly = Factor @ Simplify @ PolynomialQuotient[Numerator[rat], Denominator[rat], x];
    		limit = {Limit[poly - ToRadicals[expr], x -> Infinity], Limit[poly - ToRadicals[expr], x -> -Infinity]} /. Interval[__] :> 0;
    		If[ContainsQ[limit, 0], 
    			poly,
 				nlimit = Quiet @ TimeConstrained[Chop[#, 10^-3] & /@ {NLimit[poly - expr, x -> Infinity], NLimit[poly - expr, x -> -Infinity]},
    					$singlesteptimelimit
    			];
 				If[ContainsQ[limit, 0], 
 					poly, 
 					$Failed
 				]
 			],
    		$Failed
    	]
   	]
]

(*
In[636]:= parabolicAsymptotes[Sqrt[1 + x^4], x]
Out[636]= x^2

In[637]:= parabolicAsymptotes[(x^3 + Sin[x])/x, x]
Out[637]= x^2

In[638]:= parabolicAsymptotes[Sqrt[Exp[-x^2] + (1 + x)^4], x](* Here's one that we don't do well on... *)
Out[638]= $Failed

In[639]:= parabolicAsymptotes[Sin[x] + (1 + x)^4, x]
Out[639]= (1 + x)^4

In[640]:= parabolicAsymptotes[Log[x] + (1 + x)^4, x]
Out[640]= $Failed

In[641]:= parabolicAsymptotes[Sqrt[(1 + x)^4 + x/(x (x + 1)^2)], x]
Out[641]= (1 + x)^2

In[642]:= parabolicAsymptotes[Sqrt[(1 + x)^4 + x/(x (x + 1)^2)] + x^10, x]
Out[642]= 1 + 2 x + x^2 + x^10

In[643]:= parabolicAsymptotes[(17 + 27 x + 3 x^2 - 9 x^3 + 5 x^4 + 12 x^5 + 4 x^6)/(2 + 3 x + x^2), x]
Out[643]= 9 - 3 x^2 + 4 x^4

In[644]:= parabolicAsymptotes[Sqrt[1 + Sqrt[x] + x^4], x]
Out[644]= x^2

In[645]:= parabolicAsymptotes[ArcTan[x] + x, x](* We had to pick one.... *)
Out[645]= 1/2 (\[Pi] + 2 x)
*)


(* ::Subsection::Closed:: *)
(*asymptotesOfImplicitEquations*)


Clear[asymptotesOfImplicitEquations];
asymptotesOfImplicitEquations[cx_. x_^2 + cy_. y_^2 == k_, {x_, y_} | {y_, x_}] /; (cx cy < 0 && (NumericQ[k] || (usersymbolQ[k] && FreeQ[{x,y},k]))) := 
	{y == Sqrt[Abs[cx]/Abs[cy]] x, y == -Sqrt[Abs[cx]/Abs[cy]] x}

asymptotesOfImplicitEquations[eqn_Equal, {x_, y_}] := Block[{soln, fnsOfx, asymptotes},
  	soln = TimeConstrained[Reduce[eqn, {x, y}, Reals], 2 $singlesteptimelimit];
  	If[MatchQ[soln, _Reduce | $Aborted], Return[$Failed]];
  	fnsOfx = DeleteDuplicates @ Cases[soln, e_Equal /; ContainsQ[Last[e], x] :> Last[e], {0, Infinity}];
  	
  	If[fnsOfx == {}, Return @ $Failed];
  	
  	(* try to find parabolic asymptotes *)
  	asymptotes = parabolicAsymptotes[#, x] & /@ fnsOfx;
  	asymptotes = DeleteDuplicates[DeleteCases[asymptotes, $Failed]];
  	
  	If[asymptotes =!= {},
  		asymptotes = Collect[#, x]& /@ asymptotes;
  		asymptotes = Thread[y == asymptotes];
  		Return[ Select[asymptotes, FreeQ[N[#], Complex]&] /. {} -> $Failed ]
  	];
  	
	(* try to find vertical asymptotes *)
	asymptotes = verticalAsymptotes[#, x] & /@ fnsOfx;
	asymptotes = DeleteCases[asymptotes, $Failed];
	If[!MatchQ[asymptotes, {} | {{}}],
		asymptotes = DeleteDuplicates @ Flatten[#[[All, -1, -1]]& /@ asymptotes];
		asymptotes = Thread[x == asymptotes];
		Return[ Select[asymptotes, FreeQ[N[#], Complex]&] /. {} -> $Failed ]
	];
	
	(* try to find horizontal asymptotes *)
	asymptotes = horizontalAsymptotes[#, x] & /@ fnsOfx;
	asymptotes = DeleteCases[asymptotes, $Failed];
	If[!MatchQ[asymptotes, {} | {{}}],
		asymptotes = DeleteDuplicates @ Flatten[#[[All, 1]]& /@ asymptotes];
		asymptotes = Thread[y == asymptotes];
		Return[ Select[asymptotes, FreeQ[N[#], Complex]&] /. {} -> $Failed ]
	];
	$Failed
]

(*
In[431]:= asymptotesOfImplicitEquations[x^2 + 3 y^2 == (x y)^2, {x, y}]
Out[431]= {y == -1, y == 1}

In[432]:= asymptotesOfImplicitEquations[x^2/25 - y^2/36 == 1, {x, y}]
Out[432]= {y == -((6 x)/5), y == (6 x)/5}

In[27]:= asymptotesOfImplicitEquations[x y - y == x^2/8 + y^2, {x, y}]
Out[27]= {y == 1/4 (-2 + 2 Sqrt[2]) + 1/4 (2 - Sqrt[2]) x, y == 1/4 (-2 - 2 Sqrt[2]) + 1/4 (2 + Sqrt[2]) x}

In[99]:= asymptotesOfImplicitEquations[x^4/y^2 - (x y)^2 == 1/2, {y, x}](* note the ordering of the variables *)
Out[99]= {x == -y^2, x == y^2}

In[115]:= asymptotesOfImplicitEquations[x^2/y^2 + x y - 1/(x y) == 1/5, {y, x}]
Out[115]= {x == -y^3}

In[34]:= asymptotesOfImplicitEquations[x y == 1, {x, y}]
Out[34]= {x == 0}

In[35]:= asymptotesOfImplicitEquations[x^2 y + y == 2, {x, y}]
Out[35]= {y == 0}

In[27]:= asymptotesOfImplicitEquations[x^2 - y^3 == (x y)^2, {y, x}]
Out[27]= {y == -1, y == 1}

*)


(* ::Chapter:: *)
(*epilog*)


End[]
