# How do I use pgfmathdeclarefunction to create define a new pgf function?

I'd like to define new function for pgf so I can use it in pgfplots. I'm trying to create a unit pulse function p(x) which has a value of 1 from x=0 to x=1, and 0 elsewhere.

I read the pgf manual on Customizing the Mathematical Engine (section 65, page 541), but I'm probably misunderstanding something =P

This code doesn't work:

\documentclass{minimal}
\usepackage{pgfplots}

\pgfmathdeclarefunction{p}{1}{%
\pgfmathand{\pgfmathless{#1}{1}} {\pgfmathgreater{#1}{0}}%
}

\begin{document}

\begin{tikzpicture}
\begin{axis}
\end{axis}
\end{tikzpicture}

\end{document}

-
I saw the same question on the net without an answer and I think that you can't use only functions of pgf 2.00. I hope i'm wrong but ... the question was from C Jorssen and now is a developer in the pgf team. –  Alain Matthes Apr 10 '11 at 8:54

I got it to work by using pgfmathparse inside of pgfmathdeclarefunction (I don't know if that's how you're supposed to do it, but I'm satisfied for now)

I can also define it locally using declare function.

\documentclass{letter}
\usepackage{pgfplots}
\usepackage{setspace}
\doublespacing

\pgfmathdeclarefunction{p}{1}{%
\pgfmathparse{and(#1>0, #1<1)}%
}

\begin{document}

My pgf version is: \pgfversion

p(0.2) is \pgfmathparse{p(0.2)}\pgfmathresult

p(2) is \pgfmathparse{p(2)}\pgfmathresult

Plot of p(x):

\begin{tikzpicture}
\begin{axis}
\end{axis}
\end{tikzpicture}

Using declare function to define localp(x):

\begin{tikzpicture}
[
declare function={
localp(\t) = and(\t > 0, \t < 1);
}
]
\begin{axis}
\end{axis}
\end{tikzpicture}

\end{document}


-
Excellent work, thanks for sharing that! I've worked this approach into my answer to the question on gauss curves tex.stackexchange.com/q/11368/2552. Couldn't do it before you posted this! –  Jake Apr 10 '11 at 10:20
very fine and very useful for pgfplots users but I would like to understand why the problem exists if we take the example from the pgfmanual ( double) \pgfmathdouble works we can use the function with plot inside pgf but not in pgfplots. The error gives something about dim and pt and in the example '\pgfmathreturn\pgf@x is used to remove pt ... I'm waiting an answer from the author of pgfplots. –  Alain Matthes Apr 10 '11 at 18:04
See also Jake's solution in tex.stackexchange.com/questions/15475/… for more pgfmath insight –  kristi Apr 22 '11 at 5:27

I think I can provide some more insight into the questions here.

The good news at first: providing \begin{axis}[use fpu=false] will enable you to use all custom math functions (as long as they work in pgf, I guess).

Now the details: Let me summarize the state of the discussion: When we use custom math functions in pgfplots, we have

1. the solution containing \pgf@x=#1pt leads to

! Illegal unit of measure (pt inserted).

Y

2. The solution with \pgfmathmultiply{#1}{#1} worked
3. The solution(s) with \pgfmathparse worked as well
4. The solution with \pgfmathand{\pgfmathless{#1}{1}}{\pgfmathgreater{#1}{0}} failed (in my case something strange with ! Extra else

The problem is caused by the fact that PGFPlots has the initial configuration 'use fpu=true'. The fpu is a PGF library; it replaces the math module by something like single precision floating points.

As long as user contributed math functions rely only on high-level math functions (like \pgfmathparse or \pgfmathmultiply as above), the codebase will transparently use the FPU - and everything is consistent.

But as soon as you employ TeX registers, things become different: Writing \pgf@x=#1pt means that the first argument is interpreted as a fixed point number in the range -16000...16000 (roughly). With use fpu=true, both is essentially violated: the fpu has neither fixed point numbers nor is it restricted to this data range. The error message arises because (at the point of this writing), floating point numbers are stored like 1Y1.0e1 where the Y separates "flags" from mantissa. The Y is the first character where \pgf@x=#1pt bails out. Note, however, that the FPU is smart enough to detect if the RETURN VALUE of a custom function is a TeX register number or a float. But I am unaware of any way of asking "will the function handle floats?".

So, as already mentioned, use fpu=false disables the FPU; pgfplots will then operate with fixed point numbers in the range -16000...16000 and all the math functions should work.

The other solution is to use the basic layer math functions like \pgfmathmultiply. Note that unless I am mistaken, \pgfmathmultiply will also invoke \pgfmathparse (which is expensive). Use \pgfmathmultiply@ to suppress argument parsing (which, however, needs a \makeatletter before defining the custom function).

Unfortunately, I am unaware of why the \pgfmathand{} {} solution fails. Does it work in PGF?

I hope this helps here.

-
Does setting use fpu=false disable floating point for all of the calculations? Or just initially? (Using floating point is desirable because it is more accurate, so it would be a shame to have to do everything without floating point calculations.) –  kristi Apr 22 '11 at 5:24
Providing use fpu=false will disable the fpu for all computations. If I am not mistaken, it needs to be providing either in the document's preamble or for individual \begin{axis}[use fpu=false]. What precisely do you mean by "initially"? I agree that this is not desirable. However, if the provided data (for both, x and y) fits well into the data range of TeX, you may not notice any difference. For the more general case, a custom math function should rely on internal math functions like \pgfmath<op>@. –  Christian Feuersänger Apr 22 '11 at 11:47

I suggest this very simple code:

\documentclass{minimal}
\usepackage{tikz}
\makeatletter
\pgfmathdeclarefunction{p}{1}{\edef\pgfmathresult{\ifdim#1pt<\z@0\else\ifdim#1pt>1pt 0\else1\fi\fi}}
\makeatother
\begin{document}
\begin{tikzpicture}
\draw[very thin,color=gray] (-2,-2) grid (2,2);
\draw[color=blue] plot (\x,{p(\x)});
\end{tikzpicture}
\end{document}

-
Can you get this to work in pgfplots? I like the way pgfplots lets you modify the axes and other plot properties easily. I find plain tikz hard to work with. –  kristi Apr 10 '11 at 8:20
The pgfmanual says your code begins with \begingroupand finishes with \pgfmathreturn\pgf@x \endgroup but it's not exactly the problem here. There is no problem inside pgf but the problem is with pgfplots. I think pgfplots uses only the functions until pgf 2.00 ( but it's my personal idea) –  Alain Matthes Apr 10 '11 at 8:59

@Altermundus Thanks for that example code. I tried using a shortened version for an example. It seems like it works in pgf, but not in pgfplots.

Compiling this example code, I get

My pgf version is: 2.10

test(2.5) is 2

but no plot. I get a bunch of errors at the \addplot line: "Illegal unit of measure (pt inserted)" "Paragraph ended before \pgfflt@readlowlevelfloat was complete"

\documentclass{minimal}
\usepackage{pgfplots}

\makeatletter
\pgfmathdeclarefunction{test}{1}{%
\begingroup%
\pgfmath@xa=#1pt\relax%
\pgfmathparse{int(\pgfmath@xa)}%
\pgfmath@smuggleone\pgfmathresult%
\endgroup%
}%
\makeatother

\begin{document}

My pgf version is: \pgfversion

test(2.5) is \pgfmathparse{test(2.5)}\pgfmathresult

\begin{tikzpicture}
\begin{axis}
\end{axis}
\end{tikzpicture}

\end{document}

-
Yes I added a new example very simple, The function is plotted with pgf and not with pgfplots and I don't know why . A great TeX expert perhaps have an answer. –  Alain Matthes Apr 10 '11 at 8:19
I think you need to read the pgfplots manual. I never use this package (only to test some examples) perhaps there are some comments about the functions you can use ! –  Alain Matthes Apr 10 '11 at 8:22
I also try declare function with success in pgf and failure in pgfplots. –  Alain Matthes Apr 10 '11 at 8:29
I try your function with \draw plot [domain=0:5, samples=144, smooth] (\x,{test(\x)});  and it works in pgf –  Alain Matthes Apr 10 '11 at 8:32

I modified my answer with only an example from the pgfmanual (the first one for \pgfmathdeclarefunction. This example from the pgfmanual works with pgf and not with pgfplots (why ???)

The part with pgfplots gives Latex Error: ./add_func_pgfplots.tex:77 Illegal unit of measure (pt inserted).

\documentclass{minimal}
\usepackage{pgfplots}
\makeatletter
\pgfmathdeclarefunction{double}{1}{%
\begingroup
\pgf@x=#1pt\relax
\multiply\pgf@x by2\relax
\pgfmathreturn\pgf@x
\endgroup
}
\makeatother
\begin{document}
\pgfmathparse{double(44.3)}\pgfmathresult

\begin{tikzpicture}
\draw plot [domain=0:5, samples=144, smooth] (\x,{double(\x)});
\end{tikzpicture}

\begin{tikzpicture}
\pgfmathdouble{1}
\let\ra\pgfmathresult
\draw (0,0) circle (\ra);% \ra is fine
%  \begin{axis}
%  \end{axis}
\end{tikzpicture}

\end{document}


But this code works

 \documentclass{scrartcl}
\usepackage{pgfplots}

\begin{document}

My pgf version is: \pgfversion

\pgfmathdeclarefunction{double}{1}{
\begingroup
\pgfmathmultiply{#1}{#1} % instead of \pgfmathparse{#1*#1} from kristi
\endgroup
}

\begin{tikzpicture}
\begin{axis}

The main problem with \pgfmathparse` is the code is slow if we need to make a lot of loops