14

In nonstandard analysis, the nonstandard extension operator * is used frequently. Typesetting it is not straightforward, though, because the placement of * depends on the symbol to follow. E.g., the nonstandard extension of the reals is written

^*{\mathbb{R}}

whereas the nonstandard extension of a real function X is typically typeset

^*\!{X}

If the negative space \! is not included, the * and the X are spaced too far apart.

How negative spacing looks

I'd like to separate style from content in my LaTeX, but it's not clear how I would define a macro that expanded appropriately given the context. It would seem that I would need two macros—one where I needed a negative space, and another when I didn't. But this seems not much better than adding \! to the code. I've seen posts suggesting the tensor package, but the space is not correct.

EDIT: I've accepted an answer that allows one to specify the appropriate spacing for particular letters. A LuaLateX version is a more flexible version of this idea. The automatic approach is impressive and creative, but doesn't deliver the quality necessary for a professionally typeset document. I'm now inclined to think that an automatic approach is unlikely to suffice without detailed knowledge of the underlying font.

  • Did you see http://tex.stackexchange.com/questions/95878/superscript-asterisk-on-the-left-side-of-different-symbols-math-mode ? – egreg Apr 28 '15 at 16:24
  • Yes, I saw that. It's useful for other issues, but not this one. The answer by Manuel below get's at the difficulties: X, V, A all need slightly different spacing. – Daniel Roy Apr 28 '15 at 21:05

4 Answers4

8

Until someone comes up with a nice solution, a brute-force one could be:

\documentclass{scrartcl}
\usepackage{xparse,dsfont}

