4

I have been struggling with the following implementation for the last couple of days without being able to find a solution.

I have the following minimal working example:

\documentclass{article}

\usepackage{xkeyval} \usepackage{amssymb, amsmath} \usepackage{xparse} \usepackage{etoolbox}

\makeatletter \define@cmdkey [Notation] {nom} {A} {} \define@cmdkey [Notation] {nom} {B} {} \presetkeys [Notation] {nom} {A={},B={}}{} \NewDocumentCommand{\nom}{ m O{} }{% \setkeys[Notation]{nom}{#2}% \ifdefempty{\cmdNotation@nom@A}{% Descriptor section \ifdefempty{\cmdNotation@nom@B}{% e-\def\subscript{} }{% f-\def\subscript{\mathtt{\cmdNotation@nom@B}}% }% }{% \ifdefempty{\cmdNotation@nom@B}{% g-\def\subscript{\mathtt{\cmdNotation@nom@A}}% }{% h-\def\subscript{\mathtt{\cmdNotation@nom@A,\cmdNotation@nom@B}}% }% }%
\mathcal{#1}_{\subscript} }% \makeatother

\makeatletter \define@cmdkey [Notation] {test} {of} {} \define@cmdkey [Notation] {test} {wrt} {} \presetkeys [Notation] {test} {of={},wrt={}}{} \NewDocumentCommand{\test}{ m O{} }{% \setkeys[Notation]{test}{#2}% \nom{#1}[A=\cmdNotation@test@of, B=\cmdNotation@test@wrt] }%
\makeatother

\begin{document}

\begin{align} \nom{K}[A=A, B=B]\ \nom{K}[A=A] \ \nom{K}[B=B] \ \nom{K} \ \test{K}[of=A, wrt=B] \ \test{K}[of=A] \ \test{K}[wrt=B] \ \test{K} \end{align}

\end{document}

Basically when I call \nom inside \test and the optional inputs of test are empty, they are received in \nom as non-empty arguments.

enter image description here

So far, the only solution I have found is the following:

\makeatletter
\define@cmdkey [Notation] {test} {of} {}
\define@cmdkey [Notation] {test} {wrt} {}
\presetkeys [Notation] {test} {of={},wrt={}}{}
\NewDocumentCommand{\test}{ m O{} }{%
    \setkeys[Notation]{test}{#2}%
            \ifdefempty{\cmdNotation@test@wrt}{%
                \ifdefempty{\cmdNotation@test@of}{%  
                    \nom{#1}[] 
                }{%
                    \nom{#1}[B=\cmdNotation@test@of] 
                }%
            }{%
                \ifdefempty{\cmdNotation@test@of}{%         
                    \nom{#1}[A=\cmdNotation@test@wrt] 
                }{%
                    \nom{#1}[A=\cmdNotation@test@wrt, B=\cmdNotation@test@of] 
                }%
            }% 
}%          
\makeatother

enter image description here

But this is not feasible because in my real implementation \nom and \test have more than 10 inputs and I cannot create a check for each combination of inputs. Furthermore, I have 10 other fuctions similar to \test that internally call \nom.

I hope you can help me. Thanks in advance!

Edit:

As suggested by @Gaussler and @egreg, working with lists in principle works. But I stumbled accross some cases where the passed arguments are not part of a list, or another form of evaluation is needed instead of simple comma separation (see circled in blue). For instance \dot, \hat in the first case are two optional modifiers \mod and \modd, or K and L are part of a text descriptor where both/one/none of the inputs could exist.

enter image description here

In the case of each of the \test_i i = 1:n, I could use different combinations of inputs and pass them to \nom to produce different equations according to my needs.

enter image description here

wdsgn
  • 311
  • 1
    Welcome to TeX.SE! – Mensch Sep 10 '21 at 15:47
  • I don’t quite understand your updated question. But this sounds a lot like stuff that can be programmed with semantex which was the package used in my answer (disclaimer: I am the author). For instance, you can define a key to be equivalent to command=\hat and another to be equivalent to command=\dot. Without knowing exactly what you want, it’s a bit hard to write an answer, but you can have a look at the manual (see the link above). – Gaussler Sep 13 '21 at 11:43
  • Anyway, see my updated answer. ;-) – Gaussler Sep 13 '21 at 12:13

2 Answers2

5

I'm not sure why this indirection. Anyway, using expl3 for everything is easier. Note the grouping, so keys set at the same level will not influence each other.

The \test command will not call \nom with an optional argument, because it has already set the options.

\documentclass{article}

\usepackage{amssymb, amsmath} \usepackage{xparse}

\ExplSyntaxOn

\keys_define:nn { notation/nom } { A .tl_set:N = \l_wdsgn_notation_A_tl, B .tl_set:N = \l_wdsgn_notation_B_tl, A .initial:n = {}, B .initial:n = {}, }

\keys_define:nn { notation/test } { of .code:n = \keys_set:nn { notation/nom } { A=#1 }, wrt .code:n = \keys_set:nn { notation/nom } { B=#1 }, }

\NewDocumentCommand{\nom}{ m O{} } { \group_begin: \wdsgn_notation_nom:nn { #1 } { #2 } \group_end: }

\clist_new:N \l__wdsgn_notation_subscript_clist

\cs_new:Nn \wdsgn_notation_nom:nn { \keys_set:nn { notation/nom } { #2 } \tl_if_empty:NTF \l_wdsgn_notation_A_tl { % A is empty \tl_if_empty:NTF \l_wdsgn_notation_B_tl { e- } { f- } } { % A is not empty \tl_if_empty:NTF \l_wdsgn_notation_B_tl { g- } { h- } } \mathcal{#1} \clist_put_right:NV \l__wdsgn_notation_subscript_clist \l_wdsgn_notation_A_tl \clist_put_right:NV \l__wdsgn_notation_subscript_clist \l_wdsgn_notation_B_tl \clist_if_empty:NF \l__wdsgn_notation_subscript_clist { % here we exploit the fact that \clist_use:Nn disregards empty items \sb{\mathtt{\clist_use:Nn \l__wdsgn_notation_subscript_clist {,}}} } }

\NewDocumentCommand{\test}{ m O{} } { \group_begin: \keys_set:nn { notation/test } { #2 } \nom{#1} \group_end: }

\ExplSyntaxOff

\begin{document}

\begin{align} \nom{K}[A=A, B=B]\ \nom{K}[A=A] \ \nom{K}[B=B] \ \nom{K} \ \test{K}[of=A, wrt=B] \ \test{K}[of=A] \ \test{K}[wrt=B] \ \test{K} \end{align}

\end{document}

enter image description here

Note. Thanks to Gaussler who pointed out the need for a fix.

egreg
  • 1,121,712
  • Well, the original problem is still present, namely the unwanted commas. – Gaussler Sep 10 '21 at 17:36
  • @Gaussler oh I see. Esay fix – egreg Sep 10 '21 at 18:57
  • Yes, obviously. But I’m not gonna fix your answers for you, and I doubt you’d want me to. ;-) – Gaussler Sep 10 '21 at 18:59
  • @egreg: Thanks for your reply, I will check both solutions in my code and check which one provides the better results and come back to you guys! – wdsgn Sep 11 '21 at 10:58
  • @WDsgn Honestly, egreg’s solution is the “standard” solution. This package semantex is my own little controversial research project in semantic mathematics. You'll also find that it runs much slower then egreg’s solution. ;-) – Gaussler Sep 11 '21 at 14:28
  • I edited the question because there are some cases where lists might not be sufficient to construct the full case of \nom. – wdsgn Sep 13 '21 at 09:40
  • @WDsgn Sorry, but you give no indication at all about how to fit those symbols in \nom. Please, open a new question, but I still cannot understand what \test is about. – egreg Sep 13 '21 at 10:32
2

An alternative solution I made because I was bored. (Independently of this, allow me to comment that your syntax seems very counterintuitive to me. Are you sure this is really the way you want to type whatever it is you are writing?)

\documentclass{article}

\usepackage{semantex}

\NewSymbolClass\nom[ data provide=data A, data provide=data B, parse options={ command=\mathcal, inner return, if blank TF={\SemantexDataGetExpNot{data A}}{ if blank TF={\SemantexDataGetExpNot{data B}} { symbol put left={e-}, } { symbol put left={f-}, set keys x={ sep lower={\SemantexExpNot\mathtt{\SemantexDataGetExpNot{data B}}}, }, }, } { if blank TF={\SemantexDataGetExpNot{data B}} { symbol put left={g-}, set keys x={ sep lower={\SemantexExpNot\mathtt{\SemantexDataGetExpNot{data A}}}, }, } { symbol put left={h-}, set keys x={ sep lower={\SemantexExpNot\mathtt{\SemantexDataGetExpNot{data A}}}, sep lower={\SemantexExpNot\mathtt{\SemantexDataGetExpNot{data B}}}, }, }, }, }, define keys[1]={ {A}{ data set={data A}{#1} }, {B}{ data set={data B}{#1} }, }, ]

\NewSymbolClass\test[ parent=\nom, define keys[1]={ {of}{ A={#1} }, {wrt}{ B={#1} }, }, ]

\begin{document}

\begin{align} \nom{K}[A=A, B=B]\ \nom{K}[A=A] \ \nom{K}[B=B] \ \nom{K} \ \test{K}[of=A, wrt=B] \ \test{K}[of=A] \ \test{K}[wrt=B] \ \test{K} \end{align}

\end{document}

enter image description here


I’m not quite sure what you mean by your updated answer. But semantex can also be programmed to handle these kinds of situations. Forgive me for using weird command names in the following, but I’m not quite sure what your notation is really supposed to mean:

\documentclass{article}

\usepackage{semantex}

\NewVariableClass\MyVar[ output=\MyVar, ]

% First a few variables; the "v" stands for variable:

\NewObject\MyVar\vh{h} \NewObject\MyVar\vg{g} \NewObject\MyVar\vf{f} \NewObject\MyVar\ve{e} \NewObject\MyVar\vK{K} \NewObject\MyVar\vL{L}

% Feel free to give the following more descriptive names:

\NewObject\MyVar\guid{\mathrm{guid}} % could also use \operatorname, depending on what "guid" is

\NewObject\MyVar\scriptK{\mathcal{K}} \NewObject\MyVar\ttA{\mathtt{A}} \NewObject\MyVar\ttB{\mathtt{B}} \NewObject\MyVar\ttC{\mathtt{C}} \NewObject\MyVar\ttD{\mathtt{D}} \NewObject\MyVar\ttE{\mathtt{E}} \NewObject\MyVar\ttF{\mathtt{F}} \NewObject\MyVar\ttG{\mathtt{G}} \NewObject\MyVar\ttH{\mathtt{H}} \NewObject\MyVar\ttX{\mathtt{X}} \NewObject\MyVar\ttY{\mathtt{Y}}

\NewVariableClass\WeirdConstruction[ parent=\MyVar, data provide=data A, data provide=data B, data provide=data C, data provide=data D, data provide=data E, data provide=data F, data provide=data G, data provide=data H, define keys={ {mod}{ command=\hat }, {modd}{ command=\dot }, }, define keys[1]={ {A}{ data set={data A}{#1} }, {B}{ data set={data B}{#1} }, {C}{ data set={data C}{#1} }, {D}{ data set={data D}{#1} }, {E}{ data set={data E}{#1} }, {F}{ data set={data F}{#1} }, {G}{ data set={data G}{#1} }, {H}{ data set={data H}{#1} }, {description}{ parse, if blank TF={\SemantexDataGetExpNot{lower}} { lower={#1}, } { lower={_\bgroup #1}, post lower=\egroup, }, }, }, parse options={ set keys x={ sep upper left=\SemantexDataGetExpNot{data B}, sep upper left=\SemantexDataGetExpNot{data A}, sep lower left=\SemantexDataGetExpNot{data D}, sep lower left=\SemantexDataGetExpNot{data C}, sep upper=\SemantexDataGetExpNot{data E}, sep upper=\SemantexDataGetExpNot{data F}, sep lower=\SemantexDataGetExpNot{data G}, sep lower=\SemantexDataGetExpNot{data H}, }, }, ]

\NewObject\WeirdConstruction\ThetaConstruction{\Theta} \NewObject\WeirdConstruction\aConstruction{\mathbf{a}}

\begin{document}

[ \ThetaConstruction[ A=\ttA, B=\ttB, C=\ttC, D=\ttD, E=\ttE, F=\ttF, G=\ttG, H=\ttH, mod, modd, description=\vK, description=\vL, ] ]

[ \aConstruction[ A=\ttC,C=\ttX, mod, modd, description=\guid, description=3, ] ]

\end{document}

enter image description here

Gaussler
  • 12,801
  • Thanks for your reply. Sorry if the example was not very intitutive, I tried to simplify as much as I could. Every feedback from experienced people is very welcome! :) – wdsgn Sep 11 '21 at 10:55
  • @WDsgn See my updated answer. Did I understand your problem right? :-) – Gaussler Sep 14 '21 at 08:19