Diaa
Consider I have a transfer function (polynomial fraction)


a_1*s^n + a_2*s^{n-1} + ... + a_{n-1}*s^1 + a_n
---------------------------------------------
s^N + b_1*s^{N-1} + ... + b_{N-1}*s^1 + b_N


where the denominator order N is greater than the numerator order n.

I would like to find a robust way to transform it to a matrix \StateMat representing the phase variable form of the state-space to have


\edef\StateMat{%
{ 0 , 1 , 0 , 0 , ... , 0 },%
{ 0 , 0 , 1 , 0 , ... , 0 },%
{ 0 , 0 , 0 , 1 , ... , 0 },%
% .........................
{ 0 , 0 , 0 , ... , 0 , 1 },%
{ -b_N , -b_{N-1} , ... , -b_1 },%
{ a_n , a_{n-1} , ... , 0 }%
}


where the matrix is square of dimensions N+1*N+1.

The expected input from my side is two matrices of the coefficients

\edef\NumCoeffMat{%
{ a_1 , a_2 , ... , a_n }%
}

and

\edef\DenCoeffMat{%
{ b_1 , b_2 , ... , b_N }%
}

---

This problem is a part of converting a transfer function into a state space representation for drawing the signal flow graphs introduced here https://topanswers.xyz/tex?q=1568#a1818

## Full MWE


