# PGF Math Function to compute cube root

When I found that a simple x^(1.0/3.0) does not yield a graph in PGFplots for negative values of x, I attempted to define my own function for CubeRoot using pgfmathdeclarefunction as below. But, am not able to get them to work.

These are based on this example for a Gaussian distribution, and another one here.

This compiles as is, but has a problem if I set \DomainMin to a negative value. The CubeRootB function does not even compile, and I do not see what the problem with it is.

\documentclass{article}
\usepackage{tikz}

\newcommand*{\DomainMin}{0.1}
%\newcommand*{\DomainMin}{-2.0} % CubeRootA gives and error if DomainMin < 0

\tikzstyle{MyPlotStyle}=[domain=\DomainMin:2,samples=100,smooth]

\pgfmathdeclarefunction{gauss}{3}{% From links mentioned in the question
\pgfmathparse{1/(#3*sqrt(2*pi))*exp(-((#1-#2)^2)/(2*#3^2))}%
}

\pgfmathdeclarefunction{CubeRootA}{1}{%
\pgfmathparse{%
ifthenelse(equal(#1,abs(#1)),%
(#1)^(1.0/3.0),%            #1 >= 0
-1.0*((abs(#1))^(1.0/3.0))% #1 is negative
)%
}%
}

\pgfmathdeclarefunction{CubeRootB}{1}{%
\pgfmathparse{%
\pgfmathifthenelse
{\pgfmathequal{#1}{\pgfmathabs{#1}}}%
{exp(ln(#1)/3.0)}%            #1 >= 0
{-1.0*(exp(ln(abs(#1))/3.0))}% #1 is negative
}%

}

% Modified version of CubeRootB per Caramdir's suggestion
\pgfmathdeclarefunction{CubeRootC}{1}{%
\pgfmathparse{%
ifthenelse(
equal(#1,abs(#1)),%
exp(ln(#1)/3.0),%            #1 >= 0
-1.0*(exp(ln(abs(#1))/3.0))% #1 is negative
)
}%
}

\begin{document}
\begin{tikzpicture}
\draw [help lines] (-2,-2) grid [step=0.5] (2,2);
\draw plot [MyPlotStyle] (\x,{gauss(\x,0,0.5)});
%
\draw plot [MyPlotStyle] (\x,{    CubeRootA(\x)});% Error if DomainMin < 0
%\draw plot [MyPlotStyle] (\x,{1.0+CubeRootB(\x)});% Does not compile
\draw plot [MyPlotStyle] (\x,{    CubeRootC(\x)});% Error if DomainMin < 0
\end{tikzpicture}
\end{document}

-
forget the pgfmath stuff and use Lua-code to calculate the values of a cubic root. –  Herbert May 26 '11 at 6:35
@Herbert: Could you add an answer explaining how to do that? –  Jake May 26 '11 at 8:00
@Jake: done ... –  Herbert May 26 '11 at 8:28

The problem with CubeRootC is the way pgf/tikz deals with ifthenelse. The error message I get shows that when dealing with an ifthenelse(test,A,B), both expressions A and B are evaluated, then only one is kept. Since both are evaluated, you get an error message. The way my example is set, this problem is avoided. If you want to keep your code, just replace #1 by abs(#1) in your true clause.

Here is my version of your code. The use of the exponential and logarithm functions is the best approach. The powfunction does not behave has described in the pgf/tikz manual. I shifted the plots so they don't overlap. Note also the declare function method. I find it is easier to read; the problem is that it is local to a tikzpicture. The code is

\documentclass{minimal}
\usepackage{tikz}

\pgfmathsetmacro{\inf}{-2}
\pgfmathsetmacro{\sup}{2}

\tikzstyle{MyPlotStyle}=[domain=\inf:\sup,samples=100,smooth]

\pgfmathdeclarefunction{CubeRootA}{1}{%
\pgfmathparse{ifthenelse(#1<0,-1,1)*exp((ln(abs(#1)))/3)}
}

\pgfmathdeclarefunction{CubeRootB}{1}{%
%\pgfmathparse{ifthenelse(#1<0,-1,1)*((abs(#1))^(1.0/3.0))}
\pgfmathparse{ifthenelse(#1<0,-1,1)*pow(abs(#1),1/3)}
}

\begin{document}
\begin{tikzpicture}
[declare function={ CubeRootC(\t)=ifthenelse(\t<0,-1,1)*exp((ln(abs(\t)))/3);}]

\draw [help lines] (-2,-2) grid [step=0.5] (2,2);

\draw[red] plot [MyPlotStyle] (\x,{CubeRootA(\x)});
\draw[blue,shift={(0,0.2)}] plot [MyPlotStyle] (\x,{CubeRootB(\x)});
\draw[green,shift={(0,-0.2)}] plot [MyPlotStyle] (\x,{CubeRootC(\x)});

\end{tikzpicture}
\end{document}


The output is

-
The declare function that you provided works great. Anyway to do something similar globally so that I can have access it other graphs if needed? –  Peter Grill May 26 '11 at 4:51
Also, I see that you encountered the same problems as I did with the pow function. I attempted to create a MWE example but for some reason it did not create this incorrect graph when I did that. –  Peter Grill May 26 '11 at 4:52
the declare function only works locally, you can't use it to define a global function. Too bad, I find the syntax easier to read. –  Frédéric May 26 '11 at 5:00
@Peter Grill: You can use \tikzset{declare function={ CubeRootC(\t)=ifthenelse(\t<0,-1,1)*exp((ln(abs(\t)))/3);}} in your preamble to define the function globally. –  Jake May 26 '11 at 5:08
For me, \tikzset{declare function={ CubeRootC(\t)=ifthenelse(\t<0,-1,1)*abs(\t)^(1/3);}} also works (instead of the exp(ln construct. This might be because I'm using the CVS version of PGF. Could you try if it works for you as well? –  Jake May 26 '11 at 5:27

run with lualatex

\documentclass{article}
\def\cubicRoot#1{%
\directlua{%
tex.print(#1^(1/3))}}

\begin{document}
\cubicRoot{3}\par
\cubicRoot{-3}

\cubicRoot{3e-30}\par
\cubicRoot{-3e-30}

\cubicRoot{3e30}\par
\cubicRoot{-3e30}
\end{document}


and the code for the complete plot:

\documentclass{minimal}
\usepackage{tikz}
\def\cubicRoot#1{%
\directlua{%
tex.print(#1^(1/3))}}
\tikzstyle{MyPlotStyle}=[domain=-2:2,samples=100,smooth]

\begin{document}
\begin{tikzpicture}
\draw [help lines] (-2,-2) grid [step=0.5] (2,2);
\draw[red] plot [MyPlotStyle] (\x,\cubicRoot{\x});
\draw[blue,shift={(0,0.2)}] plot [MyPlotStyle] (\x,\cubicRoot{\x});
\draw[green,shift={(0,-0.2)}] plot [MyPlotStyle] (\x,\cubicRoot{\x});
\end{tikzpicture}
\end{document}


-
Ah, that's pleasantly simple! –  Jake May 26 '11 at 8:41
This is interesting, but am not familiar with lualatex. Am hoping that those things with some functions like pow will get fixed soon in TikZ/PGFplots. –  Peter Grill May 26 '11 at 19:26
There is no real difference to pdflatex, except the font setting. With lualatex you can use OTF and TrueType fonts as well as Type1 fonts. –  Herbert May 26 '11 at 19:32

Here's a workaround using the fact that \sqrt[3]{x} is the inverse function to x^3: A little dirty but works like a charm. Note the domain is actually the range because I've switched the x and y values.

\begin{tikzpicture}[xscale=.2,yscale=.5]
\draw[xstep=1, ystep=1, gray, very thin, dotted] (-30,-4) grid (30,4);
\draw[<->] (0,-4) -- (0,4) node[above]{$y$};
\draw[->] (-30,0) -- (30,0) node[right]{$x$};
\foreach \x in {-25,5,25} \draw(\x,1pt)--(\x,-1pt) node[below=2pt,fill=white]{\begin{tiny}$\x$\end{tiny}};
\foreach \y in {2} \draw(1pt,\y)--(-1pt,\y) node[left=2pt,fill=white]{\begin{tiny}$\y$\end{tiny}};
\draw[domain=-3.1:3.1,<->] plot ({\x^(3)},\x) node[right]{$cubert(x) = \sqrt[3]{x}$};
\draw[fill=black] (0,0) circle (2pt) node[below=10pt,right=2pt]{(0,0)};
\draw[fill=black] (1,1) circle (2pt) node[left]{(1,1)};
\draw[fill=black] (8,2) circle (2pt) node[below]{(8,2)};
\draw[fill=black] (27,3) circle (2pt) node[below]{(27,3)};
\draw[fill=black] (-1,-1) circle (2pt) node[left]{(-1,-1)};
\draw[fill=black] (-8,-2) circle (2pt) node[below]{(-8,-2)};
\draw[fill=black] (-27,-3) circle (2pt) node[below]{(-27,-3)};
\end{tikzpicture}

-

You are using \pgfmathifthenelse inside \pgfmathparse, which the math parser does not like. If you use \pgfmathparse, then you should use ifthenelse like in CubeRootA (and the same for \pgfmathequal and \pgfmathabs).

-
Ok, that explains the compile error with CubeRootB. I have corrected that and added CubeRootC to the MWE. I still can not get either CubeRootA or CubeRootC to work for negative values of x, which is my real problem. I left CubeRootB as is so that others can make sense of your comments. –  Peter Grill May 26 '11 at 4:25