0

I am writing a macro that will read a system of linear equations in a custom format and call \begin{array} with the appropriate format. For that I need to loop through each row and compute what is going to be displayed.

This is what I have so far.

\documentclass[10pt,a4paper]{article}
\usepackage{xstring}

\newcommand{\lineareqsys}[3]{
\noexpandarg
\StrCount{#3}{\\}[\rows] %check \rows = arg > 0
\newcounter{i} \setcounter{i}{0}
\def\str{#3}
\def\strout{}
\expandafter\StrSubstitute\expandafter{\str}{+}{+&}[\str]
\expandafter\StrSubstitute\expandafter{\str}{-}{-&}[\str]
\loop
\stepcounter{i}
\expandafter\def\csname strout\roman{i}\endcsname{}
\expandafter\StrCut\expandafter{\str}{\\}{\str}{\rest}
\expandafter\StrPosition\expandafter{\str}{x}[\xpos]
\expandafter\StrLeft\expandafter{\str}{\xpos}[\strappx]
\expandafter\def\expandafter\strout\expandafter{\strout \strappx &}
\expandafter\StrGobbleLeft\expandafter{\str}{\xpos}[\str]
\expandafter\StrPosition\expandafter{\str}{y}[\ypos]
\expandafter\StrLeft\expandafter{\str}{\ypos}[\strappy]
\expandafter\def\expandafter\strout\expandafter{\strout \strappy &}
\expandafter\StrGobbleLeft\expandafter{\str}{\ypos}[\str]
\expandafter\StrPosition\expandafter{\str}{=}[\eqpos]
\expandafter\StrLeft\expandafter{\str}{\eqpos}[\strappeq]
\expandafter\def\expandafter\strout\expandafter{\strout \strappeq &}
\expandafter\StrGobbleLeft\expandafter{\str}{\eqpos}[\str]
\expandafter\StrRight\expandafter{\str}{\eqpos}[\strapplb]
\expandafter\def\expandafter\strout\expandafter{\strout \strapplb \\}
\expandafter\def\expandafter\str\expandafter{\rest}
\expandafter\def\csname strout\roman{i}\endcsname{\strout}
\ifnum \thei < #1 \relax
\repeat
\newcounter{j} \setcounter{j}{0}
\def\alig{r}
\loop
\stepcounter{j}
\expandafter\def\expandafter\alig\expandafter{\alig cr}
\ifnum \thej < #2 \relax
\repeat
\left\lbrace
\begin{array}{\alig}
\strout
\end{array}
\right.
}


\begin{document}
$\lineareqsys{2}{2}{
x + y = 5 \\
x - y = 3 \\
}$
\end{document}

There is a problem with line

\expandafter\def\csname strout\roman{i}\endcsname{\strout}

because \strout is not fully expanded, so after the second time of the loop data is replaced and I get the last row repeated twice.

I've been checking other threads but I haven't managed to get it right. How can I solve this problem?

Note1: The code isn't finished so it doesn't handle the cases where there is no x or y or a line starts with a - sign.

Note2: The format I was referring to is straightforward.

ax + by + cz = d \\

for as many rows as necessary.

Edit: Simpler version of previous code.

\documentclass{article}
\newcommand{\lineareqsys}{
\newcounter{i} \setcounter{i}{0}
\def\strout{}
\loop
\stepcounter{i}
\expandafter\def\expandafter\strout\expandafter{\strout \arabic{i} row \\}
\ifnum \thei < 2 \relax
\repeat
\begin{array}{l}
\strout
\end{array}
}
\begin{document}
$\lineareqsys$
\end{document}

This ilustrates the same problem. \arabic{i} is expanded at the end when it's value is 2. Not dinamic.

7
  • 2
    if you know that \strout is safe for expansion then just replace \def by \edef or if you just want to expand it once then expandafter\def\csname strout\roman{i}\expandafter\endcsname\expandafter{\strout} but the code seems massively over complicated, can you give a small text description of the intended effect? Commented Nov 14, 2017 at 9:38
  • \edef gives a compile time error. I think because it relays on #3 but I'm not sure if this is the reason.
    – mendus
    Commented Nov 14, 2017 at 9:43
  • Do you know about the systeme package?
    – egreg
    Commented Nov 14, 2017 at 9:46
  • don't do \newcounter inside a command! (you do it twice)
    – user4686
    Commented Nov 14, 2017 at 9:48
  • @egreg Yes, I had found it previously. I wanted to write my own functions though, so I can add things as I see fit.
    – mendus
    Commented Nov 14, 2017 at 10:01

2 Answers 2

2

The core problem is that you are not expanding things. As you can see, here is meaning of \strout after a while

> \strout=macro:
->\strappx &\strappy &\strappeq &\strapplb \\\strappx &\strappy &\strappeq &\st
rapplb \\.
\iterate ... {\strout \strapplb \\} \show \strout 
                                                  \expandafter \def \expanda...
l.57 }
      $

You have to find a way to add to \strout the expanded contents of the \strappx, \strappy etc... whatever they are.

Besides, you do \newcounter inside your command call, which is very wrong. But this is other issue.

To debug, I added \show\strout at various places of your command.

Also you are lucky to call this macro only in math mode because you have tons of space tokens in it.


For example, this can give an idea of what needs to be done:

%\expandafter\def\expandafter\strout\expandafter{\strout \strapplb \\}
\expandafter\g@addto@macro\expandafter\strout\expandafter{\strapplb\\}

enter image description here

The RHS of first equation is fixed.

5
  • This works. Any alternative to \g@addto@macro by any chance?
    – mendus
    Commented Nov 14, 2017 at 10:19
  • well, \edef\strout{\unexpanded\expandafter{\strout}\unexpanded\expandafter{\strapplb\\}} should work (pay attention that copying pasting from this comment might introduce some invisible Unicode, due to the site interfering; better copy by hand). Beware that \g@addto@macro is global, so if you use it make global all other manipulations of \strout to follow good practices.
    – user4686
    Commented Nov 14, 2017 at 11:49
  • this being said, it would not be too complicated to replace by delimited macros all your invocations of xstring ... and the various pieces would then be available "raw" not incorporated in a macro.
    – user4686
    Commented Nov 14, 2017 at 11:51
  • I don't understand what you mean with the last comment. How do I search for x, y and z and how do I cut the users input into two pieces without a string package? Can you refer me to some documentation? I'm pretty new to TeX, previously I've only used high level LaTeX commands.
    – mendus
    Commented Nov 15, 2017 at 7:42
  • maybe my comment was a bit rushed. TeX has a a powerful concept of delimited macros, on which evidently packages such as xstring build up, or xparse. If you happen to know about TeX, it is natural to feel you don't really need xstring, but it also means you have your own coding habits and possibly you re-invent the wheel each time. If x, y, z are always in that order, delimited macros will solve easily problem. If the order maybe z, y, x, then they will too (only available tool after all) but require more expertise. TeX by Topic (texdoc topic) is recommended.
    – user4686
    Commented Nov 15, 2017 at 8:16
2

There are big expansion problems, as you saw.

Here's a completely different solution, which uses expl3, but has, like yours, the defect that missing unknowns spoil the result.

I also offer a comparison with systeme, that doesn't suffer from the defect.

\documentclass[10pt,a4paper]{article}
\usepackage{xparse}
%\usepackage{array} % also works with this uncommented
\usepackage{systeme} % for comparison

\ExplSyntaxOn
\NewDocumentCommand{\lineareqsys}{mm}
 {
  \seq_set_split:Nnn \l__mendus_system_in_seq { \\ } { #2 }
  \seq_clear:N \l__mendus_system_out_seq
  \seq_map_inline:Nn \l__mendus_system_in_seq
   {
    \__mendus_system_make_row:nn { #1 } { ##1 }
   }
  \left\lbrace
  \setlength{\arraycolsep}{0pt}
  \renewcommand{\arraystretch}{1.2}
  \exp_args:Nnx \begin{array}{r \prg_replicate:nn { \clist_count:n { #1 } } { c r } }
  \seq_use:Nn \l__mendus_system_out_seq { \\ }
  \end{array}
  \right.
 }

\cs_new_protected:Nn \__mendus_system_make_row:nn
 {
  \tl_set:Nn \l__mendus_system_row_tl { #2 }
  \regex_replace_all:nnN { (.+?)(\+|\-|\=) } { \1\cB\{\cE\}\2\cB\{\cE\}\cT& } \l__mendus_system_row_tl
  \clist_map_inline:nn { #1 }
   {
    \regex_replace_all:nnN { ##1 } { \cL##1 \cT& } \l__mendus_system_row_tl
   }
  \seq_put_right:NV \l__mendus_system_out_seq \l__mendus_system_row_tl
 }
\cs_generate_variant:Nn \regex_count:nnN { nV }
\ExplSyntaxOff

\begin{document}

\[
\lineareqsys{x,y}{
x + y = 5 \\
x - y = 3 \\
}
\qquad
\lineareqsys{x,y,z}{
  2x-3y+4z=0 \\
  x+12y-z=0 \\
  -x+8y+z=3
}
\]

\[
\systeme{
  x + y = 5,
  x - y = 3
}
\qquad
\systeme{
  2x-3y+4z=0,
  x+12y-z=0,
  -x+8y+z=3
}
\]

\end{document}

enter image description here

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .