0

A common math notation for restricting, to a subset A of its domain, a function f from a set X into a set Y is given by a vertical bar as shown in the first section of output shown below. This is a method by Enrico Gregorio ("egreg") https://tex.stackexchange.com/a/22255/13492.

I want to change the vertical bar to an \upharpoonright. Using the method by Heiko Oberdiek https://tex.stackexchange.com/a/67233/13492, I get the result shown in the second section of output below.

In this method with \upharpoonright, however, the \upharpoonright has its top too low and its bottom also too low. How can that be fixed, so that the vertical position is essentially the same as that used with the vertical bar?

Function restriction notations

 \documentclass{article}
 \usepackage{amsfonts,amssymb}
 \usepackage[left=1.25in,right=1.25in]{geometry}
 \usepackage{scalerel}

% Method of Enrico Gregorio ("egreg") % https://tex.stackexchange.com/a/22255/13492: \newcommand\restrict[2]{% make the whole thing an ordinary symbol \left.\kern-\nulldelimiterspace % automatically resize the bar with \right #1% the function \littletaller % pretend it's a little taller at normal size \right|_{#2}% } \newcommand{\littletaller}{\mathchoice{\vphantom{\big|}}{}{}{}}

% Method of Heiko Oberdiek % https://tex.stackexchange.com/a/67233/13492 \makeatletter \newcommand{\scaleddelims}[3]{% \ensuremath{% \mathpalette{@scaleddelims{#1}{#2}}{#3}% }% }
\newcommand
{@scaleddelims}[4]{% % #1: left delimiter % #2: right delimiter % #3: \displaystyle, \textstyle, ... % #4: inner formula \begingroup #3% \sbox0{$\m@th#3\vphantom{A}#4$}% \setbox2\vbox{\hbox{$\m@th#3#1$}\kern\z@}% \setbox4\vbox{\hbox{$\m@th#3#2$}\kern\z@}% \setbox6\hbox{$#3\vcenter{}$}% \ifx\downharpoonleft#1\relax
\let\DelimLeft=L% \else\ifx\upharpoonleft#1% \let\DelimLeft=L% \else\ifx\downharpoonright#1% \let\DelimLeft=R% \else\ifx\upharpoonright#1% \let\DelimLeft=R% \fi\fi\fi\fi \ifx\downharpoonleft#2\relax \let\DelimRight=L% \else\ifx\upharpoonleft#2\relax \let\DelimRight=L% \else\ifx\downharpoonright#2\relax \let\DelimRight=R% \else\ifx\upharpoonright#2\relax \let\DelimRight=R% \fi\fi\fi\fi \ifx\DelimLeft L% \wd2=.6\wd2 \fi \ifx\DelimRight L% \wd4=.6\wd4 \fi \ifx\DelimLeft R% \sbox2{\kern-.4\wd2\box2}% \fi \ifx\DelimRight R% \sbox4{\kern-.4\wd4\box4}% \fi \dimen0=\ht0 % \advance\dimen0 by -\ht6 % \dimen2=\dp0 % \advance\dimen2 by \ht6 % \ifdim\dimen2>\dimen0 %
\dimen0=\dimen2 % \else \dimen0=\dimen0 % \fi \dimen2=\ht6 % \advance\dimen2 by -\dimen0 % \dimen0=2\dimen0 % \def\DelimCorr{%
\mskip.5\thinmuskip \nonscript\mskip.5\thinmuskip }% \mathopen{% \ifx\DelimLeft R\DelimCorr\fi \raisebox{\dimen2}{\resizebox{!}{\dimen0}{\box2}}% \ifx\DelimLeft L\DelimCorr\fi }% \begingroup #3#4% \endgroup \mathclose{% \ifx\DelimRight R\DelimCorr\fi \raisebox{\dimen2}{\resizebox{!}{\dimen0}{\box4}}% \ifx\DelimRight L\DelimCorr\fi }% \endgroup }\makeatother % \newcommand{\rest}[2]{#1\scaleddelims{\kern-0.5\nulldelimiterspace\upharpoonright}{\vphantom{.}}{_{#2}}}

\begin{document}

\verb!\restrict! (with \verb!|!):

Map $\restrict{f}{E} \colon E \to Y, \quad \restrict{g}{E} \colon E \to Y, \quad \restrict{\Phi}{E} \colon E \to Y, \quad \restrict{f}{A, B} \colon A \to B, \quad \restrict{f}{(A, B)} \colon A \to B$

\bigskip

\verb!\rest! (with \verb!\upharpoonright!):

Map $\rest{f}{E} \colon E \to Y, \quad \rest{g}{E} \colon E \to Y, \quad \rest{\Phi}{E} \colon E \to Y, \quad \rest{f}{A, B} \colon A \to B, \quad \rest{f}{(A, B)} \colon A \to B$

\end{document}

I am aware that the amssymb package defines \restriction in effect as \mathrel{\upharpoonright} (compare https://tex.stackexchange.com/a/565926/13492). However, the horizontal spacing is then too great, and in any case the height does not seem to change appropriately.

murray
  • 7,944

2 Answers2

3

Here's a different solution based on overprinting: basically we print a tall \right|, measure it, and print a \upharpoonright shifted up so that it lines up exactly with the top of the \right|.

In the code below I included also \restrict as you copied it from egreg's solution, to illustrate the relative sizes.

Because this is based on overprinting, the result may require more fine-tuning if you are using other fonts. (For example, in kpfonts the width of \right| is thicker than the width of \upharpoonright, and so the result doesn't look as good.)

\documentclass{article}
\usepackage{amssymb}
\usepackage{mathtools}

\makeatletter \newcommand@rest[3]{% % #1 : function % #2 : \displaystyle etc % #3 : subscript / domain \begingroup #2 % \sbox0{$\m@th#2\left.\kern-\nulldelimiterspace\vphantom{#1}\littletaller\right|$}% \sbox2{$\m@th#2\upharpoonright$}% \dimen0=\ht0 % \advance\dimen0 by -\ht2 % \begingroup #2#1% \endgroup \mathclose{% \kern\nulldelimiterspace\mathclap{\usebox0}\mathclap{\raisebox{\dimen0}{\usebox2}}\kern\nulldelimiterspace}_{#3} \endgroup } \newcommand\rest[2]{% \mathpalette{@rest{#1}}{#2}% }

\newcommand\restrict[2]{% make the whole thing an ordinary symbol \left.\kern-\nulldelimiterspace % automatically resize the bar with \right #1% the function \littletaller % pretend it's a little taller at normal size \right|_{#2}% } \newcommand{\littletaller}{\mathchoice{\vphantom{\big|}}{}{}{}} \makeatother

\begin{document} $\rest{f}{E}$ $\restrict{f}{E}$ $\rest{g}{(A,B)}$ $\restrict{g}{(A,B)}$

$\rest{\frac{\partial f}{\partial x}}{x = 1}$ $\restrict{\frac{\partial f}{\partial x}}{x = 1}$ $\displaystyle \rest{\frac{\partial f}{\partial x}}{x = 1}$ $\displaystyle \restrict{\frac{\partial f}{\partial x}}{x = 1}$

\end{document}

enter image description here

Willie Wong
  • 24,733
  • 8
  • 74
  • 106
1

Is you goal to make a "restriction" operator that scales with the size of the "function"? Is your goal to implement egreg's solution but using \upharpoonright, which would necessitate using Heiko's poorman's \left...\right since the harpoon symbol is not a resizable one?

If my understanding is correct (that your answer to the questions above are both "yes"), then your definition of \rest is incorrect. It should be

\newcommand{\rest}[2]{\mathclose{\scaleddelims{\vphantom{.}}{\upharpoonright}{\kern-\nulldelimiterspace#1\vphantom{\big|}}}_{#2}}

enter image description here

The reason that your original attempt didn't work is because it didn't correctly follow what \scaledelims does: the three arguments are in order:

  • #1 the open delimiter
  • #2 the closing delimiter
  • #3 the formula between the delimiters.

egreg's solution puts a null left delimiter (\left.) and a vertical line for the right delimiter \right|, with the function in the middle, so that the restriction operator will scale with the interior function, with the caveat that the interior must be at least \big| high.

To implement the same logic using Heiko's \scaledelims you should use a null delimiter for the opening one (the \vphantom), the harpoon for the right, and the function as the third argument. Your attempt however placed only a subscript as the third argument, which meant that the scaling is computed with respect to the subscript, which caused pretty much all your problems.

The extra \mathclose that I added to enclose the whole expression is so that the subscript after the harpoon will be vertically shifted appropriately.

Of course, if you are not using the \scaleddelims macro otherwise, the whole code can be significantly compressed.

For example, just by cutting out everything having to do with the opening delimiter and the logic detecting which harpoon you are using, you can reduce the code to

\makeatletter
\newcommand*{\rest}[2]{%
   \ensuremath{%
        \mathpalette{\@resttwo{#1}}{#2}%
   }%
 }   
 \newcommand*{\@resttwo}[3]{%
   % #2: \displaystyle etc
   % #1: function
   % #3: domain
   \begingroup
     #2%
     \sbox0{$\m@th#2\vphantom{\big|}#1$}%
     \setbox4\vbox{\hbox{$\m@th#2\upharpoonright$}\kern\z@}%
     \setbox6\hbox{$#2\vcenter{}$}%
     \sbox4{\kern-.4\wd4\box4}%
     \dimen0=\ht0 %
     \advance\dimen0 by -\ht6 %
     \dimen2=\dp0 %
     \advance\dimen2 by \ht6 %
     \ifdim\dimen2>\dimen0 %  
       \dimen0=\dimen2 %
     \else
       \dimen0=\dimen0 %
     \fi
     \dimen2=\ht6 %
     \advance\dimen2 by -\dimen0 %
     \dimen0=2\dimen0 %
     \def\DelimCorr{%  
       \mskip.5\thinmuskip
       \nonscript\mskip.5\thinmuskip
     }%
     \begingroup
       #2#1%
     \endgroup
     \mathclose{%
       \DelimCorr
       \raisebox{\dimen2}{\resizebox{!}{\dimen0}{\box4}}%
        }_{#3}%
   \endgroup
 }

\makeatother

Willie Wong
  • 24,733
  • 8
  • 74
  • 106
  • The subscript is too low. How do I fix that? – murray Jul 28 '23 at 00:46
  • I am not actually a big fan of using \resizebox for this, since for taller expressions it looks horrible. Please see the other solution that I am typing up right now, it looks nicer and automatically has the same depth (subscript location) as what egreg made. – Willie Wong Jul 28 '23 at 01:26