\ExplSyntaxOn
\NewDocumentCommand \nsext { m }
 {
  {\vphantom{#1}}
  \sp
   {
    *
    \str_case:nn {#1}
     {
      { X } { \mskip-3mu }
      { A } { \mskip-6mu }
     }
   }
  #1
 }
\ExplSyntaxOff

\newcommand*{\R}{\mathds{R}}

\begin{document}
$\nsext\R \quad \nsext X \quad \nsext V \quad \nsext A$
\end{document}

You just need to add a pair inside the \str_case:nn second argument if you want to add a new letter and the according space to remove.

enter image description here

Manuel
  • 27,118
  • 2
    OK, but I would suggest you use \mkern minus whatever mu, instead of \! – Andrew Swann Apr 28 '15 at 18:15
  • That's pretty nice, but will get unwieldy fast due to the case statement, although perhaps that's the price to pay. I'll wait a bit and see if anyone comes up with something else. – Daniel Roy Apr 28 '15 at 21:03
  • @AndrewSwann It's already suggested, in an obscure way, though :) May be I will rewrite the answer. – Manuel Apr 28 '15 at 21:18
  • @DanielRoy I'm not sure if there's an automatic way of looking inside the glyphs to see if there's room or not (at least for us mortals there's not, may be one of thos TeXnical gods find a way). In any case, I don't think it would be too much work; usually only a few letters (or macros, like \nsext\R) are used in a document, and you just have to add them once in the preamble. – Manuel Apr 28 '15 at 21:21
  • @DanielRoy If I recall correctly, looking at glyphs like that is impossible (at least with a direct approach). TeX is only aware of a few font metrics – bounding box, baseline, etc. – necessary to string them together into words, lines, and paragraphs. It doesn't actually know what the character looks like. – Sean Allred Apr 29 '15 at 03:44
  • So... the reason that \nsext\R looks good is that ^*\R looked good: there's no modification to the spacing taking place. If ^*\R hadn't looked good, and I wanted to make an adjustment, how would I have done that? Naively, adding an R to the case statement doesn't work. Perhaps a more general question is: what do I do when the argument to \nsext is a compound expression, and not simply a letter? – Daniel Roy Apr 29 '15 at 12:29
  • @DanielRoy Just add the case in the second argument of \str_case:nn. Adding, for instance { \R } { \mskip-1mu } or { \mathbb{R} } { \mskip-1mu } works. I just wrote two examples with A and X but you can add whatever. The \str_case:nn compares the argument ({#1}) with the first in each pair, and, in case it's true, it adds the second argument (in this case, an appropiate \mkern…). – Manuel Apr 29 '15 at 13:30
  • @DanielRoy This solution offers an easy way to check the argument and act depending on it. That's all. The thing is that it's quite easy to add new cases (just a pair of {..} {..}). With Mico's solution, it isn't that easy to add new cases, but, on the other hand, it offers some sort of regular expressions, which may automate the problem a lot. In any case, this doesn't require Lua. – Manuel Apr 29 '15 at 13:41
7

REVISED APPROACH

Comments from the OP indicated that my original solution, while perhaps nice to look at, relied on changing the math font to ptmx, which was not acceptable. So the issue seemed to be that the math kerning of the ptmx font was OK, but that of ComputerModern (CM) was inadequate for the current task.

With that in mind, I decided to declare the ptmx math alphabet separately, and use it only for positioning of the CM glyphs. EDITED to declare a new math alphabet. Then, when I am stacking the * over/before the given argument, I use the \mathptmx version of the argument (that I just declared) to govern the offset from the right hand.

To account for arguments that are not pure alphabetic glyphs, I start out with a catcode test. In this MWE below, you see my approach on the top line, compared with the raw ComputerModern construction of $^*<letter>$ on the second line.

EDITED (8/2016) to work in subscript math styles, per an e-mail request of a reader. For this, I use the \ThisStyle{...\SavedStyle...} feature of the scalerel package to import the math style to places where it would otherwise be lost. RE-EDITED to \leavevmode to handle use-case in \substack.

\documentclass{article}
\usepackage{amssymb,stackengine,xcolor,scalerel,mathtools}
\stackMath
\def\nsa#1{\leavevmode\ThisStyle{%
\def\stackalignment{r}\def\stacktype{L}%
\ifcat A#1
  \mkern-6.5mu\stackon[0pt]{\SavedStyle\phantom{f}#1}  
    {\SavedStyle^*\mkern-1.1mu\phantom{\mathptmx{#1}}}%
\else
  \mkern-4mu\stackon[0pt]{\SavedStyle\phantom{f}#1}  
    {\SavedStyle^*\mkern-1.7mu\phantom{#1}}%
\fi
}}
\def\R{\mathbb{R}}
\DeclareMathAlphabet{\mathptmx}{OML}{ztmcm}{m}{it}
\parskip 1ex
\begin{document}
\centering
$(\nsa\R) ~ (\nsa V) ~ (\nsa X) ~ (\nsa A) ~ (\nsa M)$

vs.

$(^*\R) ~ (^*V) ~ (^*X) ~ (^*A) ~ (^*M)$

\hrulefill

Other cases requiring EDIT to \textbackslash nsa:

$(x_n)_{n\in\nsa{\mathbb N}}$. 

$\bigcup_{\substack{U\subseteq X\\ \nsa U\subseteq \mathrm{Fin}(\nsa X)}}$
\end{document}

enter image description here

ORIGINAL APPROACH (ptmx math)

This tries to align the * approximately where the right end of an f might be. The first row shows the kerning I was trying to emulate (the model); the second row shows the implemented macro; while the third row shows how the macro succeeds at its goal (the method, with * overlaying right end of f)

\documentclass{article}
\usepackage{amssymb,mathptmx,stackengine,xcolor}
\stackMath
\def\nsa#1{\def\stackalignment{r}\def\stacktype{L}%
  \mkern-1mu\stackon[0pt]{\mkern-2mu\phantom{f}#1}{^*\mkern-1.7mu\phantom{#1}}}
\def\R{\mathbb{R}}
\begin{document}
$ f\R ~fV ~fX ~fA$ The model

$\nsa\R ~ \nsa V ~ \nsa X ~ \nsa A$ The macro

\def\nsa#1{\def\stackalignment{r}\def\stacktype{L}%
  \mkern-1mu\stackon[0pt]{\color{cyan}\mkern-2mu f#1}{^*\mkern-1.7mu #1}}
$\nsa\R ~ \nsa V ~ \nsa X ~ \nsa A$ The method
\end{document}

enter image description here

5

Here's a LuaLaTeX-based solution, which sets up a Lua function that adjusts the space between the asterisk and the subsequent letter, where the adjustment amount depends on the shape of the letter.

The code defines LaTeX macro named \nsx (short for "nonstandard extension") that prefixes an asterisk to the macro's argument -- typically an uppercase letter; the default spacing adjustment between the asterisk and the letter is -4mu. (A negative thinspace, \!, equals -3mu.) The code next sets up a Lua function that overrides the default adjustment amount for selected letters.

See the table below for the adjustment amounts I've been able to come up with for the 26 uppercase letters of the Latin alphabet as well as for \mathbb{R} and \Gamma. Note that these adjustment amounts are optimized for the "Computer/Latin Modern" math fonts. Other font families will probably require different adjustment amounts.

enter image description here

% !TEX TS-program = lualatex
\documentclass{article}

\newcommand\nsx[2][4]{{}^{*}\mkern-#1mu#2}  % default neg. space: 4mu

\usepackage{amsfonts,array,booktabs} % just for this example

\usepackage{luacode,luatexbase}
\begin{luacode}
function adjust_ns ( line )
    if string.find ( line, "\\nsx" ) then
       line = string.gsub ( line, "\\nsx{([AJ])}", "\\nsx[6.5]{%1}" )
       line = string.gsub ( line, "\\nsx{([X])}", "\\nsx[4.5]{%1}" )
       line = string.gsub ( line, "\\nsx{([SZ])}", "\\nsx[3.5]{%1}" )
       line = string.gsub ( line, "\\nsx{([CGOQUVW])}", "\\nsx[2.5]{%1}" )
       line = string.gsub ( line, "\\nsx{([Y])}", "\\nsx[1.5]{%1}" )
       line = string.gsub ( line, "\\nsx{([T])}", "\\nsx[1]{%1}" )
       line = string.gsub ( line, "\\nsx{\\mathbb{R}}", "\\nsx[1.5]{\\mathbb{R}}" )
       line = string.gsub ( line, "\\nsx{\\Gamma}", "\\nsx[2]{\\Gamma}" )
    end
    return  line
end
luatexbase.add_to_callback ( "process_input_buffer", adjust_ns, "adjust_ns" )
\end{luacode}

\begin{document}

\noindent
\begin{tabular}{@{} >{$}l<{$} l @{}}
$Letter$ & Adjustment (in ``mu'')\\
\midrule
\nsx{B}\nsx{D}\nsx{E}\nsx{F}\nsx{H}\nsx{I}\nsx{K}\nsx{L}\nsx{M}\nsx{N}\nsx{P}
\nsx{R} & 4 (default)\\
\nsx{A}\nsx{J} & 6.5\\
\nsx{X} & 4.5\\
\nsx{S}\nsx{Z} & 3.5\\
\nsx{C}\nsx{G}\nsx{O}\nsx{Q}\nsx{U}\nsx{V}\nsx{W} & 2.5 \\
\nsx{Y} & 1.5 \\
\nsx{T} & 1 \\
\nsx{\mathbb{R}} & 1.5 \\
\nsx{\Gamma} & 2 \\
\end{tabular}
\end{document} 
Mico
  • 506,678
  • Not sure about \mathop (this is understatement, of course). – egreg Apr 29 '15 at 07:42
  • @egreg - I was going off the OP's own term -- "nonstandard extension operator" when I chose \ns to be of type mathop. Pls advise if you think there's a more compelling alternative. – Mico Apr 29 '15 at 07:55
  • The * is an operator, but not in the same sense of \log, \sin or \sum. It just denotes the unique nonstandard object linked to a standard one. So * should just respect the type of the following symbol. See my answer to the question I linked above for a couple of examples. – egreg Apr 29 '15 at 07:58
  • @egreg - Thanks for this explanation. (I had clearly misinterpreted the meaning of "operator"...) I've fixed the code. – Mico Apr 29 '15 at 08:37
  • Thanks. I'm not that familiar with lualatex and so I'll have to look into whether, e.g., the journal I'm likely submitting to accepts lualatex. (Every journal in my various fields accepts latex... just not sure about lualatex.) The case statement here does seem to be more flexible than the one proposed by Manuel, but, unless I'm mistaken, the idea is similar. – Daniel Roy Apr 29 '15 at 11:50
  • @DanielRoy - See the posting The differences between TeX engines for more information on the topic of pdf(La)TeX vs Lua(La)TeX. Your concern that the publisher of journal you're planning to submit your piece to may not support LuaLaTeX-based documents is quite valid, I'm afraid: Publishers' software tends not to be cutting edge (or even dull edge...). Do ask the journal staff about their support for LuaLaTeX. If nothing else, you can combine the adjustment amounts in this answer together with the macros that Manuel provided in his separate answer. – Mico Apr 30 '15 at 00:04
2

This code also recognizes some types, based on the macro \binrel@: binary operation and relations (no operators, though).

\documentclass{article}
\usepackage{amsmath}
\usepackage{amssymb}

\makeatletter
\DeclareRobustCommand{\nsext}[1]{%
  \binrel@{#1}% compute the type
  \binrel@@{%
    {\vphantom{#1}}^*% the asterisk at the proper height
    \kern-\scriptspace % remove the script space
    \csname mkern@\detokenize{#1}\endcsname % additional kerning
    {#1}% the symbol
  }%
}
\newcommand{\defineextkern}[2]{%
  \@namedef{mkern@\detokenize{#1}}{\mkern#2}%
}
\makeatother

% define some additional kerning
\defineextkern{X}{-3mu}
\defineextkern{\in}{-2mu}

\begin{document}

$x\nsext{\in}\nsext{\mathbb{R}}$

$\nsext{X}_{x\nsext{\in}\nsext{X}}$

\end{document}

enter image description here

egreg
  • 1,121,712