summaryrefslogtreecommitdiff
path: root/macros/generic/polexpr/polexprexpr.tex
blob: d896e4b39b612eda3ee7607dca5fb5983c695f81 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
%% This file polexprexpr.tex is part of the polexpr package (0.8.4, 2021/11/01)
%% Extending \xintexpr syntax:
%%
%% 1. Authorize ' in variable and function names
%%    This partially breaks infix operators 'and', 'or', 'xor', 'mod'
%%    which must be replaced by &&, ||, /: and xor() syntax
%%    if immediately following a variable name
%%
%% 2. Map infix operators to the polexprcore macros
%%
%%    Overloading of infix operators must be done even outside of \poldef's
%%    scope else functions declared via \xintdeffunc would not be usable in
%%    \poldef as they would be using the xintfrac macros unaware of polynomials
%%
%%    The overloading of // and /: is experimental.
%%
%% 3. Support for the polynomial functions to work in \xintdeffunc
%%
%% 4. Support macros for the new functions acting on polynomial variables
%
% 1.
\def\XINT_expr_scanfunc_b #1%
{%
  \ifcat \relax#1\xint_dothis{\iffalse{\fi}(_#1}\fi
  \if (#1\xint_dothis{\iffalse{\fi}(`}\fi
  \if 1\ifcat a#10\fi
       \ifnum\xint_c_ix<1\string#1 0\fi
       \if @#10\fi
       \if _#10\fi
       \if '#10\fi
      1%
      \xint_dothis{\iffalse{\fi}(_#1}\fi
  \xint_orthat {#1\XINT_expr_scanfunc_a}%
}%
% 2.
% the minus sign as prefix
\def\POL_tmp #1#2%
{%
  \expandafter\def\csname XINT_expr_exec_#1\endcsname##1##2##3% \XINT_expr_exec_<op><level>
  {%
    \expandafter ##1\expandafter ##2\expandafter
      {\romannumeral`&&@\XINT:NEhook:f:one:from:one{\romannumeral`&&@#2##3}}%
  }%
}%
\POL_tmp{-xii}  \xintPolOpp
\POL_tmp{-xiv}  \xintPolOpp
\POL_tmp{-xvi}  \xintPolOpp
\POL_tmp{-xviii}\xintPolOpp
% infix operators
\def\POL_tmp #1#2%
{%
  \expandafter\def\csname XINT_expr_exec_#1\endcsname##1##2##3##4% \XINT_expr_exec_<op>
  {%
    \expandafter##2\expandafter##3\expandafter
      {\romannumeral`&&@\XINT:NEhook:f:one:from:two{\romannumeral`&&@#2##1##4}}%
  }%
}%
\POL_tmp +  \xintPolAdd
\POL_tmp -  \xintPolSub
\POL_tmp *  \xintPolMul
\POL_tmp /  \xintPolQuo
% there is no infix operator mapped to \xintPolRem
% for lack of notation: perhaps /; ? advices welcome
\POL_tmp{//}\xintPolDivModQ
\POL_tmp{/:}\xintPolDivModR
\POL_tmp ^  \xintPolPow
\expandafter\let\csname XINT_expr_op_**\expandafter\endcsname
                \csname XINT_expr_op_^\endcsname
% 3.
% Matches with "mysterious stuff" section of xintexpr source code
\let\POL:NEhook:polfunc\expandafter
\toks0\expandafter{\XINT_expr_redefinemacros}%
\toks2 {\let\POL:NEhook:polfunc\POL:NE:polfunc}%
\edef\XINT_expr_redefinemacros{\the\toks0 \the\toks2}%
\catcode`~ 12 %
\def\POL@defpolfunc #1#2%
{%
  \expandafter\POL@defpolfunc_a
  \csname XINT_#2_func_#1\expandafter\endcsname
  \csname XINT_#2_polfunc_#1\endcsname
}%
\def\POL@defpolfunc_a #1#2%
{%
  \XINT_global
  \def#1##1##2##3%
  {%
     \expandafter##1\expandafter##2\expandafter{%
     \romannumeral`&&@\POL:NEhook:polfunc{\romannumeral`&&@#2##3}}%
  }%
}%
\def\POL:NE:polfunc #1{%
\def\POL:NE:polfunc ##1%
{%
    \if0\XINT:NE:hastilde ##1~!\relax % this ! of catcode 11
        \XINT:NE:hashash  ##1#1!\relax 0\else
        \xint_dothis\POL:NE:polfunc_a\fi
    \xint_orthat\POL:NE:polfunc_b
    ##1&&A%
}}\expandafter\POL:NE:polfunc\string#%
\def\POL:NE:polfunc_a\romannumeral`&&@#1#2&&A%
{%
% If we are here #2 was not braced; \string is done with \escapechar126
    \expandafter{\expanded{~romannumeral~POL:NE:usepolfunc%
                 {\expandafter\xint_gobble_i\string#1}}#2}%
}%
\def\POL:NE:polfunc_b#1{%
\def\POL:NE:polfunc_b\romannumeral`&&@##1##2&&A%
{%
    \expandafter{%
    \romannumeral`&&@%
        \if0\XINT:NE:hastilde ##2~!\relax
            \XINT:NE:hashash  ##2#1!\relax 0\else
        \POL:NE:polfunc_c\fi
    ##1{##2}}%
}}\expandafter\POL:NE:polfunc_b\string#%
% In this case the \expandafter inserted by \POL:NE:usepolfunc
% expansion will be superfluous
\def\POL:NE:polfunc_c#1#2% #1=\fi
{%
    \expanded{#1~romannumeral~POL:NE:usepolfunc%
              {\expandafter\xint_gobble_i\string#2}}%
}%
% This \expandafter is in case there is an \expanded after that due
% to some slicing constructs
% Call: \romannumeral\POL:NE:usepolfunc
\def\POL:NE:usepolfunc#1{`&&@\csname#1\expandafter\endcsname}%
\catcode`~ 3  % its normal catcode in xint bundle
% 4.
\def\POL_tmp #1#2#3%
{%
  \expandafter\def\csname XINT_expr_func_#1\endcsname##1##2##3%
  {%
    \expandafter ##1\expandafter ##2\expandafter
    {%
        \romannumeral`&&@#2{\romannumeral`&&@#3##3}%
    }%
  }%
}%
\POL_tmp {sqr}       \XINT:NEhook:f:one:from:one  \xintPolSqr
% 0.8.1 renames 0.8.0 icontent() to cont() and lcoeff() to lc()
% and adds topol() and lcoeffs()
\POL_tmp {pol}       \XINT:NEhook:f:one:from:one  \xintPolPol
\POL_tmp {lpol}      \XINT:NEhook:f:one:from:one  \xintPolLPol
\POL_tmp {deg}       \XINT:NEhook:f:one:from:one  \xintPolDeg
\POL_tmp {coeffs}    \XINT:NEhook:f:one:from:one  \xintPolCoeffs
\POL_tmp {lcoeffs}   \XINT:NEhook:f:one:from:one  \xintPolLCoeffs
\POL_tmp {coeff}     \XINT:NEhook:f:one:from:two  \xintPolCoeff
\POL_tmp {lc}        \XINT:NEhook:f:one:from:one  \xintPolLC
\POL_tmp {monicpart} \XINT:NEhook:f:one:from:one  \xintPolMonicPart
\POL_tmp {cont}      \XINT:NEhook:f:one:from:one  \xintPolCont
\POL_tmp {primpart}  \XINT:NEhook:f:one:from:one  \xintPolPrimPart
\POL_tmp {rdcoeffs}  \XINT:NEhook:f:one:from:one  \xintPolRedCoeffs
\POL_tmp {rdzcoeffs} \XINT:NEhook:f:one:from:one  \xintPolSRedCoeffs
\POL_tmp {diff1}     \XINT:NEhook:f:one:from:one  \xintPolDiffOne
\POL_tmp {diff2}     \XINT:NEhook:f:one:from:one  \xintPolDiffTwo
\POL_tmp {diffn}     \XINT:NEhook:f:one:from:two  \xintPolDiffN
\POL_tmp {antider}   \XINT:NEhook:f:one:from:one  \xintPolAntiOne
\POL_tmp {integral}  \XINT:NEhook:f:one:from:two  \xintPolIntegral
\POL_tmp {quorem}    \XINT:NEhook:f:one:from:two  \xintPolQuoRem
\POL_tmp {quo}       \XINT:NEhook:f:one:from:two  \xintPolQuo
\POL_tmp {rem}       \XINT:NEhook:f:one:from:two  \xintPolRem
\POL_tmp {prem}      \XINT:NEhook:f:one:from:two  \xintPolPRem
\POL_tmp {divmod}    \XINT:NEhook:f:one:from:two  \xintPolDivMod
\POL_tmp {mod}       \XINT:NEhook:f:one:from:two  \xintPolDivModR
\POL_tmp {evalp}     \XINT:NEhook:f:one:from:two  \xintPolEvalAt
\def\XINT_expr_func_polgcd #1#2#3%
{%
    \expandafter #1\expandafter #2\expandafter{\expandafter
    {\romannumeral`&&@\XINT:NEhook:f:from:delim:u\XINT_PolGCDof#3^}}%
}%
% this is provisory
\xintdeffunc polpowmod_(P, m, Q) :=
       isone(m)?
           % m=1: return P modulo Q
           {   mod(P,Q)  }
           % m > 1: test if odd or even and do recursive call
           {   odd(m)? {  mod(P*sqr(polpowmod_(P, m//2, Q)), Q) }
                       {  mod(  sqr(polpowmod_(P, m//2, Q)), Q) }
            }
         ;%
\xintdeffunc polpowmod(P, m, Q) := (m)?{polpowmod_(P, m, Q)}{1};%
%
\endinput