\documentclass[tikz,border=5mm]{standalone}
\usetikzlibrary{calc,decorations.markings,positioning,arrows.meta}
\usepackage{pgffor}
\makeatletter
\pgfkeys{/matrix games/.cd,
count/.code={\c@pgf@counta0\relax
\pgfkeys{/matrix games/step counta/.list/.expanded={#1}}%
\edef\pgfmathresult{\the\c@pgf@counta}%
cells/.code={\pgfmathparse{#1}},nrows/.initial=5,ncols/.initial=5,
create matrix/.code={\edef\pgf@util@tempa{}%
\foreach \i in {1,...,\pgfkeysvalueof{/matrix games/nrows}}%
{\foreach \j in {1,...,\pgfkeysvalueof{/matrix games/ncols}}{%
\pgfkeys{/matrix games/cells}%
\ifnum\j=1\relax
\xdef\pgf@util@tempb{\pgfmathresult}%
\else
\xdef\pgf@util@tempb{\pgf@util@tempb,\pgfmathresult}%
\fi}%
\ifnum\i=1\relax
\xdef\pgf@util@tempa{{\pgf@util@tempb}}%
\else
\xdef\pgf@util@tempa{\pgf@util@tempa,{\pgf@util@tempb}}%
\fi}%
\let#1\pgf@util@tempa
}}
\makeatother

\begin{document}
\edef\NumCoeffMat{{2,24,34}}%
\edef\DenCoeffMat{{10,31,30}}%
\pgfkeys{/matrix games/.cd,count=\NumCoeffMat}%
\pgfmathtruncatemacro\myN{\pgfmathresult+1}% now \myN is 1 + the length of \NumCoeffMat
\pgfkeys{/matrix games/.cd,count=\DenCoeffMat}%
\pgfmathtruncatemacro\myM{\pgfmathresult}% now \myM is the length of \DenCoeffMat
\pgfkeys{/matrix games/.cd,ncols=\myN,nrows=\numexpr\myN+1,
cells/.code={
\pgfmathtruncatemacro{\icase}{(\i==\myN?1:0)+(\i==\myN+1?2:0)}%
\ifcase\icase% first case: zero unless \i+1=\j
\pgfmathparse{int(\i+1==\j?1:0)}%
\or% second case
\ifnum\j>\numexpr\myN-1\relax% subcase a) \j >=\myN
\pgfmathparse{1}%
\else% subcase b) \j <\myN (fill in \NumCoeffMat reversed)
\pgfmathparse{int(\NumCoeffMat[\myN-\j-1])}%
\fi
\or% third case
\ifnum\j<\numexpr\myM+1\relax% subcase a) \j <=\myM (fill in \DenCoeffMat reversed)
\pgfmathparse{int(\DenCoeffMat[\j-1])}%
\else% subcase b) \j > \myN  (fill in zeros)
\pgfmathparse{int(0)}%
\fi
\fi},
create matrix=\StateMat}%
\begin{tikzpicture}[node distance = 15 mm,
amark/.style={
decoration={
markings,
mark=at position {0.5} with {
\arrow{stealth},
}
},
postaction={decorate,edge label={#1}}
}, % make the mark an entry of the \StateMat matrix
pmark/.code n args={2}{%
\pgfmathtruncatemacro{\myi}{int({\StateMat}[\numexpr#1][\numexpr#2])}%
\tikzset{suppress if 0=\myi,edge label={$\myi$},
amark}% <- changed
},
terminal/.style 2 args={draw,alias=ln,circle,inner sep=2pt,label={#1:#2}},
% semicircle path
semicircle/.style={to path={let \p1=($(\tikztotarget)-(\tikztostart)$)
in \ifdim\x1>0pt
\else
\fi
\tikztonodes}},
semicircle'/.style={to path={let \p1=($(\tikztotarget)-(\tikztostart)$)
in \ifdim\x1>0pt
\else
\fi
\tikztonodes}},
\ifcase\itest
\tikzset{#2}%
\else
\tikzset{#3}%
\fi
]
\pgfmathtruncatemacro{\dimy}{dim({\StateMat})} % number of rows
\pgfmathtruncatemacro{\dimx}{dim({\StateMat}[0])} % number of columns
% create the graph
\path % R node
node[terminal={left}{$R(S)$},alias={X-\dimy}] (R) {}
% loop over matrix entries
foreach \Y [evaluate=\Y as \X using {int(\dimy-\Y)}]
in {1,...,\numexpr\dimy-1}
{node[right=of ln,terminal={below right}{% sX_i node
$sX_{\X}(s)$}](sX-\X){}
node[right=of ln,terminal={below right}{% X_i node
$X_{\X}(s)$}](X-\X){}
% ege from sX_i to X_i
(sX-\X) edge[amark,edge label={$\frac{1}{s}$}] (X-\X)
% edge from X_{i+1} to X_i  (R had an alias)
(X-\the\numexpr\X+1) edge[pmark={\X-1}{\X}] (sX-\X)
% semicircle edge from X_i to sX_i
(X-\X) edge[semicircle,pmark={\X-1}{\X-1}] (sX-\X)
}
node[right=of ln,terminal={right}{$Y(s)$},alias=sX-\dimy](Y){}
(X-1) edge[pmark={\dimy-1}{0}] (Y)
% we are now done with the horizontal part,
% and have also dealt with the entries on the diagonal and
% the {i-1},i entries
% now we deal with the matrix entries
foreach \X in {1,...,\the\numexpr\dimx-1}
{% all edges that end in Y (excluding the horizontal one)
\ifnum\X>\numexpr1\relax
(X-\X) edge[pmark={\dimx-1}{\X-1},semicircle] (Y)
\fi
% all edges that start at R (excluding the horizontal one)
\ifnum\X<\numexpr\dimx-1\relax
(R) edge[pmark={\X-1}{\dimx-1},semicircle] (sX-\X)
\fi
% remaining semicircles
foreach \Y in {\the\numexpr\X+1,...,\dimy}
{% backwards pointing semicircles
\unless\ifnum\X\Y=1\dimy
(X-\X) edge[pmark={\Y-1}{\X-1},semicircle] (sX-\Y)
\fi
% forward pointing semicircles
\pgfextra{\pgfmathtruncatemacro{\itest}{(\Y<\dimy&&\Y-\X>1?1:0)}}
\ifnum\itest=\numexpr1\relax
(X-\Y) edge[swap,pmark={\X-1}{\Y-1},semicircle'] (sX-\X)
\fi
}
};
\end{tikzpicture}
\end{document}

user 3.14159
Not sure if this qualifies for an answer. It uses global macros (though hidden ones) etc. This can all be avoided with the /.list key handler but the overhead might be too confusing without an explicit manula so this has to wait.

However, I tried to add some explanations for what is going on so that one can apply this to similar scenarios. There are two steps:
1. count the entries of the two lists \NumCoeffMat and \DenCoeffMat. This can be done with the /.list key handler without introducing explicit global macros (thus falsifying the claims that the Ti*k*Z foreach cannot do that, even nesting is fine).
2. use this information to fill the matrix programmatically. (With the /.list key handler one can even build LaTeX matrices with & and so on, but spelling this out is not relevant for this post.)


\documentclass{article}
\usepackage{pgffor}
\makeatletter
\pgfkeys{/matrix games/.cd,
count/.code={\c@pgf@counta0\relax
\pgfkeys{/matrix games/step counta/.list/.expanded={#1}}%
\edef\pgfmathresult{\the\c@pgf@counta}%
cells/.code={\pgfmathparse{#1}},nrows/.initial=5,ncols/.initial=5,
create matrix/.code={\edef\pgf@util@tempa{}%
\foreach \i in {1,...,\pgfkeysvalueof{/matrix games/nrows}}%
{\foreach \j in {1,...,\pgfkeysvalueof{/matrix games/ncols}}{%
\pgfkeys{/matrix games/cells}%
\ifnum\j=1\relax
\xdef\pgf@util@tempb{\pgfmathresult}%
\else
\xdef\pgf@util@tempb{\pgf@util@tempb,\pgfmathresult}%
\fi}%
\ifnum\i=1\relax
\xdef\pgf@util@tempa{{\pgf@util@tempb}}%
\else
\xdef\pgf@util@tempa{\pgf@util@tempa,{\pgf@util@tempb}}%
\fi}%
\let#1\pgf@util@tempa
}}
\makeatother
\begin{document}
\edef\NumCoeffMat{{1,7,2}}%
\edef\DenCoeffMat{{9,26,24}}%
\pgfkeys{/matrix games/.cd,count=\DenCoeffMat}%
\pgfmathtruncatemacro\myN{\pgfmathresult}% now \myN is the length of \NumCoeffMat
\pgfkeys{/matrix games/.cd,count=\NumCoeffMat}%
\pgfmathtruncatemacro\myM{\pgfmathresult}% now \myM is the length of \DenCoeffMat
\pgfkeys{/matrix games/.cd,ncols=\numexpr\myN+1,nrows=\numexpr\myN+1,
cells/.code={% we now tell the matrix what to do depending on the row index \i
% and the column index \j
% there are three cases:
% 1. \i<\myN  (the diagonal block)
% 2. \i=\myN (the row filled with \NumCoeffMat reversed)
% 3. \i=\myN+1 (the row filled with \DenCoeffMat)
\pgfmathtruncatemacro{\icase}{(\i==\myN?1:0)+(\i==\myN+1?2:0)}%
\ifcase\icase% first case: zero unless \i+1=\j
\pgfmathparse{int(\i+1==\j?1:0)}%
\or% second case
\ifnum\j>\numexpr\myN\relax% subcase a) \j >=\myN
\pgfmathparse{1}%
\else% subcase b) \j <\myN (fill in \NumCoeffMat reversed)
\pgfmathparse{int(-1*(\DenCoeffMat[\myN-\j]))}%
\fi
\or% third case
\ifnum\j<\numexpr\myM+1\relax% subcase a) \j <=\myM (fill in \DenCoeffMat reversed)
\pgfmathparse{int(\NumCoeffMat[\myM-\j])}%
\else% subcase b) \j > \myN  (fill in zeros)
\pgfmathparse{int(0)}%
\fi
\fi},
create matrix=\StateMat}%
\StateMat
\typeout{\StateMat}
\end{document}


Of course this can be used in other codes.

\documentclass[tikz,border=5mm]{standalone}
\usetikzlibrary{calc,decorations.markings,positioning,arrows.meta}
\makeatletter
\pgfkeys{/matrix games/.cd,
count/.code={\c@pgf@counta0\relax
\pgfkeys{/matrix games/step counta/.list/.expanded={#1}}%
\edef\pgfmathresult{\the\c@pgf@counta}%
cells/.code={\pgfmathparse{#1}},nrows/.initial=5,ncols/.initial=5,
create matrix/.code={\edef\pgf@util@tempa{}%
\foreach \i in {1,...,\pgfkeysvalueof{/matrix games/nrows}}%
{\foreach \j in {1,...,\pgfkeysvalueof{/matrix games/ncols}}{%
\pgfkeys{/matrix games/cells}%
\ifnum\j=1\relax
\xdef\pgf@util@tempb{\pgfmathresult}%
\else
\xdef\pgf@util@tempb{\pgf@util@tempb,\pgfmathresult}%
\fi}%
\ifnum\i=1\relax
\xdef\pgf@util@tempa{{\pgf@util@tempb}}%
\else
\xdef\pgf@util@tempa{\pgf@util@tempa,{\pgf@util@tempb}}%
\fi}%
\let#1\pgf@util@tempa
}}
\makeatother
\begin{document}
\edef\DenCoeffMat{{9,26,24}}%
\edef\NumCoeffMat{{1,7,2}}%
\pgfkeys{/matrix games/.cd,count=\DenCoeffMat}%
\pgfmathtruncatemacro\myN{\pgfmathresult}% now \myN is the length of \NumCoeffMat
\pgfkeys{/matrix games/.cd,count=\NumCoeffMat}%
\pgfmathtruncatemacro\myM{\pgfmathresult}% now \myM is the length of \DenCoeffMat
\pgfkeys{/matrix games/.cd,ncols=\numexpr\myN+1,nrows=\numexpr\myN+1,
cells/.code={% we now tell the matrix what to do depending on the row index \i
\pgfmathtruncatemacro{\icase}{(\i==\myN?1:0)+(\i==\myN+1?2:0)}%
\ifcase\icase% first case: zero unless \i+1=\j
\pgfmathparse{int(\i+1==\j?1:0)}%
\or% second case
\ifnum\j>\numexpr\myN\relax%
\pgfmathparse{1}%
\else%
\pgfmathparse{int(-1*(\DenCoeffMat[\myN-\j]))}%
\fi
\or% third case
\ifnum\j<\numexpr\myM+1\relax%
\pgfmathparse{int(\NumCoeffMat[\myM-\j])}%
\else%
\pgfmathparse{int(0)}%
\fi
\fi},
create matrix=\StateMat}%
\let\mmat\StateMat
\typeout{\StateMat}
\begin{tikzpicture}[node distance = 15 mm,
amark/.style={
decoration={
markings,
mark=at position {0.5} with {
\arrow{stealth},
}
},
postaction={decorate,edge label={#1}}
}, % make the mark an entry of the \mmat matrix
pmark/.code n args={2}{%
\pgfmathtruncatemacro{\myi}{int({\mmat}[\numexpr#1][\numexpr#2])}%
\tikzset{suppress if 0=\myi,edge label={$\myi$},
amark}% <- changed
},
terminal/.style 2 args={draw,alias=ln,circle,inner sep=2pt,label={#1:#2}},
% semicircle path
semicircle/.style={to path={let \p1=($(\tikztotarget)-(\tikztostart)$)
in \ifdim\x1>0pt
\else
\fi
\tikztonodes}},
semicircle'/.style={to path={let \p1=($(\tikztotarget)-(\tikztostart)$)
in \ifdim\x1>0pt
\else
\fi
\tikztonodes}},
\ifcase\itest
\tikzset{#2}%
\else
\tikzset{#3}%
\fi
]
\pgfmathtruncatemacro{\dimy}{dim({\mmat})} % number of rows
\pgfmathtruncatemacro{\dimx}{dim({\mmat}[0])} % number of columns
\typeout{\dimy,\dimx}
% create the graph
\path % R node
node[terminal={left}{$R(S)$},alias={X-\dimy}] (R) {}
% loop over matrix entries
foreach \Y [evaluate=\Y as \X using {int(\dimy-\Y)}]
in {1,...,\numexpr\dimy-1}
{node[right=of ln,terminal={below right}{% sX_i node
$sX_{\X}(s)$}](sX-\X){}
node[right=of ln,terminal={below right}{% X_i node
$X_{\X}(s)$}](X-\X){}
% ege from sX_i to X_i
(sX-\X) edge[amark,edge label={$\frac{1}{s}$}] (X-\X)
% edge from X_{i+1} to X_i  (R had an alias)
(X-\the\numexpr\X+1) edge[pmark={\X-1}{\X}] (sX-\X)
% semicircle edge from X_i to sX_i
(X-\X) edge[semicircle,pmark={\X-1}{\X-1}] (sX-\X)
}
node[right=of ln,terminal={right}{$Y(s)$},alias=sX-\dimy](Y){}
(X-1) edge[pmark={\dimy-1}{0}] (Y)
% we are now done with the horizontal part,
% and have also dealt with the entries on the diagonal and
% the {i-1},i entries
% now we deal with the matrix entries
foreach \X in {1,...,\the\numexpr\dimx-1}
{% all edges that end in Y (excluding the horizontal one)
\ifnum\X>\numexpr1\relax
(X-\X) edge[pmark={\dimx-1}{\X-1},semicircle] (Y)
\fi
% all edges that start at R (excluding the horizontal one)
\ifnum\X<\numexpr\dimx-1\relax
(R) edge[pmark={\X-1}{\dimx-1},semicircle] (sX-\X)
\fi
% remaining semicircles
foreach \Y in {\the\numexpr\X+1,...,\dimy}
{% backwards pointing semicircles
\unless\ifnum\X\Y=1\dimy
(X-\X) edge[pmark={\Y-1}{\X-1},semicircle] (sX-\Y)
\fi
% forward pointing semicircles
\pgfextra{\pgfmathtruncatemacro{\itest}{(\Y<\dimy&&\Y-\X>1?1:0)}}
\ifnum\itest=\numexpr1\relax
(X-\Y) edge[swap,pmark={\X-1}{\Y-1},semicircle'] (sX-\X)
\fi
}
};
\end{tikzpicture}
\end{document}

![Screen Shot 2020-12-31 at 8.23.01 AM.png](/image?hash=255cbf3cdc2b3eff627dfd297a06dd221de65269ba4591c95077489e95f37dfe)

Enter question or answer id or url (and optionally further answer ids/urls from the same question) from

Separate each id/url with a space. No need to list your own answers; they will be imported automatically.