define(VERSION, `0.5') % Hints for selective recompilation: % % If you edit a class definition, you should probably recompile the % whole shebang. For other changes, search backwards for the string % "set_com". You will find the name of the file which needs to be % recompiled. define(TEX_IN,`tex/code.tex') define(DATA_IN,`code.data') define(newresultcounter,9) include(MACROS) |-> tex/t.ista preamble "\\begin{theindexa}\n" postamble "\n\n\\end{theindexa}\n" |-> tex/t.istb preamble "\\begin{theindexb}\n" postamble "\n\n\\end{theindexb}\n" |-> tex/t.istz preamble "\\begin{theindexz}\n" postamble "\n\n\\end{theindexz}\n" |-> tex/code.tex % \second % [.stepanov lee.] \hfuzz 10pt % Create quote macros to sync with 5n character indentation in verbatim % environment. \def\quotea{\list{}{\def\leftmargin{62pt}\advance\linewidth -26pt}\item[]} \let\endquotea=\endlist \def\quoteaneg{\vspace{-0.35in}\list{}{\def\leftmargin{62pt}\advance\linewidth -26pt}\item[]} \let\endquoteaneg=\endlist \def\quoteb{\list{}{\def\leftmargin{93pt}\advance\linewidth -29pt}\item[]} \let\endquoteb=\endlist \def\quotebneg{\vspace{-0.35in}\list{}{\def\leftmargin{93pt}\advance\linewidth -29pt}\item[]} \let\endquotebneg=\endlist \def\quotec{\list{}{\def\leftmargin{124pt}\advance\linewidth -32pt}\item[]} \let\endquotec=\endlist \def\quotecneg{\vspace{-0.35in}\list{}{\def\leftmargin{124pt}\advance\linewidth -32pt}\item[]} \let\endquotecneg=\endlist \def\quoted{\list{}{\def\leftmargin{155pt}\advance\linewidth -35pt}\item[]} \let\endquoted=\endlist \def\quotee{\list{}{\def\leftmargin{186pt}\advance\linewidth -38pt}\item[]} \let\endquotee=\endlist % Set up a svb macro, which is like verbatim, but doesn't put % vertical spacing at the beginning and end. \catcode`\@=11 \begingroup \catcode `|=0 \catcode `[= 1 \catcode`]=2 \catcode `\{=12 \catcode `\}=12 \catcode`\\=12 |gdef|@xsvb#1\end{svb}[#1|end[svb]] |gdef|@sxsvb#1\end{svb*}[#1|end[svb*]] |endgroup \def\@svb{ \leftskip\@totalleftmargin\rightskip\z@ \parindent\z@\parfillskip\@flushglue\parskip\z@ \@tempswafalse \def\par{\if@tempswa\hbox{}\fi\@tempswatrue\@@par \penalty\interlinepenalty}% \obeylines \tt \catcode``=13 \@noligs \let\do\@makeother \dospecials} \def\svb{\@svb \frenchspacing\@vobeyspaces \@xsvb} \let\endsvb=\relax \def\mindex{\@bsphack\begingroup\@sanitize\@wrindexa} \catcode`\@=12 \pagestyle{empty} \vspace*{0.8in} \widepost{40}{40}{/Times-Roman findfont 40 scalefont setfont (Binary linear codes:) dup stringwidth pop 2 div neg 0 moveto 50 0 rmoveto true charpath StrokeFill} \vspace{0.1in} \widepost{40}{40}{/Times-Roman findfont 40 scalefont setfont (new results on nonexistence) dup stringwidth pop 2 div neg 0 moveto 50 0 rmoveto true charpath StrokeFill} \vspace{0.4in} \widepost{28}{28}{/Times-Roman findfont 28 scalefont setfont (Draft, November 10, 1997) dup stringwidth pop 2 div neg 0 moveto 50 0 rmoveto true charpath StrokeFill} \vspace{-0.05in} \widepost{28}{28}{/Times-Roman findfont 28 scalefont setfont (\(Version 0.5\)) dup stringwidth pop 2 div neg 0 moveto 50 0 rmoveto true charpath StrokeFill} \vspace{0.5in} \widepost{28}{28}{/Times-Roman findfont 28 scalefont setfont (David B. Jaffe) dup stringwidth pop 2 div neg 0 moveto 50 0 rmoveto true charpath StrokeFill} \vspace{0.3in} \widepost{28}{28}{/Times-Roman findfont 28 scalefont setfont (Department of Mathematics and Statistics) dup stringwidth pop 2 div neg 0 moveto 50 0 rmoveto true charpath StrokeFill} \widepost{28}{28}{/Times-Roman findfont 28 scalefont setfont (University of Nebraska) dup stringwidth pop 2 div neg 0 moveto 50 0 rmoveto true charpath StrokeFill} \widepost{28}{28}{/Times-Roman findfont 28 scalefont setfont (Lincoln, NE 68588-0323) dup stringwidth pop 2 div neg 0 moveto 50 0 rmoveto true charpath StrokeFill} \widepost{28}{28}{/Times-Roman findfont 28 scalefont setfont (e-mail: jaffe@cpthree.unl.edu) dup stringwidth pop 2 div neg 0 moveto 50 0 rmoveto true charpath StrokeFill} \newpage %% \ \newpage %% Insert to get even number of pages if needed. \pagestyle{plain} \def\GAPref{\protect{[.groups algorithms programming.]}} \vspace*{-0.4in} \begin{center} \LARGE\bf Preface \end{center} \addcontentsline{toc}{special}{Preface} \def\classbreak{\par\noindent\kern32pt% \hbox to 6.35in{\leaders\hbox{\vbox{\hrule width1mm height 0.5pt}}\hfil}} \newenvironment{classboxedquote}% {\vskip0.065in\par\noindent\kern31pt\begin{Sbox}\begin{minipage}{6in}}% {\end{minipage}\end{Sbox}\fbox{\TheSbox}\vskip0.065in} \def\classtext#1{\begin{classboxedquote}#1\end{classboxedquote}} \newenvironment{classboxedquotet}% {\vskip0.065in\par\noindent\kern31pt\begin{Sbox}\begin{minipage}{6in}% \begin{tabbing}}% {\end{tabbing}\end{minipage}\end{Sbox}\fbox{\TheSbox}\vskip0.065in} \def\classtextt#1{\begin{classboxedquotet}#1\end{classboxedquotet}} \newenvironment{classboxedquotefour}% {\vskip0.065in\par\noindent\begin{Sbox}\begin{minipage}{4in}}% {\end{minipage}\end{Sbox}\fbox{\TheSbox}} \vspace{0.25in} {\large This is a working draft of a report which describes a new language for proving results about binary linear codes, and moreover exhibits a program in this language which proves many new results. Source code ({\tt C++}) for the language is included. The author gratefully acknowledges partial support under NSF grants DMS-9100983 and DMS-9623205, and as well wishes to thank the NSF-sponsored Geometry Center for supercomputer access, which facilitated exploratory calculations. John Gregory, Spyros Magliveras, Eric Rains, and Neil J.\ A.\ Sloane provided helpful comments and suggestions. I thank Juriaan Simonis (and TU Delft) for supporting a stimulating visit during the second half of May 1996, for introducing me to the work of [.brouwer van eupen 1997.], and for several enlightening converations which led to the work of \S\ref{menagerie-section}. The language employs the graph isomorphism package {\tt nauty} of Brendan McKay and the double-double precision floating point arithmetic package {\tt quad} of Keith Briggs. The routines {\tt prevector::sort} are in effect copyrighted by the Free Software Foundation. The definitions of {\tt pair} and \verb|make_pair| are copyrighted by Hewlett-Packard. A number of unpublished codes discovered by J.\ B.\ Shearer are included in this document, as well as one code discovered by M.\ Morii. The material on designs in \S\ref{some-unital-section}, the associated % Using {\it options} below had weird unintended consequences when using xdvi. ``options'' field in the {\tt type} command, and the implementation of the latter arose as part of joint work with Tonchev [.jaffe tonchev rank 20.]. \vspace{0.05in} To obtain this draft or the source code itself, see the World Wide \vspace{0.01in} \par\noindent Web at ``\verb|http://www.math.unl.edu/~djaffe/#coding|''. For a more leisurely introduction, see [.brief tour split main.]. } \newpage \vspace*{-0.3in} \par\noindent{\LARGE\bf Contents} \vspace{0.15in} {\footnotesize\ \catcode`\@=11 \@starttoc{toc} \catcode`\@=12} \newpage % Set up for indices. \def\indexnamez{Index of C++ classes} \def\indexnamea{Index of C++ methods} \def\indexnameb{Index of commands} \catcode`\@=11 \def\theindexz{\@restonecoltrue\if@twocolumn\@restonecolfalse\fi \columnseprule \z@ \addcontentsline{toc}{special}{\indexnamez} \columnsep 35\p@\twocolumn[{\Large\bf Index of C++ classes}\\ \\ ]% \@mkboth{\uppercase{\indexnamez}}{\uppercase{\indexnamez}}% \thispagestyle{plain}\parindent\z@ \parskip\z@ plus.3\p@\relax\let\item\@idxitem} \def\theindexa{\@restonecoltrue\if@twocolumn\@restonecolfalse\fi \columnseprule \z@ \addcontentsline{toc}{special}{\indexnamea} \columnsep 35\p@\twocolumn[{\Large\bf Index of C++ methods}\\ \\ This list should index all C++ methods and macros defined in the source code, except that not all constructors, destructors, and operators are included. We also do not include the {\tt execute\string_}$\ldots$ commands from \S\ref{main-program-section}, which execute particular commands. These may be found from the index of commands. \\ \\ ]% \@mkboth{\uppercase{\indexnamea}}{\uppercase{\indexnamea}}% \thispagestyle{plain}\parindent\z@ \parskip\z@ plus.3\p@\relax\let\item\@idxitem} \def\theindexb{\@restonecoltrue\if@twocolumn\@restonecolfalse\fi \columnseprule \z@ \addcontentsline{toc}{special}{\indexnameb} \columnsep 35\p@\twocolumn[{\Large\bf Index of commands}\\ \\ For each command, we give first the page on which the command is defined, and then the corresponding page in the source code. If the body of the command is executed as a separate subroutine, a page number is also given for that, intermediate between the first two numbers. \\ \\ ]% \@mkboth{\uppercase{\indexnameb}}{\uppercase{\indexnameb}}% \thispagestyle{plain}\parindent\z@ \parskip\z@ plus.3\p@\relax\let\item\@idxitem} \def\endtheindexa{\if@restonecol\onecolumn\else\clearpage\fi} \def\endtheindexb{\if@restonecol\onecolumn\else\clearpage\fi} \catcode`\@=12 \part{Introduction} \block{Synopsis} A basic problem in coding theory is to determine the maximum number $B(n,d)$ of codewords in a binary linear code in $\F_2^n$ having minimum weight $d$. While the original motivation for this problem came from practical problems of data transmission, continuing interest is due also to the fact that binary linear codes are such basic combinatorial structures. Many proofs of bounds for specific $B(n,d)$ have as input statements of bounds for $B(n',d')$, where $n' < n$. Proofs thus have a hierarchical nature, and if one wants specific results about the $B(n,d)$, one is naturally lead to construct tables. This has been done by Helgert and Stinaff [.helgert stinaff.], Verhoeff [.verhoeff 1987.], Brouwer and Verhoeff [.brouwer verhoeff 1993.], and Bierbrauer and Edel [.bierbrauer edel parameters binary.]. But the numbers $B(n,d)$ are extremely difficult to compute and there remain gaps even for small $n$ and $d$. The problem of finding lower bounds has been addressed by a vast array of fascinating constructions. These are of ongoing interest but do not form the subject matter of this report. Rather, we address the problem of how one may find {\it upper\/} bounds. Some of the major general contributions to this problem have been (in approximate historical order) Griesmer's bound [.griesmer 1960.], Johnson's bound [.johnson unrestricted.], Delsarte's linear programming method [.delsarte bounds unrestricted.], Hill and Traynor's examples [.hill traynor.], Brouwer's generalized parity type argument [.brouwer linear programming bound.], and Simonis's use of coordinate partitions [.simonis partitions.]. In addition, many people have contributed specific results, and thus methods, more often than not. A number of software packages have been developed for computing upper (and lower) bounds for $B(n,d)$. These packages include [.code buster.], [.guava.], LINCOR [.manev lincor 1987.], [.manev petkova golemanova.], and the system used by Brouwer and Verhoeff to generate [.brouwer verhoeff 1993.]. In addition, there exists software for computing automorphism groups of codes and for determining if two codes are isomorphic. We defer discussion of this to \S\ref{automorphismisomorphismsection}. In this report\footnote{This refers not only to this document, but also to [.jaffe optimal binary 30.], which contains results for length $\leq 30$.}, we give improved upper bounds for the $B(n,d)$, in total \ref{NewResultCount} improvements. This is actually quite modest progress: whereas before the first unknown case occurred when $n = 28$, now the first unknown case occurs when $n = 32$. As an example we establish that $B(28,9) = 2^{10}$ by showing that there is no $[28,11,9]$ binary linear code.% \footnote{General background on coding theory may be found in [.macwilliams sloane book.]. Another good reference is [.lint coding theory.]. In this paper we make the slightly non-standard convention that an $[n,k,d]$ binary linear code is a sub-vector space $C$ of $\F_2^n$ having dimension $k$, such that no non-zero element of $C$ has weight $< d$. Also, by {\bf code}, we shall always mean {\bf binary linear code}.} The vehicle for these improvements is a computer language which we present. Its general purpose is to investigate binary linear codes. We exhibit a program (written in the language) which yields the aforementioned improvements to the $B(n,d)$. This program is completely self-contained, in the sense that all needed results about specific codes are proved within the confines of the program. We do this to complement rather than supplant the ``pencil and paper'' proofs which exist in some cases. This report also includes (with proof) a complete table of all known specific upper bounds, for codes of length $85$ or less, and extensive information about the weight enumerators of codes which may or may not exist. The first part of this paper is the introduction. The second part is a description of the language and its theoretical basis. The third part is a program, written in the language, which yields specific results about binary linear codes. The forth part of the paper is C++ source code for an implementation of the language. These are also available electronically from the author.% \footnote{The program should be easy to install on any Unix-based machine. The current implementation includes a provisional implementation of the simplex method, and as an alternative also includes support for a much faster commercial linear programming package, CPLEX. As of October 1995, the cost to academic users of a CPLEX ``Linear Optimizer Single CPU License'' is \$495. Mail to \verb|info@cplex.com| for more information.} Both the language and the program are ongoing projects, to which contributions are invited. \block{Basic data structures and definitions}\label{definitions-section} We describe the basic data structures of the language, in a somewhat idealized fashion. For practical reasons the actual data structures differ slightly from the descriptions we give here; most of these differences are mentioned in \S\ref{variable-section} and \S\ref{proof-command-section}. The top-level structure in the language is a {\bf code type}. It is a triple $(n,k,\cal S)$ consisting of a positive integer $n$, an integer $k$ ($1 \leq k \leq n$), and a finite set $\cal S$ of inequalities (called {\bf assumed constraints}) having the form $$a_0 y_0 \many+ a_n y_n \leq r,$$% where $\VEC a0n,r$ are integers. The variables $y_i$ (for computer input written \verb|y|$i$) are called {\bf basic global variables}. The {\bf dimension} of a code type is $k$. The {\bf realization} of a code type $(n,k,\cal S)$ is the set of all codes $C \IN \F_2^n$ of dimension $k$ such that if $y_i$ denotes the number of words of weight $i$ in $C$, then all inequalities in $\cal S$ are satisfied. (We refer to this general sort of operation as {\bf evaluation} on a code.) A code type is {\bf unrealizable} if its realization is empty, otherwise it is {\bf realizable}. A {\bf global variable} is a $\Q$-linear combination of basic global variables, whose evaluation on every $[n,k]$ code is an integer. Below each code type $(n,k,\cal S)$ lives a family of structures called {\bf configurations}. Each such structure is a quadruple $(p, D, D', \cal T\kern2pt)$ consisting of a partition% \footnote{We mean by this that $\VEC p1r \in \N$ and that $p_1 \many+ p_r = n$.} $p = (\VEC p1r)$ of $n$, two subcodes $D, D'$ of $\F_2^r$, and a finite set $\cal T$ of inequalities (again called {\bf assumed constraints}) having the form $$a_0 y_0 \many+ a_n y_n + \sum_I a_I x_I \leq r,$$% where $I = (\VEC i1r)$ is a {\bf multi-index\/} (or more precisely a {\it multi-index for $p$}, meaning that $0 \leq i_j \leq p_j$ for each $j$), and $\VEC a0n, a_I, r \in \Z$. The variables $x_I$ (for computer input written \verb|x_|$i_1$\verb|_|$\ldots$\verb|_|$i_r$) are called {\bf basic local variables}; the {\bf trivial} basic local variable is $x_{(0,\ldots,0)}$. We say that $D$ is the {\bf small code} of the configuration, and that $D'$ is the {\bf dual small code} of it. The {\bf dimension} of a configuration is defined to be $\dim(D)$. For the duration of the introduction, we fix the above notations for code types and configurations. Supposing for simplicity that $D' = 0$ and that $\cal T = \emptyset$, we may visualize the configuration by exhibiting a basis for $D$. By way of an example, let us reverse this process. Suppose we wish to study codes $C \IN \F_2^{25}$ which contain a word of weight $10$ and a word of weight $12$, intersecting along $4$ bits: \widepost{70}{35}{ {{100 26 Box {(6) BigCenterPrint} 50 6 xyput} -150 4 xyput {100 26 Box {(4) BigCenterPrint} 50 6 xyput} -50 4 xyput {100 26 Box {(4) BigCenterPrint} 50 6 xyput} -50 -30 xyput {100 26 Box {(8) BigCenterPrint} 50 6 xyput} 50 -30 xyput} 50 xput} \par\noindent We would be led to consider the partition $(6,4,8,7)$ of $25$ and the small code $D$ with basis \setof{1100,0110}. It is the picture which justifies the term {\it configuration}: it conforms to the dictionary definition as it is a {\it relative arrangement of parts}. We return to the general situation.\label{action-def} Given $d \in D$, and a multi-index $I$, define a multi-index $d(I)$ by $$d(I)_j\ =\ \cases{i_j,&if $d_j = 0$;\cr p_j - i_j,&if $d_j = 1$.}$$% Then $D$ acts on the set of multi-indices, and accordingly on basic local variables. We regard two basic local variables as {\bf equivalent} if they lie in the same orbit \WRT\ this action. We define two configurations to be {\bf equivalent} if they differ only in changing $\cal T$ by replacing some occurrences of basic local variables by equivalent ones. Given a partition $p = (\VEC p1r)$, we shall say that a partition $\loP = (\loP_1,\ldots,\loP_s)$ {\bf refines} $p$ if there exist $$0 = \beta_0 < \beta_1 < \cdots < \beta_r = s$$% such that $$p_j\ =\ \loP_{\beta_{j-1}+1} \many+ \loP_{\beta_j}$$% for all $j = 1,\ldots,r$. There is an induced map \mp[[ \varphi || \F_2^r || \F_2^s ]] given by $\varphi(e_j) = e_{\beta_{j-1}+1} \many+ e_{\beta_j}$. Now given a configuration $c = (p,D,D',{\cal T})$ as before, and given a refinement $\loP$ of $p$ as above, we define the {\bf refinement $\loC$ of $c$ induced by $\loP$} to be $\loC = (\loP,\varphi(D),\varphi(D'),\ol{\cal T})$, where $\ol{\cal T}$ is yet to be defined. First define a {\bf pullback} map \mp[[ \Psi || \setofh{multi-indices of $\loP$} || \setofh{multi-indices of $p$} ]] by $$\Psi(\oI)_j = \oI_{\beta_{j-1}+1} \many+ \oI_{\beta_j}.$$ Now given $f \in \cal T$, define $\loF$ by replacing each basic local variable $x_I$ by $\sum x_{\oI}$, where $\oI$ ranges over the multi-indices of $\loP$ with $\Psi(\oI) = I$. Then $\ol{\cal T}$ is defined to be \setof{\loF: f \in \cal T}. Given the configuration $c$, and a basic local variable $x_I$ of $c$, we define a new configuration $c|x_I$, called the {\bf subdivision of $c$ along $x_I$}, as follows. First define a partition $\loP$ by $$q_j\ =\ \cases{(p_j),&if $i_j \notin \setof{0,p_j}$;\cr (i_j, p_j - i_j),&otherwise,}$$% and $\loP = (\VEC q1r)$ (with internal parentheses removed). Let $s$ be the length of $p$. Define $v$ by $$v_j\ =\ \cases{(0),&if $i_j = 0$;\cr (1),&if $i_j = p_j$;\cr (1,0),&otherwise,}$$ $$v\ =\ (\VEC v1r)\ \ \hbox{(with internal parentheses removed)}.$$% Let $\loC = (\loP,\oD,\ol{D'},\ol{\cal T})$ be the refinement of $c$ induced by $\loP$. Then $c|x_I = (\loP, \oD + \inn{v}, \ol{D'}, \ol{\cal T})$, where $\oD + \inn{v}$ is the subspace of $\F_2^s$ generated by $\oD$ and $v$. An element of $\F_2^r$ is a {\bf small word}. Let \mp[[ \pi_i || \F_2^n || \F_2^{p_i} ]] be the ``\th{i} projection map''. A {\bf basic word} is an element $x \in \F_2^n$ such that for each $i$, $\pi_i(x)$ is either $0\ldots0$ or $1\ldots1$. Evidently there is a bijective correspondence between small words and basic words. A {\bf basic code} is a code in $\F_2^n$ consisting entirely of basic words. For any code in $\F_2^r$, there is an {\bf associated} basic code in $\F_2^n$. If $w \in \F_2^n$, the \th{i}\ weight $\abs{w}_i$ of $w$ is the weight of $\pi_i(w)$. The {\bf multiweight} of $w$ is the $r$-tuple $(\abs{w}_1,\ldots,\abs{w}_r)$; its {\bf weight} $\abs{w}$ is $\abs{w}_1 \many+ \abs{w}_r$. The {\bf realization} of the configuration is the set of all codes $C$ in the code type, which, after permuting coordinates if need be, have all of the following properties: \begin{itemize} \item for each small word in $D$, the associated basic word lies in $C$; \item for each small word in $D'$, the associated basic word lies in $C^\perp$; \item if $y_i$ denotes the number of words of weight $i$ in $C$ and $x_I$ denotes the number of words in $C$ which have multiweight $I$, then all inequalities in $\cal T$ are satisfied. \end{itemize} For $c$ a configuration, we let ${\cal R}(c)$ denote its realization, and we let $\ol{\cal R}(c)$ denote the set of isomorphism classes in ${\cal R}(c)$. The same terminology {\bf unrealizable}, {\bf realizable} applies to configurations. A {\bf local variable} is a $\Q$-linear combination of basic local variables, whose evaluation on every code in the realization of the code type is an integer. Since basic global variables are expressible as linear combinations of basic local variables (upon evaluation), the inclusion of basic global variables in the definition of assumed constraints (for a configuration) is formally superfluous. However, it turns out to be convenient and economical to formally distinguish between local and global variables in constraints. To each configuration, the language associates a list of {\bf known} constraints. Initially, this list consists of the assumed constraints for the code type and the assumed constraints for the configuration. But as a program is executed, various commands may be used to prove that other constraints hold for the configuration: these constraints are also considered to be known. For every code type, there is the {\bf base} configuration, which by definition has the trivial partition $(n)$, $D = 0$, $D' = 0$, and $\cal T = \emptyset$. Obviously the realization of the base configuration is the same as the realization of the code type. We also refer to a {\bf basal} configuration, by which we mean a configuration with the properties of a base configuration, except that $\cal T$ may be arbitrary. Call a configuration {\bf full} if its dimension equals the dimension of the code type. A {\bf terminal} configuration is a full configuration having $D' = 0$, and whose assumed constraints involve only global variables. Obviously a terminal configuration admits (up to isomorphism) at most one realization, and if there is one, it is the basic code associated to $D$. We refer to $D$ as the code {\bf corresponding} to the given terminal configuration. If a realizable terminal configuration has assumed constraints, these constraints simply give facts which are deducible from the weight enumerator of $D$. A complete classification for a code type might be construed as being an exhibition of realizable terminal configurations $\VEC c1m$ such that $${\cal R}(\hbox{base})\ =\ {\cal R}(c_1) \sqcup \cdots \sqcup {\cal R}(c_m) \ \ \hbox{(disjoint union)}.$$% As this is a desirable goal and a feasible one so long as $\abs{\ol{\cal R}(\hbox{base})}$ is small, the language facilitates logical statements holding between the sets ${\cal R}(c)$, where $c$ ranges over the configurations associated to the code type. In brief, we refer to such statements as {\it logical statements holding between the configurations}. Even in lieu of a complete classification, such statements permit partial classification, for instance up to weight enumerator. A configuration is {\bf fully refined} if its partition has the form $1,\ldots,1$. An {\bf automorphism} of a configuration $c$ is a permutation $\sigma$ of $1,\ldots,r$ such that $\sigma(c)$ is equivalent to $c$. We let $\Aut(c)$ denote the group of all automorphisms of $c$. In case $c$ is realizable and terminal, and $p_i = 1$ for all $i$, we have $\Aut(c) = \Aut(D)$. \block{Method: finding automorphisms and isomorphisms of codes}% \label{automorphismisomorphismsection} The problem is to find generators for the automorphism group of a code $C$, and to determine if two given codes are isomorphic. There are two established schemes for solving such problems. For both schemes, one must start with a subset $S$ of $C$ which is stable under the action of $\Aut(C)$, and which is ``sufficiently large''. Here we take this to mean that $S$ generates $C$ as a vector space. In practice, one should expect the size of $S$ to grow exponentially as a function of $\dim(C)$. Thus both schemes will yield algorithms whose execution time grows exponentially, and not just for the worst cases. It remains an open problem to find algorithms whose execution time (on average, at least) is polynomial in $n$ (the length) and $k$ (the dimension). The first scheme proceeds by reducing to the analogous problems for graphs.% \footnote{This approach seems to be well-known but the author is indebted to D.\ Stinson and V.\ Tonchev for independently pointing it out to him.} One may form a zero-one matrix, with one row for each $x \in S$, by writing out $x$ as an element of $\F_2^n$. This matrix may be regarded as defining a bipartite graph $G$, and clearly $\Aut(G) = \Aut(C)$. If $C'$ is another code of length $n$, and a bipartite graph $G'$ is constructed in the same way, then $C \iso C'\ \Longleftrightarrow\ G \iso G'$. The complexity of the graph isomorphism problem is not well understood; more specifically, it is not known if the problem admits a polynomial-time algorithm, nor is it known if it is NP-complete. There do exist algorithms whose reported average running time is quadratic as a function of the number of vertices. McKay has implemented such an algorithm ([.practical graph isomorphism.], [.nauty guide onepointfive.]) and we employ his program {\tt nauty} here. The second scheme is that of Leon [.leon computing automorphism groups 1982.], [.leon computing automorphism groups 1984.]. It has the advantage of working with all linear codes, not just binary ones. The implementation [.leon partition backtrack manual.], [.leon partition backtrack source.], [.leon partition backtrack examples.] is a very impressive piece of work, over $25,000$ lines of code, the accessibility of which would be greatly enhanced by additional documentation. \block{Method: split linear programming}\label{split-intro-section} Now we turn to a method which we call {\bf split linear programming}. While the author came to this independently by combining the notion of split weight enumerator ([.macwilliams sloane book.]\ pp.\ 149-150) with Delsarte's linear programming method [.delsarte bounds unrestricted.], credit for the concept is due to Simonis [.simonis partitions.], and in fact the idea had been used successfully prior to the author by Heijnen [.heijnen.]. Having fixed a partition $(\VEC p1r)$ of $n$, let $C \IN \F_2^n$ be a code. For $I = (\VEC i1r)$ a multi-index, let $t^I$ denote $t_1^{i_1} \manycdot t_r^{i_r}$, where $\VEC t1r$ are indeterminates. An {\bf $I$-word\/} is a word of multiweight $I$; we let $x_I$ denote the number of $I$-words in $C$. Then the {\bf split weight enumerator} of $C$ is $$\sum_I x_I t^I,$$% where $I$ ranges over all multi-indices. We will show that the split weight enumerator of $C^\perp$ is $${1 \over \abs{C}} \sum_{I = (\VEC i1r)} x_I \prod_{j=1}^r (1+t_j)^{p_j - i_j} (1-t_j)^{i_j}.$$% This is not difficult to prove, and in fact the case where the partition is $(m,m)$ for some $m$ may be found as an exercise in [.macwilliams sloane book.], on p.\ 150. Regard this expression as a polynomial in $\VEC t1r$; its coefficients (say $m_I$) are $\Q$-linear combinations of the variables $x_I$. As these coefficients are evidently nonnegative, we arrive immediately at a linear programming problem, just as one would arrive at such a problem via Delsarte's original linear programming method. To actually use this method, one should start with a configuration, and not just a partition. Now if two basic local variables are equivalent, they will have the same evaluation on any realization of the configuration. Therefore we may select one basic local variable from each equivalence class, and modify the linear programming problem so that only these selected variables occur. This greatly reduces the complexity of the problem. As an example, in investigating $[31,13,10]$ codes (discussed below), we arrive at a configuration with partition $(10,10,11)$. This would (a priori) give rise to a system having $1452$ variables and $1452$ constraints. But by using equivalence of basic local variables (and other ideas, to be discussed next), we reduce this to a problem involving $136$ variables and $245$ constraints. This reduction is of paramount importance. There is a second way one can reduce the number of variables. A basic local variable $x_I$ (for a configuration $c$) is {\bf inadmissible} if at least one of the following three things happens: \begin{romanlist} \item For some equivalent basic local variable $x_J$ which is equivalent to $x_I$, the constraint $x_J = 0$ is known for the configuration. \item $x_I$ is not equivalent to the trivial basic local variable, and if $d$ is the subdivision of $c$ along $x_I$, then the weight enumerator of the basic code associated to the small code of $d$ contradicts a known constraint of the form $y_i \leq r$. \item For some equivalent basic local variable $x_J$ which is equivalent to $x_I$, there exists some $d' \in D'$ such that $d' \cdot J$ (dot product) is odd. \item It would violate the zeroness of a joint variable which is known to be zero. \end{romanlist} In any realization of the configuration, the inadmissible basic local variables will evaluate to zero. Therefore we may delete the inadmissible variables from the linear programming problem. A priori we get one constraint for each multi-index $I$. In fact, no information is lost if we use only some of the constraints, as follows. First, if $I \cdot d \not= 0$ (in $\F_2$) for some $d \in D$, then the constraint associated to $I$ is identically zero, and we may omit it. Second, for $d' in D'$, we can define $d'(I)$ just as we defined $d(I)$ (p.\ \pageref{action-def}), and we arrive thusly at a notion of {\bf dual equivalence} for the variables $m_I$. It is then sufficient to use one constraint from each equivalence class. In practice, one can do better by using (in place of $D'$) an enlarged version of it (say $(D')^+)$, which includes words known by the language to be dual. Thus if the constraint $y_j = 0$ is known for every odd $j$, then the word $1\ldots1$ is in $(D')^+$, and if the constraint $y_j = 0$ is known for every $j$ not divisible by four, then all of $D$ is in $(D')^+$ as well. Now we illustrate the application of the split linear programming method by means of a real example: we show that there is no $[31,13,10]$ code. In the program we will prove the stronger statement that there is no $[29,11,10]$ code, but this is more involved. In the course of the argument we will consider three configurations, and correspondingly apply the method three times. Only the last application will be nontrivial, as the conclusion of the first two may easily be recovered by other means. The split linear programming method gets applied three times: \begin{itemize} \item There is a word of weight $20$. This calculation corresponds to considering the trivial partition $(31)$ of $31$. One finds that \verb|x_20| is nonzero. In other words, the code has a word of weight $20$. Thus far the method is a mere rephrasing of Delsarte's linear programming method. \item Use the word of weight $20$ to subdivide the original partition, yielding the partition $(20,11)$. Show that \verb|x_10_0| $\not= 0$. That is, show that there is a word of weight $10$ in the code which is contained in the word of weight $20$. This statement is also obvious. \item Subdivide again, yielding the partition $(10,10,11)$. A final application of the method yields a contradiction. \end{itemize} In this example, $D'$ is always zero. In succession, $D$ consists of the zero code (in $\F_2^1$), then the code with basis \setof{10} (in $\F_2^2$), and finally the code with basis \setof{110,100} (in $\F_2^3$). Although there are in principle oodles of configurations, only certain ones are known to the program as it executes. These get created in various ways, for instance by explicit declaration in a ``{\tt config}'' command. (See the worked example below.) Also, the program automatically knows about the base configuration. The configurations are also the vertices of a directed multigraph\label{first-multigraph-occurrence}, whose connected components correspond to logical equivalence classes: if two configurations lie in the same connected component, then they have the same realization. There are two types of edges. The first type (which we call {\bf constructive}) corresponds to a basic local variable; a nontrivial variable is used to subdivide a given configuration, yielding another (the target of the edge). The second type of edge (which we call {\bf logical}) merely establishes that the source and target configurations have the same realization. We give here a taste of what the language is like by explaining in detail the formal code for the $[31,13,10]$ example. The following code is one way (not the shortest) or writing it in our language: \begin{verbatim} ??no [25,8,10]; type [31,13,10_2]; show x_20 != 0; config 20,11 : {10}; show x_10_0 != 0; !config 10,10,11 : {110,100}; no [31,13,10]; \end{verbatim} The first command tells the program to accept without proof the fact that there is no $[25,8,10]$ code. The proof of this (previously known) fact may also be exhibited in our language, and we do so in [.jaffe optimal binary 30.]. In a complete proof one would not have such a {\tt??no} command. The third command ({\tt type}$\ldots$) declares that our code type consists of even codes $C$ in $\F_2^{31}$ of dimension $13$, having minimum weight $\geq 10$. To conform to the description of code type given earlier, we could say the type consists of all codes in $\F_2^{31}$ of dimension $13$, satisfying the constraints $$y_1 = 0,y_2=0,\ldots,y_8=0,y_9=0,y_{11}=0,y_{13}=0,\ldots,y_{31}=0,$$% but this would be cumbersome. Given the knowledge that there is no $[25,8,10]$ code, the program automatically infers that the minimum weight of $C^\perp$ is $\geq 7$. The command ``\verb|show x_20 != 0|'' is self-explanatory. As it executes the \verb|show| command, the program automatically creates a configuration, which is then (it so happens) made the current configuration via the following \verb|config| command. Also, when the program executes the first \verb|show| command, it creates a constructive edge from the base configuration to the new configuration. The next \verb|show| and \verb|config| commands are similar. Again, the show command actually creates the configuration prior to it being made current by the \verb|config| command. Thus, after executing the second \verb|show| command, the configurations form a graph $$\begin{array}{c} \rnode{a}{\psframebox{\hbox{$\vcenter{\hbox{\kern30pt(base)}\vskip3pt% \hbox{\tt 31 : \{ \} : \{ \}}}$}}}\\[1.3cm] \rnode{b}{\psframebox{\hbox{\tt 20,11 : \{10\} : \{ \}}}}\\[1cm] \rnode{c}{\psframebox{\hbox{\tt 10,10,11 : \{110,100\} : \{ \}}}} \end{array} \arrow(a,b)\arrow(b,c)$$% where we use the format partition : small basis : dual small basis. The ``\verb|!config|'' command makes the bottom configuration current, and instructs the language to try to find a contradiction. That is, the bottom configuration is unrealizable. Following the arrows back to the base configuration, we conclude that it is unrealizable, and hence that the code type is unrealizable. As there is no {\it even\/} $[31,13,10]$ code, we conclude that there is no $[31,13,10]$ code at all, thereby justifying the final command. \block{Method: split linear programming + symmetry} Sometimes symmetry of a configuration can be employed to strengthen the split linear programming method. Let $v$ be an admissible basic local variable. Suppose we have a subgroup $G$ of the automorphism group of the configuration. Then $G$ acts on the admissible basic local variables. Use split linear programming to show that the sum over $g \in G$ of $gv$ is nonzero. Then the current configuration can be subdivided (along $v$), and a logical edge can be constructed from the current configuration to the new configuration. \block{Method: passing constraints between configurations} \def\lconfig{{\tt[}$\ell$\kern1pt{\tt]}} \def\lorconfigs{{\tt[}$\ell_1${\tt]}\kern5pt{\tt or}\kern5pt$\ldots$\kern5pt% {\tt or}\kern5pt{\tt[}$\ell_r${\tt]}} \def\rconfig{{\tt[}$r${\tt]}} \def\rpconfig{{\tt[}$r'$\kern1pt{\tt]}} \def\sconfig{{\tt[}$s${\tt]}} \def\spconfig{{\tt[}$s'$\kern1pt{\tt]}} \def\lconfigs{{\tt[}$\ell_1${\tt]}, $\ldots$, {\tt[}$\ell_r${\tt]}} \def\mconfig{{\tt[}$m${\tt]}} \def\miconfig{{\tt[}$m_i${\tt]}} \def\mconfigs{{\tt[}$\m_1${\tt]}, $\ldots$, {\tt[}$\m_r${\tt]}} Suppose we have a constructive edge \lconfig\ $\longrightarrow$ \mconfig\ of configurations. Let $x_J$ be a basic local variable for \lconfig, and let $x_{J_1},\ldots,x_{J_r}$ be the basic local variables of \mconfig\ which pull back to $x_J$. In an appropriate sense (which we leave to the reader to make precise), $$x_J\ =\ x_{J_1} \many+ x_{J_r}.$$% Therefore some known constraints of \mconfig\ will induce known constraints of \lconfig, and conversely. For example, if $x_{J_i} \geq c$ is a known constraint of \mconfig (for some $i$), then the constraint $x_J \geq c$ holds for \lconfig. One could have full and automatic propagation of constraints along constructive edges, but at present this feature is only partially implemented in the language. \block{Method: joint linear programming} The joint weight enumerator ${\cal J}_{C,C}$ of a code $C$ with itself gives rise to a linear programming problem because the coefficients of ${\cal J}_{C, C^{\perp}}$ are nonnegative. More information can be obtained from the fact that the coefficients of ${\cal J}_{C^{\perp}, C^{\perp}}$ are as well nonnegative, but this information comes at a great cost, as the resulting linear programming problem is much larger than that which one would get by using ${\cal J}_{C, C^{\perp}}$ alone. We define a {\it basic joint variable\/} to be a variable of the form {\tt jy}$r${\tt y}$s${\tt y}$t$, which represents $\abs{\setof{(v,w) \in C \times C: \abs{v} = r, \abs{w} = s, \abs{v+w} = t}}$. Note that $r$, $s$, and $t$ may be permuted without affecting the value on any realization. A basic joint variable is {\it minimal\/} if $r \leq s \leq t$. A basic joint variable is {\it inadmissible\/} if it is known to be zero (on any realization) for one of the following reasons: \begin{itemize} \item There is no word in the code of weight $p$, $q$, or $r$. \item We have $d \leq p < 2d$ (where $d$ is the minimum distance of the codes under consideration), and we know that an $[n-p, k-1, d-p/2]$ code cannot have a word of weight $(q+r-p)/2$. Thus the variable is inadmissible by the method of residual codes. With obvious modifications this also applies with $p$ replaced by $q$ or $r$. \end{itemize} To reduce the size of the linear programming problem this method gives rise to, one should first use split linear programming to kill as many as possible of the weights in the code. For more details, see the comments in the code for the C++ method\\ \verb|generate_joint_constraints|. \block{A canned procedure for table-building}\label{canned-section} In this section we describe an automated procedure for proving the nonexistence of $[n,k,d]$ codes. As such, the procedure has as input a triple $[n,k,d]$ and as output {\tt true} if it can show there is no $[n,k,d]$ code, else {\tt false}. The procedure is allowed to access all specific results known to the program at the time of its execution. The goodness of the procedure can be measured in two ways. On the one hand, the more often it returns {\tt true}, the better it is. On the other hand, faster is better. These two criteria compete, and we have done our best to find a compromise which runs reasonably fast and yields reasonably many results.\footnote{For experimental purposes, it makes sense to deemphasize speed. See the description of the {\tt no} command for modifications to this procedure which allow for this.} Almost any general nonexistence method can be evaluated in terms of how it could contribute to the goodness of this procedure. The less computationally intense the method, the better it can make the procedure. Thus a ``traditional theorem'' which yielded new general consequences would have great merit as a new ingredient of the procedure. The body of the procedure has three stages, but before starting it, we note that by replacing $[n,k,d]$ by $[n+1,k,d+1]$ if need be, we may reduce to the case where $d$ is even. The goal of the first stage is to simultaneously check general criteria (which would yield the nonexistence of $[n,k,d]$ codes) and to similarly derive inequalities involving the global variables. Thus the first stage is very fast; it proceeds as follows: \begin{itemize} \item If $\nexists [n,k,d]$ or $\nexists [n-1,k-1,d]$, return {\tt true}. \item We may assume that $\verb|y|_i = 0$ for $i$ odd. Also deduce $\verb|y|_i = 0$ for specific $i$ by the method of residual codes. \item If the Griesmer bound is violated, return {\tt true}. \item From known nonexistence results, deduce that $\verb|mu|_i = 0$ for $i < r$, where $r$ is as large as possible. \item If $\nexists [n,n-k,r]$, return {\tt true}. \item Use known nonexistence results in conjunction with Brouwer's results to bound the number of doubly even words in the code. \end{itemize} The goal of the second stage is to show that for various $i$, we have $\verb|y|_i = 0$, by using split linear programming applied to the configuration associated to the existence of a word of weight $i$. It is this stage which usually consumes the lion's share of the execution time: \begin{romanlist} \item If it is not known that $4 \nmid i \Longrightarrow y_i = 0$, use ordinary linear programming to try to show that $y_0 + y_4 + y_8 + \cdots > {3\over4}(2^k)$. In that case, we may by Brouwer's results delete those words whose weights are not divisible by $4$. \item Use ordinary linear programming to try to show that the system of inequalities is infeasible. If so, return {\tt true}. \item Let $i$ be the highest weight which the code might have, and which has not already been tested for. Attempt to show by split linear programming that there can be no word of weight $i$. If this succeeds, go back to step (i). If it fails, repeat this step again, but on a second consecutive failure, go on to the third stage. \end{romanlist} In the case where $k < n$, we stop now, as the third stage seems never to help. The goal of the third stage is to show that for various $i$, we have $\verb|mu|_i = 0$, by using split linear programming applied to the configuration associated to the existence of a dual word of weight $i$: \begin{romanlist} \item Let $i$ be the lowest weight which the dual code might have, which has not already been tested for. Attempt to show by split linear programming that there can be no dual word of weight $i$. If this fails, repeat with the next lowest weight. On a second consecutive failure, return {\tt false}. \item If at this point we know that there is no nonzero dual word of weight $\leq i$, check to see if we also know that there is no $[n,n-k,i+1]$ code. If so, return {\tt true}. \item Use ordinary linear programming to try to show that the system of inequalities is infeasible. If so, return {\tt true}. Otherwise, go to (i). \end{romanlist} Some technical details regarding this procedure will be given when we describe the {\tt no} command. \block{Method: finding extensions of a code}\label{extension-section} We describe how to classify extensions of a given code. First we give an example of how this comes up. We will prove $(*)$ that there is no $[29,11,10]$ code. This of course supersedes the result (described in \S\ref{split-intro-section}) that there is no $[31,13,10]$ code. Now $(*)$ works by showing that a $[29,11,10]$ code must contain a dual word $w$ of weight $5$, and thus must contain a $[24,7,10]$ subcode, disjoint from $w$. We classify the $[24,7,10]$ codes (itself a new result); there are six of them. For each of these we then show that there is no extension to a $[31,13,10]$ code, thereby proving $(*)$. Here is the main idea behind the extension classifier, which is based on ideas the author gleaned from Simonis [.simonis 1987 25_15_6.]. For the above example, we would have to first add a zero bit to make a $[25,7,10]$ code. In general, starting from an $[n-r,s]$ code $D$ (here $n = 29$, $r = 4$, $s = 7$), you look for extensions to an $[n-r+1,s+1]$ code $D_1$, thence to an $[n-r+2,s+2]$ code $D_2$, and ultimately to an $[n,s+r]$ code $D_r$, hoping (in the above example) that the process fails at some point. But there is a neat trick for doing this. Form a matrix $M$ ($n-r-s \times n-r)$ whose rows form a basis for $D^\perp$. Extending from $D$ to $D_1$ corresponds to adding a column to $M$, yielding a matrix $M_1$. Then to get to $D_2$, you add another column, yielding a matrix $M_2$. These columns lie in $V := \F_2^{n-r-s}$. Choose a total order on $V$. Let $\Lex^j(V)$ denote the set of lexicographically ordered $j$-element sequences of $V$. Call such a sequence {\it admissible\/} if the corresponding code $D_j$ is ``consistent'' with the larger code type. In the example, we can require that $D_j$ is even and has no word of weight smaller than $10$. Without loss of generality, we can also assume that the word of weight $j+1$ whose last $j+1$ bits are $1$ is in $D_j^\perp$. This corresponds to the disjointness of $D$ from $w$. Suppose you have a subgroup $G$ of $\Aut(D)$. (In practice it is sometimes convenient to let $G$ be a mere subset of $\Aut(D)$, and what follows will make sense in this setting.) There is an induced contravariant action of $G$ on $V$, as follows. For $\sigma \in \Aut(D)$, let $P$ be the associated permutation matrix ($n-r \times n-r$). Let $Q$ be the unique invertible $n-r-s \times n-r-s$ matrix such that $QMP = M$. Let $v \in V$. Then we define $\sigma(v)$ to be $Qv$. For the moment letting $|$ denote horizontal concatenation of matrices, we see that $M|v \sim MP|v \sim QMP|Qv = M|Qv$, where these matrices are equivalent in the sense that they define isomorphic codes. From the action of $G$ on $V$ we get an action of $G$ on $\Lex^j(V)$, by acting individually on the elements of a sequence, and then sorting. For $g \in G$, $M|x \sim M|gx$. Call an element $x$ of $\Lex^j(V)$ {\it $G$-minimal\/} if $gx \geq x$ for all $g \in G$. Then it is enough to find $$\Gamma_j\ :=\ \setof{G\hbox{-minimal, admissible elements of\ }\Lex^j(V)}.$$% Fortunately, if you take some $x \in \Gamma_j$, and discard its rightmost element, you get an element of $\Gamma_{j-1}$. Therefore the ``extension'' algorithm boils down to computing in succession $\Gamma_1,\Gamma_2,\ldots,\Gamma_r$. However, exactly how to compute $\Gamma_j$ from $\Gamma_{j-1}$ in an efficient way is an interesting problem open to further investigation. In the case where $\Gamma_r$ is nonempty, the user needs to provide in advance a list of configurations which the elements of $\Gamma_r$ can be tested against. Thus (for example) when we classify $[24,7,10]$ codes, we classify the extensions of one of the two $[21,5,10]$ codes by means of the command \begin{verbatim} via extension [21_5_10.a] implies [c], [d], [e0], [f]; \end{verbatim} To make full sense out of this one has to see the configurations labelled {\tt[c]}, and so forth. The method of this section is limited by the exponential growth of its execution time. In the present implementation, it takes roughly a small constant times $(2^{n-r-s})(n-r+1)(s)$ operations to find $\Lex^1(V)$. Thus for example, whereas it is practical to find extensions from $[24,7,10]$ to $[29,11,10]$, it is not practical to find extensions from $[35,4,18]$ to $[38,6,18]$, which would require almost 60,000 times the execution time of the $[24,7,10]$ case. Although one could almost certainly make the $\Lex^1(V)$ calculation much faster, it is not clear that the method can be made acceptably fast as a whole. \block{Method: finding the minimum weight of a code} In our extension algorithm, we have to repeatedly check partial extensions, with the goal of ruling out those whose minimum weight is too small. At present we do this by literally checking every element in the partial extension. This is almost certainly not optimal. Much faster probabilistic methods have been invented by Leon [.leon probabilistic algorithm.] and Stern [.stern codewords small weight.]; an analysis of these has been given by Chabaud [.chabaud asymptotic analysis.]. Since no harm will come if an occasional partial extension squeaks past this checker, such a method would probably speed up our algorithm. \newpage \part{Background and language structure} \block{The split weight enumerator of the dual code} We establish the formula for the split weight enumerator of $C^\perp$. This is just an elaboration on an exercise in [.macwilliams sloane book.]. Let $(\VEC p1r)$ be a partition of $n$. Define \mp[[ f || \F_2^n || \Z[\VEC t1r] ]] by $f(v) = \prod_{i=1}^r t_i^{\abs{v}_i}$. Let \mp[[ \lhF || \F_2^n || \Z[\VEC t1r] ]] be the Hadamard transform of $f$ ([.macwilliams sloane book.]\ pp.\ 54, 127) defined by $$\lhF(w) = \sum_{v \in \F_2^n} (-1)^{w \cdot v} f(v).$$% By (op.\ cit.\ Ch.\ 5, \S2, Lemma 2) we know that $$\sum_{w \in C^\perp} f(w)\ =\ {1 \over \abs{C}} \sum_{w \in C} \lhF(w).$$% So to prove the split weight enumerator formula, it is enough to show that $$\lhF(w) = \prod_{i=1}^r (1+t_i)^{p_i - \abs{w}_i} (1-t_i)^{\abs{w}_i}.$$% We proceed to prove this: \begin{eqnarray*} \lhF(w) & = & \sum_{v \in \F_2^n} (-1)^{w_1 v_1 \many+ w_n v_n} \prod_{i=1}^r t_i^{\abs{v}_i}\\ & = & \sum_{v \in \F_2^n} (-1)^{w_1 v_1 \many+ w_n v_n} \left( \prod_{i=1}^{p_1} t_1^{v_i} \right) \left( \prod_{i=p_1+1}^{p_1+p_2} t_2^{v_i} \right) \manycdot \left( \prod_{i=p_1 \many+ p_{r-1} +1}^n t_r^{v_i} \right)\\ & = & \sum_{v_1=0}^1 \sum_{v_2=0}^1 \cdots \sum_{v_n=0}^1 \left( \prod_{i=1}^{p_1} (-1)^{w_i v_i} t_1^{v_i} \right) \left( \prod_{i=p_1+1}^{p_1+p_2} (-1)^{w_i v_i} t_2^{v_i} \right) \manycdot \left( \prod_{i=p_1 \many+ p_{r-1} +1}^n (-1)^{w_i v_i} t_r^{v_i} \right)\\ & = & \left( \prod_{i=1}^{p_1} \sum_{u=0}^1 (-1)^{w_i u} t_1^u \right) \left( \prod_{i=p_1+1}^{p_1+p_2} \sum_{u=0}^1 (-1)^{w_i u} t_2^u \right) \manycdot \left( \prod_{i=p_1 \many+ p_{r-1} +1}^n \sum_{u=0}^1 (-1)^{w_i u} t_r^u \right)\\ & = & \left( \prod_{i=1}^{p_1} \left[ 1 + (-1)^{w_i} t_1 \right] \right) \left( \prod_{i=p_1+1}^{p_1+p_2} \left[ 1 + (-1)^{w_i} t_2 \right] \right) \manycdot \left( \prod_{i=p_1 \many+ p_{r-1} +1}^n \left[ 1 + (-1)^{w_i} t_r \right] \right)\\ & = & \prod_{i=1}^r (1+t_i)^{p_i - \abs{w}_i}(1-t_i)^{\abs{w}_i}. \kern1in \square \end{eqnarray*} \block{Exact linear programming} The split linear programming method leads to a system of linear inequalities, which we may write in the form $Ax \geq b$, where for some $r,s$ we have $A \in \Mat_{r \times s}(\Z)$ and $b \in \Z^r$; the solution set is $${\cal S}\ =\ \setof{x \in \Z^s: x \geq 0 \hbox{\ and\ } Ax \geq b}.$$% The basic problem is to prove that $\cal S$ is empty. This is because solutions have integer components, and thus to show that all solutions satisfy some inequality (e.g. $x_3 \geq 53$), we can always proceed by adjoining an additional constraint to the original system (e.g.\ $x_3 \leq 52$), and then showing that the new system has no solutions. While in practice this may not be efficient, it seems reasonable for purposes of discussion to consider only the case of showing ${\cal S} = \emptyset$. Beyond aiding in this simplification, the constraint that solutions have integer coefficients is not as useful as it might look: the analysis of integer solutions ({\it integer linear programming}) is computationally much more complex than the analysis of rational solutions. The simplex algorithm can in principle be used to directly show that a system has no solutions. But to actually get a proof from the algorithm, one would have to do exact arithmetic, rather than floating point calculation. As such, we do not know of an implementation which is acceptably fast. Indeed, we doubt it is possible, and offer the following heuristic argument as an explanation. Consider a random $n \times n$ matrix $M$ whose entries are $d$-digit (or less) integers, i.e.\ whose entries are chosen uniformly from $[-(10^d - 1), 10^d - 1]$. One would expect $\det(M)$ to have about $nd$ digits. Similarly, if one tries to compute $M^{-1}$ or an $LU$ decomposition of $M$, one would expect the average number of digits% \footnote{Define the {\it number of digits\/} in a rational number $a/b$ to be the maximum of the number of digits in $a$ and $b$, supposing of course that $\gcd(a,b) = 1$. Generally, we use base $10$ just for illustration.} in the entries of these matrices to have a comparable growth rate. Now fixing the number of digits, one should expect (for example) that computing the ``floating-point inverse'' of an $n \times n$ integer matrix will require $O(n^3)$ operations, but computing its exact inverse will require $O(n^4)$ operations; the extra $n$ comes from the $n$ in $nd$. But it may be difficult to make such statements precise, since (e.g.) $O(n^3)$ is not optimal for matrix inversion. The remarks of this paragraph are obviously provisional. A lemma of Farkas [.farkas 1902.] (see e.g.{\ }[.schrijver.] Corollary 7.1f) asserts that $${\cal S}_\Q\ :=\ \setof{x \in \Q^s: x \geq 0 \hbox{\ and\ } Ax \geq b}.$$% is empty \IFF\ there exists a $y \geq 0$ such that $A^T y \geq 0$ and $y \cdot b < 0$. Otherwise said, if the system is inconsistent, then one can find a nonnegative linear combination of the constraints which is in and of itself contradictory. (This may also be viewed as a consequence of duality.) Moreover, the simplex algorithm produces such a $y$. If an algorithm (via floating point calculations) can produce a $y$ as above, then we can form the corresponding {\it exact\/} linear combination of constraints and try to show (independently) that it gives rise to a contradiction. This turns out to work very nicely in practice. Here then is our approach. Given the original system (with integer coefficients), find a floating point $y$ which numerically appears to satisfy $A^T y \geq 0$ and $y \cdot b < 0$. Let $\loY$ be the best rational approximation to $y$. If $\VEC c1r$ are the original constraints, then we get a new constraint $\loY_1 c_1 \many+ \loY_r c_r$, which although perhaps not inherently contradictory, can be used to deduce a contradiction. Indeed the negative coefficients of variables (if any) on the \LHS\ will be small (close to $0$), and we have a priori upper bounds on the variables, so (barring misfortune) we will be able to prove that the original system is infeasible. The worst that can happen is that we will be forced to report that the calculation is inconclusive. Note too that the proof step is simple and moreover thoroughly insulated from the intricacies of linear programming calculation. The current implementation of the program contains both a provisional implementation of the simplex algorithm, and the ability as well to use a commercial solver, CPLEX, which is both faster and more robust. The included implementation however has the advantage of being able to use higher precision floating point arithmetic, which becomes critical when investigating codes of length about $70$ or greater. Aside from being slow, the included implementation has the disadvantage that it handles ``numerical anomalies'' poorly, and thus (depending on the state of an internal random number generator) will sometimes (but very infrequently) stop in the middle of a simplex calculation, and issue an error message indicating that the calculation has failed. For further information, we refer to a small subset the vast literature on linear programming: [.chvatal.], [.goldfarb todd.], [.gregory faq.], [.karloff linear programming.], [.more wright.], and [.murtagh advanced.] \block{Variables and constraints}\label{variable-section} There are three kinds of variables in the language: {\it local}, {\it global}, and {\it joint}. The first two have already been discussed in \S\ref{definitions-section}. In the language, a {\bf variable} will always mean a specific, predefined variable, global, local, or joint, and these are exhibited below. In discussing these, we refer to a code $C$, which is to be a code in the realization of the particular configuration one is working with. The basic global variables are \begin{center} {\tt y0},\ {\tt y1},\ $\ldots$,\ {\tt y}$n$ \end{center} where $n$ is the length of $C$; {\tt y}$i$ gives the number of words of weight $i$ in $C$. Other global variables are \begin{center} {\tt mu0},\ {\tt mu1},\ $\ldots$,\ {\tt mu}\kern1pt$n$ \end{center} which give the number of words of given weight in $C^\perp$. The last global variables are \begin{center} {\tt div2},\ {\tt div4},\ {\tt div8},\ $\ldots$, \end{center} which give the number of words in $C$ whose weight is divisible by the given power of $2$. Now we come to {\it local\/} variables. For a given configuration, the basic local variables have the form \begin{center} \verb|x_|$a_1$\verb|_|$\ldots$\verb|_|$a_r,$ \end{center} where $r$ is the number of parts in the partition of the configuration. Such a basic local variable must be {\it admissible}. If $\VEC a1r$ are all single digits, such a basic local variable may also be written as \begin{center} \verb|x|\kern1pt$a_1a_2 \ldots a_r$. \end{center} In addition to this formatting choice, each basic local variable has a number of equivalent forms, since the smallcode acts on wordtypes. For internal purposes, we select a canonical form for each basic local variable, which we call {\bf minimal}. Of course we could take minimal to mean lexicographically minimal, but this turns out to be computationally inconvenient. The actual definition is somewhat technical and of limited significance. \label{minimal-promise}We defer the details to \S\ref{partition-wordtype-mawhome-section}. Again for internal purposes, the minimal form is further translated to {\tt v}$i$, for some $i$, so that the basic local variables are (up to equivalence) \begin{center} {\tt v1}, {\tt v2}, $\ldots$, {\tt v}$t$. \end{center} To discourage reliance on the internal ordering scheme used for these variables, their use in the language is not permitted. By convention, {\tt v1} is the trivial basic local variable. See also the discussion of {\it basic joint variables}, below. There are various local variables which are derived from the basic local variables. The variable \begin{center} \verb|z_|$a_1$\verb|_|$\ldots$\verb|_|$a_r$ \end{center} denotes the number of words of multiweight $(\VEC a1r)$ in $C^\perp$. As with basic local variables, there is an abbreviated form without underscores. Now for each $i$ ($1 \leq i \leq r$), let $a_i$ be either an integer (between $0$ and $p_i$) or else the character {\tt z}. Then \begin{center} \verb|q_|$a_1$\verb|_|$\ldots$\verb|_|$a_r$ \end{center} is a local variable. To see what it represents, consider the subcode $D$ of $C$ consisting of words having zeroes in at least the positions marked by {\tt z} in the variable. (We regard $D$ as a code of length shorter than $C$ -- it is supported on the non-{\tt z} positions.) Let $I = (\VEC a1r)|_{\hbox{\small\tt z} \mapsto 0}$: each {\tt z} is replaced by a $0$. Then \verb|q_|$a_1$\verb|_|$\ldots$\verb|_|$a_r$ represents $\abs{D} \cdot \abs{\setofh{$I$-words in $D^\perp$}}$. Such variables arise during the processing of {\tt incorporate} commands. There is also an abbreviated form without underscores. Note that if $\VEC a1r$ are all integers, then \verb|q_|$a_1$\verb|_|$\ldots$\verb|_|$a_r$ = $\abs{C} \cdot$ \verb|z_|$a_1$\verb|_|$\ldots$\verb|_|$a_r$ in any realization. This introduces an apparent redundancy, which is needed because (in general) we do not know the value of $\abs{D}$, and we want every variable to take on only integer values. Relative to the current configuration, if $w$ is a small word (represented by a string of {\tt0}'s and {\tt1}'s), then \begin{center} {\tt sub}$w$ \hbox{\ \ and\ \ } {\tt sub}$w$\verb|_|$k$ \end{center} denote respectively the number of words in the subcode of $C$ supported on $w$, and the number of words of weight $k$ in that subcode. For a configuration whose partition has only one part, the basic local variable \verb|x_|$i$ will have the same evaluation as the basic global variable \verb|y|$i$. While this does not mean that \verb|x_|$i$ and \verb|y|$i$ may be used interchangeably, we have tried to minimize the number of places where the use of one variable as opposed to the other will make a difference. We have already defined basic joint variables. The minimal admissible basic joint variables represented internally as as {\tt v1}, {\tt v2}, and so forth. Another joint variable is {\tt jy}$r${\tt d}$s${\tt i}$t$, which represents $$\abs{\setof{(v,w) \in C \times C^\perp: \abs{v} = r, \abs{w} = s, \abs{v \cap w} = t}}.$$% We also allow {\tt jy}$r${\tt d}$s$, which equals {\tt jy}$r${\tt d}$s${\tt i}$0$. The variable {\tt co}$r$ is defined to be equal to {\tt jy}$r${\tt d}$r${\tt i}$r$, and the variable {\tt co} is defined to be equal to $\sum_{j=r}^n \verb|co|r$, so $\verb|co| = \abs{C \cap C^\perp}$. The joint variable {\tt jd}$r${\tt d}$s${\tt d}$t$ represents $\abs{\setof{(v,w) \in C^\perp \times C^\perp: \abs{v} = r, \abs{w} = s, \abs{v + w} = t}}$. For purposes of data entry, a {\bf constraint} is a linear inequality or equality involving any of the above variables, with $\Z$-coefficients. Examples of the allowed forms are: \vspace{0.1in} \leavevmode\kern0.5in\begin{tabular}{ll} \verb|4y3 + 6x_2_5 >= 9| \\ \verb|-8y3 + y10 - 2y4 <= 40| \\ \verb|y32 = 1| \\ \verb|5y10 < 100| & (equivalent to \verb|5y10 <= 99|) \\ \verb|5y10 > 100| & (equivalent to \verb|5y10 >= 101|) \\ \verb|y6 != 0| & (equivalent to \verb|y6 >= 1|; \\ & \LHS\ must be a variable). \end{tabular} \vspace{0.1in} Note that the \RHS\ is always an integer, and you can't put an integer on the \LHS, unless it is used as a coefficient of a variable. We call a constraint {\bf simple} if its \LHS\ is a variable. Local and joint variables may not appear in the same constraint. Constraints are stored as is, and not converted to constraints involving only basic global and local variables, as would appear to be the case from the definitions in \S\ref{definitions-section}. Moreover, the order in which the terms are entered matters. Thus if {\tt y10 + y12 <= 20} is known, it does not follow that {\tt y12 + y10 <= 20} is known. This is a dorky ``feature'', but is unlikely to cause problems. A {\bf constraint list} is a list of zero or more constraints, separated by commas. However, certain compound forms are allowed, as in \par\noindent\kern0.5in\verb|5 <= y10 + y12 <= 20|; \par\noindent one or both of the inequalities may be replaced by strict inequalities, with the expected effect. \block{Language structure}\label{proof-command-section} Statements in the language could be divided into two general classes: {\bf proof} statements and {\bf exploratory} statements; in a finished proof one should have only proof statements. There are three main functions of proof statements: (1) establish a logical statement between configurations; (2) establish that a given configuration must satisfy a particular constraint; (3) establish that a given permutation is an automorphism of a given configuration. In addition the language permits the definition of constructive connections between configurations, as discussed in \S\ref{split-intro-section}. Before considering the commands themselves, we describe more carefully the data kept by the program. The abstract notion of {\it code type} is realized by the class {\tt codehome} and the abstract notion of {\it configuration} is realized by the class {\tt config}. Part of the {\tt codehome} definition is an {\bf assumed weight list}, a list of nonnegative integers which the weight sets of the codes are supposed to form subsets of. This would be formally equivalent to including assumed constraints of the form $y_i = 0$, but it is more efficient and convenient to keep track of weights instead. However, for the remainder of this report, if we say that a codehome has ``no assumed constraints'', we do not by this imply anything about its assumed weight list. Similarly, for each configuration, there is a {\bf working weight list}, which is a possibly smaller list of weights, such that each code realizing the configuration has weights in the smaller list. The {\tt codehome} definition also includes a directed multigraph as discussed on p.\ \pageref{first-multigraph-occurrence}; the graph structure is realized by a {\tt ShareGraph} object. Path components in this graph are realizability equivalence classes. To facilitate sharing, each path component has associated to it a \verb|config_share| object, which carries various pieces of information known about the configurations. For example, each \verb|config_share| object has a \verb|realizable| flag which indicates if the configurations are known to be realizable or unrealizable. Logical edges in the digraph are not explicitly recorded as data items. Rather, if we wish to ``add a logical edge'' from one configuration to another, we merge their \verb|config_share| objects. Constructive edges are labelled by the corresponding basic local variable (which is known to be nonzero); going from head to tail of the edge corresponds to subdivision. Labels may be associated by the user to code types, configurations, automorphisms, and {\tt incorporate} commands, to be described later. The latter command also creates new labels. When created by the user, a label is allowed to be any non-null sequence of letters, digits, and underscores, enclosed in square brackets. It is also permissible to use a configuration label of the form {\tt[}$a${\tt:}$b${\tt]}, where {\tt[}$a${\tt]} is the name of a code type (of the same length as the current code type) and {\tt[}$b${\tt]} is the name of a configuration of {\tt[}$a${\tt]}. The first time this is used, configuration {\tt[}$b${\tt]} is copied to the current code type. (Known facts cannot be copied.) In usage thereafter, the configuration {\tt[}$a${\tt:}$b${\tt]}, will be treated just like any other configuration of the current code type. A {\it\bf configuration-list} is a comma-separated sequence of zero or more configuration labels, except that amongst these, some configuration labels may be replaced by certain compound constructions, which we illustrate by examples: \begin{itemize} \item \verb|[xy*]| expands to all user-defined configuration labels which start with {\tt xy}. \item \verb|[21{r,s,tt}]| expands to \verb|[21r]|, \verb|[21s]|, \verb|[21tt]|. \item \verb|[21_8.{x*,y*,z}]| expands to \verb|[21_8.z]| and all user-defined configuration labels which start with either \verb|[21_8.x| or \verb|[21_8.y|. \end{itemize} The {\tt*} construction never matches {\tt[base]} or {\tt[current]}, nor does the {\tt*} part ever match a string containing ``{\tt!}''. In the description of commands that follows, $n$ will always denote the dimension of the ambient space (i.e.\ the length of the codes under consideration), and $k$ will denote the dimension of the codes. All commands are terminated by a semicolon. White space is always irrelevant. Any command preceeded by ``??'' will be accepted without verification, as if a ``{\tt set gullible}'' command had been used. Any block of commands may bracketed as in the following example: \begin{verbatim} ... config 8,10,4,5 : {1100,1010} :: {y12 >= 31, y13 = 0, y14 >= 1}; { show div4 >= 44; ... show x1524 = 0, x2415 = 0, x2433 = 0, x2514 = 0, x2525 = 0, x3324 = 0, x3405 = 0, x3423 = 0, x3425 = 0, x3434 = 0, x3443 = 0, x3504 = 0 }; config from x4422; via building [current] implies ; ... \end{verbatim} The bracketed code is treated in the following way. In gullible mode, it is completely ignored. Otherwise, the code is executed as usual. In this way, code which executes slowly in gullible mode can be completely skipped over. Any command may be postfixed (before the semicolon) with ``{\tt<}{\it parameters}{\tt>}'', where {\it parameters\/} is a comma-separated list of parameters as in (for example) \begin{verbatim} no [43,20,12]; \end{verbatim} The given parameters are set prior to execution of the command and then restored to their original value at the end. See the {\tt set} command for the list of allowed parameters; one may not use {\tt gullible}, {\tt gullible commands}, or {\tt test mask} in this way. Do not use this option with a command which is expanded into a list of other commands, such as {\tt n =}. \def\config#1{{\tt[}$#1${\tt]}} \def\cconfig{{\tt[}$c${\tt]}} \def\mconfig{{\tt[}$m${\tt]}} \def\czconfig{{\tt[}$c_0${\tt]}} \def\coconfig{{\tt[}$c_1${\tt]}} \def\ctconfig{{\tt[}$c_2${\tt]}} \def\ciconfig{{\tt[}$c_i${\tt]}} A {\it\bf matrix-descriptor} means (for the time being) either \par\noindent\kern1in{\tt[}$c.m${\tt]}\ \ or \par\noindent\kern1in{\tt[}$c.m${\tt-}$r${\tt]}, \par\noindent where \cconfig\ is a code type, \mconfig\ is a configuration for \cconfig\ having the same dimension as it, and (in the second form) $r$ is an integer between $1$ and the length of the code type \cconfig. Associated to the matrix-descriptor is a matrix $M$, defined as follows. In the first form, $M$ is the generator matrix (in \RREF) for the basic code associated to \mconfig. In the second form, take the $M$ (as in the first form), delete column $r$, convert to \RREF, and call the new matrix again $M$. \block{How to define a code type} A code type is defined with the {\tt type} command, as follows: \newenvironment{commanddeclaration}% {\vspace{0.1in}\begin{center}\begin{Sbox}\kern2pt}% {\end{Sbox}\psshadowbox{\TheSbox}\end{center}\vspace{0.1in}} \indexb{type} \begin{commanddeclaration} $\displaystyle{\underbrace{\hbox{\lconfig}}_{\hbox{optional}}}$ {\tt type[}\kern2pt{\it length}{\tt, }{\it dimension}{\tt, }{\it weights}% \kern2pt{\tt]} $\displaystyle{\underbrace{\hbox{% {\tt\{}\kern5pt{\it constraint list}\kern5pt{\tt\}}}}_{\hbox{optional}}}$ $\displaystyle{\overbrace{\hbox{% {\tt/}\kern5pt{\it options}\kern5pt{\tt/}}}^{\hbox{optional}}}$ {\tt;} \end{commanddeclaration} Here {\it length\/} is the length of the code, i.e.\ $n$ if the code lives in $\F_2^n$; the {\it dimension\/} is the dimension $k$ of the code; {\it weights\/} represents a list $w$ of weights, and has several allowed formats: \vspace{0.05in} \begin{tabular}{lll} \verb|{|$w_1$\verb|,|$\ldots$\verb|,|$w_m$\verb|}|& -- & all weights in the given set, which should be in increasing order\\ & & (also $0$, which should not be listed)\\ $d$ & -- & $0$ and all weights $\geq d$\\ $d$\verb|_|$r$ & -- & $0$ and all weights $\geq d$ which are divisible by $r$\\ $d$ \verb| - {|$w_1$\verb|,|$\ldots$\verb|,|$w_m$\verb|}|& -- & $0$ and all weights $\geq d$, except $\VEC w1m$\\ $d$\verb|_|$r$ \verb| - {|$w_1$\verb|,|$\ldots$\verb|,|$w_m$\verb|}|& -- & $0$ and all weights $\geq d$ which are divisible by $r$,\\ & & except $\VEC w1m$ \end{tabular} \vspace{0.05in} It is permissable to use ellipsis in the above situations, for example \begin{center} ``\verb|66_2 - {98,114,118..138}|'' \end{center} denotes all even weights $\geq 66$, except $98$, $114$, and those numbers lying between $118$ and $138$. \vspace{0.05in} As an example of a {\tt type} command, ``\verb|type [29,11,6_2]|'' would cause the program to think about even codes of dimension $11$ in $\F_2^{26}$, having minimum weight $\geq 6$. The program will automatically use the method of residual codes to infer that certain weights cannot occur. Let $d$ be the minimum weight in the weightlist. Suppose that $i$ satisfies $d \leq i < 2d$. Suppose that we know there is no code of type $[n-i,k-1,d - \floor{i/2}]$. Then weight $i$ does not occur. If the code is at the Griesmer bound, and its minimum weight is even, all its words have even weight ([.tilborg griesmer.] 1.11). This is automatically known to the program. In the case of an even code, we automatically include lower and upper bounds on the number of words whose weights are divisible by $4$, in accordance with the results of Brouwer [.brouwer linear programming bound.]. If for a given $d'$, it is known that there is no $[n-(d'-1),k-(d'-1)+1,w]$ code, then it is automatically inferred that the minimum weight of the dual code is at least $d'$. The optional {\it constraint list\/} is a list of constraints, which all codes $C$ in the type are to satisfy. The optional argument \lconfig\ if present assigns the label \lconfig\ to the code type for future reference. The same label may not be used for two code types. The {\it options} field is a comma-separated list of fields. At this point there are three allowed fields, each of which may appear only once. The first field is: \par\noindent\kern0.5in\verb|dual_may_be_code_of_design(t = 2, k = |$\kappa$% \verb|, lambda = |$\lambda$\verb|)|. \par\noindent The effect of this option is to check that $C^\perp$ satisfies certain conditions which are necessary (but not sufficient) for it to be generated by a $t$-design $D$ with the given parameters. (We use $\kappa$ to avoid conflict with our convention that $k$ is the dimension of the code.) To explain these conditions, let $S(2)$ denote the set of all $2$-words in $\F_2^n$, and let $T(\kappa)$ denote the set of all $\kappa$-words in $C^\perp$. If $\lambda > 1$, we check only that every element of $S(2)$ is contained in at least $\lambda$ elements of $T(\kappa)$. In the case where $\lambda = 1$, we check the following more elaborate condition\label{elaborate-design-condition}: \vspace{0.1in} \par\noindent $A := S(2)$;\\ $B := T(\kappa)$;\\ $E := \emptyset$;\\ \begin{tabular}{ll} \kern-6pt repeat \{\ \ \ \ & (At this point every $a \in A$ lies in some element of $D \cap B$.)\\ & if $(\kern4pt \exists\kern1pt a \in A \hbox{\ not contained in any\ } b \in B\kern4pt )$ return false;\\ & $U := \setof{a \in A: \exists! \kern4pt b \in B \hbox{\ containing\ } a}$;\\ & if $( \kern4pt U = \emptyset \kern4pt )$ return (($\abs{E} \not= {n \choose 2}/{\kappa \choose 2}$) or ($E$ generates $C^\perp$));\\ & $F := \setof{b \in B \hbox{\ which contains an element\ } u \in U}$;\\ & (Note that $F \IN D$.)\\ & $E := E \cup F$;\\ & if $(\kern4pt \exists f_1, f_2 \in F \hbox{\ such that\ } \abs{f_1 \cap f_2} \geq 2\kern4pt )$ return false;\\ & $A_0 := \setof{a \in A: a \hbox{\ is contained in some\ } f \in F}$;\\ & $A := A - A_0$;\\ & $B := \setof{b \in B: b \hbox{\ contains no element of\ } A_0}$; \kern0.9cm\} \end{tabular} \vspace{0.1in} \par\noindent The second condition is \par\noindent\kern0.5in\verb|partition_of_word_by_dual_words(weight = |$w$% \verb|, dual_weight = |$d$\verb|)|. \par\noindent For this condition to be satisfied, every word of weight $w$ in $C$ must admit a nonoverlapping cover by words of weight $d$ in $C^\perp$. If both conditions (\verb|partition_of_word_by_dual_words|, \verb|dual_may_be_code_of_design|) are employed, $\lambda = 1$, and $d = \kappa$, the meaning of the two conditions is modified and the above tests are combined and strengthened, as follows. First, the change in meaning is that now we require that there exists a $t$-design $D$ with the given parameters, generating $C^\perp$, such that moreover every word of weight $w$ in $C$ admits a nonoverlapping cover by elements of $D$. As for the change in tests, make the following definition. A {\it covering plan\/} is a choice, for each word of weight $w$ in $C$, of a nonoverlapping cover by words of weight $\kappa$ in $C^\perp$, in such a way that no two words in the covering plan meet at more than one position. We cycle through all covering plans $\cal D$, and for each, we execute the condition outlined above, except that the initial choices for $A$, $B$, and $E$ are modified as follows: \begin{itemize} \item $A = \setof{w \in S(2):\ w \hbox{\ is not contained in any\ } d \in \cal D}$; \item $B = \setofh{words in $T(\kappa)$ not meeting any $d \in {\cal D}$ along more than one bit}$; \item $E = \cal D$. \end{itemize} In the above, we have used ${\cal D}$ to denote the set of all dual words appearing in the given covering plan. The third field is \par\noindent\kern0.5in\verb|doubly_even_part_is_subcode|. \par\noindent This condition says that the set $D$ of words in the code whose weight is divisible by four must constitute a subcode of $C$. This is equivalent to saying that $D \IN C^\perp$. \vspace{0.1in} If at some point it is found that the code type is unrealizable, the language interpreter will discard all information about the code type except this fact. After a {\tt type} command is entered, that type remains in effect until the next {\tt type} command (or some other command which changes the type, such as ``{\tt no}''). See also the ``{\tt at}'' command. \block{Matrix descriptors}\label{matrix-descriptor-section} In this section, we will define what we call a {\it matrix descriptor}, which is a string representation of a matrix over $\F_2$. More precisely, it is a string representation of an equivalence class of such matrices, where the equivalence relation is given by elementary row operations. Accordingly, when we define operators on matrix descriptors, we require that the underlying matrix operators are defined modulo this equivalence relation. In short, a matrix descriptor represents a subspace of $\F_2^n$ for some $n$, i.e.\ a code. The matrix descriptor syntax has evolved over a short period to efficiently (and where possible) meaningfully represent the codes encountered in this report. Over time, new and better representations will be found (and indeed some are known, but not to the author). As this happens, the descriptor syntax will be enlarged. \def\superopt#1{$\displaystyle{\overbrace{#1}^{\hbox{optional}}}$} \def\subopt#1{$\displaystyle{\underbrace{#1}_{\hbox{optional}}}$} First we make the convention that when we refer to a column number of a matrix with $n$ columns, the number will be between $1$ and $n$. (And not between $0$ and $n-1$.) Now we define {\it atoms}, which are the following: \begin{itemize} \item \verb|{|$\VEC r1k$\verb|}|, where $\VEC r1k$ are $\F_2$-independent zero-one vectors (e.g.\ $010001110$) which are to be the rows of the associated matrix. \item {\tt[}$c.m${\tt]}, where \cconfig\ is a code type and \mconfig\ is a configuration for \cconfig\ having the same dimension as it. The associated matrix is the generator matrix (in \RREF) for the basic code associated to \mconfig. \item {\tt[}$c.m${\tt-}$r${\tt]}, shorthand for {\tt[}$c.m${\tt] - column}\kern5pt$r$. \item $\Simp(r)$, representing the matrix of the simplex code, whose columns are in lexicographic order the nonzero elements of $\F_2^r$. \item $\Proj(r)$, representing the matrix whose columns are in lexicographic order the elements of $\F_2^r$. \item $\Even(n)$, the \RREF\ matrix whose rows span the even codewords of $\F_2^n$. \item $\verb|RM1(|r\verb|)|$, representing the matrix of the first-order Reed-Muller code of length $2^r$. \item $\verb|QuadraticResidue(|q\verb|)|$, representing the matrix of the length $q$ quadratic residue code. Here $q$ must be a prime, equivalent to $\pm1\ (mod\ 8)$. \item \superopt{\hbox{$c${\tt-}}}\verb|cyclic {|{\it generator}% \subopt{\hbox{\kern5pt{\tt,}\kern5pt{\it extra word}\kern5pt}}\verb|}|, whose representation $M$ is as follows. First one can define the {\it standard permutation\/} on $n$ of cycle type $(a_1,\ldots,a_r)$. By way of example, the standard permutation on $10$ of cycle type $(3,2)$ is given as a product of disjoint cycles by $(1,2,3)(4,5)$. Now the argument $c$ describes a permutation $\sigma$. It is the standard permutation on $n$ of a certain cycle type. First, if ``$c${\tt-}'' is not present, the cycle type is $(n)$. Second, if $c$ is a positive integer dividing $n$, the cycle type is $(n/c, \ldots, n/c)$, with $n/c$ appearing $c$ times. Finally, $c$ may itself be a cycle type. The generator and the extra word (if present) are to be zero-one vectors of length $\leq n$. Pad on the right with zeros to form vectors $v$ and $w$ of length $n$. If the extra word is not present, let $M$ have rows $\setof{v, \sigma(v), \ldots, \sigma^{k-1}(v)}$. Otherwise let the rows be $\setof{v, \sigma(v), \ldots, \sigma^{k-2}(v),w}$. Note that there is no guarantee that $\sigma$ is an automorphism of $M$.% \footnote{The {\tt cyclic} atom does not tell us what $n$ and $k$ are. They have to be inferred from context. See the {\tt :=} command for consequent restrictions on the use of the {\tt cyclic} atom.} \end{itemize} Now we define a variety of unary and binary matrix operators. A {\it matrix descriptor} is by definition a string built up from the atoms by these operators and parentheses, which is free of ambiguity.% \footnote{For example, if $\alpha$, $\beta$, and $\gamma$ are matrix descriptors, you cannot write $\alpha \kern5pt {\tt\#} \kern5pt \beta \kern5pt {\tt\#} \kern5pt \gamma$. Use parentheses.} \begin{itemize} \item {\bf[P]} Let $M$ be a matrix. Let $\Simp$ be short for $\Simp({\tt M.nrows} - 1)$. Then $P(M)$ is $\BRMAT{1&0\cr\Simp&M}$. \item {\bf[sharp]} Let $M$ and $N$ be matrices. Then $M \verb|#| N$ is defined in the following way. First let $A$ be the horizontal concatenation of $N\verb|.ncols|$ copies of $M$. Then let $B$ be obtained from $N$ by replicating each column $M\verb|.ncols|$ times. Finally $M \verb|#| N$ is the vertical concatenation of $A$ and $B$. \item {\bf[dual]} Let $M$ be a matrix, with associated code $C$. Then $\verb|dual(|M\verb|)|$ is the generator matrix of $C^\perp$. \item {\bf[parity check]} Let $M$ be a matrix, with associated code $C$. Assume that $C$ has a word of odd weight. Then $M\verb| + check|$ is obtained from $M$ by adjoining a parity check as the last column. \item {\bf[column duplication]} Let $M$ be a matrix, and let $r$ be an integer between $1$ and $M\verb|.ncols|$. Then $M\verb| + column |r$ is obtained from $M$ by duplicating column $r$. \item {\bf[column deletion]} Let $M$ be a matrix, and let $r$ be an integer between $1$ and $M\verb|.ncols|$. Then $M\verb| - column |r$ is obtained from $M$ by deleting column $r$. \item {\bf[add zero column]} $M$\verb| + zero column| adjoins a zero column to $M$ on the right. \end{itemize} \midhead{The dual transform} The syntax of this operator is $M$\verb|^T using|\kern5pt$\setof{\VEC w1r}$, where $M$ is a matrix descriptor and the $w_i$ are yet to be defined. Let $C$ be $M$'s row space. Each $w_i$ defines a certain subset $S_i$ of $C$, as follows. If $w_i$ is a number, then $S_i$ is the set of words of weight $w_i$ in $C$. If $w_i$ has the form ``$a$\verb|_{|$\VEC b1t$\verb|}|'', where each $b_i$ is a nonzero integer, then $S_i$ is the set of words of weight $a$ which for each $j$ have a $1$ in position $b_j$ (if $b_j > 0$), and a $0$ in position $-b_j$ (if $b_j < 0$). \par\noindent{\sc Note.}\ For purposes of display in the program part of this report, we will write (e.g.) $\ldots$\ {\tt using} $\{10,12_{\ol{1},2,\ol{5}},20\}$ instead of $\ldots$\ {\tt using} \verb|{10,12_{-1,2,-5},20}|. Let $S$ be the multiset $\bigcup_{i=1^r} S_i$. For $s \in S$, let $\lambda(s)$ denote its coordinate vector \WRT\ the ordered basis given by the rows of $M$. The value of the dual transform operator is the matrix whose columns are $\setof{\lambda(s)}_{s \in S}$, in lexicographical order (for definiteness). \midhead{The dual orbit transform} The syntax of this operator is $M$\verb|^T using {|\kern5pt% $\VEC g1r$\kern5pt\verb|:|\kern5pt$\VEC c1m$\verb|}|, where $M$ is a matrix descriptor; the $g_i$ and $c_i$ are yet to be defined. Let $C$ be $M$'s row space. Each $g_i$ is to have the form $\verb|$|r$, where $r \in \N$; it represents the \th{r}\ generating automorphism of $\Aut(M)$, as computed by {\tt Split}. As such these automorphisms are perilously dependent on slight changes to internal routines which might appear in a future version of {\tt Split}. Let $\VEC c1m$ be coordinate vectors for elements $\VEC w1m \in C$, relative to the rows of $M$. Let $S$ be the orbit of $\VEC w1m$ under the given automorphisms, viewed as a subset of $C$ (or a multiset in $C$ if there is repetition amongst $\VEC w1m$). Then proceed as with the dual transform. \block{How to define a configuration} There are two main ways to define a configuration: the {\tt config} command, and the {\tt :=} command. We describe these first. Then we describe some other commands which can be used to define a configuration: {\tt config from}, {\tt incorporate}, and {\tt subdivide along}. \indexb{config} \begin{commanddeclaration} \vbox{\hbox{% $\displaystyle{\overbrace{\hbox{\tt=}}^{\hbox{optional}}} \displaystyle{\underbrace{\hbox{\lconfig}}_{\hbox{optional}}}$ {\tt config}\ \ {\it partition} {\tt:} {\it \{basis\}\/} $\displaystyle{\overbrace{\hbox{{\tt:} {\it \{dual basis\}} $\displaystyle{\underbrace{\hbox{{\tt:}\kern5pt{\tt\{}% \ {\it constraint list\/}\ {\tt\}}}}% _{\hbox{optional}}}$ }}^{\hbox{optional}}}$ {\tt;}% }% \hbox{\footnotesize{\ \ }}% \hbox{\footnotesize{\sc Note:}\ You never have to write ``{\tt\{\}}'' as part of this command -- replace it by the null string.}} \end{commanddeclaration} This command defines a {\it configuration}. We illustrate by an example: \begin{verbatim} type [32,14,10_2]; config 10,10,12 : {110,100}; \end{verbatim} These two commands tell us that we are looking at even codes of dimension $14$ in $\F_2^{32}$, which contain the following two words: \begin{verbatim} 1111111111 1111111111 000000000000 1111111111 0000000000 000000000000. \end{verbatim} (The spaces have been inserted to enhance readability.) If a dual basis is given, the dual code is expected to contain the given words. The elements of the ``basis'' are expected to be \LI, and likewise for the elements of the ``dual basis''. Use of the command \par\noindent\kern0.5in{\tt type [}$n${\tt, ...];} automatically generates the base configuration, as if the command ``{\tt config}\ $n$\ \verb|: { };|'' had been executed. If the {\it constraint list\/} is present, attention is restricted to those codes which satisfy the given constraints. A weight enumerator (e.g.\ \verb|1 + 6t^10 + t^20|) may be given as a ``constraint''. The optional \lconfig\ is a label which is associated to the configuration for future reference. Within a given code type, a configuration label may not be defined more than once. The labels {\tt[base]} and {\tt[current]} are reserved for reference to the base and current configurations of the current code type. More complicated labels are created by the ``{\tt incorporate}'' ``{\tt:=}'' commands. The optional ``{\tt=}'' will cause the ``{\tt=}'' command to be automatically invoked on the configuration defined by this command and the configuration that was current prior to it. When a {\tt config} command is entered, aside from syntax, not much is checked. The language reserves the right to flag as errors certain things that no one would do deliberately. For example, for every word in the small code, the weight of the associated basic word should be in the working weight list for the base configuration. If at the some point it is found that a configuration is unrealizable, the language interpreter will discard all information about the configuration except this fact. \indexb{:=} \begin{commanddeclaration} \lconfig\kern5pt\verb|:= |{\it matrix descriptor}\kern5pt% $\displaystyle{\underbrace{\hbox{{\tt::}\kern5pt{\tt\{}% \ {\it constraint list\/}\ {\tt\}}}}% _{\hbox{optional}}}${\tt;} \end{commanddeclaration} Create a fully refined, terminal, realizable configuration named \lconfig\ whose associated code has the generator matrix given by the matrix descriptor.% \footnote{There are restrictions on the way in which a {\tt cyclic} atom may enter into the matrix descriptor: the descriptor may be a {\tt cyclic} atom, or it may have the form {\tt cyclic} atom {\tt+ check}. No other use of the cyclic atom is allowed.} If {\it constraint list\/} is supplied, this command also automatically creates a configuration labelled {\tt[}$\ell${\tt!]} which is basal and has {\it constraint list\/} for its assumed constraints. As well, the implication ${\cal R}(\ell) \IN {\cal R}(\ell\hbox{\tt!})$ is noted. \indexb{config from} \begin{commanddeclaration} $\displaystyle{\underbrace{\hbox{\lconfig}}_{\hbox{optional}}}$ {\tt config from }$v_1${\tt|}$\ldots${\tt|}$v_r${\tt;} \end{commanddeclaration} Let $v_1$ be a basic local variable for {\tt[current]}. Show that it is nonzero, and subdivide along it to obtain a new configuration, which $v_2$ should be a basic local variable for. Show that $v_2$ is nonzero, and subdivide along it. Continue in this manner. The last configuration is made current, and is named \lconfig\ if the optional label is present. \def\nconfig{{\tt[}$n${\tt]}} \indexb{incorporate} \begin{commanddeclaration} \nconfig\kern5pt{\tt incorporate}\kern5pt\lconfig\kern5pt{\tt below}% \kern5pt\mconfig\kern5pt{\tt via sub}$w${\tt;} \end{commanddeclaration} \par\noindent{\sc Idea:} \ The fact that one code is known to contain another code may be used to copy configurations from one code type to another. \vspace{0.05in}\par\noindent{\sc Requirements:} \begin{itemize} \item \lconfig\ is an existing code type, which has no joint variables in its assumed constraints, and such that none of its configurations have joint variables in their assumed constraints; \item \mconfig\ is a configuration of the current code type; \item \nconfig\ identifies the given {\tt incorporate} command; it may not be used to label any other {\tt incorporate} command within the current code type; \item $w$ is a small word (relative to \mconfig), which has weight $1$ (as a small word); \item it must be known that $\verb|sub|w \geq 2^d$, where $d$ is the dimension of the code type referred to by \lconfig; \item Let $r$ be the part of the partition corresponding to the $1$ in $w$. Then the code type referred to by \lconfig\ must have length $r$. Its assumed weight list must contain \mconfig's working weight list. (Weights greater than $r$ are ignored.) Its assumed constraints must lift to known constraints for \mconfig, as in the following example: \begin{verbatim} [c] type [30,10,10]{y14 >= 10}; ... [d] type [36,15,10]; ... show mu6 != 0; [x] config 30,6 :: {01}; ... show x_14_0 >= 10; infer sub10 = 1024; [u] incorporate [c] below [x] via sub10; \end{verbatim} \end{itemize} \vspace{0.05in}\par\noindent{\sc Action:} \ The {\tt incorporate} command causes more or less the entire body of information for \lconfig\ to be imported into the current code type, sort of below \mconfig. In particular, each configuration \sconfig\ of \lconfig\ is used to generate a configuration \spconfig\ of the current code type. To do this it is necessary to carry out a number of conversions: \begin{itemize} \item All variables which appear in assumed or known constraints of \sconfig\ are reconstituted in terms of appropriate variables for \spconfig. Global variables are translated into {\tt sub} variables or linear combinations of them. Known constraints involving joint variables are lost. \item Words in the dual small code of \sconfig\ do not induce words in the dual small code of \spconfig. So instead such words are converted into assumed constraints involving {\tt q} variables. \item \spconfig\ has the label {\tt[}$n${\tt.}$s${\tt]}. Iterative use of incorporate will lead to configurations whose labels have more than one dot. \end{itemize} Automorphism labels are unchanged in the process. Continuing the preceeding example, if code type \verb|[c]| has a configuration defined via \begin{verbatim} [a] config 8,10,12 : {110,001} :: {y6 <= 4, x_0_1_0 = 0}; \end{verbatim} then after the {\tt incorporate} command, code type \verb|[d]| will have a configuration defined as if via \begin{verbatim} [u.a] config 8,10,12,6 : {1100,0010} : {0001} : {sub1110_6 <= 4, x_0_1_0_0 = 0}; \end{verbatim} although it would not be permissable to make such a definition, since the label would not be accepted. \indexb{subdivide along} \begin{commanddeclaration} $\displaystyle{\underbrace{\hbox{\lconfig}}_{\hbox{optional}}}$ {\tt subdivide along}\kern5pt$v${\tt;} \end{commanddeclaration} Forcibly subdivide {\tt[current]} along the given basic local variable, passing all known constraints for {\tt[current]} to it. Label the new configuration \lconfig, and make it current. \block{Group manipulation commands} To each configuration, there is associated a data item which relates to automorphisms: the list of {\bf known} automorphisms. These are to be viewed as generators. Some of the automorphisms have labels. Note that whenever a constraint which sets a basic local variable $v$ to zero is proved, the program automatically computes the orbit of $v$ under the group of known automorphisms, and sets all these variables equal to zero. Here are the commands: \indexb{automorphism} \begin{commanddeclaration} $\displaystyle{\underbrace{\hbox{\lconfig}}_{\hbox{optional}}}$ {\tt automorphism }$\VEC a1r${\tt;} \end{commanddeclaration} Verify that the given permutation defines an automorphism of the current configuration. Append it to the list of known automorphisms for the current configuration. A label \lconfig\ may be given. Within a given configuration, automorphism labels may not be repeated. \indexb{show full automorphism group} \begin{commanddeclaration} {\tt show full automorphism group;} \end{commanddeclaration} Print out all the elements of the automorphism group of {\tt[current]}, using cycle notation. \indexb{group size} \begin{commanddeclaration} {\tt group size = }$m${\tt;} \end{commanddeclaration} Verify that the group generated by the list of known automorphisms has $m$ elements. The implementation is very inefficient. \indexb{full group size} \begin{commanddeclaration} {\tt full group size = }$m${\tt;} \end{commanddeclaration} Verify that the automorphism group of {\tt[current]} has $m$ elements. For this command, {\tt[current]} may not have local variables in its assumed constraints. \indexb{report group size} \begin{commanddeclaration} {\tt report group size [}$\ell_1${\tt]}, $\ldots$\kern2pt, {\tt[}$\ell_r${\tt];} \end{commanddeclaration} This is a purely exploratory command. Given automorphisms {\tt[}$\ell_1${\tt]}, $\ldots$, {\tt[}$\ell_r${\tt]}, this command reports in order the size of the group generated by {\tt[}$\ell_1${\tt]}, then the size of the group generated by {\tt[}$\ell_1${\tt]}, {\tt[}$\ell_2${\tt]}, and so forth, lastly reporting the size of the group generated by {\tt[}$\ell_1${\tt]}, $\ldots$, {\tt[}$\ell_r${\tt]}. However, if one of these groups turns out to be very large, the command may never finish. The implementation is very inefficient. \indexb{reduce variable set} \begin{commanddeclaration} {\tt reduce variable set;} \end{commanddeclaration} Compute the automorphism group of the configuration. From the list of minimal admissible basic local variables $v$ (for {\tt[current]}), find those which are carried by an automorphism to an inadmissible basic local variable, and adjoin the corresponding constraints $v = 0$ to the list of known constraints. Ideally this would be done automatically as needed. \block{Configuration relation makers} Many of the commands of the language create logical relationships between configurations. All of the commands of this section do this. The {\tt !config} command does too. In addition, certain logical relationships come for free and are automatically known to the language: \begin{itemize} \item every configuration \lconfig\ implies the base configuration, i.e.\ ${\cal R}(\ell) \IN {\cal R}(\hbox{\tt base})$. \end{itemize} All commands in this section leave the current configuration undefined upon termination. \indexb{kill current by} \begin{commanddeclaration} {\tt kill current by }$\VEC v1r${\tt;} \end{commanddeclaration} Let \config{c_1} denote the current configuration. Let $v_1$ be a basic local variable for \config{c_1}. First show by split linear programming that $v_1 \not= 0$. Then subdivide \config{c_1} along $v_1$ to obtain a new configuration \config{c_2}. If $r = 1$, use split linear programming to show that \config{c_2} is unrealizable. If $r > 1$, $v_2$ should be a basic local variable for \config{c_2}. One then shows by split linear programming that $v_2 \not= 0$, and continues as above, constructing configurations \config{c_3},$\ldots$,\config{c_{r+1}}. From the ultimate finding that \config{c_{r+1}} is unrealizable, one deduces that the current configuration is unrealizable. For example, if \config{c1} = \verb|config 50,2 : {10}|, then ``\verb|kill current by x_20_0|'' is equivalent to \begin{verbatim} show x_20_0 != 0; !config 20,30,2 : {110,100}; \end{verbatim} \indexb{via dual nonexistence infer} \begin{commanddeclaration} \verb|via dual nonexistence infer [base] = ;| \end{commanddeclaration} Assume that the code type has no assumed constraints. Let $d$ be the minimum weight in the working weight list $w$ for {\tt[base]}. Suppose the minimum weight of the dual code is known to be $\geq d'$. Suppose we know that no \par\noindent\kern0.5in \verb|[n, n-k, d']{mu1 = 0,|\kern5pt$\ldots$\verb|, mu|$(d-1)$\verb| = 0}| \par\noindent code exists. Then one may infer that {\tt[base]} is unrealizable. In the case where $w$ has no odd weights, it is enough to know that no \par\noindent\kern0.5in \verb|[n, n-k, d']{mu1 = 0,|\kern5pt$\ldots$\verb|, mu|$(d-1)$\verb| = 0, y|% \kern1pt$n$\verb| = 1}| \par\noindent code exists. The intended purpose of this command is to bypass numerical instability of linear programming problems arising from the split linear programming method. It is useful when $k > n/2$. \indexb{implies}\indexb{=} \begin{commanddeclaration} \vbox{% \hbox{\lconfig\kern5pt{\tt implies}\kern5pt\mconfig{\tt;}}% \hbox{\lconfig\kern5pt{\tt =}\kern5pt\mconfig{\tt;}}} \end{commanddeclaration} \def\ttvec#1#2#3{$#1_#2${\tt,}$\ldots${\tt,}$#1_#3$} Let \lconfig, \mconfig\ be configurations. These commands are placeholders for the most trivial of trivial implications, whose conclusion in the first case is that ${\cal R}(\ell) \IN {\cal R}(m)$ and in the second case that ${\cal R}(\ell) = {\cal R}(m)$. The following cases are handled at present: \begin{itemize} \item (for {\tt implies})\ \mconfig\ has the form\\ \verb| config |$n$\verb| ::: {|% \kern3pt{\it constraint list}\kern3pt\verb|}|\\ and each of its assumed constraints are known to \lconfig. \item (for {\tt implies})\ \lconfig, \mconfig\ differ only in their assumed constraints, and every assumed constraint of \mconfig\ is a known constraint of \lconfig. \item (for {\tt =})\ \lconfig\ has the form\\ \verb| config |\ttvec p1r\verb| ::: |$\cal S$\\ and \mconfig\ has the form\\ \verb| config |$n-i$\verb|, |$i$\verb| :: {01} : |$\cal T$,\\ where $\cal S$ and $\cal T$ contain only global constraints, every constraint in $\cal T$ as well as the constraint \verb|mu|\kern1pt$i$\verb| != 0| is known for \lconfig, and every constraint in $\cal S$ is either known for \mconfig\ or else is the constraint \verb|mu|\kern1pt$i$\verb| != 0|; one may reverse the roles of \lconfig\ and \mconfig. \item (for {\tt =})\ \lconfig\ has the form\\ \verb| config |\ttvec p1r\verb| ::: |$\cal S$\\ and \mconfig\ has the form\\ \verb| config |$i$\verb|, |$n-i$\verb| : {10} :: |$\cal T$,\\ where $\cal S$ and $\cal T$ contain only global constraints, every constraint in $\cal T$ as well as the constraint \verb|y|\kern1pt$i$\verb| != 0| is known for \lconfig, and every constraint in $\cal S$ is either known for \mconfig\ or else is the constraint \verb|y|\kern1pt$i$\verb| != 0|; one may reverse the roles of \lconfig\ and \mconfig. The obvious variant when $i = n$ is also allowed. \item (for {\tt =})\ \mconfig\ is some refinement of \lconfig. For example, one could use: \begin{verbatim} [l] config 5,4,6 : {100,010} : {001}; [m] config 5,1,3,6 : {1000,0110} : {0001}; \end{verbatim} No local variables are permitted in the assumed constraints of the configurations. \item (for {\tt=})\ \lconfig\ and \mconfig\ are realizable full configurations, and their associated basic codes are isomorphic. \end{itemize} A large number of the commands in this section have the following general form: \begin{commanddeclaration} {\tt via}\kern5pt{\it method}\kern5pt\lconfig\kern5pt{\tt=}\kern5pt% {\it configuration-list}{\tt;} \end{commanddeclaration} Let the configuration-list expand out to \lconfigs. By the given method, show that the class of codes corresponding to configuration \lconfig\ equals the union of the classes of codes corresponding to configurations labelled \lconfigs. In the degenerate case ``\lconfig\ {\tt=}\ {\tt;}'' one in effect shows that no codes have configuration \lconfig. The case ``\lconfig\ {\tt=}\ {\tt[}$\ell_1${\tt];}'' is also in general permissable. Note however that you cannot in general replace this by ``{\tt[}$\ell_1${\tt]}\ {\tt=}\ \lconfig'': the conclusion would be the same, but the method may not be smart enough to handle the reversal. \indexb{via lp} \begin{commanddeclaration} {\tt via lp}\kern5pt\superopt{\it lp-specifier}\kern5pt{\it configuration-list}% \kern5pt{\tt= ;} \end{commanddeclaration} The optional argument {\it lp-specifier\/} should be either ``{\tt(joint)}'' or ``{\tt(joint:}$r${\tt)}'', where $r \geq 0$. For each configuration \lconfig\ in the expansion of the configuration-list, proceed as follows. If the {\it lp-specifier\/} is present, use joint linear programming to deduce (if possible) that \lconfig\ leads to a contradiction. (If the second form of the {\it lp-specifier\/} is used, the parameter ``{\tt use dual dual for joint}'' is set to $r$ prior to executing the {\tt show}, and then restored to its original value afterwards.) Otherwise, try to do this with split linear programming. However, to save time, the program will first attempt to determine if some known constraints are ``blatantly'' contradictory. Thus if we know that $y_{10} \geq 80$ and $y_{10} \leq 79$, then no calculation is required. For example, one might use a command sequence of the form \begin{verbatim} config ... ; show 79 < y10 < 80; via lp [current] = ; \end{verbatim} to exploit the fact that a variable does not take on an integer value. Similarly, if there is a known constraint of the form {\tt y}$i$ {\tt != 0}, where $i$ is not in the working weight list of {\tt[current]}, then no calculation is required. \indexb{via dual word} \begin{commanddeclaration} {\tt via dual word [base] implies}\kern5pt\lconfig{\tt;} \end{commanddeclaration} Suppose it is known (from an ``{\tt infer dual min <=}'' command) that every code in the code type has a nonzero dual word of weight $\leq r$, for some given $r \leq k+1$. Let \lconfig\ be\\ \verb| config|\kern5pt$n-r${\tt,}\kern5pt$r$\verb|::: {sub10 =|% \kern5pt$2^{k-r+1}$\verb|}|.\\ Then one may infer that ${\cal R}(\hbox{\tt base}) \IN {\cal R}(\ell)$. \def\lpconfig{{\tt[}$\ell'${\tt]}} \indexb{via variable split} \begin{commanddeclaration} {\tt via variable split}\kern5pt\lconfig\kern5pt{\tt =}\kern5pt% {\tt[}$\ell_1${\tt]}\kern5pt{\tt or}\kern5pt$\ldots$\kern5pt{\tt or}% \kern5pt{\tt[}$\ell_r${\tt];} \end{commanddeclaration} \def\liconfig{{\tt[}$\ell_i${\tt]}} \def\ljconfig{{\tt[}$\ell_j${\tt]}} \par\noindent{\sc Idea:} \ A given configuration \lconfig\ may be broken up into several cases by making assumptions about the values of specified variables. \vspace{0.05in}\par\noindent{\sc Requirements:} \ The given configurations \lconfig, \lconfigs\ may differ only in their assumed constraints. Every assumed constraint of \lconfig\ must also be an assumed constraint of \liconfig, for each $i$. Apart from these shared constraints, all assumed constraints must be simple. \vspace{0.05in}\par\noindent{\sc Action:} \ Analyze the constraints not shared by all of \lconfig, \lconfigs, and deduce from these that ${\cal R}(\ell) = {\cal R}(\ell_1) \manycup {\cal R}(\ell_r)$. \indexb{via constraint drop} \begin{commanddeclaration} {\tt via constraint drop}\kern5pt\lconfig\ {\tt= [}$\ell'${\tt];} \end{commanddeclaration} This method is used to get rid of assumed constraints. The configuration \lconfig\ is arbitrary, and \lpconfig\ is the same as \lconfig, except that some of the assumed constraints from \lconfig\ have been deleted. Use one of two submethods to show that these are satisfied anyway. If \lconfig\ is terminal, apply the first submethod, which is to explicitly compute the weight enumerator. Otherwise, apply the second submethod, which is split linear programming, as in the ``{\tt show}'' command. \def\clabel{{\tt[}$c${\tt]}} \def\yieqr{{\tt y}$i${\tt\ = }$r$} \indexb{via configuration search} \begin{commanddeclaration} {\tt via configuration search}\kern5pt\lconfig\kern5pt{\tt implies}% \kern5pt\mconfig{\tt;} \end{commanddeclaration} \par\noindent{\sc Idea:}\ One can check to see if a code realizes a particular $r$-dimensional configuration by explicitly checking each $r$-tuple of elements of the code. \vspace{0.05in}\par\noindent{\sc Requirements:}\ The configuration \lconfig\ must be terminal. The configuration \mconfig\ must have zero dual small code, and each of its assumed constraints must be known to \lconfig. \vspace{0.05in}\par\noindent{\sc Action:}\ Let $C$ be the code associated to \lconfig. Let $\VEC w1r$ be the basic words associated to the basis elements for the small code of \mconfig. Call an $r$-tuple $\VEC v1r \in C$ an \mconfig-{\it configuration\/} if for all subsets $S \IN \setof{1,\ldots,r}$, we have $\abs{\cap_{i \in S} v_i} = \abs{\cap_{i \in S} w_i}$. By an explicit search, determine if $C$ has an \mconfig-configuration. If it does, conclude that ${\cal R}(\ell) \IN {\cal R}(m)$. Otherwise ${\cal R}(\ell) \notIN {\cal R}(m)$ and the command fails. The current configuration is horrendously inefficient and deathly slow if $r$ is large. \vspace{0.05in}\par\noindent{\sc Note:}\ Let $\lambda_C(m) = $ the number of \mconfig-configurations in $C$. As \mconfig\ ranges over all one-dimensional configurations, the information carried by $\lambda_C(m)$ is equivalent to the information carried by the weight enumerator of $C$. As \mconfig\ ranges over two-dimensional configurations, we similarly obtain the information carried by the joint weight enumerator of $C$ with itself (see [.macwilliams sloane book.]\ p.\ 147 for the definition of joint weight enumerator). \indexb{via unique wordtypes} \begin{commanddeclaration} {\tt via unique wordtypes}\kern5pt\lconfig\kern5pt{\tt implies}\kern5pt% \mconfig{\tt;} \end{commanddeclaration} The conclusion is that ${\cal R}(\ell) \IN {\cal R}(m)$. The configuration \mconfig\ must be terminal and realizable, and it must be known already that ${\cal R}(m) \IN {\cal R}(\ell)$. It must be known that the basic code associated to \lconfig\ contains all possible codewords, except for words of one weight. The justification for this command is: \begin{lemma} Let $C$ be a code in $\F_2^n$. Then for fixed $k$ and $q$, there exists (up to isomorphism) at most one $k$-dimensional code $D$ in $\F_2^n$ which contains $C$ and which has the property that $\abs{v} = q$ for all $v \in D - C$. \end{lemma} \begin{proof} First consider a projective code $E \IN \F_2^r$ of dimension $m$. Form the zero-one matrix $M$ whose rows are the nonzero elements of $E$. I claim that if one regards the columns of $M$ as vectors over $\Q$, they are independent. To see this, let $B$ be a generator matrix for $E$. By adding columns to $B$, we obtain a matrix $B'$ in which each nonzero element of $\F_2^m$ appears as a column exactly once. Let $M'$ be the zero-one matrix whose rows are the nonzero elements of the row space of $B'$. It is enough to show that the columns of $M'$ are $\Q$-independent. But $M'$ is square, so it is enough to show that its rows are $\Q$-independent. Now consider the set $S$ of functions \mapx[[ \F_2^m - \setof{0} || \F_2 ]] which are given by a nonzero, homogeneous, degree one element of $\F_2[\VEC x1m]$. Form the zero-one matrix $N'$ whose rows correspond to the elements of $S$. (One has to choose an order for the elements of $\F_2^m - \setof{0}$.) As an $\F_2$-basis for $S \cup \setof{0}$ is given by $\VEC x1m$, we see the rows of $N'$ corresponding to this basis are the same (up to permutation of columns) as the rows of $B'$, and hence $N' = M'$, modulo permutation of columns. Thinking in characteristic zero, view $\setof{0,1}$ as a subset of $\Q$, and regard the elements of $S$ as functions \mapx[[ \setof{0,1}^m - \setof{0} || \setof{0,1} ]]. I claim that these functions are $\Q$-linearly independent. The idea is as follows. The function $x_1$ over $\F_2$ is also represented by $x_1$ over $\Q$. The function $x_1+x_2$ over $\F_2$ is represented by $x_1+x_2-2x_1x_2$ over $\Q$. The function $x_1+x_2+x_3$ over $\F_2$ is represented by $x_1+x_2+x_3-2x_1x_2-2x_2x_3-2x_1x_3+4x_1x_2x_3$ over $\Q$. The function $x_1+x_2+x_3+x_4$ over $\F_2$ is represented by $x_1+x_2+x_3+x_4-2x_1x_2-2x_1x_3-2x_1x_4-2x_2x_3-2x_2x_4-2x_3x_4 +4(x_1x_2x_3 + x_1x_3x_4 + x_1x_2x_4 + x_2x_3x_4 ) - 8x_1x_2x_3x_4$ over $\Q$. Let $V$ be the subspace of $\Q[\VEC x1m]$ having as a basis the monomials of degree $d$ ($1 \leq d \leq m$) in which no exponent greater than $1$ appears. Note that if $f \in V$ induces the zero function \mapx[[ \setof{0,1}^m - \setof{0} || \setof{0,1} ]], then $f = 0$. Thus we see that the elements of the $\Q$-linear span of $S$ may be identified with the elements of $V$. But $\dim(V) = \abs{S}$, so it follows that the elements of $S$ are $\Q$-linearly independent. Hence the rows of $M'$ are independent over $\Q$, and so the columns of $M$ are $\Q$-independent. Now choose an ordered basis for $C$ and use it to define a configuration, whose small code $E$ is projective. I claim that this configuration has at most one nontrivial wordtype, up to equivalence. Indeed, a nontrivial wordtype for this configuration [say $(\VEC w1r)$] must satisfy one equation for each nonzero element $x$ of $E$: $\sum_{i=1}^r x_i w_i = \abs{x}/2$, where $\abs{x}$ is the weight of the basic word associated to $x$. The coefficient matrix of this system of equations is $M$, which we have shown has $\Q$-independent columns. Hence the system has at most one solution, which proves the lemma in the case where $k = \dim(C) + 1$. The general case follows by induction. \qed \end{proof} \indexb{via weight enumerator} \begin{commanddeclaration} {\tt via weight enumerator}\kern5pt\lconfig\kern5pt{\tt implies}\kern5pt% \mconfig{\tt;} \end{commanddeclaration} The conclusion is that ${\cal R}(\ell) \IN {\cal R}(m)$. This is entered into the logical database kept by the program. The configuration \lconfig\ must be terminal, and \mconfig\ must be basal. The command is executed by computing the weight enumerator of the code corresponding to \lconfig, by explicitly computing the weight of each element, and then checking that each assumed constraint of \mconfig\ is satisfied. \indexb{via extension} \begin{commanddeclaration} {\tt via extension}\kern5pt$\hbox{\it configuration-list}_1$% \kern5pt{\tt implies}\kern5pt$\hbox{\it configuration-list}_2${\tt;} \end{commanddeclaration} The program expands $\hbox{\it configuration-list}_1$ and runs the command once with \lconfig\ set to an element of this list. Let $\hbox{\it configuration-list}_2$ expand to \lconfigs. The last configuration {\tt[}$\ell_r${\tt]} may have the form {\tt[}$\alpha$\verb|#]|, which is explained below. Let $D$ be the subcode associated to the small code of \lconfig. Search for all extensions of $D$ to codes which realize the code type, and using this information, attempt to show that $${\cal R}(\ell) \IN {\cal R}(\ell_1) \manycup {\cal R}(\ell_r).$$% However, in the special case where {\tt[}$\ell_r${\tt]} has the form {\tt[}$\alpha$\verb|#]|, any codes in ${\cal R}(\ell)$ which do not lie in ${\cal R}(\ell_1) \manycup {\cal R}(\ell_{r-1})$ are placed in (newly created) terminal configurations {\tt[}$\alpha${\tt1]}, {\tt[}$\alpha${\tt2]}, $\ldots$. (One should not rely on the ordering of these.) To use this command, the partition of \lconfig\ must have the form $1,\ldots,1,r$, for some $r$, and the smallcode of \lconfig\ must be confined to the first $n-r$ bits. Also it must be the case that $$r + \dim(\hbox{\lconfig}) \geq k.\eqno(*)$$% When the extensions have been found, their weight enumerators are computed, and the extensions are matched against the given configurations, according to the following scheme: \begin{itemize} \item Any of the extensions which match a given basal configuration are checked off. \item If there are any configurations which are neither basal or terminal, we determine if any of the extensions match them by means of a configuration search. \item The terminal configurations in \lconfigs\ are then compared with the remaining extensions. \end{itemize} The right hand side of the command could be empty, in which case it is expected that no extensions will be found. If the inequality in $(*)$ is strict, refine to get a partition $1,\ldots,1,r-1$ or $1,\ldots,1,r-2$, etc. Then after adjusting $r$, \WMAT\ $(*)$ is an equality. We then apply the method of \S\ref{extension-section}. Note that to be admissible, the weight list of $D_j$ must be contained in the working weight list \lconfig. We do not know of any practical rules to help pick the group $G$, beyond the obvious comment that it is advantageous for it to be large, but not too large. In the current version of the program, if ``{\tt alternate extension method}'' is set, we use the known automorphism group for $G$. Otherwise, we use $200$ elements of it (after the first step), and we also use a slightly different method for determining minimality. \par\noindent{\sc Note.}\ To use this command as an exploratory tool, first ``{\tt unset warnings are fatal}'', and then use \par\noindent\kern0.5in {\tt via extension}\kern5pt\lconfig\kern5pt{\tt implies ;} \par\noindent if you only want to know the weight enumerators of the extensions, or \par\noindent\kern0.5in {\tt via extension}\kern5pt\lconfig\kern5pt{\tt implies [base];} \par\noindent if you want to see all the extensions. \indexb{via building} \begin{commanddeclaration} {\tt via building}\kern5pt$\hbox{\it configuration-list}_1$% \kern5pt{\tt implies}\kern5pt$\hbox{\it configuration-list}_2${\tt;} \end{commanddeclaration} The command is repeated with \mconfig\ ranging over the elements of $\hbox{\it configuration-list}_1$. Let $\hbox{\it configuration-list}_2$ expand to \lconfigs. The last configuration {\tt[}$\ell_r${\tt]} may have the form {\tt[}$\alpha$\verb|#]|, as in the \verb|via extension| command. In that case the newly created configurations will always be converted to refined configurations. \vspace{0.05in}\par\noindent{\sc Goal:}\ Show that $${\cal R}(m) \IN {\cal R}(\ell_1) \manycup {\cal R}(\ell_r).$$% Do this by constructing a complete set $S$ of isomorphism class representatives for configurations which can be obtained by iterated subdivision of {\tt[current]}. (Obviously, if $S$ is gargantuan, the program will run out of memory.) For those configurations which are terminal, proceed as in the ``{\tt via extension}'' command to match them with \lorconfigs. In outline, here is the algorithm used to find the set of isomorphism class representatives: \begin{verbatim} list := { ( [m], {nontrivial minimal admissible wordtypes for [m]}, true ) }; repeat { pick p from those members of list whose 3rd member is true; (Exit if there isn't one.) wt := p.2nd, modulo the action of Aut( p.1st ); loop over w in wt { c := subdivision of p.1st along w; s := {nontrivial minimal admissible wordtypes for c}; (Obtained by considering those wordtypes of c which subdivide an element of p.2nd.) if ( c is not isomorphic to any config in list ) append (c, s, false) to list; } p.3rd = false; } \end{verbatim} \vspace{0.1in} \par\noindent Each configuration is printed as it is encountered. Known assumed and local constraints for \mconfig\ are ignored, except at the first step. In case $r = 1$ and the single configuration \config{\ell_1} is basal with a single assumed constraint of the form $y_i \leq m$, the procedure is modified, as follows. When we first compute {\tt list}, instead of using all nontrivial minimal admissible wordtypes for \mconfig, we use only those which are equivalent to a wordtype of weight $i$. As a result, {\tt s} gets modified in the same way. If we ever encounter a configuration with $y_i > m$, exit with error. \indexb{via varying} \begin{commanddeclaration} {\tt via varying y}$i$\kern5pt{\tt[current] implies}\kern5pt {\tt[}$\ell_1${\tt]}\kern5pt{\tt or}\kern5pt$\ldots$\kern5pt{\tt or}% \kern5pt{\tt[}$\ell_r${\tt];} \end{commanddeclaration} This is an extremely primitive facility for analyzing the integer solutions of the system of inequalities associated by split linear programming to {\tt[current]}. Each \ljconfig\ must be basal. Each must have an assumed constraint of the form $\hbox{\tt y}_i = m_j$. The $m_j$'s must all be distinct, and must form a list of consecutive integers (after reordering if necessary). For purposes of explanation, assume that they are already in order. First show that $m_1 \leq \hbox{\tt y}_i \leq m_r$. Then show that for each $j$, if one assumes that $\hbox{\tt y}_i = m_j$, then all the other assumed constraints of \ljconfig\ are satisfied. In total, the calculation is equivalent to $r+1$ {\tt show} commands. \indexb{disjoint} \begin{commanddeclaration} {\tt disjoint }\lconfigs{\tt;} \end{commanddeclaration} Verify that for each $i \not= j$, ${\cal R}(\ell_i) \cap {\cal R}(\ell_j) = \emptyset$, using the following procedure: \begin{itemize} \item Attempt to show that known constraints of \liconfig\ contradict known constraints of \ljconfig. The program will only find explicit single variable contradictions, e.g.\ if \liconfig\ has \verb|y10 = 4| but \ljconfig\ has \verb|y10 >= 11|. If a contradiction is found, we're done. (A better way to do this would be to merge the known constraints from the two configurations, and apply linear programming, expecting a contradiction.) \item In case both configurations are terminal, show that they are not isomorphic. \item Assuming that one of the two configurations (\WLOG\ \liconfig) is terminal, by explicit search obtain a contradiction from the small code of \ljconfig. This is only practical if the dimension of \ljconfig\ is very small. The current implementation is very inefficient. \end{itemize} The command will fail if a contradiction is not obtained by one of the above two steps. \indexb{realizable} \begin{commanddeclaration} {\tt realizable [}$\ell_1${\tt]}, $\ldots$, {\tt[}$\ell_r${\tt];} \end{commanddeclaration} Attempt to show that each configuration \liconfig\ is realizable. It must be the case that each \liconfig\ is terminal. Compute the weight enumerator of the associated code and check that it is consistent with the code type as well as with the assumed constraints of the configuration. Options associated with the code type are also checked. \indexb{classification of} \begin{commanddeclaration} {\tt classification of }\mconfig{\tt:}\kern7pt% \superopt{\hbox{{\it justification}\kern5pt$\Longrightarrow$}}% \kern5pt{\it configuration-list}{tt;} \end{commanddeclaration} The configuration-list is expanded out to \lconfigs. We first describe what the command does when the optional part is absent. It will make a logical deduction from known facts, by verifying that ${\cal R}(m)$ is the disjoint union of ${\cal R}(\ell_1),\ldots {\cal R}(\ell_r)$ and moreover that each ${\cal R}(\ell_i)$ is nonempty. If needed, this command will invoke {\tt disjoint} and {\tt realizable} for {\tt[}$\ell_1${\tt]}, $\ldots$, {\tt[}$\ell_r${\tt]}. The classification command (as implemented) does not generally add logical data to the current configuration. However, in the special case where $r = 0$, the command will set configuration \mconfig\ to unrealizable, and in the special case where $r = 1$, the command will take note of the corresponding implication. Any elements of the working weightlist of \mconfig\ which do not appear in any of the working weightlists of {\tt[}$\ell_1${\tt]}, $\ldots$, {\tt[}$\ell_r${\tt]} are deleted from the working weightlist of \mconfig. Now suppose that the optional part is present, and the {\it justification\/} has the form ``$v_1${\tt|}$\ldots${\tt|}$v_r$''. Then the command is expanded to: \par\noindent\kern0.5in{\tt at }\mconfig{\tt;} \par\noindent\kern0.5in{\tt config from }$v_1${\tt|}$\ldots${\tt|}$v_r${\tt;} \par\noindent\kern0.5in{\tt via building [current] implies }\lconfigs{\tt;} \par\noindent\kern0.5in{\tt classification of }\mconfig{\tt:}\kern5pt% \lconfigs{\tt;} \par\noindent For input to {\tt Split}, the symbol $\Longrightarrow$ should be encoded as the ascii sequence ``{\tt -->}''. Finally suppose that the optional part is present, and the {\it justification\/} has the form {\tt[}{\it type}{\tt.}{\it config list}{\tt]}, where {\it type\/} is the name of a preexisting code type with parameters $[n0, k0]$, and {\it config list\/} is a list of configurations for it; the following are examples of the allowed formats: \verb|[17_5_8.a]|, \verb|[17_5_8.{a,b,c}]|, \verb|[28_10_10.g*]|, \verb|[28_10_10.{g*.a}]|. In this case, \mconfig\ must be basal; let $\cal T$ be its assumed constraints. Let $r = n-n0$; we require that $r = k-k0$ or $r = k-k0+1$. Then the command is expanded to: \par\noindent\kern0.5in\verb|at|\kern5pt\mconfig; \par\noindent\kern0.5in\verb|show mu|$r$\kern5pt\verb|!= 0;|% \kern1in(if $r = k - k0 + 1$) \par\noindent\kern0.5in\verb|=config n0, n - n0 ::: {|$\cal T$\verb|};|% \kern1in(if $r = k - k0$) \par\noindent\kern0.5in\verb|=config n0, n - n0 :: {01} : {|$\cal T$\verb|};|% \kern1in(if $r = k - k0 + 1$) \par\noindent\kern0.5in{\tt[}{\it type}{\tt] incorporate [}{\it type}% {\tt] below [current] via sub10;} \par\noindent\kern0.5in{\tt via extension [}{\it type}{\tt.}{\it config list}% {\tt] implies}\kern5pt\lconfigs{\tt;} \par\noindent\kern0.5in{\tt classification of }\mconfig{\tt:}\kern5pt% \lconfigs{\tt;} \indexb{deduce} \begin{commanddeclaration} {\tt deduce }\mconfig\kern5pt{\tt= }% {\tt[}$\ell_1${\tt]}\kern5pt{\tt or}\kern5pt$\ldots$\kern5pt{\tt or}% \kern5pt{\tt[}$\ell_r${\tt];} \end{commanddeclaration} This is just like ``{\tt classification of}'', except that disjointness and nonemptyness are not checked. \block{Constraint generators and weight killers} The commands of this section use various methods to prove that certain constraints hold for the current configuration. Some also create other configurations, and create edges from the current configuration to these new ones. The current configuration is still current upon completion. When a command from this section shows that a basic local variable is nonzero, the current (parent) configuration is subdivided, and thus a new (child) configuration is created. A constructive edge is created from the parent configuration to the child configuration. To a very limited extent, constraints involving local variables are translated from the parent configuration to the child configuration. Specifically, any constraint of the form $v = 0$ ($v$ a basic local variable), which is known at the time the child configuration is created, gets passed to it, and is used to reduce the number of admissible basic local variables for the child configuration. \def\constraintor{$\hbox{\it constraint}_1, \ldots, \hbox{\it constraint\kern1pt}_r$} \def\constrainti{$\hbox{\it constraint\kern1pt}_i$} \indexb{show} \begin{commanddeclaration} {\tt show}\kern5pt\superopt{\it lp-specifier}\kern5pt\constraintor{\tt;} \end{commanddeclaration} The optional argument {\it lp-specifier\/} should be either ``{\tt(joint)}'' or ``{\tt(joint:}$r${\tt)}'', where $r \geq 0$. This command causes the program to attempt to simultaneously verify the given constraints by split linear programming (or joint linear programming, if the {\it lp-specifier} is present). In the joint case, if the second form of the {\it lp-specifier\/} is used, the parameter ``{\tt use dual dual for joint}'' is set to $r$ prior to executing the {\tt show}, and then restored to its original value afterwards. The order of the constraints is irrelevant; one may use separate ``{\tt show}'' commands if the verification of one constraint depends on knowledge of another. (This will be slower.) Assuming that verification succeeds, the constraints are then added to the list of constraints known for the current configuration. If verification fails, execution is terminated. Some short cuts are employed to avoid linear programming. First, if {\tt[current]} has up to equivalence exactly one admissible basic local variable $v$ aside from the trivial basic local variable, and the dimension of {\tt[current]} is less than the dimension of the code type, then a constraint of the form $v != 0$ will be accepted without split linear programming, since it is true. Second, suppose that every admissible local variable of weight $i$ except one (say $v$) is equivalent to the trivial basic local variable, and it is known that $y_i$ exceeds the number of words of weight $i$ in the basic code associated to the small code. Then $v != 0$ will be accepted without split linear programming. Third, suppose that there are $r$ words of weight $i$ in the basic code associated to the small code, and that every admissible basic local variable of weight $i$ is equivalent to the trivial basic local variable. Then the constraint {\tt y}$i$\verb| <= |$r$ will be accepted without split linear programming. (If $r = 0$, one can write ``\verb|=|'' instead of ``\verb|<=|''.) \indexb{check secondary residuals} \begin{commanddeclaration} {\tt check secondary residuals;} \end{commanddeclaration} Assume that the dimension of the code type is at least $3$. Let $d$ be the minimum distance, meaning the smallest nonzero element in the working weightlist for {\tt[current]}. For each $w$ in the basic code associated to the small code of {\tt[current]}, such that $d \leq \abs{w} < 2d$, consider the residual code $D$ \WRT\ $w$, which is a $\lambda = [n-\abs{w}, k-1, d - \floor{\abs{w}/2}]$ code. Let $v$ be a basic local variable for {\tt[current]}. Let $r$ be the residue of $v$ \WRT\ $w$. If a $\lambda$-code is known not to have a word of weight $r$, we can conclude immediately that $v = 0$. Otherwise, suppose that $d - \floor{\abs{w}/2} \leq r < 2(d - \floor{\abs{w}/2})$. Then the residual code $E$ of $D$ \WRT\ $v$ is a $[n-\abs{w}-r, k-2, d - \floor{\abs{w}/2} - \floor{r/2}]$ code. Supposing that codes with these parameters are known not to exist, conclude that $v = 0$. This is tested for all choices $v$ and $w$. If the parameter ``{\tt secondary plus}'' is set, the following procedure is also carried out. Let $v$ be a basic local variable for {\tt[current]} which survived the above test. Let \lconfig\ be the subdivision of {\tt[current]} along $v$. Form a list $L$ of all admissible basic local variables for \lconfig. Let $r$ be the number of parts in the partition of \lconfig. For each $w \in \F_2^r$, consider the subcode $S$ of $C$ supported on $w$, and the projection $P$ of $C$ onto the complement of $w$. Find all variables in $L$ supported on $S$, and use this to get a lower bound on the minimum distance of $S$. Then use known nonexistence results for codes with particular parameters to obtain an upper bound for $\dim(S)$. This gives a lower bound (say $k_P$) on $\dim(P)$. Again look through $L$ to get a lower bound $d_P$ on the minimum distance of $P$. Let $n_P$ denote the length of $P$. If we know that there is no $[n_P,k_P,d_P]$ code, we deduce that $v = 0$. The process of the preceding paragraph is carried out for each $v$, and in the event of a single success, it is repeated (over and over if need be). This is necessary in the interest of robustness, as otherwise the ordering of the basic local variables for {\tt[current]} could effect the outcome. Note also that in the interest of efficiency, we do not actually compute \lconfig, and instead work with a set of basic local variables for it which may include some inadmissible ones. \indexb{infer dual min $<$=} \begin{commanddeclaration} {\tt infer dual min <= $d'$;} \end{commanddeclaration} Attempt to infer that for the current configuration, the minimum weight of the dual code is no greater than $d'$. The attempt succeeds \IFF\ it is known that there is no $[n, n-k, d' + 1]$ code. \indexb{infer} \begin{commanddeclaration} $\displaystyle{\underbrace{\hbox{{\tt@}\lconfig}}_{\hbox{optional}}}$% \kern5pt{\tt infer}\ {\it constraint}{\tt;} \end{commanddeclaration} If {\tt@}\lconfig\ is used, first set the current configuration to \lconfig. Then use accumulated data on nonexistence of codes or configurations to deduce that {\it constraint\/} holds for the current configuration. Various methods of deduction are known to this program: \begin{itemize} \item Suppose that the constraint $\alpha \geq r$ is known for {\tt[current]}, for some variable $\alpha$ and some integer $r$, and that the configuration obtained from {\tt[current]} by adjoining the constraint $\alpha = r$ is known to be unrealizable. Then one may infer the constraint $\alpha \geq r + 1$. \item Suppose that the constraint $\alpha \leq r$ is known for {\tt[current]}, for some variable $\alpha$ and some integer $r$, and that the configuration obtained from {\tt[current]} by adjoining the constraint $\alpha = r$ is known to be unrealizable. Then one may infer the constraint $\alpha \leq r - 1$. A similar inference is possible when $\leq$ is replaced by $\geq$. \item Let $d' \in \N$. If the configuration $n-d'${\tt, }$d'$\verb| :: {01}| is known to be unrealizable, then one can infer \verb|mu|\kern1pt$d'\verb| = 0|$. \item If the configuration $i$\verb|,|\kern5pt$n-i$\verb| : {10}| is known to be unrealizable, then one can infer \verb|y|$i$\verb| = 0|. \item You can infer that $\verb|div2| \geq 2^{k-1}$. If you know that $\verb|div2| > 2^{k-1}$, then you can infer that $\verb|div2| = 2^k$. \item Let $S$ be the working weight list for the current configuration. Suppose that $S \IN 2\Z$. A result of Brouwer ([.brouwer linear programming bound.], IV, Proposition) gives us information about {\tt div4}. First, {\tt div4} must lie in the set $$2^{k-1} - 2^{k-2}, 2^{k-1} - 2^{k-3}, \ldots, 2^{k-1} - 2^0, 2^{k-1}, 2^{k-1} + 2^0, 2^{k-1} + 2^1, \ldots, 2^{k-1} + 2^{k-1}.$$% If we know that there is no $[n,k,S \cap 4\Z]$ code, then of course the last possibility may be ruled out. Further, if for some $r \leq k-1$ we know that there is no $[n,r,S \cap 4\Z]$ code, it follows that {\tt div4} must lie in the set $$2^{k-1} - 2^{r-1}, 2^{k-1} - 2^{r-2}, \ldots, 2^{k-1} - 2^0, 2^{k-1}, 2^{k-1} + 2^0, 2^{k-1} + 2^1, \ldots, 2^{k-1} + 2^{r-2}.$$% Any constraint whose \LHS\ is {\tt div4} and which follows from these restrictions (and/or from known constraints on {\tt div4}) may be inferred. \item If $\verb|div8| > 2^k - 2^{k-3}$, by a result of Brouwer one may infer that $\verb|div8| = 2^k$. \item Let the working weight list for the current configuration be (in order) $0, d_1, d_2, \ldots$. Suppose that $\sum_{i=0}^{k-1} \ceiling{d_2/2^i} > n$. Then by the Griesmer bound, one may infer the constraint $y_{d_1}$ {\tt != 0}. \item Let $v$ be a basic local variable for the current configuration. Suppose that subdividing along $v$ would yield a configuration which is known to be unrealizable. Then one may infer the constraint $v$\kern5pt{\tt = 0}. \item Let $v$ be a basic local variable for \verb|[current]|. Suppose there is a constructive edge \verb|[current]| $\rightarrow$ \lconfig, that $w$ is a basic local variable for \lconfig, and that $w$ pulls back to $v$. (This pull back is verbatim, and does not take into account equivalence of basic local variables.) Suppose that the constraint $w \geq r$ is known for \lconfig. Then one can infer the constraint $v \geq r$ for \verb|[current]|. \item For any $w$, {\tt sub}$w$ is a power of $2$. If the complement $\loW$ of $w$ lies in the dual small code, then $\log_2(\hbox{\tt sub}w) \geq n - \abs{v} + 1$. On the other hand, if we know that codes of a particular type do not exist, we get an inequality going the other way. Suppose $w$ lies in the small code and that by weight considerations, no nonzero word of the code can be properly contained in the basic word associated to $w$. Then one may infer that \verb|sub|$w = 2$. \item If \verb|sub|$w$\verb|_|$k \geq r$ is known (for some $w$, $k$, $r$), one may infer \verb|y|$k \geq r$. \end{itemize} \indexb{up to isomorphism show} \begin{commanddeclaration} {\tt up to isomorphism show}\kern5pt$v$\kern5pt{\tt != 0;} \end{commanddeclaration} Let $v$ be an admissible basic local variable. Consider its orbit under the automorphism group of {\tt[current]}. Use split linear programming to show that the sum of the variables in the orbit is nonzero. This implies that if $v$ is used to subdivide the current configuration, then all codes of the given type have the current configuration \IFF\ they have the new configuration. Therefore a {\it logical\/} link is created between the current configuration and the new configuration. The following special case is handled without linear programming. Suppose that the dimension of {\tt[current]} is less than the dimension of the code type. Suppose that under the action of the known automorphisms of {\tt[current]} on admissible basic local variables, there are exactly two orbits. Then if $v$ is any admissible basic local variable (that is not equivalent to the trivial basic local variable), no calculation is required. \indexb{projection onto} \begin{commanddeclaration} {\tt projection onto}\kern5pt$w$\kern5pt{\tt is}\kern5pt\clabel{\tt;} \end{commanddeclaration} Let $w$ be a small word, and let $\loW$ be its complement. The value $m$ of {\tt sub}$\loW$ must be known. Consider the projection $P$ of a code in ${\cal R}(\hbox{\tt current})$ onto the bits defined by the $1$'s in $w$. Let \clabel\ be a code type and suppose its length equals the weight of the basic word associated to $w$, it has dimension $k - \log_2(m)$, and it has no assumed constraints. Assume moreover that if $x_I$ is an admissible basic local variable for the current configuration, then $w \cdot I$ (dot product) lies in the assumed weight list of \clabel. If \clabel\ is known to be unrealizable, we conclude that {\tt[current]} is unrealizable. Otherwise, each known constraint for the base configuration of \clabel\ which involves only global variables is translated into a constraint for the current configuration, which is appended to the list of known constraints. This translation is accomplished by replacing each occurrence of $y_i$ by $1/m$ times the sum of all admissible basic local variables $x_I$ such that $w \cdot I = i$. \indexb{kill} \begin{commanddeclaration} {\tt kill}\kern5pt$v_1$\kern5pt% $\displaystyle{\overbrace{\hbox{by {\it local-variable-sequence}}_1}% ^{\hbox{optional}}}${\tt,}$\ldots${\tt,}\kern5pt$v_s$\kern5pt% $\displaystyle{\overbrace{\hbox{by {\it local-variable-sequence}}_s}% ^{\hbox{optional}}}${\tt;} \end{commanddeclaration} \par\noindent{\sc Syntax:}\ Let \czconfig\ denote the current configuration. Each $v_i$ is a basic global or basic local variable for \czconfig, or ``{\tt ndiv4}'', or ``{\tt ndiv8}''. Each $\hbox{\it local-variable-sequence}_i$ has the form \vspace{0.05in} \par\noindent\kern0.5in\verb|(|$w_1${\tt|}$\ldots${\tt|}$w_r$\verb|)| or \par\noindent\kern0.5in\verb|(|$w_1${\tt,}$\ldots${\tt,}$w_r$\verb|)| or \par\noindent\kern0.5in$w_1$ (equivalent to ``{\tt(}$w_1${\tt)}'') \vspace{0.05in} \par\noindent where $\VEC w1r$ are basic local variables for certain configurations described below. \vspace{0.05in}\par\noindent{\sc Goal:}\ By one or more subdivisions and applications of split linear programming, show in succession that $v_1 = 0, \ldots, v_s = 0$. \vspace{0.05in}\par\noindent{\sc Action:}\ There are six cases: \vspace{0.05in} \par\noindent\circno1\ $v_i$ is local and the ``{\tt by }$\ldots$'' is absent. Subdivide \czconfig\ along $v_i$ to obtain a configuration \coconfig. Use split linear programming to show that \coconfig\ is unrealizable. We first attempt to reduce the number of basic local variables as if via ``{\tt check secondary residuals}''. \vspace{0.05in} \par\noindent\circno2\ $v_i$ is global (say $= y_t$) and the ``{\tt by }$\ldots$'' is absent. Find all admissible basic local variables of weight $t$ and kill each of those as in case \circno1\kern2pt. \vspace{0.05in} \par\noindent\circno3\ $v_i$ is local and the ``{\tt by }$\ldots$'' is present, with $\hbox{\it local-variable-sequence}_i$ = \verb|(|$w_1${\tt|}$\ldots${\tt|}$w_r$\verb|)|. Let \config{c_1} be obtained by subdividing \czconfig\ along $v_i$. Let $w_1$ be a basic local variable for \config{c_1}. Show by split linear programming that $w_1 \not= 0$. Let \config{c_2} be obtained by subdividing \config{c_1} along $w_1$. If $r = 1$, use split linear programming to show that \config{c_2} is unrealizable. If $r > 1$, $w_2$ should be a basic local variable for \config{c_2}. One then shows by split linear programming that $w_2 \not= 0$, and continues as above, constructing configurations \config{c_3},$\ldots$,\config{c_{r+1}}. From the ultimate finding that \config{c_{r+1}} is unrealizable, one deduces that $v_i = 0$ for the current configuration. \vspace{0.05in} \par\noindent\circno4\ $v_i$ is local and the ``{\tt by }$\ldots$'' is present, with $\hbox{\it local-variable-sequence}_i$ = \verb|(|$w_1${\tt,}$\ldots${\tt,}$w_r$\verb|)|. Let \config{c_1} be obtained by subdividing \czconfig\ along $v_i$. Let $\VEC w1r$ be basic local variables for \config{c_1}. For $j = 1,\ldots,r$, show in succession by split linear programming that the configuration obtained from \config{c_1} by subdividing along $w_j$ is unrealizable. Then show by split linear programming that \config{c_1} is unrealizable. \vspace{0.05in} \par\noindent\circno5\ $v_i = \verb|ndiv4|$. Then we show that $\verb|div4| > {3\over4}2^k$ and deduce (via a theorem of Brouwer) that all words have doubly even weight. \vspace{0.05in} \par\noindent\circno6\ $v_i = \verb|ndiv8|$. Then we show that $\verb|div8| > {7\over8}2^k$ and deduce (via a theorem of Brouwer) that all words have weight divisible by $8$. The current configuration is restored to what it was prior to the command. \indexb{bound} \begin{commanddeclaration} {\tt bound}\kern5pt\superopt{\tt(joint)}\kern5pt\ttvec f1r{\tt;} \end{commanddeclaration} For each $i$, $f_i$ must have one of the following forms: \begin{itemize} \item a homogeneous $\Z$-linear combination of variables (but you can't have both local and joint variables in the same combination); \item {\tt y*}, which expands to the list of all basic global variables {\tt y}$i$ ($i > 0$) which are not known to be zero; \item {\tt x*}, which expands to the list of all nonzero minimal admissible basic local variables, modulo the action of $\Aut(\hbox{\tt[current]})$, if it can be computed; \item \verb|~x*|, same as {\tt x*}, but instead expand to the sums over the orbits of the {\tt x}'s, under the action of the configuration's automorphism group\footnote{For this, the assumed constraints of {\tt[current]} should not have any local variables in them.}; \item {\tt mu*}, which expands to {\tt mu1}, {\tt mu2}, $\ldots$; \item {\tt j*}, which expands to the list of all minimal basic joint variables; \item {\tt jyd*}, expands to the list of all variables of the form \verb|jy|$r$\verb|d|$s$; \item Any of the above, but enclosed in brackets ({\tt[}, {\tt]}). \end{itemize} This command gets numerical bounds on the given variables, \WRT\ the current configuration. If the bracket form is used, do not report anything unless the variable is found either to be zero or nonzero. (We use $10^{-6}$ as a threshold.) The the optional ``{\tt(joint)}'' is present, joint linear programming will be used instead of split linear programming. \par\noindent{\sc Note.}\ This is an exploratory command, and is not intended to prove anything. Do not rely on its results! The implementation of this command which runs with the ``{\tt homebrew}'' option on is tentative and provisional. It can be extremely slow, and is useless in situations where there are a small number of variables and a large number of constraints. \indexb{infer by residual code} \begin{commanddeclaration} {\tt infer by residual code }\cconfig\verb| that |$v_1$\verb| = 0,|% $\ldots$\verb|, |$v_r$\verb| = 0;| \end{commanddeclaration} \par\noindent{\sc Idea:} \ If $v_i$ is a basic local variable of weight $m$, and the residual code (of a code in the current code type) \WRT\ a word of weight $m$ has type \cconfig, then some word in the small code of \verb|[current]| may have a residue (\WRT\ $v_i$) of a weight which is known not to occur in \cconfig. Then one may infer that $v_i = 0$. \vspace{0.05in}\par\noindent{\sc Requirements:} \ Let $n_0$ be the length of the code type \cconfig. Each $v_i$ must be a basic local variable (for \verb|[current]|) of weight $n - n_0$. Let $d$ be the minimum weight in the working weight list of {\tt[current]}. It must be the case that $\abs{v_i} < 2d$. The code type \cconfig\ must have dimension exactly one less than the dimension of the current code type, and it may not have assumed constraints. The assumed weight list of \cconfig\ must contain all weights $\geq d - \abs{v_i}/2$. \vspace{0.05in}\par\noindent{\sc Action:} \ For each $i$, find a word in the small code of {\tt[current]} such that the associated basic word has residue (\WRT\ $v_i$) of weight not in the working weightlist of the base configuration of \cconfig. Infer $v_i = 0$ for {\tt[current]}. \indexb{load constraints by parity check from} \begin{commanddeclaration} {\tt load constraints by parity check from }\cconfig{\tt;} \end{commanddeclaration} \par\noindent{\sc Idea:} \ Any constraint on $[n,k,d]$ codes, where $d$ is even, induces a constraint on $[n-1,k,d-1]$ codes. \vspace{0.05in}\par\noindent{\sc Requirements:} \ The current code type should not have any assumed constraints, nor should the code type \cconfig. The current configuration should be the base configuration. The code type \cconfig\ should have the same dimension as the current code type, and should be exactly one bit longer. For each weight $w$ in the working weight list for the base configuration of the current code type, $w'$ must be in the assumed weight list for \cconfig, where $w'$ is obtained by rounding $w$ up to the nearest even integer. \vspace{0.05in}\par\noindent{\sc Action:} \ For each known constraint of the base configuration of \cconfig, a translated constraint is inferred for the base configuration of the current code type. This translation is accomplished by $$y_i\ \mapsto\ \cases{0,&if $i$ is odd;\cr y_0,&if $i = 0$;\cr y_{i-1} + y_i,&if $i$ is even and positive.}$$ If for $i$ even, $i$ is not in the working weight list for the base configuration of \cconfig, it is inferred that neither $i$ nor $i-1$ is in the working weight list for the base configuration of the current code type. \indexb{propagate} \begin{commanddeclaration} {\tt propagate} \constraintor{\tt;} \end{commanddeclaration} The given constraints may have only global variables in them. This command affects all configurations, and so for aesthetic reasons, we require that {\tt[current]} $=$ {\tt[base]}. For each $i = 1,\ldots,r$, proceed as follows. First determine all configurations for which \constrainti\ is known to hold. Then use known implications to deduce (if possible) that \constrainti\ holds for other configurations. \block{Other commands} \indexb{at} \begin{commanddeclaration} {\tt at}\kern5pt\superopt{type}\kern5pt\lconfig{\tt;} \end{commanddeclaration} If ``{\tt type}'' is present, reenter the code type \lconfig. Otherwise, set the current configuration to \lconfig. \indexb{help} \begin{commanddeclaration} {\tt help}\kern5pt{\it command name}{\tt;} \end{commanddeclaration} This command will only work if you have {\tt xdvi} installed. Search the LaTeX index file for the given command name. Then use {\tt xdvi} to open this document at the appropriate page. \indexb{status} \begin{commanddeclaration} {\tt status:}\kern5pt$\hbox{\it fact}_1, \ldots, \hbox{\it fact}_r${\tt;} \end{commanddeclaration} This command asserts certain facts about the base configuration. If the command is encountered while the program is in {\tt gullible} mode, these facts are accepted as true. This is particularly useful in connection with the {\tt tables only} parameter. We describe now the allowed fact types, and how they are treated if encountered when the program is not in {\tt gullible} mode. \begin{itemize} \item {\tt realizable} -- Check that the code type is known to be realizable. \item {\tt classified} -- Check that the codes in the realization of the code type have been classified up to isomorphism; this is established by the ``{\tt classification of}'' command. \item {\tt unique} -- Check that the code type has (up to isomorphism) exactly one realization. \item {\tt weights =}\kern5pt$w$ -- Here $w$ is formatted as with a list of weights for the type command. Let $\lambda$ be the working weight list of {\tt[base]}. If $w \notIN \lambda$, issue a warning. If $\lambda \notIN w$, issue a {\tt kill} command for the weights in $\lambda - w$, in descending order. If that doesn't work, use joint linear programming, with {\tt use dual dual for joint} = 0. If that doesn't work, try again with {\tt use dual dual for joint} = 5. \item {\tt enumerator =}\kern5pt{\it weight enumerator} -- Here the {\it weight enumerator\/} is to be the weight enumerator of all codes (if any) in the realization of the code type, e.g. $$\hbox{``\verb|1 + 190t^12 + 255t^16 + 66t^20|''}.$$% In this report, we display the exponents using superscripts. If the weight enumerator is not known to be {\it weight enumerator}, first try to kill (in descending order) any weights which have zero coefficient in {\it weight enumerator}. Then try to show that each of the nonzero coefficients are correct, as if via ``{\tt show}''. First use split linear programming, and if that doesn't work, use joint linear programming. \item \verb|constraints = {|$\VEC h1r$\verb|}| -- Check that the given constraints $\VEC h1r$ (involving only global variables) are known to hold for the base configuration. \end{itemize} \indexb{build web directory} \begin{commanddeclaration} {\tt build web directory for}\kern5pt$n_0$\kern5pt{\tt<= n <=}\kern5pt$n_1$% {\tt,}\kern5pt$k_0$\kern5pt{\tt<= k <=}\kern5pt$k_1${\tt;} \end{commanddeclaration} This is provisional implementation. For the given range of $[n,k]$, find the largest $d$ for which there might exist an $[n,k,d]$ code, and determine the weights which such a code might have. Put this in files in the {\tt web} directory. See that directory for instructions on how to set up a web site which provides this information. \indexb{alias} \begin{commanddeclaration} {\tt alias}\kern5pt{\it short-form}\kern5pt{\tt=}\kern5pt{\it long-form}{\tt;} \end{commanddeclaration} After using this command, any subsequently entered command starting with the string {\it short-form\/} will have that string replaced by {\it long-form}. \indexb{print} \begin{commanddeclaration} {\tt print}\kern5pt{\it print-item}{\tt;} \end{commanddeclaration} The allowed choices for {\it print-item\/} are given in the following table. We let $C$ denote the basic code associated to the small code of the current configuration. \def\dtext#1#2{\vbox{\hbox{\tt #1}\kern3pt\hbox{\tt #2}}} \def\dtextp#1#2{\vbox{\kern5pt\hbox{\tt #1}\kern3pt\hbox{\tt #2}}} \begin{center} \begin{tabular}{|l|l|}\hline {\bf print-item} & {\bf effect} \\ \hline\hline {\tt weight enumerator} & \parbox{4.2in}{\vskip 0.05in Print the weight enumerator of $C$. \vskip 0.05in}\\ \hline {\tt intersection weight enumerator} & \parbox{4.2in}{\vskip 0.05in Print the weight enumerator of $C \cap C^\perp$. \vskip 0.05in}\\ \hline {\tt joint weight enumerator} & \parbox{4.2in}{\vskip 0.05in Print the joint weight enumerator of $C$. This is printed in the nonhomogeneous asymmetric form wherein the coefficient of $b^i c^j d^k$ for $i \leq j$ gives the number of pairs of words of respective weights $i$ and $j$ which meet along $k$ bits. \vskip 0.05in}\\ \hline {\tt config} & \parbox{4.2in}{\vskip 0.05in Print some information about the current configuration. \vskip 0.05in}\\ \hline {\tt time used} & \parbox{4.2in}{\vskip 0.05in Print the total elapsed real time in minutes since execution started. \vskip 0.05in}\\ \hline {\tt basis} & \parbox{4.2in}{\vskip 0.05in Print a basis for $C$. \vskip 0.05in}\\ \hline {\tt reduced basis} & \parbox{4.2in}{\vskip 0.05in Remove duplicated columns from a generator matrix for $C$, and print it. \vskip 0.05in}\\ \hline {\tt dual basis} & \parbox{4.2in}{\vskip 0.05in Print a basis for $C^\perp$. \vskip 0.05in}\\ \hline {\tt intersection basis} & \parbox{4.2in}{\vskip 0.05in Print a basis for $C \cap C^\perp$. \vskip 0.05in}\\ \hline {\tt even subcode basis} & \parbox{4.2in}{\vskip 0.05in Print a basis for the subcode of $C$ consisting of all even words. \vskip 0.05in}\\ \hline {\tt variable classes} & \parbox{4.2in}{\vskip 0.05in List the equivalence classes of minimal admissible basic local variables, where the equivalence relation is induced by the automorphisms known for {\tt[current]}. \vskip 0.05in}\\ \hline {\tt variables of weight} $m$& \parbox{4.2in}{\vskip 0.05in List all admissible basic local variables of weight $m$. Equivalent variables are shown as such in the printout. \vskip 0.05in}\\ \hline {\tt codeword orbits}& \parbox{4.2in}{\vskip 0.05in Compute the orbits of the codewords (elements of small code) under the known automorphisms. \vskip 0.05in}\\ \hline {\tt punctured codes}& \parbox{4.2in}{\vskip 0.05in Classify up to isomorphism the codes which can be obtained by deleting a column from $C$. \vskip 0.05in}\\ \hline \dtext{projections onto}{words of weight $m$} & \parbox{4.2in}{\vskip 0.05in Classify, up to isomorphism, the codes obtained by projecting onto a codeword of weight $m$. \vskip 0.05in}\\ \hline {\tt automorphism group}& \parbox{4.2in}{\vskip 0.05in Find and print generators for the automorphism group of the current configuration; declare these to be the known automorphisms. Also report the group size. For this print-item, {\tt[current]} may not have local variables in its assumed constraints. \vskip 0.05in}\\ \hline \end{tabular} \end{center} \indexb{!config} \begin{commanddeclaration} {\tt!config} $\ldots$ {\tt;} \end{commanddeclaration} This is expanded out to: \par\noindent\kern0.5in{\tt config} $\ldots$ {\tt;} \par\noindent\kern0.5in{\tt via lp [current] = ;} \indexb{no} \begin{commanddeclaration} {\tt no [}\kern3pt$n${\tt,}\kern4pt$k${\tt,}\kern4pt$d$\kern3pt{\tt];} \end{commanddeclaration} This command implements approximately the procedure described in \S\ref{canned-section} for showing that there is no $[n,k,d]$ code. Here we describe some technical details and differences between what we actually do and what was described in \S\ref{canned-section}. Not all of the differences are mentioned here, and it is (at this point) necessary to refer to the code to see exactly what is done. The parameter $d$ may either be an integer, or else it may have the form $s$\verb|_4|, in which case attention is restricted to doubly even codes. In the second stage, when we attempt to show that there is no word of weight $i$ by split linear programming, we proceed as if via the command ``{\tt kill y}$i$'', except that code equivalent to ``{\tt check secondary residuals}'' is used in executing the {\tt kill} if $k \leq n/2$. In the third stage, when we try to show that there is no dual word of weight $i$, we do this by trying to show that the configuration ``$n-i${\tt, }$i$\verb| : { } : {01}|'' gives a contradiction by split linear programming. A more intensive attempt to prove the nonexistence of $[n,k,d]$ codes may be invoked by using a larger value for the {\tt allowed failures} parameter. (The default is $2$.) For all of the linear programming calculations, if $k > n/2$, we convert the problem to a problem about the dual code, and work with that instead, because it is numerically more stable. The code type is left undefined at the completion of the command. \indexb{test} \begin{commanddeclaration} {\tt test [}\kern3pt$n${\tt,}\kern4pt$k${\tt,}\kern4pt$d$\kern3pt{\tt];} \end{commanddeclaration} This exploratory command proceeds as with ``{\tt no [}\kern3pt$n${\tt,}\kern4pt$k${\tt,}\kern4pt$d$\kern3pt{\tt];}'' but interprets the outcome differently. If ``{\tt no}'' would succeed, issue a warning message. Otherwise, take no action. Also, the command is treated as a null command if it is not known that there is no $[n-1,k,d]$ command. In any case, the code type is left undefined upon completion. \indexb{test yes} \begin{commanddeclaration} {\tt test yes [}\kern3pt$n${\tt,}\kern4pt$k${\tt,}\kern4pt$d$\kern3pt{\tt];} \end{commanddeclaration} This exploratory command proceeds as with ``{\tt yes [}\kern3pt$n${\tt,}\kern4pt$k${\tt,}\kern4pt$d$\kern3pt{\tt];}'' but interprets the outcome differently. If ``{\tt yes}'' would succeed, issue a warning message. Otherwise, take no action. The code type is left undefined upon completion. \indexb{yes} \begin{commanddeclaration} {\tt yes [}\kern3pt$n${\tt,}\kern4pt$k${\tt,}\kern4pt$d$\kern3pt{\tt];} \end{commanddeclaration} This command implements a primitive facility for showing that an $[n,k,d]$ code exists. All it will do is use known results together with the following rules of inference: \def\existsk{\exists\kern1pt} \begin{itemize} \item $\existsk [n,n,1]$ \item $\existsk [n,k,d]$, $d$ odd $\Longrightarrow \existsk [n+1,k,d+1]$ \item $\existsk [n,k,d] \Longrightarrow \existsk [n-a,k-b,d-\max(a-b,0)]$ for all $a \in \Z$ and all $b \geq 0$ \item $\existsk [n_1,k,d_1], [n_2,k,d_2] \Longrightarrow \existsk [n_1 + n_2, k, d_1 + d_2]$ \item $\existsk [n,k_1,d_1], [n,k_2,d_2] \Longrightarrow \existsk [2n, k_1 + k_2, \min\setof{2d_1,d_2}]$ \item $\existsk [n,k,d] \Longrightarrow \existsk [n + 2^k, k + 1, \min( d + 2^{k-1}, 2^k )]$. \end{itemize} The next to the last rule comes from the ``$|u|u+v|$'' construction ([.macwilliams sloane book.]\ p. 76). The last rule comes from construction {\tt P} (see matrix-descriptor section). In fact, we only make partial use of these inferences, so some valid deductions may not be known to the command. \indexb{n =} \begin{commanddeclaration} {\tt n = $n$, k >= $k$: $I_k$, $I_{k+1}$, $\ldots$, $I_r$;} \end{commanddeclaration} \vspace{0.05in}\par\noindent{\sc Requirements:}\ One must have $r < n$. Each $I_k$ is to be $a${\tt-}$b$ (or an abbreviated form; see below), where $a \leq b$ are positive integers. The abbreviated forms are $b$ (abbreviating $b${\tt-}$b$), {\tt-}$b$ (abbreviating $1${\tt-}$b$), and $a${\tt-} (abbreviating $a${\tt-}$n$). \vspace{0.05in}\par\noindent{\sc Action:}\ For $i = 0, \ldots, r - k$ in succession, invoke the commands \par\noindent\kern1.5cm {\tt no [}\kern3pt$n${\tt,}\kern4pt$k+i${\tt,}\kern4pt$d_{k+i}+1$% \kern3pt{\tt];} and \par\noindent\kern1.5cm {\tt yes [}\kern3pt$n${\tt,}\kern4pt$k+i${\tt,}\kern4pt$d_{k+i}$% \kern3pt{\tt];}. \par\noindent Follow each of the above pairs for which $d_{k+i}$ is even with ``{\tt test [}\kern3pt$n${\tt,}\kern4pt$k+i${\tt,}\kern4pt$d_{k+i}$% \kern3pt{\tt];}'' and follow each pair with ``{\tt test yes [}\kern3pt$n${\tt,}\kern4pt$k+i${\tt,}\kern4pt$d_{k+i}+1$% \kern3pt{\tt];}''. Leave the code type undefined upon completion. \vspace{0.05in}\par\noindent{\sc Effect of parameters:}\ If the parameter ``{\tt optimal}'' is not set, the ``{\tt test}'' and ``{\tt test yes}'' commands will not be carried out. If the parameter ``{\tt lower bound check}'' is not set, the ``{\tt yes}'' and ``{\tt test yes}'' commands will not be carried out. The {\tt test mask} parameter may be used to restrict the scope of these tests. \indexb{set}\indexb{unset} \begin{commanddeclaration} \vbox{% \hbox{{\tt set}\kern5pt{\it parameter}\kern5pt$=$\kern5pt{\it value}{\tt;}}% \hbox{{\tt set}\kern5pt{\it parameter}{\tt;}}% \hbox{{\tt unset}\kern5pt{\it parameter}{\tt;}}} \end{commanddeclaration} The first form sets the given {\it parameter\/} to {\it value}. The second form sets it to $1$, and the third form sets it to $0$. The allowed parameters are shown below: \def\ttext#1#2#3{\vbox{\hbox{\tt #1}\kern3pt\hbox{\tt #2}\kern3pt\hbox{\tt #3}}} \def\ttextp#1#2#3{\vbox{\kern5pt\hbox{\tt #1}\kern3pt\hbox{\tt #2}\kern3pt% \hbox{\tt #3}}} \def\ftext#1#2#3#4{\vbox{\hbox{\tt #1}\kern3pt\hbox{\tt #2}\kern3pt% \hbox{\tt #3}\kern3pt\hbox{\tt #4}}} \def\parwa{3.3in} \begin{center} \begin{longtable}{|l|l|l|l|}\hline \parbox{1.6in}{\bf parameter} & \parbox{1.0in}{\vskip 0.05in {\bf allowed}\\ {\bf values}\vskip 0.05in } & {\bf default} & \parbox{\parwa}{\bf meaning} \\ \hline\hline \endhead {\tt secondary echo} & $0$, $1$ & $1$ & \parbox{\parwa}{\vskip 0.05in If set to $0$, and a command (e.g.\ {\tt n=}) causes other commands to be executed, they will not be echoed to standard output\vskip 0.05in}\\ \hline {\tt optimal} & $0$, $1$ & $0$ & See ``{\tt n=}'' command.\\ \hline {\tt warnings are fatal} & $0$, $1$ & $0$ & \parbox{\parwa}{\vskip 0.05in If set to $0$, recoverable errors will not be regarded as fatal. Use with caution.\vskip 0.05in}\\ \hline {\tt gullible} & $0$, $1$ & $0$ & \parbox{\parwa}{\vskip 0.05in If set to $1$, commands that follow are accepted without verification. This facilitates incremental verification of results.\vskip 0.05in}\\ \hline {\tt gullible commands} & \vbox{\hbox{\tt list of}\kern3pt\hbox{\tt strings}} & {\tt null} & \parbox{\parwa}{\vskip 0.05in Those commands which start with one of the given strings are executed in gullible mode. Thus one might use ``{\tt set gullible commands = no}'' or ``{\tt set gullible commands = via ext, via build}''. \vskip 0.05in}\\ \hline \vbox{\hbox{\tt show terminals}\kern3pt\hbox{\tt only}} & $0$, $1$ & $1$ & \parbox{\parwa}{\vskip 0.05in If set to $0$, when a ``{\tt via building}'' command is invoked, all configurations (and not just terminal ones) will be printed out as they are encountered. \vskip 0.05in}\\ \hline {\tt allowed failures} & $\geq 1$ & $2$ & \parbox{\parwa}{\vskip 0.05in If set to a number $> 2$, certain steps in the {\tt no} command are allowed to fail more than twice. This is an exploratory feature. \vskip 0.05in}\\ \hline {\tt sort} & $0$, $1$ & $1$ & \parbox{\parwa}{\vskip 0.05in If set to $0$, the constraints generated by split linear programming will not be piped through a unique sort. \vskip 0.05in}\\ \hline {\tt secondary plus} & $0$, $1$ & $0$ & \parbox{\parwa}{\vskip 0.05in See the ``{\tt check secondary residuals}'' command. This option indirectly affects the ``{\tt kill}'', ``{\tt no}'', and ``{\tt test}'' commands. \vskip 0.05in}\\ \hline {\tt auto macaulay} & $0$, $1$ & $0$ & \parbox{\parwa}{\vskip 0.05in If set to $1$, terminal configurations found by the ``{\tt via building}'' command will be piped to the {\tt macaulay} command. \vskip 0.05in}\\ \hline {\tt auto round} & $0$, $1$ & $0$ & \parbox{\parwa}{\vskip 0.05in If set to $1$, automatically invoke the command {\tt round local variables} prior to attempting to prove infeasibility by split linear programming. For experimental use only. In the current version, CPLEX will be used, and so this option will only have an effect if ${n \choose k}$ is small enough to allow CPLEX to be invoked reliably. \vskip 0.05in}\\ \hline {\tt depth first } & $0$, $1$ & $0$ & \parbox{\parwa}{\vskip 0.05in If set to $1$, the ``{\tt via building}'' command will always process the highest dimensional outstanding configuration first. This conceivably could be useful for finding examples. \vskip 0.05in}\\ \hline {\tt tables only } & $0$, $1$ & $0$ & \parbox{\parwa}{\vskip 0.05in If set to $1$, only {\tt n=}, {\tt no}, {\tt yes}, {\tt type}, {\tt status}, {\tt set}, {\tt unset}, and {\tt exit} commands will be executed; {\tt no}, {\tt yes}, and {\tt status} commands will be executed in the gullible mode. This option can be used to test just the tables defined by the {\tt n=} command. To use it, be sure that each calculation which proves the (non)existence of a code type or limits its weights is followed by an appropriate ``{\tt no}'' or ``{\tt status}'' command. \vskip 0.05in}\\ \hline {\tt homebrew} & $0$, $1$ & $0$ & \parbox{\parwa}{\vskip 0.05in If set to $1$, a preliminary built-in simplex routine will be used for proofs. Independent of whether this parameter is set, the built-in routine will automatically be used if ${n \choose k} > 3 \times 10^{18}$. \vskip 0.05in}\\ \hline \dtext{homebrew full}{report} & $0$, $1$ & $0$ & \parbox{\parwa}{\vskip 0.05in If set to $1$, and {\tt homebrew} is set, it will print out simplex iterations in excruciating detail. For debugging and optimization. \vskip 0.05in}\\ \hline {\tt quad} & $0$, $1$ & $0$ & \parbox{\parwa}{\vskip 0.05in If set to $1$, the built-in simplex routine (see {\tt homebrew} option) will use quad precision arithmetic. It may do so anyway if warranted. \vskip 0.05in}\\ \hline \dtext{refactorization}{rate} & $\geq 0$ & $0$ & \parbox{\parwa}{\vskip 0.05in If set to a positive value $r$, the basis matrix for the simplex method will be refactored every $r$ iterations. \vskip 0.05in}\\ \hline {\tt quiet build} & $0$, $1$ & $1$ & \parbox{\parwa}{\vskip 0.05in If set to $0$, the ``{\tt via building}'' command will issue various informative messages. \vskip 0.05in}\\ \hline \dtext{dual constraint}{bound} & $\geq 0$ & $0$ & \parbox{\parwa}{\vskip 0.05in If set to a positive value $r$, only constraints corresponding to wordtypes whose first part is $\leq r$ will be used in split linear programming. This condition is obviously tentative, but can tremendously speed up execution. \vskip 0.05in}\\ \hline \dtext{dcb depth}{limit} & $\geq 0$ & $0$ & \parbox{\parwa}{\vskip 0.05in If set to a positive value $r$, the ``{\tt dual constraint bound}'' restriction will only apply to configurations whose partitions have length $\leq r$. \vskip 0.05in}\\ \hline \ttextp{alternate}{extension}{method} & $0$, $1$ & $0$ & \parbox{\parwa}{\vskip 0.05in If set to $1$, an alternate (conceivably faster) method will be used by the ``{\tt via extension}'' command. \vskip 0.05in}\\ \hline \dtext{auto group}{computation} & $0$, $1$ & $0$ & \parbox{\parwa}{\vskip 0.05in If set to $1$, when a ``{\tt config}'' command is encountered (having no local variables in its assumed constraints), automatically compute the automorphism group of the configuration, and associate generators for the group to the configuration, as if via the ``{\tt automorphism}'' command. \vskip 0.05in}\\ \hline {\tt smart dual} & $0$, $1$ & $0$ & \parbox{\parwa}{\vskip 0.05in If set to $1$, every split linear programming calculation will include certain constraints of the form \verb|z\_|$a_1$\verb|\_|$\ldots$\verb|\_|$a_r <= 1$, when $\sum_{i=1}^r 2\min(a_i, p_i - a_i)$ is less than the known lower bound for the minimum distance of the dual code. (Here $(\VEC p1r)$ is the partition of the configuration.) \vskip 0.05in}\\ \hline {\tt silent} & $0$, $1$ & $0$ & \parbox{\parwa}{\vskip 0.05in If set to $1$, most output will be suppressed. \vskip 0.05in}\\ \hline \dtext{limited secondary}{kill} & $0$, $1$ & $0$ & \parbox{\parwa}{\vskip 0.05in If set to $1$, when the {\tt no} command is executed, and $k < n/2$, and an attempt to prove $\verb|y|_i = 0$ by split linear programming fails, try again, but this time first try to kill those basic local variables for the configuration $i,n-i$ {\tt:}\kern6pt{\tt\{10\}} (or $i$ {\tt:}\kern6pt{\tt\{1\}} if $i = n$) which have only one nonzero component (e.g.\ \verb|x\_12\_0|). \vskip 0.05in}\\ \hline \dtextp{full secondary}{kill} & $0$, $1$ & $0$ & \parbox{\parwa}{\vskip 0.05in Same as {\tt limited secondary kill}, but tries to kill all basic local variables. \vskip 0.05in}\\ \hline \vbox{\hbox{\tt secondary kill}\kern3pt\hbox{\tt maxvars}} & $\geq 0$ & $0$ & \parbox{\parwa}{\vskip 0.05in If positive, {\tt limited secondary kill} and {\tt full secondary kill} will only be applied in situations where one has $\leq$ the given number of basic local variables. \vskip 0.05in}\\ \hline {\tt test mask} & \vbox{\hbox{\tt a list of}\kern3pt\hbox{\tt constraints}} & null & \parbox{\parwa}{\vskip 0.05in The given linear constraints may involve only the variables $n$, $k$, and $d$. Whenever a {\tt test [n,k,d]} command is encountered, the constraints are checked, and if one fails, the {\tt test} command is ignored. \vskip 0.05in}\\ \hline {\tt lower bound check} & $0$, $1$ & $1$ & \parbox{\parwa}{\vskip 0.05in See the {\tt n=} command. \vskip 0.05in}\\ \hline {\tt homebrew speedy} & $0$, $1$ & $1$ & \parbox{\parwa}{\vskip 0.05in If set to $0$, when doing homebrew simplex calculations, do some extra error checking. Slower but safer. \vskip 0.05in}\\ \hline {\tt show variables} & $0$, $1$ & $0$ & \parbox{\parwa}{\vskip 0.05in If set to $1$, when computing the list of admissible basic local variables for the current configuration, print them out as found. \vskip 0.05in}\\ \hline {\tt doubly even test} & $0$, $1$ & $0$ & \parbox{\parwa}{\vskip 0.05in If set to $1$, whenever a ``{\tt test[n,k,d]}'' command is invoked, only process it if $4 \mid d$, and instead check for the existence of a doubly even $[n,k,d]$ code. Even so, do nothing is nonexistence follows immediately from known results. \vskip 0.05in}\\ \hline {\tt fill weight} & $\geq 0$ & $0$ & \parbox{\parwa}{\vskip 0.05in If set to a nonzero value $w$, and {\tt[current]} has less words of weight $w$ than the known lower bound for $y_w$, ignore configurations that have not achieved this lower bound and do not increase the number of words of weight $w$. \vskip 0.05in}\\ \hline \dtext{show config}{creation} & $0$, $1$ & $1$ & \parbox{\parwa}{\vskip 0.05in If set to $0$, do not automatically subdivide when a variable is found to be nonzero by a show command. \vskip 0.05in}\\ \hline \dtext{auto joint}{search} & $\geq 0$ & $0$ & \parbox{\parwa}{\vskip 0.05in If set to a nonzero value $r$, do joint linear programming (to bound global variables) at the end of the execution of each {\tt no} (and {\tt test}) command, if the code type has not been shown unrealizable, provided that the number of minimal basic joint variables is $\leq r$. This option is exploratory. \vskip 0.05in}\\ \hline \dtext{auto joint}{test} & $\geq 0$ & $0$ & \parbox{\parwa}{\vskip 0.05in If set to a nonzero value $r$, at the end of the execution of each {\tt no} (and {\tt test}) command, if the code type has not been shown unrealizable, and if $r=1$ or the number of minimal basic joint variables is $\leq r$, attempt to show by joint linear programming that the code type is unrealizable. \vskip 0.05in}\\ \hline \dtext{use dual}{dual for joint} & $\geq 0$ & $0$ & \parbox{\parwa}{\vskip 0.05in If set to a positive value $r$, when doing joint linear programming, also use the constraints arising from the fact that the coefficients of the joint weight enumerator of $C^\perp$ with itself are nonnegative, but use only those constraints coming from dual words of weight $\leq r + {\tt dl}$, where {\tt dl} is the known lower bound for the minimum weight of the dual code. \vskip 0.05in}\\ \hline \dtext{no test}{if classified} & $0$, $1$ & $0$ & \parbox{\parwa}{\vskip 0.05in If set to $1$, do not run the {\tt test} command on code types which have been classified or for which the weight enumerator is known, because of a ``{\tt status: enumerator = } $\ldots$'' command. \vskip 0.05in}\\ \hline {\tt partial pricing} & $\geq 0$ & $50$ & \parbox{\parwa}{\vskip 0.05in If set to a nonzero value $r$, when using the homebrew simplex method, do {\it partial pricing}, by (roughly) only looking at $r$ candidates for an entering variable. \vskip 0.05in}\\ \hline {\tt iteration limit} & $\geq 1000$ & $50000$ & \parbox{\parwa}{\vskip 0.05in Set the maximum number of iterations attempted by the simplex algorithm before giving up. \vskip 0.05in}\\ \hline {\tt auto mu1} & $0$, $1$ & $0$ & \parbox{\parwa}{\vskip 0.05in If set to $1$, whenever a {\tt type} command with no assumed constraints or options is encountered, say (in effect) ``{\tt type[}$n${\tt,}$k$\verb|,\{|$d,\ldots$\verb|\}];|'', first (in effect) execute the command ``{\tt no [}$n-1${\tt,}$k${\tt,}$d${\tt]}''. \vskip 0.05in}\\ \hline {\tt debug} & $0$, $1$ & $0$ & \parbox{\parwa}{\vskip 0.05in If set to $1$, do extra checks for internal errors. \vskip 0.05in}\\ \hline {\tt gullible silent} & $0$, $1$ & $0$ & \parbox{\parwa}{\vskip 0.05in If set to $1$, do not display commands which are executed in {\tt gullible} mode. \vskip 0.05in}\\ \hline \dtext{residual check}{for kill} & $0$, $1$ & $0$ & \parbox{\parwa}{\vskip 0.05in If set to $1$, when executing {\tt no} and {\tt test} commands with the {\tt limited secondary kill} or {\tt full secondary kill} options turned on, do some addtional checking, as if via the ``{\tt check secondary residuals}'' command. Very slow at present. \vskip 0.05in}\\ \hline {\tt auto projection} & $0$, $1$ & $0$ & \parbox{\parwa}{\vskip 0.05in If set to $1$, when doing split linear programming, automatically adjoin certain constraints coming from the known constraints of residual codes. (These are printed out as they are adjoined.) \vskip 0.05in}\\ \hline {\tt save bounds} & $0,1$ & $0$ & \parbox{\parwa}{\vskip 0.05in If set to $1$, at the end of each ``{\tt test}'' command, assume that the bounds on global variables arising from the {\tt auto joint search} option are correct, and save them. Because these numerical results are not verified, incorrect bounds may be saved! This experimental option is conceivably useful in connection with the ``{\tt auto projection}'' option. \vskip 0.05in}\\ \hline \dtext{generate}{noneven bounds} & $\geq 0$ & $0$ & \parbox{\parwa}{\vskip 0.05in If set to a nonzero value $r$, at the end of each ``{\tt test}'' command, proceed as if with {\tt save bounds}, but work with all codes, not just even ones. Use the given parameter $r$ in place of {\tt auto joint search}. \vskip 0.05in}\\ \hline \dtext{price}{refinement count} & $\geq 0$ & $1$ & \parbox{\parwa}{\vskip 0.05in Set the number of times which the homebrew simplex calculator refines the price vector. This choice will presumably be automated in a later version. \vskip 0.05in}\\ \hline \dtext{auto dual}{transform} & $0$, $1$ & $0$ & \parbox{\parwa}{\vskip 0.05in If set to $1$, when a {\tt config} command is encountered (or when some other command is encountered which invokes a {\tt config} command, such as {\tt cyclic}), and if the dimension of the configuration is the same as that of the code type, do a search for dual transform codes from the code defined by the configuration. (See \S\ref{matrix-descriptor-section} for the definition of dual transform.) \vskip 0.05in}\\ \hline \dtext{auto transform}{depth} & $\geq 0$ & $0$ & \parbox{\parwa}{\vskip 0.05in Let $r$ be the given value. When invoking the ``{\tt auto dual transform }'' option, sort codewords into piles according to their weight and according to how they meet $r$ fixed bits. All possible choices of $r$ bits (up to isomorphism) will be cycled over, except that we quit after ``{\tt tuple orbit max}'' choices. \vskip 0.05in}\\ \hline {\tt tuple orbit max} & $\geq 1$ & $5$ & \parbox{\parwa}{\vskip 0.05in See ``{\tt auto transform depth}''. \vskip 0.05in}\\ \hline {\tt nzv length max} & $\geq 1$ & $18$ & \parbox{\parwa}{\vskip 0.05in This governs the extent of the code search carried out when the ``{\tt auto dual transform }'' or ``{\tt auto orbit transform}'' option is invoked. \vskip 0.05in}\\ \hline {\tt nzv length max2} & $\geq 0$ & $0$ & \parbox{\parwa}{\vskip 0.05in If set to a positive value, this causes ``{\tt auto dual transform }'' to carry out a second tier of searches, when a code within ``{\tt transform pass level}'' of the best $d$ is found. \vskip 0.05in}\\ \hline \dtext{transform}{pass level} & $\geq 0$ & $5$ & \parbox{\parwa}{\vskip 0.05in See ``{\tt nzv length max2}''. \vskip 0.05in}\\ \hline \dtext{dual transform}{length limit} & $\geq 1$ & $255$ & \parbox{\parwa}{\vskip 0.05in When using the ``{\tt auto dual transform}'' option, only look for codes of length at most the given value. \vskip 0.05in}\\ \hline \dtext{dual transform}{dim low} & $\geq 1$ & $1$ & \parbox{\parwa}{\vskip 0.05in When using the ``{\tt auto dual transform}'' option, only look for codes of dimension at least the given value. \vskip 0.05in}\\ \hline \dtext{dual transform}{dim high} & $\geq 1$ & $1000$ & \parbox{\parwa}{\vskip 0.05in When using the ``{\tt auto dual transform}'' option, only look for codes of dimension at most the given value. \vskip 0.05in}\\ \hline \dtext{auto orbit}{transform} & $0$, $1$ & $0$ & \parbox{\parwa}{\vskip 0.05in Like ``{\tt auto dual transform}'', but looks for ``{\tt dual orbit}'' codes instead. \vskip 0.05in}\\ \hline \dtext{auto dual}{column deletion} & $0$, $1$, $2$ & $0$ & \parbox{\parwa}{\vskip 0.05in If set to $1$, when using the ``{\tt auto dual transform}'' or ``{\tt auto orbit transform}'' option, also try deleting columns from the generator matrix of the code defined by the {\tt config} command. If set to $2$, only do this. \vskip 0.05in}\\ \hline \dtext{matrix isomorphism}{silent} & $0$, $1$ & $1$ & \parbox{\parwa}{\vskip 0.05in If set to $1$, the isomorphism and automorphism routines for matrices (except in trivial cases) print some information. \vskip 0.05in}\\ \hline {\tt auto joint list} & $0$, $1$ & $1$ & \parbox{\parwa}{\vskip 0.05in If set to $0$, do not automatically compute a list of joint variables for each code type. \vskip 0.05in}\\ \hline \dtext{double}{column pairs} & $0$, $1$ & $0$ & \parbox{\parwa}{\vskip 0.05in If set to $1$, {\tt auto dual transform} will consider doubling pairs of columns when this may lead to a good code. \vskip 0.05in}\\ \hline \dtext{double}{column triples} & $0$, $1$ & $0$ & \parbox{\parwa}{\vskip 0.05in If set to $1$, {\tt auto dual transform} will consider doubling triples of columns when this may lead to a good code. Unusably slow. \vskip 0.05in}\\ \hline \dtext{double}{column groups} & $0$, $1$ & $0$ & \parbox{\parwa}{\vskip 0.05in If set to $1$, {\tt auto dual transform} will consider doubling groups of columns when this may lead to a good code. \vskip 0.05in}\\ \hline {\tt show even if known} & $0$, $1$ & $0$ & \parbox{\parwa}{\vskip 0.05in If set to $1$, when a new code is generated which has optimal parameters, show it even if it is isomorphic to a known code. \vskip 0.05in}\\ \hline \dtext{starting}{tuple orbit} & $\geq 1$ & $1$ & \parbox{\parwa}{\vskip 0.05in The {\tt auto dual transform} command will start with the indicated tuple orbit, and then reset the parameter to $1$. \vskip 0.05in}\\ \hline {\tt set ring} & F2 & F2 & \parbox{\parwa}{\vskip 0.05in This is a dummy parameter, to allow for compatibility with future versions in which codes over rings other than $\F_2$ will be allowed. \vskip 0.05in}\\ \hline \end{longtable} \end{center} \indexb{try to kill} \begin{commanddeclaration} {\tt try to kill}\kern5pt{\it variable-list}{\tt;} \end{commanddeclaration} This is an exploratory command, whose behavior depends on the parameter {\it variable-list}. The currently allowed possibilities are ``{\tt x*}'' and ``{\tt jy*}''. In case the parameter is {\tt x*}, the goal is to find a proof that {\tt [current]} is unrealizable. First try split linear programming. Then make a list of all nontrivial minimal admissible basic local variables for {\tt [current]}. For each such variable $v$, compute the number $\varphi(v)$ of minimal admissible basic local variables in the subdivision of {\tt [current]} along $v$. Put the nontrivial basic local variables for {\tt [current]} in increasing order according to the values taken by $\varphi$. One-by-one, attempt to show (as in ``{\tt kill} $v$'') that each of these variables $v$ is $0$. Whenever a success occurs, try split linear programming again on {\tt [current]}. Note that successes may cause the number of basic local variables in the subdivisions to decrease. In case the parameter is {\tt jy*}, to each joint variable, associate the corresponding configuration (usually two-dimensional), and try to kill it by split linear programming. In this way accumulate known facts about joint variables (that some are zero) for the base configuration. \indexb{isomorphic} \begin{commanddeclaration} {\tt isomorphic}\kern5pt\coconfig{\tt, }\ctconfig{\tt;} \end{commanddeclaration} This exploratory command will determine if configurations \coconfig\ and \ctconfig\ are isomorphic. \indexb{(* ... *)} \begin{commanddeclaration} {\tt (* ... *);} \end{commanddeclaration} Comment. \indexb{random weight enumerator} \begin{commanddeclaration} {\tt random weight enumerator( n = }$n${\tt, k = }$k${\tt, div = }$d$ {\tt, modulus = }$m${\tt, count = }$c${\tt\ );} \end{commanddeclaration} The approximate function of this command is to find $c$ ``random'' codes of type $[n,k]$ and print out their weight enumerators. To explain more carefully what the command does, we have to explain the parameters $d$ and $m$. First, $d$ must be in \setof{1,4}, and if $d = 4$, we look only for ``random'' doubly even codes. Second, the weight enumerators are not literally printed out. Rather, for each code we print the list $$y_0 + y_m + y_{2m} + \cdots, y_1 + y_{m+1} + y_{2m+1} + \cdots, \ldots, y_{m-1} + y_{m+(m-1)} + y_{2m+(m-1)} + \cdots.$$% If you want the actual coefficients of the weight enumerator, use $m = n+1$. \indexb{dump} \begin{commanddeclaration} {\tt dump;} \end{commanddeclaration} Print information about all the configurations known for the current code type. \indexb{round local variables} \begin{commanddeclaration} {\tt round local variables;} \end{commanddeclaration} This is an exploratory command. First use floating point linear programming (without exact verification) to get bounds on all the admissible basic local variables. Whenever one of the bounds appears to not be an integer, adjoin and print a constraint corresponding to rounding the bound (up for lower bound, down for upper bound) to an integer. The output of this command could be modified slightly to create a {\tt show} command, which could then be tentatively included in a proof. \indexb{accept} \begin{commanddeclaration} {\tt accept} $\displaystyle{\underbrace{{\tt (tables\ only)}}_{\hbox{optional}}}$% \kern5pt{\it file}{\tt;} \end{commanddeclaration} Read in the given file of commands, as if in gullible mode, and do so as quietly as possible. If the {\tt(tables only)} option is included, only read in the following commands: {\tt n =}, {\tt no}, {\tt yes}, {\tt type}, {\tt status}, {\tt set lower bound check}, and {\tt unset lower bound check}. \indexb{go to} \begin{commanddeclaration} {\tt go to}\kern5pt{\it string\/}{\tt;} \end{commanddeclaration} The given {\it string\/} may be any character string which does not contain semicolons; white space is ignored. Read downward in the command file until a command which starts with {\it string\/} is encountered, and continue execution from there. \indexb{exit} \begin{commanddeclaration} {\tt exit;} \end{commanddeclaration} Terminate execution. \indexb{find cyclic codes} \begin{commanddeclaration} {\tt find}\kern5pt% $\displaystyle{\overbrace{\hbox{$r${\tt-}}}^{\hbox{optional}}}$% {\tt cyclic codes;} \end{commanddeclaration} If ``$r${\tt-}'' is omitted, $r$ is assumed to be $1$. It must be the case that $r|n$. Let $\sigma$ be the permutation of $n$ given by $x \mapsto x+r$. Consider all binary vectors $v$ of length $n$, having zeroes in (at least) the rightmost $k-1$ positions. If the code with basis $v,\sigma(v), \ldots,\sigma^{k-1}(v)$ realizes the code type, and has not (up to isomorphism) already been printed out, print it out, giving a definition for it using the ``{\tt cyclic}'' command. The codes generated by this command are not necessarily cyclic! \indexb{is cyclic?} \begin{commanddeclaration} {\tt is cyclic?}\kern5pt\superopt{\hbox{\tt(use extra)}}{\tt;} \end{commanddeclaration} The current configuration must be terminal. Determine if it could be described by a ``{\tt cyclic}'' command. If the ``{\tt(use extra)}'' is present, the {\it extra word\/} form of the ``{\tt cyclic}'' command is used; otherwise it is not. The implementation is horrible. \par\noindent{\sc Note.}\ The command will not in fact find all codes that could be described by the ``{\tt cyclic}'' command, because the permutation $\sigma$ defined by that command is not necessarily an automorphism of the code it generates, and the ``{\tt is cyclic?}'' command restricts attention to $\sigma$'s lying in the automorphism group of the code. \indexb{process} \begin{commanddeclaration} \verb|process |{\it matrix-descriptor}\verb|;| \end{commanddeclaration} Attempt to make good codes from the given matrix-descriptor, doubling or deleting columns if that helps. If the string ``\verb|@1|'' appears, it will be replaced by each code known to the program. If ``\verb|@2|'' also appears, it will be replaced by each code known to the program, and $\geq$ the code substituted for ``\verb|@1|'', \WRT\ some internal ordering scheme. \indexb{perturb} \begin{commanddeclaration} \verb|perturb |\lconfig{\tt;} \end{commanddeclaration} Let \lconfig\ be a terminal configuration. Let $M$ be the generator matrix for the associated basic code. Start a list $\cal L$ of matrices by putting $M$ in it. Perturb $M$ by replacing one of its columns by an arbitrary column, to yield $M'$. If the rowspace of $M'$ realizes the code type\footnote{Actually, we only check that $M'$ is consistent with the assumed weightlist of the code type.}, and $M'$ is not isomorphic to any matrix in $\cal L$, append $M'$ to $\cal L$. Continue doing this until $\cal L$ cannot be so enlarged. Print out the new matrices. \block{Experimental commands} The commands of this section are not guaranteed to do what they claim to do. \indexb{macaulay} \begin{commanddeclaration} {\tt macaulay;} \end{commanddeclaration} The current configuration must be terminal, and the associated code $C$ must not have any dual words of weight one or two. Then $C$ corresponds to a set $S$ of $n$ points in $\PP^{k-1}$. Use the program {\tt Macaulay} to find generators for the homogeneous ideal defining $S$, modulo the obvious generators of the form $a^2b + ab^2$, which are always present. To use this command, {\tt Macaulay} must be executable via a command of the same name. \indexb{random macaulay} \begin{commanddeclaration} {\tt random macaulay( n = }$n${\tt, k = }$k${\tt, minimum distance >= }$d$% {\tt, count = }$c${\tt\ );} \end{commanddeclaration} Find $c$ ``random'' projective codes of type $[n,k,d]$ and pipe the output to the {\tt macaulay} command. \indexb{clean} \begin{commanddeclaration} {\tt clean <}\kern5pt{\it input file\/}\kern5pt{\tt>}\kern5pt% {\it output file}\kern5pt% $\displaystyle{\underbrace{\hbox{{\tt(}$\VEC v1s${\tt)}}}% _{\hbox{optional}}}${\tt;} \end{commanddeclaration} The {\it input file\/} is to be a file of constraints. Read it in, try to simplify, and write the resulting system to {\it output file}. If the input file contains equality constraints, they will be used to eliminate variables, preferentially avoiding $\VEC v1s$ if they are present. Constraints in the input file should not have repeated variables in them. \block{Implementation notes}\label{implementation-section} The source code is written in the language C++. Although a standard for C++ is nearing completion [.C++ working paper.], implementations have naturally lagged behind, and thus the behavior of existing compilers varies. For this reason, at this time the source code will compile only under a single compiler, the GNU (Free Software Foundation) compiler, called {\tt g++}. We also use the GNU library {\tt libg++}. Fortunately, {\tt g++} and {\tt libg++} are freely available over the network and generally easy to install. This source code should compile and run on almost any Unix machine.% \footnote{If you want to use CPLEX, obviously you are restricted to those platforms for which it is available. Also, for unknown reasons, spurious segmentation faults occur under NeXTStep-Intel.} We would like to say exactly how much memory the program needs, but we do not know how to compute this at present. The results were obtained on a machine with $192$ megabytes of RAM and about $270$ megabytes of swap space; it is hard to say how much of this was really used by the program. Much can be done on a machine having only $32$ megabytes of RAM. As references both for the C++ language and the GNU implementation, we refer to Stroustrup's book [.stroustrup.], the libg++ manuals [.lea users guide.], [.bothner pesch.], [.regex manual.], and the help guides [.buck faq.], [.cline faq.]. Other relevant sources are [.stallman compiler manual.], [.C++ working paper.], and [.stepanov lee.]. We make use of Brendan McKay's graph isomorphism package {\tt nauty} and Keith Briggs double-double precision package {\tt quad}. For installation of the source code, we refer to the script ``{\tt INSTALL}''. It is not possible at present to compile a working TeX file for this document from the distribution. If all goes well, you can now execute with {\tt Split < prog}, where {\tt prog} is a program file. The author will be happy to assist if there are any problems! A primitive interactive mode may be entered with {\tt Split -i}. This automatically turns off the option ``warnings are fatal''. |-> prep # # Usage: "prep all" (for first compilation) or "prep" or "prep main" or e.g. # "prep simplex". # # The -O1 option causes some optimization which greatly speeds up # some parts of the program. Deleting it will however cut the compilation time # in half. The -s option reduces the size of the binary executable file. # # The -pipe option slightly speeds up compilation, but should be removed # for a machine which does not have lots of memory. # # To insure compatibility with other systems in which "char"s are by default # unsigned, it is advisable to test that the program will still compile when # the option "-funsigned-char" is used. if ($1 == "all") then gcc -c -O -DMAXN=1024 cc/nauty.c -Iinc gcc -c -O -DMAXN=1024 cc/nautil.c -Iinc g++ -c -O3 cc/quad.cc -Iinc mv nauty.o obj mv nautil.o obj mv quad.o obj endif if ($1 != "all" && $1 != "main" && $1 != "") goto component set objs = "" foreach i (permutation constraint matgf2 matreal simplex graph process \ wordtype split extensions codetable op execute1 execute2 config \ codehome opt mawhome prevec1 sort misc woof woof2) if ($1 != "main") then echo compiling $i.cc g++ -c cc/$i.cc -pipe -Iinc -I. -O1 -s -o obj/$i.o endif set objs = "$objs obj/$i.o" end echo "compiling main program" g++ cc/code.c $objs obj/nauty.o obj/nautil.o obj/quad.o -pipe -Iinc -I. -O1 \ -lm -o Split -s |& c++filt -sgnu exit component: g++ -c cc/$1.cc -pipe -Iinc -I. -O1 -s -o obj/$1.o |-> dprep # # Compiles demo --> DSplit. # gcc -c -O -DMAXN=1024 cc/nauty.c -Iinc gcc -c -O -DMAXN=1024 cc/nautil.c -Iinc g++ -c -O3 cc/quad.cc -Iinc mv nauty.o obj mv nautil.o obj mv quad.o obj set objs = "" foreach i (permutation constraint matgf2 matreal simplex graph process \ wordtype split extensions codetable op execute1 execute2 config \ codehome opt mawhome prevec1 sort misc woof woof2) if ($1 != "main") then echo compiling $i.cc g++ -c cc/$i.cc -DDEMO -pipe -Iinc -I. -O1 -s -o obj/$i.o endif set objs = "$objs obj/$i.o" end echo "compiling main program" g++ cc/code.c $objs obj/nauty.o obj/nautil.o obj/quad.o -DDEMO -pipe -Iinc \ -I. -O1 -lm -o DSplit -s |& c++filt -sgnu |-> tex/code.tex If you wish to modify the source code, note that there are several lines of the form \begin{verbatim} // #define DEBUG \end{verbatim} in {\tt CODE}. Deleting the first three characters from these lines will cause some extra internal error checking to be done. For instance, vector references will be checked to see if they are out of bounds. \midhead{Execution of the proofs in this report} I describe here a battery of tests for {\tt Split}, which are carried out (on my hardware) each time a new version of {\tt Split} is released, and which you can test on your hardware. For the steps which require a significant amount of execution time, I put the location of a log file and the running time.\footnote{The calculations were performed on a Sun Ultra 1 Model 140, with 192MB of RAM. For speed comparisons with other hardware, see {\tt http://open.specbench.org}. Note that since a test of this paper's results can be divided into several smaller computations, as via the ``{\tt set gullible}'' and ``{\tt unset gullible}'' commands, any program file can be executed in segments.} \vspace{0.1in} \par\noindent\circno1\ The file {\tt code.data1} is a {\tt Split} program file for the results which appear in [.jaffe optimal binary 30.]. You can execute these results with ``{\tt Split < code.data1}''. There is one line which takes a very long time to execute on my machine, and so I put a ``{\tt??}'' in front of it to circumvent its execution. \par\noindent[logfile: {\tt log/code.data1.out}; running time: 11 hours] \vspace{0.1in} \par\noindent\circno2\ Edit {\tt code.data1} as follows, to execute the line mentioned in \circno1\kern2pt. Put ``\verb|set gullible; set silent;|'' at the beginning. Before the key line, put ``\verb|unset gullible; unset silent;|''. This line has been properly carried out only once, using an unreleased version of {\tt Split} slightly preceding version 0.5. \par\noindent[logfile: {\tt log/code.data1.hard.out}; running time: 115 hours] \vspace{0.1in} \par\noindent\circno3\ To execute the results contained in this document, type ``{\tt Split < code.data}''. This will automatically accept (without proof) the results of [.jaffe optimal binary 30.]. \par\noindent[logfile: {\tt log/code.data.out}; running time: 46 hours] \vspace{0.1in} \par\noindent\circno4\ You might also wish to type ``{\tt Split -i}'' (interactive), and then enter ``{\tt accept code.data1;}'' followed by ``{\tt exit;}''. \vspace{0.1in} \par\noindent\circno5\ The command ``{\tt Split < code.misc.test}'' will test some exploratory commands (and miscellaneous strange things). \vspace{0.1in} \par\noindent\circno6\ Add the lines \begin{verbatim} set tables only; set optimal; set gullible commands = no, yes; \end{verbatim} to the beginning of {\tt code.data1} and again execute it. \par\noindent[logfile: {\tt log/code.data1.test.out}; running time: ??? hours] \vspace{0.1in} \par\noindent\circno7\ Add the same lines to the beginning of {\tt code.data} (after the {\tt accept} line), and again execute it. \par\noindent[logfile: {\tt log/code.data.test.out}; running time: 9 hours] \vspace{0.1in} \par\noindent\circno8\ Run {\tt Split} on {\tt web/script}. |-> code.misc.test type [12,4,6]; bound y*; show y6 != 0; bound y*, [x*] ; config 6,6 : {10}; show x24 != 0; config 2,4,4,2 : {1100,1010}; bound y*, [x*] ; set optimal; set lower bound check; n=3,k>=2:2; n=4,k>=2:2,2; n=5,k>=2:3,2,2; n=6,k>=2:4,3,2,2; n=7,k>=2:4,4,3,2,2; n=8, k >= 2: 5-5, 4, 4, 2, 2, 2; unset optimal; n=8, k >= 2: 5-5, 2-4, 4-, 2, 2, 2; set gullible; n=9,k>=2:6,4,4,3,2,2,2; n=10,k>=2:6,5,4,4,3,2,2,2; n=11,k>=2:7,6,5,4,4,3,2,2,2; n=12,k>=2:8,6,6,4,4,4,3,2,2,2; n=13,k>=2:8,7,6,5,4,4,4,3,2,2,2; n=14,k>=2:9,8,7,6,5,4,4,4,3,2,2,2; n=15,k>=2:10,8,8,7,6,5,4,4,4,3,2,2,2; n=16,k>=2:10,8,8,8,6,6,5,4,4,4,2,2,2,2; unset gullible; type [21,8,8_2]; [b] := {011110000011110000000,110010110001101000000,101011010010100100000, 100111100011000010000,111111111100000000000,000100011011100001100, 001001111001000001010,010011010011000001001} :: {y8 = 89, y10 = 41, y12 = 98, y14 = 22, y16 = 4, y18 = 1, y20 = 0}; is cyclic?; type [16,8,4]; [a] := cyclic {000100111} :: {y4 = 55, y6 = 96, y8 = 87, y10 = 16, y12 = 1}; full group size = 3456; print automorphism group; [woof] type [12,4,6]; find 2-cyclic codes; [a] config 6,6 :: {01} : {q_z_6 = 1}; bound q_z_4, q_6_z; type [16,7,6]; show mu4 != 0; [mu4] config 12,4 :: {01}; infer sub10 = 16; [woof] incorporate [woof] below [mu4] via sub10; dump; at [woof.a]; bound y*, [x*]; accept (tables only) code.data1; accept (tables only) code.data; type [24,7,10]; show mu1 = 0; print config;;print config;print config;printconfig; print time used; set homebrew; type [72,36,16_4]; bound y*, [x*]; (* Each line should look like y_i = nonnegative integer. *); random weight enumerator(n = 20, k = 8, div = 4, modulus = 8, count = 100); goto (*next*); This line does not get executed!; (* next *); type [3,1,2_2]; |-> tex/code.tex \block{Plans} As should be obvious, there are many ways in which the program could be improved. We list first some of the most obvious, with comments. \begin{itemize} \item The program could be revised to allow for an arbitrary finite base field (or ring). Although worthwhile, this is likely to be a stupendous project, as almost every aspect of the program would have to be revised. The author is interested in collaboratively pursuing this expansion with one or more other persons. A good first step would be to write just enough code to see if something new can be proved about ternary codes using split linear programming. \item We could include lower bound constructions as in Brouwer and Verhoeff [.brouwer verhoeff 1993.]. This version includes a few tentative steps in such a direction. \item Finish the included provisional implementation of the simplex algorithm and eliminate the use of CPLEX. It is not clear how hard this will be. \item Find new methods. For example, for partitions with two parts, can one use the split weight enumerator to get closed-form inequalities involving the variables $y_i$? \item Rationalize, restructure, and simplify the language and code so as to make it more readable. The importance of this should not be underestimated, as it is the readability of the code which governs the ability of other people to verify the correctness of the claims made in this report. \end{itemize} \midhead{Other projects} \par\noindent \circno1\ Simonis has pointed out that the automorphism group of a configuration can be used to reduce the size of the associated linear programming problem. Implementing this would have significant benefits. \vspace{0.1in} \par\noindent \circno2\ Within reason, convert to ``generic C++''. In particular, reduce reliance on the GNU C++ Library, and make use of the Standard Template Library (STL) where possible. Don't copy sort code from the GNU C++ Library. Use private member functions where appropriate. Do not use \verb|const_cast|. \vspace{0.1in} \par\noindent \circno3\ For codes whose dimension exceeds half their length, split linear programming problems should be automatically translated into problems about the dual code, because this greatly improves the numerical conditioning of the problem. This is at present done only for the {\tt no} and {\tt test} commands. \vspace{0.1in} \par\noindent \circno4\ At present we do a unique sort on the list of main constraints generated by the split linear programming method. In some cases this significantly reduces the length of the constraint file. Why? This is a rather fundamental question. Would it be better to turn off the sort most of the time? This is a minor practical question. \vspace{0.1in} \par\noindent \circno5\ The ``{\tt infer by residual code}'' command could (in effect) be invoked automatically on each admissible basic local variable. \vspace{0.1in} \par\noindent \circno6\ Unnamed configurations should not be saved when a code type is left, but to implement this one has to keep track of logical relationships which use unnamed intermediaries. \vspace{0.1in} \par\noindent \circno7\ Systematically propagate constraints. The current approach is haphazard and poorly documented. \vspace{0.1in} \par\noindent \circno8\ Clean up the god-awful messes necessitated by the compiler's flaky template instantiation. These have gotten worse and worse. \vspace{0.1in} \par\noindent \circno{9}\ Check the correctness of the two key routines {\tt Isomorphic} and \verb|find_automorphism_group| (for \verb|vertex_colored_graph|'s) which invoke {\tt nauty}. \vspace{0.1in} \par\noindent \circno{10}\ Use decent algorithms for working with permutation groups. \vspace{0.1in} \par\noindent \circno{11}\ Add the capability of subdividing along dual local ({\tt z}) variables. \midhead{Minor issues and proposed changes} \par\noindent \circno{A}\ Program output should be automatically folded to split long lines. \vspace{0.1in} \par\noindent \circno{B}\ Make it impossible to crash the program by entering anomalous commands. \vspace{0.1in} \par\noindent \circno{C}\ Investigate memory usage by the program. Some modest changes should substantially reduce memory usage. \vspace{0.1in} \par\noindent \circno{D}\ The {\tt bound} command will not print out values using the maximum available accuracy. To fix this, the class \verb|opt_card| should somehow allow for {\tt Quad} precision min and max. \vspace{0.1in} \par\noindent \circno{E}\ One could easily add a ``{\tt verify search}'' command to verify the assertion of the last {\tt search} command. \vspace{0.1in} \par\noindent \circno{F}\ Check for two {\tt Split} processes running concurrently in the same directory. This can cause strange results and should not be allowed. \vspace{0.1in} \par\noindent \circno{G}\ Add capability of computing weight enumerator of dual code of a full configuration. \vspace{0.1in} \par\noindent \circno{H}\ Main joint constraints should not be recomputed over and over. \vspace{0.1in} \par\noindent \circno{I}\ When you use ``{\tt bound (joint)}'', CPLEX is always used. \vspace{0.1in} \par\noindent \circno{J}\ Implement configuration-list versions of {\tt var variable split}, {\tt via varying}, {\tt realizable}, {\tt disjoint}, and {\tt deduce}. \vspace{0.1in} \par\noindent \circno{K}\ The infer command should allow multiple constraints. \vspace{0.1in} \par\noindent \circno{L}\ The following bug in {\tt libg++} has been reported to \verb|bug-lib-g++@prep.ai.mit.edu| (5/24/96), but no response has yet been received. This bug (until fixed) calls into question the reliability of all code which uses the ``{\tt contains}'' method. \begin{verbatim} // The following program prints 1. Shouldn't it print 0? #include #include main( ) { String swine = "y=5"; String op = "="; cout << swine.contains(Regex(op), 0) << "\n"; } \end{verbatim} \par\noindent Similarly, the following code prints 0: \begin{verbatim} #include #include main( ) { static Regex pound_config( "\\[[a-zA-Z_0-9]+#\\]" ); String commandx = "[x#]"; cerr << commandx.contains( pound_config, -1 ) << "\n"; } \end{verbatim} \par\noindent Another example: \begin{verbatim} #include #include main( ) { static Regex brack( "\\[" ); String s = "P([3_2_2.a])"; cerr << s.contains( brack, 0 ) << "\n"; cerr << s.contains( brack, 1 ) << "\n"; cerr << s.contains( brack, 2 ) << "\n"; cerr << s.contains( brack, 3 ) << "\n"; } \end{verbatim} \par\noindent The following bug has been reported to \verb|bug-g++@prep.ai.mit.edu| (7/19/96). The following code yields internal compiler error 9. It is suppose to be fixed in {\tt g++} version 2.8.0. \begin{verbatim} template class prevector { public: prevector( ) { } }; template class matrix { public: matrix(const prevector< prevector >&); }; template matrix::matrix( const prevector< prevector >& ); \end{verbatim} \par\noindent The following bug has been reported to \verb|bug-g++@prep.ai.mit.edu| (8/22/96). The following code yields internal compiler error $107$. \begin{verbatim} #include main( ) { static int noptions = 3; static Regex option_pats[noptions] = {"a", "b", "c"}; }; \end{verbatim} \par\noindent The following bug has only occurred under NeXTStep-Intel. Executing the following code results in a segmentation fault. \begin{verbatim} ??no [17,9,6]; type [18,9,6]; config 17,1 : { }; infer sub10 = 256; \end{verbatim} If you remove the line \begin{verbatim} ERROR("Constraint cannot be inferred."); \end{verbatim} from this file, the error goes away. I believe this has something to do with improper handling of ``go to'' statements by the compiler. \newpage \part{Results on specific codes} This part is a program which proves many specific results about codes. There are seven places (sections \ref{some-unital-section}, \ref{38-27-section}, \ref{40-11-16-section}, \ref{73-12-32}, \ref{section-56-71}, \ref{section-72-80}, \ref{menagerie-section}) where we use arguments which have not yet been completely formalized in the language. These have to be checked by hand. (Also, due to an undiagnosed problem with the ``{\tt auto projection}'' option, one line under \verb|type [142,7,70_2]| must also be checked by hand.) We include a number of tables which give upper bounds for the minimum distance of codes. These were constructed by first copying the tables of Brouwer and Verhoeff, adjoining a few other previously known results, and then adjoining our new results. For the tables through $n = 36$, we check the lower bounds as well as the upper bounds. We have not included references for the lower bounds. Note that Brouwer and Verhoeff's table gives both upper and lower bounds (with references). All of the tables given here are part of the program, and so each result is independently verified. For display in this paper, certain informational subscripts and superscripts have been added to the entries of the table. These do not in any way effect execution, and correspondingly may not be completely reliable. They in general do not reflect any results of other people obtained after about January 1995 or results of other people obtained before then but unknown to the author. Corrections will be gratefully accepted. A question mark as a pre-superscript indicates that the given upper bound is not known to be sharp. References are given as post-superscripts. These have been copied from [.brouwer verhoeff 1993.], and reflect only ``main results''. Often a single such result yielded many corollaries, but we do not cite the reference for each such corollary, although credit is in fact due. A diamond as a pre-subscript indicates that the bound is new. In most cases the new bound is just one better than the old bound, but in several cases $$(n,k) = (42,20), (102,13), (168,12), (168,14),$$% the minimum distance $d$ has been improved by two. \newpage \begin{svb} data_comment( ![ \block{Some doubly even codes that do not exist} The results of this section are curiously independent of the rest of the program. In all cases (except those listed in this section), where we know that a doubly even $[n,k,d]$ code does not exist, and $4 \mid d$, we know that there are no $[n,k,d]$ codes at all. (This statement does not take account of trivial cases -- cf.\ \verb|codetable::not_exist(int, int, weightlist)|). ]! ) accept code.data1; no [11, 5, 4_4]; no [13, 6, 4_4]; no [27, 13, 8_4]; no [29, 14, 8_4]; no [35, 13, 12_4]; no [34, 17, 8_4]; no [38, 15, 12_4]; no [43, 13, 16_4]; no [46, 15, 16_4]; no [50, 25, 12_4]; no [51, 19, 16_4]; no [53, 20, 16_4]; no [54, 15, 20_4]; no [51, 25, 12_4]; no [59, 19, 20_4]; no [61, 20, 20_4]; no [65, 18, 24_4]; no [67, 19, 24_4]; no [69, 20, 24_4]; no [59, 25, 16_4]; no [66, 24, 20_4]; no [69, 34, 16_4]; no [73, 18, 28_4]; no [75, 19, 28_4]; no [77, 20, 28_4]; no [81, 18, 32_4]; no [84, 20, 32_4]; no [73, 23, 24_4]; no [74, 31, 20_4]; no [79, 28, 24_4]; no [82, 24, 28_4]; no [83, 39, 20_4]; no [84, 25, 28_4]; data_comment( ![ \def\simonis1896ref{\protect{[.simonis 1896 unique.]}} \def\enchevareference{\protect{[.encheva 1992 report.]}} \def\dodunekovenchevareference{\protect{[.golay subcodes 1993.]}} \def\tilborgreference{\protect{[.tilborg griesmer.]}} \block{Classification of various codes at the Griesmer bound (most due to van Tilborg \tilborgreference)} In this section we classify codes with various parameters at the Griesmer bound: $[32,6,16]$, $[35,4,18]$, $[38,4,20]$, $[38,6,18]$, and $[42,4,22]$. All of these (except the $[35,4,18]$, $[38,4,20]$, and $[42,4,22]$) results are special cases of more general results which may be found in [.tilborg griesmer.]. ]! ) type [32,6,16]; [a] := {11111111 11111111 11111111 11111111, 11111111 11111111 00000000 00000000, 11111111 00000000 11111111 00000000, 11110000 11110000 11110000 11110000, 11001100 11001100 11001100 11001100, 10101010 10101010 10101010 10101010} :: {y16 = 62, y32 = 1}; via building [base] implies [a]; classification of [base]: [a]; status: classified, weights = {16,32}; type [35,4,18]; [1] config 1,3,2,3,1,3,2,3,3,2,3,1,3,2,3 : {100101101001011,010101011010101, 001100111100110,000011111111000} :: {y18 = 12, y20 = 2, y24 = 1}; [2] config 1,3,2,3,2,2,2,3,3,2,2,2,3,2,3 : {100101101001011,010101011010101, 001100111100110,000011111111000} :: {y18 = 11, y20 = 3, y22 = 1}; [3] config 2,2,2,3,2,2,2,3,2,3,2,2,3,2,3 : {100101101001011,010101011010101, 001100111100110,000011111111000} :: {y18 = 10, y20 = 5}; CLASSIFICATION_OF([base], x_18|x99|x4455, ![[1], [2], [3]]! ) status: classified, weights = {18,20,22,24}; type [38,4,20]; config from x_20|x_10_10; show y20 = 14, y24 = 1; [a] config from x5555|x22223333; classification of [base]: [a]; STATUS_UNIQUE_WE(1 + 14t^20 + t^24) no [36,5,18]; [38_6_18] type [38,6,18]; [x] := P( Even(6) ) :: {y18 = 30, y20 = 30, y22 = 2, y32 = 1}; { at [base]; show y36 = 0, y38 = 0; kill y28 by (x_10_10, x_12_8, x_13_5, x_14_6); config 24,14 : {10}; check secondary residuals; show y32 = 0; kill x_12_10, x_11_7, x_12_8; via lp [current] = ; @[base] infer y24 = 0; config from x_32; check secondary residuals; config from x_16_6|x882|x444402; via building [current] implies [x] }; classification of [base]: [x]; STATUS_UNIQUE_WE(1 + 30t^18 + 30t^20 + 2t^22 + t^32) no [41,4,22]; type [42,4,22]; config from x_22; show y22 = 12, y24 = 3, y28 = 0; [a] config from x_10_12|x4666|x23333332; classification of [base]: [a]; STATUS_UNIQUE_WE(1 + 12t^22 + 3t^24) [23_7_9] type [23,7,9]; load constraints by parity check from [24_7_10]; data_comment( ![ \def\simonis1987ref{\protect{[.simonis 1987 25_15_6.]}} \def\simoniswagnerref{\protect{[.simonis wagner unique.]}} \block{Classification of projective $[27,6,12]$ codes up to weight enumerator} A code $C$ is {\it projective\/} if the minimum weight of $C^\perp$ is at least $3$. We show that amongst the projective $[27,6,12]$ codes, exactly $22$ weight enumerators occur. This answers a question accidentally posed to the author by V.\ D.\ Tonchev, who has [.tonchev uniformly packed 1996.] classified the {\it two-weight\/} projective $[27,6,12]$ codes. ]! ) type [27,6,12]{mu1 = 0, mu2 = 0}; CYCLIC_WE([t1], 1001000110111100111011, 1 + 16t^12 + 30t^13 + 15t^16 + 2t^21) WECAT2B(![[t2] := {100100101000011000101011011,010100010001100110101101011, 001100111001110001111110110,000010100010110010011110011, 000001011010111101100001001,000000000111111111111111100}]!, 1 + 20t^12 + 25t^13 + 11t^16 + 6t^17 + t^21) CYCLIC_WE([t3], 1001000110011110110111, 1 + 18t^12 + 28t^13 + 11t^16 + 4t^17 + 2t^20) CYCLIC_WE([t4], 1000011010011111101011, 1 + 21t^12 + 24t^13 + 9t^16 + 8t^17 + t^20) WECAT2B(![[t5] := {100101010010011010101101110,010101010101011101010101010, 001100001011001011110100111,000011001100001100110011011, 000000111111000000111111000,000000000000111111111111000}]!, 1 + 26t^12 + 24t^14 + 12t^16 + t^24) CYCLIC_WE([t6], 1001010011111011010111, 1 + 25t^12 + 27t^14 + 9t^16 + t^18 + t^24) CYCLIC_WE([t7], 1000011000101011101111, 1 + 36t^12 + 27t^16) CYCLIC_WE([t8], 1001100011110010101101, 1 + 21t^12 + 35t^14 + 6t^16 + t^26) CYCLIC_WE([t9], 1001111100100001101011, 1 + 27t^12 + 24t^14 + 8t^16 + 3t^18 + t^22) WECAT2B(![[t10] := {100000011110011111000010111,010010101100101011100100001, 001010110100000110101001101,000110000110110001110010011, 000001111110000011111111000,000000000001111111111110000}]!, 1 + 27t^12 + 23t^14 + 11t^16 + t^20 + t^22) CYCLIC_WE([t11], 1001010011001111110111, 1 + 28t^12 + 21t^14 + 11t^16 + 2t^18 + t^22) WECAT2B(![[t12] := {100000001110111111100000111,010010110010100101100101001, 001010100100010101001011101,000110011000001100110011011, 000001111110000011111111000,000000000001111111111110000}]!, 1 + 25t^12 + 30t^14 + 2t^16 + 5t^18 + t^22) CYCLIC_WE([t13], 1001011111001100010101, 1 + 30t^12 + 15t^14 + 17t^16 + t^22) CYCLIC_WE([t14], 1000101001001100111111, 1 + 30t^12 + 18t^14 + 9t^16 + 6t^18) CYCLIC_WE([t15], 1000011011110100010111, 1 + 29t^12 + 21t^14 + 6t^16 + 7t^18) RCYCLIC_WE([t16], 3, 01001000001011010001110111, 1 + 27t^12 + 27t^14 + 9t^18) CYCLIC_WE([t17], 1001100101111001111101, 1 + 28t^12 + 22t^14 + 9t^16 + 2t^18 + 2t^20) CYCLIC_WE([t18], 1000101110111101000011, 1 + 27t^12 + 25t^14 + 6t^16 + 3t^18 + 2t^20) CYCLIC_WE([t19], 1000111111001100100101, 1 + 28t^12 + 23t^14 + 6t^16 + 5t^18 + t^20) CYCLIC_WE([t20], 1000011001011110011011, 1 + 29t^12 + 20t^14 + 9t^16 + 4t^18 + t^20) CYCLIC_WE([t21], 1000110110001010111101, 1 + 30t^12 + 16t^14 + 15t^16 + 2t^20) CYCLIC_WE([t22], 1000101010010011101111, 1 + 31t^12 + 14t^14 + 15t^16 + 2t^18 + t^20) { (* begin bracketing *); at [base]; config from x_12; show y27 = 0; at [base]; kill y25; [case1] config 27 ::: {y13 >= 1, y17 = 0, y21 = 0, y26 = 0}; via lp (joint) [current] = ; [case2] config 27 ::: {y13 = 0, y14 = 0, y17 = 0, y21 = 0, y26 = 0}; show y24 = 0; via varying y12 [current] implies [t7!]; [case3] config 27 ::: {y13 = 0, y17 = 0, y21 = 0, y22 >= 1, y24 = 0, y26 = 0}; config from x_22|x_11_1|x5511; via building [current] implies [t9!], [t10!], [t11!], [t12!], [t13!]; [case4] config 27 ::: {y13 = 0, y14 >= 1, y17 = 0, y20 = 0, y21 = 0, y22 = 0, y24 = 0, y26 = 0}; [case4x] config from x_18|x_8_4; [case4a] config 8,10,4,5 : {1100,1010} :: {y12 <= 27, y13 = 0, y14 >= 1, y17 = 0, y20 = 0, y21 = 0, y22 = 0, y24 = 0, y26 = 0}; via varying y14 [current] implies [t16!]; [case4b] config 8,10,4,5 : {1100,1010} :: {y12 = 28, y13 = 0, y14 >= 1, y17 = 0, y20 = 0, y21 = 0, y22 = 0, y24 = 0, y26 = 0}; show y14 = 24, y16 = 3, y18 = 8; config from x4422; via building [current] implies ; [case4c] config 8,10,4,5 : {1100,1010} :: {y12 >= 29, y12 <= 30, y13 = 0, y14 >= 1, y17 = 0, y20 = 0, y21 = 0, y22 = 0, y24 = 0, y26 = 0}; via varying y12 [current] implies [t14!] or [t15!]; [case4d] config 8,10,4,5 : {1100,1010} :: {y12 >= 31, y13 = 0, y14 >= 1, y17 = 0, y20 = 0, y21 = 0, y22 = 0, y24 = 0, y26 = 0}; show div4 >= 44; infer div4 >= 48; show x1524 = 0, x2415 = 0, x2433 = 0, x2514 = 0, x2525 = 0, x3324 = 0, x3405 = 0, x3423 = 0, x3425 = 0, x3434 = 0, x3443 = 0, x3504 = 0, x3522 = 0, x3524 = 0, x4314 = 0, x4325 = 0, x4413 = 0, x4415 = 0, x4505 = 0, x4512 = 0, x4514 = 0, x4523 = 0; config from x4422; reduce variable set; via building [current] implies ; via variable split [case4x] = [case4a] or [case4b] or [case4c] or [case4d]; [w_30_no] config 27 ::: {y12 = 30, y14 = 17, y16 = 12, y18 = 3, y20 = 1}; show div4 = 44; infer div4 <= 40; via lp [current] = ; [w_27_no] config 27 ::: {y12 = 27, y14 = 26, y16 = 3, y18 = 6, y20 = 1}; config from x_20|x_10_2; show x3405 = 0, x3414 = 0, x3513 = 0, x4404 = 0, x4415 = 0, x4505 = 0; kill current by x4424; [case5] config 27 ::: {y13 = 0, y17 = 0, y20 = 1, y21 = 0, y22 = 0, y24 = 0, y26 = 0}; config from x_20|x_10_2; show y12 >= 27, y14 <= 27, y16 >= 2, y18 <= 6; show div4 <= 56; infer div4 <= 48; via varying y12 [current] implies [w_27_no] or [t19!] or [t20!] or [t22!] or [w_30_no]; [case6] config 27 ::: {y13 = 0, y17 = 0, y21 = 0, y24 >= 1, y26 = 0}; config from x_24|x_12_0; kill x363, x633; config from x660; show x13323 = 0; kill x33132; via varying y12 [current] implies [t5!] or [t6!]; [case7] config 27 ::: {y21 >= 1}; =config 21,6 : {10}; kill x_7_6; show x_9_4 != 0; via varying y21 [current] implies [t1!] or [t2!]; [case8] config 27 ::: {y17 >= 1, y21 = 0}; =config 17,10 : {10} :: {y21 = 0}; config from x_8_4; show y24 = 0; config from x4422; show y13 >= 22, y16 >= 8, y17 <= 10, 1 <= y20 <= 2; via varying y20 [current] implies [t3!] or [t4!]; [case9] config 27 ::: {y26 >= 1}; config from x_26|x_11_1; show x_5_6_1 = 0; config from x471; via varying y26 [current] implies [t8!]; [w_29_no] config 27 ::: {y12 = 29, y14 = 19, y16 = 12, y18 = 1, y20 = 2}; show div4 = 44; infer div4 <= 40; via lp [current] = ; [case10] config 27 ::: {y13 = 0, y17 = 0, y20 >= 2, y21 = 0, y22 = 0, y24 = 0, y26 = 0}; = [case10x] config 20,7 : {10} :: {y13 = 0, y17 = 0, y20 >= 2, y21 = 0, y22 = 0, y24 = 0, y26 = 0}; show x_9_7 = 0, x_13_7 + x_14_6 >= 1; config 13,7,7 : {110,101} :: {y13 = 0, y17 = 0, y20 >= 2, y21 = 0, y22 = 0, y24 = 0, y26 = 0}; config from x624; show x320232 = 0, x321123 = 0, x321222 = 0; via varying y12 [current] implies [t18!] or [t17!] or [w_29_no] or [t21!]; config 14,6,6,1 : {1100,1010} :: {y13 = 0, y17 = 0, y20 >= 2, y21 = 0, y22 = 0, y24 = 0, y26 = 0}; show x5151 = 0, x5241 = 0, x5331 = 0; config from x6240; show x3301221 = 0, x3301311 = 0, x3302211 = 0, x3302301 = 0, x3302310 = 0, x3302411 = 0, x3310221 = 0, x3311121 = 0, x3311211 = 0, x3311220 = 0, x3312210 = 0; via building [current] implies [t17!], [t18!], [t21!]; via variable split [base] = [case1] or [case2] or [case3] or [case4] or [case5] or [case6] or [case7] or [case8] or [case9] or [case10]; (* end bracketing *) }; classification of [base]: [t1!], [t2!], [t3!], [t4!], [t5!], [t6!], [t7!], [t8!], [t9!], [t10!], [t11!], [t12!], [t13!], [t14!], [t15!], [t16!], [t17!], [t18!], [t19!], [t20!], [t21!], [t22!]; data_comment( ![ \block{Some unital $[28,\geq 7,10]$ codes whose dual codes may contain designs} \label{some-unital-section} This section contains a partial classification of the codes which are the codes of $2-(28,4,1)$ designs of rank $20$ or $21$. The classification is partial because of the following: \begin{itemize} \item There may be some codes listed which are not the codes of such designs. \item There are some forced gullibilities (``{\tt ??}''), although the validity of the forced commands is trivially checked. \item We rely on facts from design theory. \end{itemize} This material is part of joint work with Tonchev [.jaffe tonchev rank 20.], which contains a classification of all $2-(28,4,1)$ designs of rank $20$ and $21$. ]! ) [28_5_10deu] type [28,5,10_4]{y28 = 1}; [1] config 1,3,1,2,3,2,1,2,3,2,2,3,2,1 : {10001100111100,01001100110011,00101001010101,00010101011010,00000011111111}; [2] config 1,1,2,1,2,2,3,1,2,2,3,4,1,1,2 : {100001100111100,010010101011010,001011001101001,000111100001111, 000000011111111}; [3] config 1,2,1,2,1,2,1,2,1,2,1,2,1,2,5,2 : {1001011001101001,0101010101010101,0011001100110011,0000111100001111, 0000000011111111}; [4] config 4,2,2,2,2,2,2,2,2,2,2,2,2 : {1000000001111,0100101101001,0010101011010,0001100111100,0000011111111}; [5] config 1,1,1,1,1,1,3,3,1,3,1,3,1,3,3,1 : {1001011001101001,0101010101010101,0011001100110011,0000111100001111, 0000000011111111}; CLASSIFICATION_OF([base], x_28|x_12, ![[1], [2], [3], [4], [5]]!) [28_6_10deu] type [28,6,10_4]{y28 = 1}; [1] config 1,3,1,1,1,2,1,1,1,1,1,1,2,1,1,1,1,1,1,2,1,1,1 : {10000111100011111111000,01000111100011110000111,00100110001100110011001, 00010101001010101010101,00001100100110010110011,00000000011111111111111}; [2] config 1,1,2,1,2,1,2,2,1,1,1,1,2,1,1,1,1,2,1,1,1,1 : {1000011100011111111000,0100010101010101010101,0010001001001011010010, 0001011001100110011001,0000100101100111100110,0000000011111111111111}; [3] config 1,1,2,1,2,2,1,1,1,1,1,1,1,2,1,1,1,1,2,1,2,1 : {1000011110001111111100,0100010100101010101010,0010001010100101101001, 0001011000110011001101,0000100110110011110010,0000000001111111111111}; [4] config 1,1,1,1,1,1,2,1,2,1,1,2,1,1,2,1,1,2,1,2,1,1 : {1001010110001110110101,0101010011011011011001,0011000101010101010011, 0000110101010010101011,0000001010010010010100,0000000000111111111111}; [5] config 1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 : {1001011000011110011000011,0101010010110011001100110,0011001010101101001011010, 0000111010101010110101010,0000000100101010101010101,0000000001111111111111111}; CLASSIFICATION_OF([base], x_28|x_12|x_4_8, ![[1], [2], [3], [4], [5]]!) [28_7_10deu] type [28,7,10_4]{y28 = 1}; [1] := {1000010110110001011000101100,0100010101000010100111011100, 0010000011100100110001110011,0001000011010110101101001010, 0000110011000001101100110110,0000001111110000001111111111, 0000000000001111111111111111}; [2] := {1000010110110001011000100011,0100010101000010100111010011, 0010000011100100110001110011,0001000011010110101101001010, 0000110011000001101100110110,0000001111110000001111111111, 0000000000001111111111111111}; [3] := {1000010110110101001010100100,0100010101000110110101010100, 0010000011100100110001110011,0001000011010110101101001010, 0000110011000001101100110110,0000001111110000001111111111, 0000000000001111111111111111}; [4] := {1000010111100111100011101101,0100010100010100011100011101, 0010010010010010011101100011,0001010001010001011011011010, 0000110000110000110110110110,0000001111110000001111111111, 0000000000001111111111111111}; CLASSIFICATION_OF([base], x_28|x_12|x_6_6|x2226, ![[1], [2], [3], [4]]!) no [28,8,12]; type [28,8,10_2]{y28 = 1} /partition_of_word_by_dual_words(weight = 12, dual_weight = 4), dual_may_be_code_of_design(t = 2, k = 4, lambda = 1), doubly_even_part_is_subcode/; [128] config 28 ::: {div4 = 128}; via building [28_7_10deu:{1,2,3,4}] implies ; ??classification of [128]: ; [64] config 28 ::: {div4 = 64}; via building [28_6_10deu:{1,2,3,4,5}] implies ; ??classification of [64]: ; ??classification of [base]: ; type [28,7,10_2]{y28 = 1} /partition_of_word_by_dual_words(weight = 12, dual_weight = 4), dual_may_be_code_of_design(t = 2, k = 4, lambda = 1), doubly_even_part_is_subcode/; [a] := {1000010111100111100011101101,0100010100010100011100011101, 0010010010010010011101100011,0001010001010001011011011010, 0000110000110000110110110110,0000001111110000001111111111, 0000000000001111111111111111} :: {y12 = 63, y16 = 63, y28 = 1}; [b] config 1,1,1,1,2,1,1,1,1,2,2,1,1,2,1,1,2,2,1,1,1,1 : {1001001010001001101010,0101001010001110111001,0011000000000111101100, 0000100001011100100011,0000011001011011101100,0000000111000111110000, 0000000000111111111111} :: {y10 = 24, y12 = 15, y14 = 48, y16 = 15, y18 = 24, y28 = 1}; [c] config 1,3,2,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,2 : {10000001000010110011101,01000001000010111100010,00100001101111001100001, 00010011101011010101111,00001010000111101001001,00000111100011111111000, 00000000011111111111111} :: {y10 = 24, y12 = 15, y14 = 48, y16 = 15, y18 = 24, y28 = 1}; [d] config 2,2,2,2,1,1,1,1,2,2,1,1,1,1,1,1,1,1,1,1,1,1 : {1000001100101000111010,0100001100101011000101,0010001101110011000011, 0001001101001111001100,0000101001011010101010,0000010101100101011010, 0000000011111111111111} :: {y10 = 24, y12 = 15, y14 = 48, y16 = 15, y18 = 24, y28 = 1}; [e] config 2,2,1,1,1,1,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 : {100000010000101000111010,010000010000101011000101,001001010110101010011111, 000101000101011001011100,000011010011001111001100,000000110000111111110000, 000000001111111111111111} :: {y10 = 20, y12 = 15, y14 = 56, y16 = 15, y18 = 20, y28 = 1}; [f] config 2,2,1,1,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 : {100000000010101100101011,010000000010101111010100,001000100111000101101001, 000100010100110110101010,000010110011001111001100,000001110000111111110000, 000000001111111111111111} :: {y10 = 20, y12 = 15, y14 = 56, y16 = 15, y18 = 20, y28 = 1}; [g] config 4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 : {1000000000000000011111111,0100100110110100101010000,0010100000101010110010011, 0001100110011001111001100,0000010100011101010101010,0000001010011010101011010, 0000000001111111111111111} :: {y10 = 24, y12 = 15, y14 = 48, y16 = 15, y18 = 24, y28 = 1}; [h] config 1,1,1,1,1,1,2,1,2,1,1,2,1,1,2,1,1,2,1,2,1,1 : {1001010100001100011010,0101010001011001110110,0011000101010101010011, 0000110101010010101011,0000001000010000111011,0000000010000010101111, 0000000000111111111111} :: {y10 = 20, y12 = 31, y14 = 24, y16 = 31, y18 = 20, y28 = 1}; [128] config 28 ::: {div4 = 128}; CLASSIFICATION_OF([128], x_28|x_12|x_6_6|x2226, [a]) [64] config 28 ::: {div4 = 64}; { via building [28_6_10deu:{1,2,3,5}] implies ; via building [28_6_10deu:4] implies [a], [h] }; ??classification of [64]: [h]; [32] config 28 ::: {div4 = 32}; via building [28_5_10deu:{1,2,3}] implies ; via building [28_5_10deu:4] implies [a], [b], [c], [d], [e], [f], [g], [h]; via building [28_5_10deu:5] implies [a], [h]; ??classification of [32]: [b], [c], [d], [e], [f], [g]; ??classification of [base]: [a], [b], [c], [d], [e], [f], [g], [h]; data_comment( ![ \block{Classification of $[31,10,12]$ and $[32,11,12]$ codes up to weight enumerator} In each case, it turns out that there is a unique weight enumerator. ]! ) TYPE_WE(31,10,12,1 + 310t^12 + 527t^16 + 186t^20) TYPE_WE(32,11,12,1 + 496t^12 + 1054t^16 + 496t^20 + t^32) data_comment( ![ The existence of a $[32,11,12]$ code follows from: ]! ) type [31,11,11]; [a] := cyclic {100001100101100111011}; status: realizable; data_comment(![\def\heijnenref{\protect{[.heijnen.]}} \def\hyttref{\protect{[.helleseth ytrehus 33_8_14.]}}]!) no [31,7,14]; type [33,8,14_2]; kill y30 by (x_11_3, x_12_2), y28 by x_14_0; status: weights = 14_2 - {28..33}; type [33,8,14]; kill y15,y17,y21,y25; { show (joint:0) 89 <= y14 <= 105, 51 <= y16 <= 96, 4 <= y18 <= 59, 12 <= y20 <= 54, 7 <= y22 <= 30, y24 <= 6, y26 <= 2; show (joint:0) y14 <= 102, 55 <= y16 <= 95, 5 <= y18 <= 58, 13 <= y20 <= 53, y22 >= 8, y24 <= 5; show (joint:0) y14 <= 101, y16 >= 56, y18 <= 57, 73 <= div4 <= 140, mu3 <= 4; infer div4 >= 96; infer div4 <= 136; show (joint:0) y16 >= 58, y18 <= 46, y22 >= 9; show (joint:0) y16 >= 58, y18 <= 45, 134 <= mu4 <= 165; show (joint:0) y16 >= 59; show (joint:5) y14 <= 99, y16 >= 60, y20 <= 52, mu4 <= 164; show (joint:5) mu3 = 0, y16 >= 61; show (joint:0) y16 >= 62; show (joint:0) y18 <= 44; show (joint:0) y18 >= 6, y20 >= 20 }; data_comment( ![ The following code is due to Said and Palazzo [.said palazzo.]. ]! ) [a] := {100000000111101100011100101101000,010000000100111011010110010100011, 001000001100010101001101010010111,000100001110110110000000100111110, 000010001101110010111011101110011,000001000011110001100111100001110, 000000100000001111100000011111111,000000010000000000011111111111110}; [b] := {100000010010001110011111100000011,010000011110010001010111001000110, 001000011000111110000100001011110,000100011010100110001011011100100, 000010010110101001111100100100100,000001010100110101111010001010001, 000000111100011100111001010001010,000000000001111111111111111111111}; disjoint [a], [b]; status: realizable, weights = 14_2 - {28..33}, constraints = {89 <= y14 <= 99, 62 <= y16 <= 95, 6 <= y18 <= 44, 20 <= y20 <= 52, 9 <= y22 <= 30, y24 <= 5, y26 <= 2}; [29_6_13] type [29,6,13]; load constraints by parity check from [30_6_14]; data_block(There is no $[34,9,14]$ code (Heijnen \heijnenref)) type [34,9,14_2]; { config from x_14; show y34 = 0, y22 != 0; at [base]; =config 22,12 : {10}; config from x_11_3; show mu4 != 0; [mu4] config 30,4 :: {01}; [30_6_14] incorporate [30_6_14] below [mu4] via sub10; @[30_6_14.base] infer y30 != 0; via lp [base] = }; no [34,9,14]; type [36,10,14_2]; show (joint:5) 176 <= y14 <= 247, 125 <= y16 <= 321, 45 <= y18 <= 336, 72 <= y20 <= 364, 63 <= y22 <= 243, y24 <= 68, y26 <= 24, y28 <= 10, y30 <= 4, y32 <= 2, y34 <= 1; status: constraints = {176 <= y14 <= 247, 125 <= y16 <= 321, 45 <= y18 <= 336, 72 <= y20 <= 364, 63 <= y22 <= 243, y24 <= 68, y26 <= 24, y28 <= 10, y30 <= 4, y32 <= 2, y34 <= 1}; data_comment( ![ \def\dodunekovref{\protect{[.dodunekov 1987.]}} \block{Classification of $[36,8,16]$ codes up to weight enumerator Dodunekov et.\ al.{\ }\dodunekovref} We give two examples, the first of which may be found in [.dodunekov 1987.]. ]! ) [36_8_16] type [36,8,16]; show y16 = 153, y20 = 72, y24 = 30; [a] := {111111111111111111111111000000000000, 111111111111111100000000111111110000,111111111110000011111000111110001110, 111111000001111011110110111101101100,111100110001110111101101111011011010, 110010111101101111001110110100111110,101011101001001110001111101011101000, 100011100111100010100101111111111111}; (* pseudocyclic (1,2,15,34,33,22)(3,24,14,19,11,27,6,36,30,20,29,4) (5,35,10,31,32,9,26,21,8,13,16,7)(12,17,18,23,28,25) : 000000000000000011111111111111110000 *); [b] := {100000011111011111100000111111111111, 010000000100000111000111111010001111,001000010001001110110011100100101011, 000100001010010101101011100001100111,000010011100011011111100110000000011, 000001011010010000011010111100111010,000000111001001000011001110011110101, 000000000000111111111111111111110000}; (* pseudocyclic (1,11,7,22,27,28,10,15,23,13,36,34) (2,29,33,16,14,6,5,35,30,19,12,24)(3,8,32,20,17,25)(4,9,31,21,18,26) : 000100001010010101101011100001100111 *); STATUS_RE_WE(1 + 153t^16 + 72t^20 + 30t^24) data_block(Table for codes of length $32$ through $36$) type [31,25,4_2]; status: weights = 4_2 - {30}; type [36,17,10_2]; config 36 ::: {mu8 != 0}; =[mu8] config 28,8 :: {01}; [28_10_10] incorporate [28_10_10] below [mu8] via sub10; via extension [28_10_10.{a,b,c,d*,e*,f,g*}] implies ; classification of [mu8]: ; @[base] infer mu8 = 0; show y32 = 0, y34 = 0, y36 = 0; via lp (joint) [current] = ; no [36,17,10]; type [37,5,18_2]; status: weights = 18_2 - {34,36}; data_comment( ![ The following example is due to Bierbrauer and Edel [.bierbrauer edel reed solomon.]. ]! ) type [39,12,14_2]; [a] := { 111100101000011111011010011000000000000, 000110111001101100110111010100000000000, 110101111101100011000001110010000000000, 010110011111010010111010100001000000000, 001011001111000111011101010000100000000, 101101000011111010110100110000010000000, 100010010101100001110011100000001000001, 001011110110110010111101100000000100001, 011111010001000010001100110000000010001, 100100011111110111010110010000000001001, 011010001000111001100011010000000000101, 101010100101101110011110110000000000011}; status: realizable; data_comment( ![ The following five codes were discovered by J.\ B.\ Shearer. ]! ) unset auto group computation; type [33,23,5]; [a] := {010100101010000000000000000000000, 110001110000000000000000000000000,011001000001100000000000000000000, 110100100001010000000000000000000,110101001001001000000000000000000, 111110000000000000000000000000000,111001000000000110000000000000000, 100100100000000101000000000000000,111100101000000100100000000000000, 101101000001000100010000000000000,110000101001000100001000000000000, 101001001100000000000000000000000,001101000000000000000110000000000, 100000101000000000000101000000000,111101101000000000000100100000000, 000001100001000000000100010000000,001100101001000000000100001000000, 110101100000000100000100000100000,101100001000000100000100000010000, 001000000001000100000100000001000,011101100001000100000100000000100, 010001001001000100000100000000010,101001101001000100000100000000001}; status: realizable; type [37,22,7]; [a] := {1110000111100000000000000000000000000,1101010110000001100000000000000000000, 1111111000000000000000000000000000000,1000110101000000011000000000000000000, 1001100110011000000000000000000000000,0110100100010000000110000000000000000, 0111000000000001010101000000000000000,0100000111010001010100100000000000000, 0101010101010100000000000000000000000,0100110110000000000000011000000000000, 1110000100000001010000010100000000000,0110010011010001010000010010000000000, 0101110000000001000100010001000000000,1010110100010001000100010000100000000, 0001100010000000010100010000010000000,0010000111000000010100010000001000000, 0010110011010010000000000000000000000,0011010110000000000000000000000110000, 0000110100000001000100000000000101000,1011100101000001000000010000000100100, 0001110001010001000000010000000100010,1101000110010000000100010000000100001}; status: realizable; type [47,36,5]; [a] := {10010100001100000000000000000000000000000000000, 10010010101010000000000000000000000000000000000, 11111000000000000000000000000000000000000000000, 11010010000001100000000000000000000000000000000, 00110110100001010000000000000000000000000000000, 11110110001001001000000000000000000000000000000, 00100100101001000100000000000000000000000000000, 01010110101001000010000000000000000000000000000, 10100110110000000000000000000000000000000000000, 11100100000000000001100000000000000000000000000, 10110100100000000001010000000000000000000000000, 11010010001000000001001000000000000000000000000, 11100000101000000001000100000000000000000000000, 00000010101000000001000010000000000000000000000, 01100000000001000001000001000000000000000000000, 01010000100001000001000000100000000000000000000, 11100010100001000001000000010000000000000000000, 10100000001001000001000000001000000000000000000, 10000110001001000001000000000100000000000000000, 10010100101001000001000000000010000000000000000, 11000111000000000000000000000000000000000000000, 10100100000000000000000000000001100000000000000, 01010010000000000000000000000001010000000000000, 01110000100000000000000000000001001000000000000, 00010100100000000000000000000001000100000000000, 01000100001000000000000000000001000010000000000, 00100010001000000000000000000001000001000000000, 11100010000001000000000000000001000000100000000, 10010000001001000000000000000001000000010000000, 11000100101001000000000000000001000000001000000, 01110100000000000001000000000001000000000100000, 10000110100000000001000000000001000000000010000, 00110100101000000001000000000001000000000001000, 10010100000001000001000000000001000000000000100, 00100110100001000001000000000001000000000000010, 00110110001001000001000000000001000000000000001}; status: realizable; type [35,16,9]; [a] := {01010101001010010101000000000000000,11110000011111000000000000000000000, 01010110001100100000110000000000000,11001100011000111000000000000000000, 01100111000110100000001100000000000,01110010010000010000101010000000000, 10000001011100110100101001000000000,11111111100000000000000000000000000, 00011111001100110100000000110000000,01001111010100010000001000101000000, 11111010001110100100101000100100000,10101010010100100110000000000000000, 10010111011100000100100000000011000,01000100010110110100001000000010100, 00110001010010100000100000100010010,10000000010010000100101000100010001}; status: realizable; type [33,12,11]; [a] := {001101101001101001001100000000000,101011010101010100101010000000000, 111110000001111110000000000000000,100111011001011001000001100000000, 110001110001110001110000000000000,011010111000111001000000011000000, 110001001101010100000001010100000,111111111110000000000000000000000, 000111101100100100101000000011000,000010101001110101000001000010100, 000001000001111100101000010010010,101001000101001001001001010010001}; status: realizable; data_comment( ![ Something like the following example was given by Piret [.piret good block codes.]. ]! ) [35_9_14] type [35,9,14_2]; [a] := (17,17)-cyclic {01111000000111101000001101001011001}; status: realizable; data_comment( ![ The following code is due to Dougherty and Janwa [.dougherty janwa radius.]. ]! ) type [45,16,13]; [a] := cyclic {10110000111000100011100001101, 111110011100000010001000100000000000000000011}; status: realizable; data_comment( The following code was found by Masakatu Morii. ) type [36,14,11]; [a] := {100000000000001111111111000000000000,010000000000000110000001101110010011, 001000000000000010011110000010011011,000100000000001100001000000111101011, 000010000000000011010011010101100100,000001000000000100010100101010101110, 000000100000001111000100100101000110,000000010000001110010000011000111011, 000000001000001011001010100110110000,000000000100000101101001101001001010, 000000000010000100101110001100000111,000000000001001010000111001000110110, 000000000000100001101000011110101100,000000000000010111100101010110000101}; status: realizable; type [32,7,14]; status: weights = 14_2 - {32}; config 30,2 : {10}; show y22 = 0, y24 = 0, y26 = 0, y28 = 0, y30 = 1; show (joint:5) 52 <= y14 <= 56, 33 <= y16 <= 44, 6 <= y18 <= 21, 18 <= y20 <= 24; kill x_15_1, x_13_1; config from x_12_2|x_5_7_2|x13352; via lp [current] = ; @[base] infer y30 = 0; config 28,4 : {10}; show y24 = 0, y26 = 0, y28 = 1; show (joint:5) y14 <= 57, y16 >= 29, y20 <= 23; config from x_14_0; check secondary residuals; kill x774, x464; reduce variable set; kill x374, x574, x554; via lp [current] = ; @[base] infer y28 = 0; status: weights = 14_2 - {28..32}; no [33,12,12]; no [35,13,12]; no [33,12,12]; type [34,12,12_2]; (* If the following line is executed in homebrew mode, you have to set quad. *); show (joint:5) y34 = 0; status: weights = {12,14,16,18,20,22,24,26,28,30,32}; type [35,7,16_2]; kill y34, y32, y18; status: weights = {16,20,24,28}; type [35,7,16]; status: weights = {16,20,24,28}; psheadx(90) // k = 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 psnext n=31, k >= 2: 20, 17, 16, 16, 15, 13coderef(tilborg 1981), 12, 12, 12, 11, 10, 9coderef(prins thesis), 8, 8, 8; sn n=32, k >= 2: 21, 18, 16, 16, 16, 14, 13, 12, 12, 12, 10, 10, 8-9, 8, 8; sn n=33, k >= 2: 22, 18, 16, 16, 16, 14, 14, 12coderef(heijnen), 12, 12, 11coderef(hill traynor), 10, 9-10, 8-9, 8; sn n=34, k >= 2: 22, 19, 17, 16, 16, 15coderef(tilborg 1981), 14, 13, 12, 12, 12, newd1()10, 10, 9-10, 8-9; sn n=35, k >= 2: 23, 20, 18, 16, 16, 16, 15, 14, 12-13, 12, 12, newd1()11, newd1()10, 10, 9-10; sn n=36, k >= 2: 24, 20, 18, 17, 16, 16, 16, 14, 13-14, 12-13, 12, 12, newd1()11, newd1k(16)10, 10; pstail pshead(90) // k = 17 18 19 20 21 22 23 24 25 26 27 28 29 30 psnext n=31, k >=17: newd()7, newd1k(21)6, 6, 6, 5, 4, 4, 4, 4, 3, 2, 2, 2, 2; sn n=32, k >=17: 8, 6-newd1()7, newd()6, 6, 6, 5, 4, 4, 4, 4, 2, 2, 2, 2; sn n=33, k >=17: 8, 7-8, 6-newd1()7, newd()6, 6, 6, 5, 4, 4, 4, 3, 2, 2, 2; sn n=34, k >=17: 8, 8, 7-8, 6-newd1()7, 6, 6, 6, 4-5, 4, 4, 4, 3, 2, 2; sn n=35, k >=17: newd()8, 8, 8, 7-8, 6-7coderef(brouwer linear programming bound), 6, 6, 5-6, 4-5, 4, 4, 4, 3, 2; sn n=36, k >=17: 8-newd1()9, newd()8, 8, 8, 7-8, 6-7, 6, 6, 5-6, 4-5, 4, 4, 4, 3; pstail pshead(80) // k = 31 32 33 34 35 psnext n=32, k >=31: 2; sn n=33, k >=31: 2, 2; sn n=34, k >=31: 2, 2, 2; sn n=35, k >=31: 2, 2, 2, 2; sn n=36, k >=31: 2, 2, 2, 2, 2; pstail \vspace{0.12in} \begin{svb} |-> tex/code.tex, code.data unset lower bound check; data_comment(![\def\tonchevquadricsref{\protect{[.tonchev designs codes quadrics.]}} \block{Classification of self-complementary $[36,7,16]$ codes (Tonchev \tonchevquadricsref)} ]! ) type [36,7,16]{y36=1}; [1] := {100001000110010101111101001101001000, 010001000101101001110010110010111000,001000011100001100110001111110001100, 000100010011001101010110010110010101,000011001100111101101000011000010110, 000000111111111100000000001111111111,000000000000000011111111111111111111}; [2] := {100001000110010101111101000101010001, 010001000101101001110010111010100001,001000011100001100110001111110001100, 000100010011001101010110010110010101,000011001100111101101000011000010110, 000000111111111100000000001111111111,000000000000000011111111111111111111}; [3] := {100001000110010101001101000101011101, 010001000101101001000010111010101101,001000011100001100110001111110001100, 000100010011001101010110010110010101,000011001100111101101000011000010110, 000000111111111100000000001111111111,000000000000000011111111111111111111}; [4] := {100001000100111000010011100011101101, 010001000111000100011100011100011101,001001011000100101100010011101100011, 000101010110110101011011011011011010,000011001101101100110110110110110110, 000000111111111100000000001111111111,000000000000000011111111111111111111}; { at [base]; =config 36 : {1}; show y17 = 0, y18 = 0, y19 = 0; config from x_16|x_6_10|x2446; via building [current] implies [1], [2], [3], [4]; disjoint [1], [2], [3], [4] }; classification of [base]: [1], [2], [3], [4]; data_comment(\block{There is no $[38,27,6]$ code}\label{38-27-section} This section contains an informal argument which has not yet been formalized in the language.) type [38,27,6_2]; show mu14 >= 2; data_comment(![ Let $C$ be an even $[38,27,6]$ code. Consider $w \in C^\perp$ of weight $14$. The subcode of $C$ disjoint from it is a $[24,14,6]$ code, which we know [.jaffe optimal binary 30.] must have a word of weight $24$. Thus for each such $w$, we can find some word of weight $24$ which is in $C \cap C^\perp$. In particular, we see that $C \cap C^\perp$ has at least two words of weight $24$. There are exactly three plausible ways in which these two words may intersect. We proceed to show that none of these may happen, and hence that no such code $C$ exists. ]!) !config 12,12,12,2 : {1100,0110} : {1100,0110}; !config 10,14,10,4 : {1100,0110} : {1100,0110}; !config 8,16,8,6 : {1100,0110} : {1100,0110}; ??classification of [base]: ; data_comment(\block{There is no $[40,11,16]$ code}\label{40-11-16-section}) [32_5_16x20x24] type [32,5,{16,20,24}]; [a] config 2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2 : {100101011010101001010110,010101010101101010101010, 001100001111111100001100,000011001100110011001111, 000000110011001100111111} :: {y16 = 29, y20 = 0, y24 = 2}; [b] config 2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2 : {1001010101101010100101010110,0101010101010110101010101010, 0011000011001100110011110011,0000110011110011000011001111, 0000001111111111111111000000} :: {y16 = 27, y20 = 4, y24 = 0}; [c] config 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 : {10010110011010010110100110010110,01010101010101011010101010101010, 00110011001100111100110011001100,00001111000011111111000011110000, 00000000111111111111111100000000} :: {y16 = 31, y20 = 0, y24 = 0}; CLASSIFICATION_OF([base], x_16|x88|x4444, ![[a], [b], [c]]!) type [32,6,{16,20,24}]; via lp [current] = ; [36_8_16x20x24] type [36,8,{16,20,24}]; at [base]; show mu4 != 0; [mu4] config 32,4 :: {01}; [32] incorporate [32_5_16x20x24] below [mu4] via sub10; at [base]; show y24 != 0; config 24,12 : {10}; show z_0_4 != 0; data_comment( The above calculation shows that there is a word of weight $24$ disjoint from a dual word of weight $4$. This justifies the following line: ) ??[base] = [32.a]; [1] := {100000100001000111001111100110101010, 010000010100010000111111100110100101,001001110000010101011111111001110011, 000101000101000011110101001010110011,000011110000000010100101110011001111, 000000001100001110011001110000111111,000000000011001100110011111111110000, 000000000000111101010101001111001111}; [2] := {100001110000010100100111100101010101, 010001000101000010111110100110101010,001000100000010111010111101010101100, 000100010101000001111101011001101100,000011110000000011001100110000111111, 000000001100001111110000110011001111,000000000011001100110011111111110000, 000000000000111100111100001100111111}; via building [32.a] implies [1], [2]; disjoint [1], [2]; classification of [base]: [1], [2]; type [40,11,16_2]; { kill y38, ndiv4, y36, y32, y28; show (joint:0) mu4 != 0; [mu4] config 36,4 :: {01}; [36] incorporate [36_8_16x20x24] below [mu4] via sub10; via building [36.1] implies ; via building [36.2] implies ; classification of [base]: }; no [40,11,16]; data_comment( ![ We give some information about $[39,10,16]$ codes, whose existence is unknown. ]! ) type [39,10,16_2]; show (joint) y30 = 0, y32 = 0, y34 = 0, y36 = 0; show (joint) y38 = 0 ; show (joint) div4 >= 845; infer div4 = 1024; status: weights = {16,20,24,28}; type [39,10,16]; status: weights = {16,20,24,28}; data_comment( ![ There is a word of weight $28$, as otherwise (by adjoining the all-ones word) one would obtain a $[39,11,15]$ code, and thence a $[40,11,16]$ code. ]! ) ??show y28 >= 1; show (joint:7) y28 = 2; show y16 = 367, y20 = 414, y24 = 240, y28 = 2, mu4 = 14; config 33,2,2,2 :: {0110,0011}; show x_24_0_2_2 = 0, x_24_2_0_2 = 0, x_24_2_2_0 = 0, x_25_1_1_1 = 0, x_26_0_0_2 = 0, x_26_0_2_0 = 0, x_26_2_0_0 = 0, x_28_0_0_0 = 0; kill current by x_10_2_2_2; data_comment(![ Thus two dual words of weight $4$ can't meet along $2$ bits. ]!) at [base]; ??show jd4d4d4 = 0; STATUS_WE(1 + 367t^16 + 414t^20 + 240t^24 + 2t^28) data_block(Table for codes of length $37$ through $39$) no [38,27,6]; no [38,16,12]; type [38,12,14_2]; kill y38 by x_14; status: weights = {14,16,18,20,22,24,26,28,30,32,34,36}; no [39,13,14]; no [37,9,16]; type [38,9,16_2]; { kill y38, y36, y34 by (x_12_4, x_13_3); show (joint:5) y32 = 0; show (joint:5) y30 = 0 }; status: weights = {16,18,20,22,24,26,28}; type [38,9,16]; status: weights = {16,17,18,20,21,22,24,26,28}; type [38,12,14_2]; show (joint:0) y36 = 0; status: weights = 14_2 - {36,38}; type [38,19,10_2]; status: weights = 10_2 - {36}; psheadx(60) // k = 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 psnext n=37, k >= 2: 24, 20, 19, 18, 17, 16, 16, 15coderef(hill traynor), 14, quest1()14, quest1()13, 12, 12, newdquest1()11, newd1()10, quest1()10, newdquest()9, newd()8, 8; sn n=38, k >= 2: 25, 21, 20, 18, 18, 16, 16, 16, quest1()15, 14, quest1()14, newd1()12, 12, quest1()12, newdquest1()11, newd1()10, quest1()10, newdquest()9, newd()8; sn n=39, k >= 2: 26, 22, 20, 19, 18, 17, 16, 16, quest1()16, newd1()14, 14, newdquest1()13, newd1()12, 12, quest1()12, newdquest1()11, newd1()10, quest1()10, newdquest()9; pstail pshead(60) // k = 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 psnext n=37, k >=21: 8, quest()8, quest()7, 6, 6, quest()6, newd()4, 4, 4, 4, 3, 2, 2, 2, 2, 2; sn n=38, k >=21: 8, 8, quest()8, quest()7, 6, 6, newd()5, 4, 4, 4, 4, 3, 2, 2, 2, 2, 2; sn n=39, k >=21: newd()8, 8, quest()8, quest()8, quest()7, 6, 6, 5coderef(hill traynor), 4, 4, 4, 4, 3, 2, 2, 2, 2, 2; pstail \vspace{0.12in} \begin{svb} data_block(There is no $[41,8,18]$ code) type [41,8,18_2]; { show y40 = 0; kill y38, y36 by x_18_0; config 34,7 : {10}; infer by residual code [23_7_9] that x_11_7 = 0, x_14_4 = 0, x_15_3 = 0; via lp [current] = ; @[base] infer y34 = 0; config 32,9 : {10}; infer by residual code [23_7_9] that x_13_5 = 0, x_12_6 = 0, x_9_9 = 0; via lp [current] = ; @[base] infer y32 = 0; config 30,11 : {10}; infer by residual code [23_7_9] that x_10_8 = 0, x_11_7 = 0; via lp [current] = ; @[base] infer y30 = 0; [mu3] config 38,3 : { } : {01}; [38_6_18] incorporate [38_6_18] below [mu3] via sub10; @[38_6_18.base] infer y32 != 0; via lp [mu3] = ; @[base] infer mu3 = 0; show y28 != 0; config 28,13 : {10}; infer by residual code [23_7_9] that x_9_9 = 0; kill current by x_10_10 }; no [41,8,18]; data_block(There is no $[42,27,8]$ code) type [42,15,14]{mu1=0, mu2=0, mu3=0, mu4=0, mu5=0, mu6=0, mu7=0, y42=1}; { =config 42 : {1}; config from x_14; kill x_0_14, x_1_13 }; via lp [current] = ; type [42,27,8_2]; via dual nonexistence infer [base] = ; no [42,27,8]; data_block(Table for codes of length $40$ through $45$) type [40,5,20]; kill y40, ndiv4 ; show (joint:5) 26 <= y20 <= 28, 2 <= y24 <= 5, y28 <= 1, y32 <= 1; status: weights = {20,24,28,32}, constraints = {26 <= y20 <= 28, 2 <= y24 <= 5, y28 <= 1, y32 <= 1}; type [40,7,18]; status: weights = 18_2 - {40}; type [42,6,20_2]; status: weights = {20,22,24,26,28,32,36}; type [42,6,20]; status: weights = {20,21,22,24,26,28,32,36}; no [41,6,20]; no [43,13,16]; no [43,20,12]; no [45,18,14]; type [42,8,18_2]; show (joint:5) y42 = 0; status: weights = {18,20,22,24,26,28,30,32,34,36,38,40}; no [41,12,16]; type [42,12,16_2]; kill y42 by x_16; status: weights = {16,18,20,22,24,26,28,30,32,34,36,38,40}; type [43,7,20]; status: weights = {20,24,28,32,36}; type [44,5,22_2]; status: weights = {22,24,30,32}; type [44,10,18_2]; kill y44, y40 by (x_18_0, x_18_2, x_18_4, x_19_1, x_19_3, x_20_0); status: weights = 18_2 - {40,42,44}; type [44,13,16_2]; status: weights = 16_2 - {44}; TYPE_WE(45,6,22,1 + 45t^22 + 15t^24 + 3t^30) type [45,8,20_2]; status: weights = {20,22,24,26,28,30,32,34,36,38,40}; type [45,8,20]; status: weights = 20_1 - {23,27,31,35,39,41..45}; type [45,11,18_2]; status: weights = 18_2 - {38..45}; psheadx(90) // k = 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 psnext n=40, k >= 2: 26, 22, 20, 20, 18coderef(baumert mceliece), 18, newd1()16, 16, 16, newdquest1()15, 14, quest1()14, newdquest1()13, newd1()12, 12, quest1()12, newdquest1()11, newd1()10, quest1()10; sn n=41, k >= 2: 27, 23, 21, 20, 19, 18, newd1()17, 16, 16, quest1()16, quest1()15coderef(hill traynor), quest1()14, quest1()14, newdquest1()13, 12, 12, quest1()12, newdquest1()11, newd1()10; sn n=42, k >= 2: 28, 24, 22, 20, 20, 19, 18, quest1()17, 16, 16, quest1()16, newd1()14, quest1()14, quest1()14, quest1()13coderef(brouwer linear programming bound), 12, 12, quest1()12, newd1()10; sn n=43, k >= 2: 28, 24, 22, 21, 20, 20, 18, quest1()18, quest1()17, 16, 16, newdquest1()15, newd1()14, quest1()14, quest1()14, quest1()13, 12, 12, newd1()11; sn n=44, k >= 2: 29, 24, 23, 22, 21, 20, 19coderef(dodunekov manev 1985), 18, quest1()18, quest1()17, 16, 16, newdquest1()15, newd1()14, quest1()14, quest1()14, newd1()12, 12, 12; sn n=45, k >= 2: 30, 25, 24, 22, 22, 20, 20, quest1()19, 18, quest1()18, newd1()16, 16, 16, newdquest1()15, quest1()14, quest1()14, newdquest1()13, newd1()12, 12; pstail pshead(90) // k = 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 psnext n=40, k >=21: newdquest()9, newd()8, 8, quest()8, quest()8, quest()7, 6, 6, 5, 4, 4, 4, 4, 3, 2, 2, 2, 2, 2; sn n=41, k >=21: quest1()10, newdquest()9, newd()8, 8, quest()8, quest()8, newd()6, 6, 6, 5, 4, 4, 4, 4, 3, 2, 2, 2, 2; sn n=42, k >=21: 10, quest1()10, newdquest()9, newd()8, 8, quest()8, newdquest()7, newd()6, 6, 6, 5, 4, 4, 4, 4, 3, 2, 2, 2; sn n=43, k >=21: newd1()10, quest1()10, quest1()10, newdquest()9, newd()8, 8, quest()8, newdquest()7, newd()6, 6, 6, 5, 4, 4, 4, 4, 3, 2, 2; sn n=44, k >=21: newd1()11, newd1()10, quest1()10, quest1()10, newdquest()9, newd()8, 8, quest()8, newdquest()7, 6, 6, 6, 5, 4, 4, 4, 4, 3, 2; sn n=45, k >=21: 12, newd1()11, newd1()10, quest1()10, quest1()10, newdquest()9, newd()8, 8, quest()8, quest()7coderef(brouwer linear programming bound), 6, 6, 6, 5, 4, 4, 4, 4, 3; pstail pshead(80) // k = 40 41 42 43 44 psnext n=41, k>=40: 2; sn n=42, k>=40: 2, 2; sn n=43, k>=40: 2, 2, 2; sn n=44, k>=40: 2, 2, 2, 2; sn n=45, k>=40: 2, 2, 2, 2, 2; pstail \vspace{0.12in} \begin{svb} data_comment( ![ \block{There is a unique $[48,8,22]$ code} The existence of this code is due to Dodunekov and Manev [.dodunekov manev 1985.]. ]! ) no [46,7,22]; [48_8_22] type [48,8,22]; [a] := {100000000001111101111111111000001111100000000001, 010000001110001101110000111011110001100001111000, 001000001101101001001110100010001001111101110100, 000100001011010100101101010001000101111011101010, 000010011101010000111011010111011000101000010110, 000001010100011101010100011000011010101111001110, 000000111111111100000011111111111111111111000000, 000000000000000011111111111111111111111111111111}; (* pseudocyclic (1,2,3,9,10,11,6,13)(4,14,16,15,7,12,8,5) (17,35,26,43,31,47,23,41)(18,39,29,42,30,34,25,40) (19,44,20,45,24,36,21,38)(22,48,27,37,28,46,32,33) : 000000111111111100000011111111111111111111000000 *); at [base]; show y29 = 0, y45 = 0, y46 = 0, y47 = 0, y48 = 0; kill y44,y40,y36; show (joint:0) y22 = 144, y24 = 60, y28 = 0, y30 = 48, y32 = 3; config 32,16 : {10}; kill x_16_14; show 141 <= y22 <= 144, 60 <= y24 <= 65, 43 <= y30 <= 48, 3 <= y32 <= 6; show (joint) y22 = 144, y24 = 60, y30 = 48, y32 = 3; config from x_16_16|x_6_6_10; via building [current] implies [a]; classification of [base]: [a]; status: classified, weights = {22,24,30,32}; data_block(There is no $[48,11,20]$ code}\label{section-48-11) type [48,11,20_2]; { show y42 = 0, y44 = 0, y46 = 0, y48 = 0; kill y40, y38, y34, y26; show y32 != 0; config 32,16 : {10}; kill x_16_16, x_12_16, x_10_14; via lp [current] = }; no [48,11,20]; data_block(Table for codes of length $46$ through $50$) type [51,9,22_2]; show (joint:5) y50 = 0; status: weights = 22_2 - {50}; no [51,10,22]; no [49,18,16]; type [46,9,20_2]; kill y46, y38, y34, y30, y26, y40; status: weights = {20,24,28,32,36}; type [46,9,20]; status: weights = {20,24,28,32,36}; type [47,7,22]; status: weights = {22,24,30,32}; show (joint:5) y30 = 18; show (joint:5) y32 = 1; show (joint:5) y22 = 78, y24 = 30; status: enumerator = 1 + 78t^22 + 30t^24 + 18t^30 + t^32; type [47,10,20]; show (joint:5) 418 <= y20 <= 420, 309 <= y24 <= 318, 278 <= y28 <= 291, y32 <= 9, y36 <= 2; show (joint:0) y20 <= 419, y24 >= 313, y28 <= 286, y32 >= 4, y36 <= 1; show (joint:0) y24 >= 314, y28 <= 284, y32 >= 5; status: weights = {20,24,28,32,36}, constraints = {418 <= y20 <= 419, 313 <= y24 <= 318, 278 <= y28 <= 284, 5 <= y32 <= 9, y36 <= 1}; TYPE_WE(48,6,24,1 + 60t^24 + 3t^32) type [48,13,18_2]; status: weights = 18_2 - {48}; no [48,11,20]; type [49,11,20_2]; kill y46 by x_20_0; status: weights = {20,22,24,26,28,30,32,34,36,38,40,42,44,48}; type [50,4,26_2]; status: weights = {26,28,30,32}; no [49,9,22]; no [50,9,22] ; type [50,12,20]; kill y50 by x_20, y48 by x_18_2, y42, y38, y34, y30, y26; status: weights = {20,24,28,32,36,40,44}; TYPE_WE(50,7,24,1 + 108t^24 + 19t^32) psheadx(80) // k = 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 psnext n=46, k >= 2: 30, 26, 24, 23, 22, 21, 20, quest1()20, quest1()19, quest1()18, newdquest1()17, newd1()16, 16, quest1()16, quest1()15coderef(daskalov kapralov), quest1()14, quest1()14, newdquest1()13, newd1()12; sn n=47, k >= 2: 31, 26, 24, 24, 23, 22, 21, 20, quest1()20, newd1()18, quest1()18, newdquest1()17, 16, quest1()16, quest1()16, quest1()15, quest1()14, quest1()14, newdquest1()13; sn n=48, k >= 2: 32, 27, 24, 24, 24, 22, 22, 20, quest1()20, newdquest1()19, quest1()18, quest1()18, quest1()17, 16, quest1()16, quest1()16, newdquest1()14, quest1()14, quest1()14; sn n=49, k >= 2: 32, 28, 25, 24, 24, 23, 22, newdquest1()20, 20, quest1()20, quest1()19coderef(hill traynor), quest1()18, quest1()18, quest1()17, 16, quest1()16, newdquest1()15, newdquest1()14, quest1()14; sn n=50, k >= 2: 33, 28, 26, 24, 24, 24, 23, newdquest1()21, newd1()20, 20, quest1()20, quest1()19, quest1()18, quest1()18, quest1()17, quest1()16, quest1()16, newdquest1()15, newdquest1()14; pstail pshead(80) // k = 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 psnext n=46, k >=21: 12, 12, newd1()11, newd1()10, quest1()10, quest1()10, newdquest()9, 8, 8, quest()8, quest()7, 6, 6, 6, 5, 4, 4, 4, 4; sn n=47, k >=21: newd1()12, 12, 12, newd1()11, newdquest1()10, quest1()10, quest1()10, quest()9, 8, 8, quest()8, quest()7, 6, 6, 6, 5, 4, 4, 4; sn n=48, k >=21: newdquest1()13, newd1()12, 12, 12, newdquest1()11, newdquest1()10, quest1()10, quest1()10, quest()9, 8, 8, quest()8, quest()7, 6, 6, 6, quest()5, 4, 4; sn n=49, k >=21: quest1()14, newdquest1()13, newd1()12, 12, quest1()12, newdquest1()11, newdquest1()10, quest1()10, quest1()10, newd()8, 8, quest()8, quest()8, quest()7, 6, 6, quest()6, quest()5, 4; sn n=50, k >=21: quest1()14, quest1()14, newdquest1()13, newd1()12, quest1()12, quest1()12, newdquest1()11, newdquest1()10, quest1()10, newdquest()9, newd()8, 8, quest()8, quest()8, quest()7, 6, 6, quest()6, quest()5; pstail pshead(80) // k = 40 41 42 43 44 45 46 47 48 49 psnext n=46, k>=40: 3, 2, 2, 2, 2, 2; sn n=47, k>=40: 4, 3, 2, 2, 2, 2, 2; sn n=48, k>=40: 4, 4, 3, 2, 2, 2, 2, 2; sn n=49, k>=40: 4, 4, 4, 3, 2, 2, 2, 2, 2; sn n=50, k>=40: 4, 4, 4, 4, 3, 2, 2, 2, 2, 2; pstail \vspace{0.12in} \begin{svb} data_block(There is a unique $[51,8,24]$ code) [51_8_24] type [51,8,24]; [a] := {100000000001111101111111111000001111100000000001011, 010000001110001101110000111011110001100001111000011, 001000001101101001001110100010001001111101110100101, 000100001011010100101101010001000101111011101010101, 000010011101010000111011010111011000101000010110011, 000001010100011101010100011000011010101111001110101, 000000111111111100000011111111111111111111000000110, 000000000000000011111111111111111111111111111111000} :: {y24 = 204, y32 = 51}; CLASSIFICATION_OF([base], x_32|x_16_16|x_6_6_10_2|x15155511, [a]) STATUS_UNIQUE_WE(1 + 204t^24 + 51t^32) data_block(There is no $[55,39,8]$ code) type [55,16,13] {y55=1, mu1=0, mu2=0, mu3=0, mu4=0, mu5=0, mu6=0, mu7=0}; =config 55 : {1}; kill y13, y14, y15, y16, y17 by x_0_18, y18 by x_0_18, y19; kill current by x_20; type [55,39,8_2]; via dual nonexistence infer [base] = ; no [55,39,8]; data_block(Table for codes of length $51$ through $55$) no [51,10,22]; type [51,13,20_2]; status: weights = {20,24,28,32,36,40}; type [51,13,20]; status: weights = {20,24,28,32,36,40}; type [52,5,26_2]; status: weights = {26,28,30,32}; type [52,10,22_2]; kill y52 by x_22; status: weights = {22,24,26,28,30,32,34,36,38,40,42,44,46,48}; no [52,11,22]; type [53,6,26]; status: weights = {26,28,30,32}; no [53,9,24]; type [53,11,22_2]; kill y48 by (x_22_0, x_22_2, x_18_4); status: weights = {22,24,26,28,30,32,34,36,38,40,42,44,46}; type [53,14,20_2]; show (joint:0) y52 = 0 ; status: weights = {20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50}; no [53,18,18]; no [54,7,26]; type [54,9,24_2]; status: weights = {24,26,28,32,34,36,40,44,48}; type [54,9,24]; status: weights = {24,25,26,28,32,33,34,36,40,44,48}; type [54,12,22_2]; { kill y54, y46 by (x_14_8, x_15_7, x_16_6, x_16_8), y44 by (x_12_10, x_13_9, x_14_10, x_15_7, x_15_9, x_17_7), y42 by (x_11_11, x_12_10, x_13_9, x_13_11, x_14_8, x_14_10), y40 by (x_11_11, x_12_10, x_12_12, x_13_9, x_13_11, x_14_8) }; status: weights = 22_2 - {26,40..54}; type [54,12,22]; status: weights = 22_2 - {26,40..54}; no [54,19,18]; [55_5_28] type [55,5,28]; [a] config 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1 : {1001011001101001011010011001011,0101010101010101101010101010101, 0011001100110011110011001100110,0000111100001111111100001111000, 0000000011111111111111110000000} :: {1 + 28t^28 + 3t^32}; at [base]; show y40 = 0; via building [current] implies [a]; classification of [base]: [a]; STATUS_UNIQUE_WE(1 + 28t^28 + 3t^32) no [55,7,26]; type [55,10,24_2]; kill y26, y34, y48; status: weights = {24,28,32,36,40,44}; type [55,10,24]; status: weights = {24,28,32,36,40,44}; no [55,13,22]; TYPE_WE(56,6,28,1 + 56t^28 + 7t^32) type [56,11,24_2]; kill y56 by x_28 ; status: weights = {24,28,32,36,40}; type [56,13,22_2]; status: weights = 22_2 - {56}; psheadx(80) // k = 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 psnext n=51, k >= 2: 34, 28, 26, 25, 24, 24, 24, quest1()22, newdquest1()21, newd1()20, quest1()20, quest1()20, newdquest1()18, quest1()18, quest1()18, quest1()17, quest1()16, quest1()16, newdquest1()15; sn n=52, k >= 2: 34, 29, 27, 26, 25, 24, 24, 22, quest1()22, newdquest1()21, newd1()20, quest1()20, newdquest1()19, newdquest1()18, quest1()18, quest1()18, newdquest1()16, quest1()16, quest1()16; sn n=53, k >= 2: 35, 30, 28, 26, 26, 24, 24, quest1()23coderef(dodunekov encheva ivanov), 22, quest1()22, newdquest1()21, 20, quest1()20, newdquest1()19, newdquest1()18, quest1()18, newdquest1()17, newdquest1()16, quest1()16; sn n=54, k >= 2: 36, 30, 28, 27, 26, 24, 24, quest1()24, quest1()23, quest1()22, quest1()22, newd1()20, 20, quest1()20, newdquest1()19, newdquest1()18, quest1()18, newdquest1()17, newdquest1()16; sn n=55, k >= 2: 36, 31, 28, 28, 27, 25coderef(tilborg 1979), 24, 24, quest1()24, quest1()23, quest1()22, newdquest1()21, newd1()20, 20, quest1()20, newdquest1()19, quest1()18, quest1()18, newdquest1()17; pstail pshead(80) // k = 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 psnext n=51, k >=21: newdquest1()14, quest1()14, quest1()14, newdquest1()13, newdquest1()12, quest1()12, quest1()12, newdquest1()11, quest1()10, quest1()10, newdquest()9, newd()8, 8, quest()8, quest()8, quest()7, 6, 6, quest()6; sn n=52, k >=21: newdquest1()15, newdquest1()14, quest1()14, quest1()14, newdquest1()13, newdquest1()12, quest1()12, quest1()12, quest1()11coderef(brouwer linear programming bound), quest1()10, quest1()10, newdquest()9, newd()8, 8, quest()8, quest()8, quest()7, 6, 6; sn n=53, k >=21: quest1()16, newdquest1()15, newdquest1()14, quest1()14, quest1()14, newdquest1()13, newdquest1()12, quest1()12, quest1()12, quest1()11, quest1()10, quest1()10, newdquest()9, newd()8, 8, quest()8, quest()8, quest()7, 6; sn n=54, k >=21: quest1()16, quest1()16, newdquest1()15, newdquest1()14, quest1()14, quest1()14, newdquest1()13, newdquest1()12, quest1()12, quest1()12, quest1()11, quest1()10, quest1()10, newdquest()9, newd()8, 8, quest()8, quest()8, newd()6; sn n=55, k >=21: newdquest1()16, quest1()16, quest1()16, newdquest1()15, newdquest1()14, quest1()14, quest1()14, newdquest1()13, quest1()12, quest1()12, quest1()12, quest1()11, quest1()10, quest1()10, newdquest()9, newd()8, 8, quest()8, newdquest()7; pstail pshead(80) // k = 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 psnext n=51, k >=40: quest()5, 4, 4, 4, 4, 3, 2, 2, 2, 2, 2; sn n=52, k >=40: quest()6, quest()5, 4, 4, 4, 4, 3, 2, 2, 2, 2, 2; sn n=53, k >=40: 6, quest()6, quest()5, 4, 4, 4, 4, 3, 2, 2, 2, 2, 2; sn n=54, k >=40: 6, 6, quest()6, quest()5, 4, 4, 4, 4, 3, 2, 2, 2, 2, 2; sn n=55, k >=40: newd()6, 6, 6, quest()6, quest()5, 4, 4, 4, 4, 3, 2, 2, 2, 2, 2; pstail \vspace{0.12in} \begin{svb} data_comment( ![ \block{Table for codes of length $56$ through $71$}\label{section-56-71} ]! ) no [63,8,30]; no [64,8,30]; type [64,21,22_2]; kill y64,y62,y60,y58,y56,y44,y42,y40; via lp [base] = ; no [64,21,22]; no [58,27,16]; no [58,9,26]; no [58,7,28]; no [67,8,32]; no [67,10,30]; type [57,4,30_2]; status: weights = {30,32}; no [57,12,24]; type [58,12,24_2]; kill y58, y54, y50, y46, y42, y38 by (x_5_19, x_6_20, x_7_17, x_8_18, x_9_15), y34 by (x_1_23, x_2_24, x_3_21, x_4_22, x_5_19, x_5_23, x_6_20, x_7_17, x_7_21, x_8_18, x_9_15, x_9_19); show (joint) y26 = 0; show (joint:0) y56 = 0; status: weights = 24_4 - {56}; type [57,18,20_2]; kill y56 by x_26_0, y54 by x_17_3, y52 by (x_15_5, x_17_3); status: weights = 20_2 - {22,52..57}; type [58,19,20_2]; kill y58 by x_20, y50 by (x_16_8, x_18_8, x_20_0); status: weights = 20_2 - {22,50..58}; no [60,36,12] ; type [57,8,26_2]; status: weights = {26,28,30,32,34,36,38,40,42,44}; type [57,8,26]; status: weights = 26_2 - {46..57}; type [59,5,30_2]; status: enumerator = 1 + 24t^30 + 7t^32; type [59,7,28]; status: weights = {28,30,32,36,40,44,48,52,56}; config 56,3 : {10}; kill x_27_3 ; at [base]; ??infer jy56y30y32 = 0; show (joint:5) y30 = 0; status: weights = 28_4 - {58}; type [59,9,26_2]; status: weights = 26_2 - {58}; no [57,12,24]; type [59,13,24]; status: weights = {24,28,32,36,40,44,48}; TYPE_WE(60,6,30,1 + 48t^30 + 15t^32) type [60,8,28_2]; status: weights = {28,32,36,40,44}; type [60,8,28]; status: weights = {28,32,36,40,44}; no [58,9,26]; type [60,10,26_2]; kill y60, y56 by (x_26_0, x_26_2, x_27_1, x_27_3, x_28_0); status: weights = {26,28,30,32,34,36,38,40,42,44,46,48,50,52,54}; no [60,18,22]; type [61,18,22_2]; kill y60, y58, y56 by (x_17_5, x_27_5, x_25_5), y54 by (x_15_7, x_16_6, x_17_7, x_18_6), y52 by (x_13_9, x_15_9, x_19_9, x_21_9, x_22_0); status: weights = {22,24,28,30,32,34,36,38,40,42,44,46,48,50}; type [60,21,20_2]; kill y60,y42,y38,y34,y48,y46,y44; via lp [current] = ; no [60,21,20]; type [60,32,14_2]; show y60 = 1; status: weights = 14_2 - {48..58}, constraints = {y60 = 1}; type [61,11,26_2]; kill y54 by (x_21_5, x_23_5, x_23_7, x_24_2); status: weights = 26_2 - {54..61}; type [62,19,22_2]; kill y62 by x_22, y50 by (x_12_12, x_16_12, x_18_12, x_22_12, x_20_12, x_24_12, x_11_11, x_13_11, x_22_0); status: weights = {22,24,28,30,32,34,36,38,40,42,44,46,48}; TYPE_WE(62,7,30_2,1 + 63t^30 + 63t^32 + t^62) type [62,7,30]; status: weights = {30,31,32,62}; no [61,9,28]; type [62,9,28_2]; kill y62, y60, y58, y54, y50, y56 by (x_22_6, x_26_2); status: weights = {28,30,32,34,36,40,42,44,46,48,52}; type [62,55,4_2]; status: weights = 4_2 - {62} ; TYPE_WE(63,6,32,1 + 63t^32) type [63,10,28]; status: weights = {28,32,36,40,44,48}; type [63,20,22_2]; status: weights = 22_2 - {26,50,52,54,56,58,60,62}; set auto mu1; type [63,31,16_2]; status: weights = 16_2 - {62}; TYPE_WE(64,7,32,1 + 126t^32 + t^64) type [64,11,28_2]; status: weights = {28,32,36,40,44}; kill y44 by x_18_10, y40 by x_16_12 ; no [64,11,28]; psheadx(110) // k = 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 psnext n=56, k >= 2: 37, 32, 29, 28, 28, 26, quest1()25, 24, 24, quest1()24, newdquest1()22, quest1()22, newdquest1()21, newd1()20, 20, quest1()20, quest1()19coderef(brouwer linear programming bound), quest1()18, quest1()18; sn n=57, k >= 2: 38, 32, 30, 28, 28, 26, quest1()26, newd1()24, 24, quest1()24, newdquest1()23, quest1()22, quest1()22, newdquest1()21, 20, quest1()20, quest1()20, quest1()19, quest1()18; sn n=58, k >= 2: 38, 32, 30, 29, 28, 27coderef(tilborg 1981), 26, newdquest1()25, 24, 24, quest1()24, quest1()23coderef(hill traynor), quest1()22, quest1()22, quest1()21coderef(brouwer linear programming bound), quest1()20, quest1()20, quest1()20, quest1()19; sn n=59, k >= 2: 39, 33, 31, 30, 29, 28, quest1()27, quest1()26, quest1()25, 24, quest1()24, quest1()24, newdquest1()22, quest1()22, quest1()22, quest1()21, quest1()20, quest1()20, quest1()20; sn n=60, k >= 2: 40, 34, 32, 30, 30, 28, quest1()28, 26, quest1()26, quest1()25, 24, quest1()24, newdquest1()23, newdquest1()22, quest1()22, quest1()22, quest1()21, quest1()20, quest1()20; sn n=61, k >= 2: 40, 34, 32, 31, 30, 29coderef(logacev), 28, quest1()27coderef(dodunekov encheva ivanov), 26, quest1()26, newd1()24, 24, quest1()24, newdquest1()23, quest1()22, quest1()22, quest1()22, quest1()21, quest1()20; sn n=62, k >= 2: 41, 35, 32, 32, 31, 30, 28, quest1()28, quest1()27, quest1()26, newdquest1()25, newd1()24, 24, quest1()24, quest1()23coderef(brouwer linear programming bound), quest1()22, quest1()22, quest1()22, quest1()21; sn n=63, k >= 2: 42, 36, 32, 32, 32, 31, newd1()28, 28, quest1()28, newd1()26, quest1()26, newdquest1()25, newd1()24, 24, quest1()24, quest1()23, quest1()22, quest1()22, quest1()22; pstailx type [64,32,16_2]; kill y60,y58,y56,y54,y52,y50; show y64 = 1 ; status: weights = 16_2 - {50..62}, constraints = {y64 = 1}; set dual constraint bound = 3; no [64,8,30]; type [66,9,30_2]; { kill y66,y64,y62,y60,y58; show (joint:0) y56 = 0; kill y54 by (x_18_12, x_20_10, x_21_11) }; status: weights = {30,32,34,36,38,40,44,46,48,50,52}; set dual constraint bound = 0; type [66,9,30]; status: weights = {30,32,34,36,38,40,44,46,48,50,52}; type [65,4,34_2]; status: weights = {34,36,38,40}; type [65,8,30_2]; kill y64, y60 by x_30_0, y62 by x_27_3, y58; status: weights = {30,32,34,36,38,40,42,44,46,48,50,52,54,56}; type [65,11,28_2]; status: weights = 28_2 - {58,62}; type [65,14,26_2]; kill y64 by x_26_0 ; status: weights = 26_2 - {64}; type [65,18,24_2]; kill y64, y60 by x_24_0; kill y62 by x_21_3 ; status: weights = 24_2 - {30,60..65}; type [66,9,30_2]; status: weights = 30_2 - {42,50..66}; type [66,12,28_2]; status: weights = {28,32,36,40,44,48,52,56,60}; type [66,19,24_2]; status: weights = 24_2 - {30,60..66}; type [67,13,28_2]; status: weights = {28,32,36,40,44,48,52,56}; kill y56 by (x_18_10, x_22_6) ; status: weights = {28,32,36,40,44,48,52}; type [68,5,34_2]; status: weights = 34_2 - {50..68}; type [68,8,32_2]; status: weights = {32,34,36,40,42,44,48,50,52,64}; type [68,8,32]; status: weights = {32,33,34,36,40,41,42,44,48,50,52,64}; type [68,10,30_2]; kill y68, y66 by x_30_0; kill y62 by (x_27_3, x_27_5, x_28_2), y60 by x_30_0 ; status: weights = 30_2 - {60,62,66,68}; no [65,12,28]; type [68,14,28_2]; status: weights = {28,32,36,40,44,48}; type [68,14,28]; status: weights = {28,32,36,40,44,48}; type [68,17,26_2]; kill y64 by x_24_2; status: weights = 26_2 - {64}; type [69,9,32_2]; kill y64, y52, y50, y34, y36 by (x_10_22, x_16_20); STATUS_WE(1 + 351t^32 + 156t^40 + 4t^48) TYPE_WE(69,9,32,1 + 351t^32 + 156t^40 + 4t^48) type [69,11,30_2]; kill y58 by (x_19_11, x_20_10, x_21_9, x_21_11, x_22_8, x_22_10, x_23_9, x_23_11, x_24_6); status: weights = 30_2 - {58,60,62,66,68}; type [69,18,26_2]; status: weights = 26_2 - {34,56..69}; set dual constraint bound = 3; type [70,6,34_2]; status: weights = {34,36,38,40,42,44,46,48,50,52,54,56,60,64,70}; status: weights = {34,36,38,40,42,44,46,48,50,52,54,56,60,64}; set dual constraint bound = 0; type [70,12,30_2]; kill y56 by (x_16_14, x_17_13, x_18_12, x_18_14, x_20_10, x_20_12, x_22_10, x_22_12, x_22_14, x_23_7); status: weights = {30,32,34,36,38,40,44,46,48,50,52,54,64,70}; type [70,15,28_2]; kill y70 by x_28, y68 by x_26_2; status: weights = {28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,66}; type [70,26,22_2]; kill y70, y68 by x_20_2; status: weights = 22_2 - {68,70}; type [70,30,20_2]; kill y70 by x_20, y68 by x_20_0; status: weights = 20_2 - {68,70}; type [70,45,12_2]; status: weights = 12_2 - {70}; type [71,5,36_2]; kill y56, ndiv4; status: weights = 36_4 - {52..71}; type [71,10,32_2]; status: weights = {32,34,36,40,42,44,48,52,64}; show (joint:5) 474 <= y32 <= 601, y34 <= 168, y36 <= 162, 237 <= y40 <= 448, y42 <= 122; show (joint:5) 478 <= y32 <= 595, y34 <= 160, y40 >= 249, y42 <= 109, y52 <= 6; show (joint:5) y32 >= 480, y34 <= 156, y40 >= 255; show (joint:5) div4 >= 769; infer div4 = 1024; show (joint:5) y32 >= 525, y40 >= 266, y44 <= 70, y48 <= 17, y64 <= 1; status: weights = {32,36,40,44,48,52,64}, constraints = {525 <= y32 <= 595, y36 <= 162, 266 <= y40 <= 448, y44 <= 70, y48 <= 17, y52 <= 6, y64 <= 1}; type [71,13,30_2]; status: weights = {30,32,34,36,38,40,44,46,48,50,52,54}; no [71,13,30]; no [69,6,34]; type [71,7,34]; show (joint:0) y34 = 42 ; kill y60,y56,y54,y52,y48,y46; show y64 = 1; STATUS_WE(1 + 14t^38 + 42t^34 + 70t^36 + t^64) type [71,16,28_2]; kill y66 by (x_30_0, x_32_0); status: weights = {28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64}; type [71,23,24_2]; kill y70 by x_24_0; status: weights = 24_2 - {70}; type [71,31,20_2]; status: weights = 20_2 - {22,68,70}; type [72,4,38_2]; status: weights = {38,40}; type [72,11,32]; kill y52 by (x_18_18, x_16_16, x_24_20, x_22_14, x_20_12, x_22_10), y44, y36 by (x_0_36, x_18_31) ; status: weights = {32,40,48,64}; unset auto mu1; psheadx(110) // k = 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 psnext n=64, k >= 2: 42, 36, 33, 32, 32, 32, newd1()29, 28, 28, newdquest1()27, newdquest1()26, quest1()26, newdquest1()25, 24, 24, quest1()24, newdquest1()22, quest1()22, quest1()22; sn n=65, k >= 2: 43, 36, 34, 32, 32, 32, 30, quest1()29coderef(dodunekov encheva ivanov), 28, quest1()28, newdquest1()27, quest1()26, quest1()26, quest1()25, 24, quest1()24, newdquest1()23, newdquest1()22, quest1()22; sn n=66, k >= 2: 44, 37, 34, 32, 32, 32, 30, quest1()30, newd1()28, 28, quest1()28, quest1()27coderef(daskalov 66_13_28), quest1()26, quest1()26, quest1()25, 24, quest1()24, newdquest1()23, newdquest1()22; sn n=67, k >= 2: 44, 38, 35, 33, 32, 32, 31coderef(dodunekov 1987), 30, newd1()29, newd1()28, quest1()28, quest1()28, quest1()27, quest1()26, quest1()26, quest1()25, 24, quest1()24, newdquest1()23; sn n=68, k >= 2: 45, 38, 36, 34, 32, 32, 32, quest1()31, 30, newdquest1()29, newdquest1()28, quest1()28, quest1()28, newdquest1()26, quest1()26, quest1()26, newd1()24, quest1()24, quest1()24; sn n=69, k >= 2: 46, 39, 36, 34, 33, 32, 32, quest1()32, 30, quest1()30, newdquest1()29, quest1()28, quest1()28, newdquest1()27, newdquest1()26, quest1()26, newdquest1()25, newdquest1()24, quest1()24; sn n=70, k >= 2: 46, 40, 36, 35, 34, 33, 32, 32, 31coderef(hill traynor), quest1()30, quest1()30, newd1()28, quest1()28, quest1()28, newdquest1()27, newdquest1()26, quest1()26, newdquest1()25, newdquest1()24; sn n=71, k >= 2: 47, 40, 37, 36, 34, 34, 32, 32, 32, quest1()31, quest1()30, newdquest1()29, newdquest1()28, quest1()28, quest1()28, newdquest1()27, quest1()26, quest1()26, newdquest1()25; pstailx no [68,36,16]; no [67,36,15]; no [67,31,18]; psheadx(110) // k = 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 psnext n=56, k >=21: newdquest1()17, newdquest1()16, quest1()16, quest1()16, newdquest1()15, newdquest1()14, quest1()14, quest1()14, quest1()13, quest1()12, quest1()12, quest1()12, quest1()11, quest1()10, quest1()10, newdquest()9, newd()8, 8, quest()8; sn n=57, k >=21: quest1()18, newdquest1()17, newdquest1()16, quest1()16, quest1()16, newdquest1()15, newdquest1()14, quest1()14, quest1()14, quest1()13, quest1()12, quest1()12, quest1()12, quest1()11, quest1()10, quest1()10, newdquest()9, newd()8, 8; sn n=58, k >=21: quest1()18, quest1()18, newdquest1()17, newdquest1()16, quest1()16, quest1()16, newdquest1()15, newdquest1()14, quest1()14, quest1()14, quest1()13, quest1()12, quest1()12, quest1()12, quest1()11, quest1()10, quest1()10, newdquest()9, 8; sn n=59, k >=21: newdquest1()18, quest1()18, quest1()18, newdquest1()17, quest1()16, quest1()16, quest1()16, newdquest1()15, quest1()14, quest1()14, quest1()14, quest1()13, quest1()12, quest1()12, quest1()12, newdquest1()10, quest1()10, quest1()10, quest()9; sn n=60, k >=21: newdquest1()19, newdquest1()18, quest1()18, quest1()18, quest1()17, quest1()16, quest1()16, quest1()16, quest1()15, quest1()14, quest1()14, quest1()14, newdquest1()12, quest1()12, quest1()12, newdquest1()11, newdquest1()10, quest1()10, quest1()10; sn n=61, k >=21: quest1()20, newdquest1()19, newdquest1()18, quest1()18, quest1()18, quest1()17, quest1()16, quest1()16, quest1()16, quest1()15, quest1()14, quest1()14, newdquest1()13, newdquest1()12, quest1()12, quest1()12, newdquest1()11, newdquest1()10, quest1()10; sn n=62, k >=21: quest1()20, quest1()20, newdquest1()19, newdquest1()18, quest1()18, quest1()18, quest1()17, quest1()16, quest1()16, quest1()16, quest1()15, quest1()14, quest1()14, newdquest1()13, newdquest1()12, quest1()12, quest1()12, newdquest1()11, quest1()10; sn n=63, k >=21: newdquest1()20, quest1()20, quest1()20, newdquest1()19, newdquest1()18, quest1()18, quest1()18, quest1()17, quest1()16, quest1()16, quest1()16, quest1()15, quest1()14, quest1()14, newdquest1()13, newdquest1()12, quest1()12, quest1()12, quest1()11coderef(brouwer linear programming bound) ; pstail pshead(110) // k = 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 psnext n=64, k >=21: newdquest1()21, newdquest1()20, quest1()20, quest1()20, newdquest1()19, quest1()18, quest1()18, quest1()18, quest1()17, quest1()16, quest1()16, quest1()16, newdquest1()14, quest1()14, quest1()14, newdquest1()13, newdquest1()12, quest1()12, quest1()12; sn n=65, k >=21: quest1()22, newdquest1()21, newdquest1()20, quest1()20, quest1()20, quest1()19coderef(brouwer linear programming bound), quest1()18, quest1()18, quest1()18, quest1()17, quest1()16, quest1()16, newdquest1()15, newdquest1()14, quest1()14, quest1()14, newdquest1()13, newdquest1()12, quest1()12; sn n=66, k >=21: quest1()22, quest1()22, newdquest1()21, newdquest1()20, quest1()20, quest1()20, quest1()19, quest1()18, quest1()18, quest1()18, newdquest1()16, quest1()16, quest1()16, newdquest1()15, newdquest1()14, quest1()14, quest1()14, newdquest1()13, newdquest1()12; sn n=67, k >=21: newdquest1()22, quest1()22, quest1()22, newdquest1()21, newdquest1()20, quest1()20, quest1()20, quest1()19, quest1()18, quest1()18, newdquest1()17, quest1()17, quest1()16, quest1()16, newdquest1()15, newdquest1()14, quest1()14, quest1()14, newdquest1()13; sn n=68, k >=21: newdquest1()23, newdquest1()22, quest1()22, quest1()22, newdquest1()21, quest1()20, quest1()20, quest1()20, quest1()19, quest1()18, quest1()18, newdquest1()17, newdquest1()16, quest1()16, quest1()16, newdquest1()15, newdquest1()14, quest1()14, quest1()14; sn n=69, k >=21: quest1()24, newdquest1()23, newdquest1()22, quest1()22, quest1()22, quest1()21coderef(brouwer linear programming bound), quest1()20, quest1()20, quest1()20, quest1()19, quest1()18, quest1()18, newdquest1()17, newdquest1()16, quest1()16, quest1()16, newdquest1()15, quest1()14, quest1()14; sn n=70, k >=21: quest1()24, quest1()24, newdquest1()23, newdquest1()22, quest1()22, quest1()22, quest1()21, quest1()20, quest1()20, quest1()20, quest1()19, quest1()18, quest1()18, newdquest1()17, newdquest1()16, quest1()16, quest1()16, quest1()15coderef(brouwer linear programming bound), quest1()14; sn n=71, k >=21: newdquest1()24, quest1()24, quest1()24, newdquest1()23, newdquest1()22, quest1()22, quest1()22, quest1()21, quest1()20, quest1()20, quest1()20, quest1()19, quest1()18, quest1()18, newdquest1()17, newdquest1()16, quest1()16, quest1()16, quest1()15; pstail pshead(110) // k = 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 psnext n=56, k >=40: newdquest()7, newd()6, 6, 6, quest()6, quest()5, 4, 4, 4, 4, 3, 2, 2, 2, 2, 2; sn n=57, k >=40: quest()8, newdquest()7, 6, 6, 6, quest()6, quest()5, 4, 4, 4, 4, 3, 2, 2, 2, 2, 2; sn n=58, k >=40: 8, quest()8, quest()7coderef(brouwer linear programming bound), 6, 6, 6, quest()6, quest()5, 4, 4, 4, 4, 3, 2, 2, 2, 2, 2; sn n=59, k >=40: 8, 8, quest()8, quest()7, 6, 6, 6, quest()6, quest()5, 4, 4, 4, 4, 3, 2, 2, 2, 2, 2; sn n=60, k >=40: quest()9, 8, 8, quest()8, quest()7, 6, 6, 6, quest()6, quest()5, 4, 4, 4, 4, 3, 2, 2, 2, 2; sn n=61, k >=40: quest1()10, quest()9, 8, 8, quest()8, quest()7, 6, 6, 6, quest()6, newd()4, 4, 4, 4, 4, 3, 2, 2, 2; sn n=62, k >=40: quest1()10, quest1()10, quest()9, 8, 8, quest()8, quest()7, 6, 6, 6, newd()5, 4coderef(brouwer linear programming bound), 4, 4, 4, 4, 3, 2, 2; sn n=63, k >=40: quest1()10, quest1()10, quest1()10, quest()9, 8, 8, quest()8, quest()7, 6, 6, 6, 5, 4, 4, 4, 4, 4, 3, 2; pstail pshead(110) // k = 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 psnext n=64, k >=40: quest1()11, quest1()10, quest1()10, quest1()10, quest()9, 8, 8, quest()8, quest()7, 6, 6, 6, 5, 4, 4, 4, 4, 4, 2; sn n=65, k >=40: quest1()12, quest1()11, quest1()10, quest1()10, quest1()10, quest()9, 8, quest()8, quest()8, quest()7, 6, 6, 6, 5, 4, 4, 4, 4, 3; sn n=66, k >=40: quest1()12, quest1()12, quest1()11, quest1()10, quest1()10, quest1()10, quest()9, 8, quest()8, quest()8, quest()7, 6, 6, 6, quest()5, 4, 4, 4, 4; sn n=67, k >=40: quest1()12, quest1()12, quest1()12, quest1()11, quest1()10, quest1()10, quest1()10, quest()9, 8, quest()8, quest()8, quest()7, 6, 6, quest()6, quest()5, 4, 4, 4; sn n=68, k >=40: quest1()13, quest1()12, quest1()12, quest1()12, quest1()11, quest1()10, quest1()10, quest1()10, newd()8, 8, quest()8, quest()8, quest()7, 6, 6, quest()6, quest()5, 4, 4; sn n=69, k >=40: quest1()14, quest1()13, quest1()12, quest1()12, quest1()12, quest1()11, quest1()10, quest1()10, newdquest()9, newd()8, 8, quest()8, quest()8, quest()7, 6, 6, quest()6, quest()5, 4; sn n=70, k >=40: quest1()14, quest1()14, quest1()13, quest1()12, quest1()12, quest1()12, newdquest1()10, quest1()10, quest1()10, newdquest()9, 8coderef(brouwer linear programming bound), quest()8, quest()8, quest()8, newd()6, 6, 6, quest()6, quest()5; sn n=71, k >=40: quest1()14, quest1()14, quest1()14, quest1()13, quest1()12, quest1()12, newdquest1()11, newdquest1()10, quest1()10, quest1()10, quest()9, 8, quest()8, quest()8, newdquest()7, 6, 6, 6, quest()6; pstail pshead(180) // k = 59 60 61 62 63 64 65 66 67 68 69 70 psnext n=60, k >=59: 2; sn n=61, k >=59: 2, 2; sn n=62, k >=59: 2, 2, 2; sn n=63, k >=59: 2, 2, 2, 2; sn n=64, k >=59: 2, 2, 2, 2, 2; sn n=65, k >=59: 2, 2, 2, 2, 2, 2; sn n=66, k >=59: 3, 2, 2, 2, 2, 2, 2; sn n=67, k >=59: 4, 3, 2, 2, 2, 2, 2, 2; sn n=68, k >=59: 4, 4, 3, 2, 2, 2, 2, 2, 2; sn n=69, k >=59: 4, 4, 4, 3, 2, 2, 2, 2, 2, 2; sn n=70, k >=59: 4, 4, 4, 4, 3, 2, 2, 2, 2, 2, 2; sn n=71, k >=59: quest()5, 4, 4, 4, 4, 3, 2, 2, 2, 2, 2, 2; pstail \vspace{0.12in} \begin{svb} data_comment(\block{There is no $[81,12,36]$ code}\label{81-12-36-section}) no [77,9,36]; (* new result *); type [81,12,36_2]; { show y66 = 0, y68 = 0, y70 = 0, y72 = 0, y74 = 0, y76 = 0, y78 = 0, y80=0; kill y64, y60, y58, y56; show y50 = 0; kill y48 by (x_24_24, x_24_20); via lp [base] = }; no [81,12,36]; data_comment(![\block{There is no $[73,12,32]$ code}\label{73-12-32}]!) type [73,12,32_2]; { kill y64; !config 24,24,24,1 : {1100,0110}; !config 18,30,18,7 : {1100,0110}; at [base]; ??show jy48y48y48 = 0, jy48y48y36 = 0; via lp (joint:5) [current] = }; no [73,12,32]; data_comment(![ \block{Table for codes of length $72$ through $85$}\label{section-72-80} ]!) type [73,8,34_2]; kill y72, y68, y66, y70; kill y64 by (x_26_8, x_27_9, x_29_5) ; status: weights = 34_2 - {62..73}; type [73,14,30_2]; kill y72, y70, y68 by x_30_0; status: weights = {30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,66}; type [73,18,28_2]; status: weights = {28,30,32,34,36,40,44,48,52,56,60}; no [72,6,36]; type [74,7,36_2]; show y72 = 0, y74 = 0, y36 != 0; kill y36 ; no [74,7,36]; type [74,12,32_2]; kill y70, y66 by (x_28_6, x_29_5, x_30_2), y62 by (x_23_11, x_24_10, x_28_10, x_30_10, x_30_12, x_31_1); status: weights = {32,34,36,38,40,42,44,48,50,52,54,56,58,60,64,68,72,74}; type [74,15,30_2]; status: weights = 30_2 - {68..74}; type [74,26,24_2]; status: weights = 24_2 - {72,74}; type [74,30,22_2]; status: weights = 22_2 - {70..74}; type [75,5,38_2]; status: weights = {38,40,46,48}; type [75,7,36_2]; status: weights = {36,38,40,42,44,48,52,56,60,64,68,72}; type [75,9,34_2]; kill y74, y72, y70 by (x_31_3, x_31_5, x_32_4, x_33_1, x_33_3, x_33_5, x_34_0); kill y68 by x_34_0 ; status: weights = 34_2 - {68..75}; type [75,13,32_2]; kill y64 by (x_21_11, x_23_9, x_24_10, x_25_9, x_25_11, x_27_5, x_27_7, x_28_6, x_29_3, x_29_5, x_29_7, x_30_4, x_30_8, x_31_1, x_31_3, x_31_5, x_31_7, x_31_9, x_32_2, x_32_6) ; status: weights = {32,34,36,38,40,42,44,48,50,52,54,56,58,60}; type [75,23,26_2]; status: weights = 26_2 - {74}; set auto mu1; type [79,7,38_2]; { show (joint:5) y72 = 0; kill y76, y68 }; status: weights = {38,40,42,44,46,48,50,52,54,56,60,62,64}; type [79,10,36_2]; status: weights = {36,40,44,48,52,56,60}; show (joint:5) 542 <= y36 <= 578, 56 <= y40 <= 164 ; show (joint:5) 210 <= y44 <= 330 ; show (joint:5) 35 <= y48 <= 107, y52 <= 18, y56 <= 6, y60 <= 2 ; status: constraints = {542 <= y36 <= 578, 56 <= y40 <= 164, 210 <= y44 <= 330, 35 <= y48 <= 107, y52 <= 18, y56 <= 6, y60 <= 2}; type [79,19,30_2]; kill y78, y76 by x_30_0; status: weights = 30_2 - {76,78}; type [79,23,28_2]; status: weights = 28_2 - {74..79}; type [79,27,26_2]; status: weights = 26_2 - {66..79}; no [81,9,38]; no [81,7,40]; type [81,14,34_2]; status: weights = 34_2 - {76..81}; unset auto mu1; type [83,8,40_2]; { show y80 = 0, y82 = 0; kill y64; [56bound] config 83 ::: {y56 <= 5}; at [base]; via building [current] implies [56bound]; via lp [56bound] = ; classification of [base]: }; no [83,8,40]; (* Dodunekov et. al., 1987 *); no [84,6,42]; type [86,7,42_2]; { show y84 = 0, y86 = 0; kill y68, y60, y56; show div4 <= 47; infer div4 = 32; kill y42; via lp [current] = }; no [86,7,42]; set auto mu1; no [72,25,24]; type [72,28,22_2]; kill y72 by x_22; status: weights = 22_2 - {68..72}; type [72,32,20_2]; kill y72 by x_20; status: weights = 20_2 - {22,68..72}; type [73,6,36_2]; kill y72, ndiv4; status: weights = {36,40,44,48,52,56}; type [73,18,28_2]; status: weights = 28_2 - {38,42,46,50,54,58,62..73}; type [74,19,28_2]; kill y74,y34; no [74,19,28]; type [75,19,28_2]; kill y74 by x_28_0; status: weights = 28_2 - {74}; type [76,8,36_2]; { kill y76,y72,y68,y64,y60; show (joint:5) y42 = 0, y50 = 0 }; status: weights = {36,40,44,48,52,56}; type [76,8,36]; status: weights = {36,40,44,48,52,56}; type [76,10,34_2]; kill y76, y66 by (x_27_7, x_27_9, x_28_8, x_28_10, x_29_5, x_29_7, x_29_9, x_30_4); status: weights = {34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64}; type [76,14,32]; status: weights = {32,36,40,44,48,52}; type [76,17,30_2]; kill y76 by x_30; status: weights = {30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,66}; type [76,20,28_2]; kill y76 by x_28; status: weights = 28_2 - {74,76}; type [77,6,38_2]; kill y76, y60 by x_28_12; status: weights = {38,40,44,46,48,50,52,54,56,62}; status: weights = {38,40,46,48,54,56,62}; no [74,9,34]; type [77,11,34_2]; status: weights = 34_2 - {66..77}; kill y64 by (x_23_13, x_24_12, x_25_13, x_27_13, x_28_10, x_28_12, x_30_8, x_30_12, x_31_13, x_32_2) ; status: weights = 34_2 - {64..77}; type [77,18,30_2]; status: weights = 30_2 - {42,66..77}; type [78,9,36_2]; status: weights = {36,40,44,48,52,56,60,64}; type [78,12,34_2]; status: weights = {34,36,38,40,42,44,46,48,52,54,56,58,60}; type [78,15,32_2]; status: weights = 32_2 - {74..78}; type [78,26,26_2]; status: weights = 26_2 - {70..78}; unset auto mu1; set dual constraint bound = 0; type [79,7,38_2]; show (joint:0) y50 = 0, y60 = 0; status: weights = {38,40,42,44,46,48,52,54,56,62,64}; type [80,4,42_2]; status: weights = {42,44,46,48}; type [80,6,40_2]; kill y52, ndiv4; status: weights = {40,48,56,64,80}; type [80,6,40]; kill y80 ; status: weights = {40,48,56,64}; type [80,6,{40,48,56}]; show (joint:5) y40 <= 59, y48 >= 3, y56 <= 1; show (joint:5) 58 <= y40 <= 59, 3 <= y48 <= 5, y56 <= 1; type [80,8,38_2]; show (joint:5) y38 >= 133, 5 <= y54 <= 8, y56 <= 2; show (joint:5) 139 <= y38 <= 151, 58 <= y40 <= 76, y48 <= 6, y54 >= 6, y56 <= 1; show (joint:5) y38 >= 142, y40 <= 71, 30 <= y46 <= 37, y48 <= 5 ; show (joint:5) y38 >= 144, y40 <= 68, y46 >= 32; show (joint:5) y40 <= 67, y46 >= 33 ; show (joint:5) y38 >= 145, y46 >= 34; show (joint:5) y40 <= 66; show (joint:5) y38 >= 146; show (joint:5) y40 <= 65; show (joint:5) mu3 >= 178, 64 <= co <= 81, co54 = 0; ??infer co = 64; show (joint:5) div4 = 64; (* From analysis of [80,6] codes: *); ??show 58 <= y40 <= 59, 3 <= y48 <= 5, y56 <= 1; show (joint:5) y54 <= 7; show (joint:5) 150 <= y38 <= 151, 58 <= y40 <= 59, 34 <= y46 <= 36, 3 <= y48 <= 5; show (joint:5) 6 <= y54 <= 7, y56 <= 1 ; status: weights = {38,40,46,48,54,56}, constraints = {150 <= y38 <= 151, 58 <= y40 <= 59, 34 <= y46 <= 36, 3 <= y48 <= 5, 6 <= y54 <= 7, y56 <= 1}; type [80,8,38]; status: weights = {38,40,46,48,54,56}; type [80,10,36_2]; kill y80, y78, y76, y74 by (x_30_6, x_31_5, x_33_3, x_34_2); status: weights = {36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,66,68,70,72}; type [80,24,28_2]; status: weights = 28_2 - {62,66,70..80}; psheadx(105) // k = 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 psnext n=72, k >= 2: 48, 40, 38, 36, 35, 34, quest1()33, 32, 32, quest1()32, newdquest1()30, quest1()30, newdquest1()29, quest1()28, quest1()28, quest1()28, newdquest1()26coderef(brouwer linear programming bound), quest1()26, quest1()26; sn n=73, k >= 2: 48, 41, 38, 36, 36, 34, quest1()34, newd1()32, 32, quest1()32, newdquest1()31, newdquest1()30, quest1()30, quest1()29coderef(brouwer linear programming bound), quest1()28, quest1()28, newdquest1()27, newdquest1()26, quest1()26; sn n=74, k >= 2: 49, 42, 39, 37, 36, 35coderef(tilborg griesmer), 34, newdquest1()33, 32, 32, quest1()32, newdquest1()31, quest1()30, quest1()30, quest1()29, quest1()28, quest1()28, newdquest1()27, newdquest1()26; sn n=75, k >= 2: 50, 42, 40, 38, 36, 36, quest1()35, quest1()34, quest1()33, 32, quest1()32, quest1()32, quest1()31, quest1()30, quest1()30, quest1()29, quest1()28, quest1()28, newdquest1()27; sn n=76, k >= 2: 50, 43, 40, 38, 37, 36, quest1()36, newdquest1()34, quest1()34, quest1()33, 32, quest1()32, quest1()32, newdquest1()30, quest1()30, quest1()30, newdquest1()28, quest1()28, quest1()28; sn n=77, k >= 2: 51, 44, 40, 39, 38, 36, 36, newdquest1()35, quest1()34, quest1()34, quest1()33, quest1()32, quest1()32, newdquest1()31, quest1()30, quest1()30, newdquest1()29, newdquest1()28, quest1()28; sn n=78, k >= 2: 52, 44, 40, 40, 38, 37, 36, quest1()36, quest1()35, quest1()34, quest1()34, newd1()32, quest1()32, quest1()32, quest1()31coderef(brouwer linear programming bound), quest1()30, quest1()30, newdquest1()29, quest1()28; pstailx no [81,9,38]; no [83,10,38]; type [80,13,34_2]; kill y76 by x_34_0; status: weights = 34_2 - {76}; type [80,17,32_2]; status: weights = 32_2 - {74,76,78}; type [80,20,30_2]; status: weights = 30_2 - {76,78,80}; type [81,11,36_2]; kill y70 by (x_25_11, x_27_9, x_29_11, x_30_10, x_31_9, x_31_11, x_32_8, x_32_10, x_33_3, x_33_5, x_33_7, x_33_9, x_33_11, x_34_2); status: weights = {36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,66,68,72}; type [81,14,34_2]; kill y74 by (x_34_0, x_36_0); status: weights = {34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,66,68,70,72}; kill y72 by (x_26_8, x_27_7) ; status: weights = 34_2 - {72..81}; type [81,18,32_2]; status: weights = 32_2 - {46,66..81}; type [82,7,40]; status: weights = {40,44,48,56,64}; type [82,9,38_2]; status: weights = {38,40,44,46,48,50,52,54,56,60,62,64,66}; show (joint:0) y66 = 0; status: weights = {38,40,44,46,48,50,52,54,56,60,62,64}; type [82,12,36_2]; { kill y72 by (x_26_10, x_29_7, x_30_6, x_30_10, x_31_5), y68 by (x_23_13, x_29_11, x_29_13, x_30_12, x_30_14, x_31_11, x_31_13, x_32_12, x_32_14, x_33_3, x_33_9, x_33_11, x_33_13, x_34_2) }; status: weights = {36,38,40,42,44,46,48,50,52,56,58,60,62,64,66,82}; type [82,15,34_2]; status: weights = 34_2 - {72..82}; type [83,5,42_2]; status: weights = {42,44,46,48}; type [83,13,36_2]; kill y66,y62,y58,y50,y46,y42,y82; status: weights = {36,40,44,48,52,56,60,64}; type [83,16,34_2]; status: weights = 34_2 - {70..83}; type [83,19,32_2]; status: weights = 32_2 - {78..83}; type [83,23,30_2]; status: weights = 30_2 - {72..83}; type [83,38,22_2]; status: weights = 22_2 - {76..83}; type [84,8,40_2]; status: weights = {40,42,44,48,50,52,56,58,60,64}; type [84,10,38_2]; kill y84, y82, y80, y78 by x_38_0, y76 by x_38_0, y74 by (x_28_10, x_29_9, x_30_8, x_30_10, x_31_7, x_31_9, x_32_6); status: weights = {38,40,42,44,46,48,50,52,54,56,58,60,62,64,66,68,70,72}; no [79,13,34]; type [84,14,36_2]; status: weights = {36,40,44,48,52,56,60}; type [84,17,34_2]; status: weights = 34_2 - {70..84}; type [84,20,32_2]; status: weights = 32_2 - {78..84}; type [84,31,26_2]; status: weights = 26_2 - {82,84}; type [84,35,24_2]; status: weights = 24_2 - {82,84}; type [85,6,42_2]; kill y84, y68 by x_32_12; status: weights = {42,44,46,48,52,54,56,58,60,62,64,70}; show (joint:0) y52 = 0; kill y70 ; status: weights = {42,44,46,48,54,56,58,60,62,64}; type [85,9,40]; kill ndiv4, y64, y52 by x_20_20; STATUS_WE(1 + 361t^40 + 135t^48 + 15t^56) type [85,11,38_2]; { kill y72 by (x_25_13, x_27_11, x_27_13, x_28_10, x_28_12, x_29_9, x_29_11, x_30_8), y70 by (x_23_15, x_24_14, x_25_15, x_26_12, x_27_11, x_27_13, x_29_15, x_30_14, x_31_15, x_32_12, x_32_14, x_33_9, x_33_13, x_34_10, x_34_12) }; status: weights = {38,40,42,44,46,48,50,52,54,56,58,60,62,64,66,68}; type [85,14,36_2]; kill y84, y82, y80, y78 by x_36_0, y76 by (x_27_9, x_30_8, x_31_7, x_31_9, x_33_7, x_34_8, x_35_1, x_35_3, x_35_5, x_35_7, x_35_9, x_36_2, x_36_6, x_37_1, x_37_3, x_37_5, x_37_7, x_37_9, x_38_0, x_38_4); status: weights = {36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,66,68,70,72,74}; type [85,21,32_2]; status: weights = 32_2 - {74..85}; type [85,28,28_2]; status: weights = 28_2 - {84}; psheadx(105) // k = 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 psnext n=79, k >= 2: 52, 44, 41, 40, 39, 38, quest1()37, quest1()36, quest1()36, newdquest1()34, quest1()34, newdquest1()33, newdquest1()32, quest1()32, quest1()32, quest1()31, quest1()30, quest1()30, quest1()29coderef(brouwer linear programming bound) ; sn n=80, k >= 2: 53, 45, 42, 40, 40, 38, quest1()38, 36, quest1()36, newdquest1()35, newdquest1()34, quest1()34, newdquest1()33, quest1()32, quest1()32, quest1()32, newdquest1()30, quest1()30, quest1()30; sn n=81, k >= 2: 54, 46, 42, 40, 40, 39, 38, quest1()37, 36, quest1()36, newdquest1()35, quest1()34, quest1()34, quest1()33, quest1()32, quest1()32, newdquest1()31, newdquest1()30, quest1()30; sn n=82, k >= 2: 54, 46, 43, 41, 40, 40, 38, quest1()38, newd1()36, quest1()36, quest1()36, quest1()35, quest1()34, quest1()34, quest1()33, quest1()32, quest1()32, newdquest1()31, quest1()30; sn n=83, k >= 2: 55, 47, 44, 42, 40, 40, 39coderef(dodunekov 1987), 38, newdquest1()37, newdquest1()36, quest1()36, quest1()36, quest1()35, quest1()34, quest1()34, quest1()33, quest1()32, quest1()32, quest1()31coderef(brouwer linear programming bound) ; sn n=84, k >= 2: 56, 48, 44, 42, 41, 40, 40, quest1()39, quest1()38, newdquest1()37, newdquest1()36, quest1()36, quest1()36, newdquest1()34, quest1()34, quest1()34, newdquest1()32, quest1()32, quest1()32; sn n=85, k >= 2: 56, 48, 44, 43, 42, 40, 40, quest1()40, 38, quest1()38, newdquest1()37, quest1()36, quest1()36, newdquest1()35, quest1()34, quest1()34, newdquest1()33, quest1()32, quest1()32; pstail pshead(105) // k = 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 psnext n=72, k >=21: newdquest1()25, newdquest1()24, quest1()24, quest1()24, newdquest1()23, quest1()22, quest1()22, quest1()22, quest1()21, quest1()20, quest1()20, quest1()20, quest1()19, quest1()18, quest1()18, newdquest1()17, quest1()16, quest1()16, quest1()16; sn n=73, k >=21: quest1()26, newdquest1()25, quest1()24, quest1()24, quest1()24, quest1()23coderef(brouwer linear programming bound), quest1()22, quest1()22, quest1()22, quest1()21, quest1()20, quest1()20, quest1()20, quest1()18, quest1()18, quest1()18, quest1()17coderef(brouwer linear programming bound), quest1()16, quest1()16; sn n=74, k >=21: quest1()26, quest1()26, quest1()25coderef(brouwer linear programming bound), quest1()24, quest1()24, quest1()24, quest1()23, quest1()22, quest1()22, quest1()22, newdquest1()20, quest1()20, quest1()20, quest1()19coderef(brouwer linear programming bound), quest1()18, quest1()18, quest1()18, quest1()17, quest1()16; sn n=75, k >=21: newdquest1()26, quest1()26, quest1()26, quest1()25, quest1()24, quest1()24, quest1()24, newdquest1()22, quest1()22, quest1()22, newdquest1()21, newdquest1()20, quest1()20, quest1()20, quest1()19, quest1()18, quest1()18, quest1()18, quest1()17; sn n=76, k >=21: newdquest1()27, quest1()26, quest1()26, quest1()26, quest1()25, quest1()24, quest1()24, newdquest1()23, newdquest1()22, quest1()22, quest1()22, newdquest1()21, quest1()20, quest1()20, quest1()20, quest1()19, quest1()18, quest1()18, quest1()18; sn n=77, k >=21: quest1()28, quest1()27coderef(brouwer linear programming bound), quest1()26, quest1()26, quest1()26, quest1()25, quest1()24, quest1()24, newdquest1()23, newdquest1()22, quest1()22, quest1()22, quest1()21coderef(brouwer linear programming bound), quest1()20, quest1()20, quest1()20, quest1()19, quest1()18, quest1()18; sn n=78, k >=21: quest1()28, quest1()28, quest1()27, quest1()26, quest1()26, quest1()26, quest1()25, quest1()24, quest1()24, newdquest1()23, quest1()22, quest1()22, quest1()22, quest1()21, quest1()20, quest1()20, quest1()20, quest1()19, quest1()18; pstail pshead(105) // k = 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 psnext n=79, k >=21: quest1()28, quest1()28, quest1()28, quest1()27, quest1()26, quest1()26, quest1()26, newdquest1()24, quest1()24, quest1()24, quest1()23coderef(brouwer linear programming bound), quest1()22, quest1()22, quest1()22, quest1()21, quest1()20, quest1()20, quest1()20, quest1()19; sn n=80, k >=21: quest1()29, quest1()28, quest1()28, quest1()28, newdquest1()26, quest1()26, quest1()26, newdquest1()25, newdquest1()24, quest1()24, quest1()24, quest1()23, quest1()22, quest1()22, quest1()22, quest1()21, quest1()20, quest1()20, quest1()20; sn n=81, k >=21: quest1()30, quest1()29, quest1()28, quest1()28, newdquest1()27, newdquest1()26, quest1()26, quest1()26, newdquest1()25, quest1()24, quest1()24, quest1()24, quest1()23, quest1()22, quest1()22, quest1()22, quest1()21, quest1()20, quest1()20; sn n=82, k >=21: quest1()30, quest1()30, quest1()29, quest1()28, quest1()28, newdquest1()27, quest1()26, quest1()26, quest1()26, quest1()25coderef(brouwer linear programming bound), quest1()24, quest1()24, quest1()24, quest1()23, quest1()22, quest1()22, quest1()22, quest1()21, quest1()20; sn n=83, k >=21: quest1()30, quest1()30, quest1()30, quest1()28, quest1()28, quest1()28, quest1()27coderef(brouwer linear programming bound), quest1()26, quest1()26, quest1()26, quest1()25, quest1()24, quest1()24, quest1()24, quest1()23, quest1()22, quest1()22, quest1()22, newdquest1()20; sn n=84, k >=21: quest1()31, quest1()30, quest1()30, quest1()29coderef(brouwer linear programming bound), quest1()28, quest1()28, quest1()28, quest1()27, quest1()26, quest1()26, quest1()26, quest1()25, quest1()24, quest1()24, quest1()24, quest1()23, quest1()22, quest1()22, newdquest1()21; sn n=85, k >=21: 32, quest1()31, quest1()30, quest1()30, quest1()29, quest1()28, quest1()28, quest1()28, quest1()27, quest1()26, quest1()26, quest1()26, quest1()25, quest1()24, quest1()24, quest1()24, quest1()23, quest1()22, quest1()22; pstailx no [74,46,14]; psheadx(105) // k = 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 psnext n=72, k >=40: quest1()15, quest1()14, quest1()14, quest1()14, quest1()13, quest1()12, quest1()12, newdquest1()11, quest1()10, quest1()10, quest1()10, quest()9, 8, quest()8, quest()8, quest()7, 6, 6, 6; sn n=73, k >=40: quest1()16, quest1()15, quest1()14, quest1()14, quest1()14, quest1()13, quest1()12, quest1()12, quest1()11, quest1()10, quest1()10, quest1()10, quest()9, 8, quest()8, quest()8, quest()7, 6, 6; sn n=74, k >=40: quest1()16, quest1()16, quest1()15, quest1()14, quest1()14, quest1()14, newdquest1()12, quest1()12, quest1()12, quest1()11, quest1()10, quest1()10, quest1()10, quest()9, 8, quest()8, quest()8, quest()7, 6; sn n=75, k >=40: quest1()16, quest1()16, quest1()16, quest1()15, quest1()14, quest1()14, newdquest1()13, quest1()12, quest1()12, quest1()12, quest1()11, quest1()10, quest1()10, quest1()10, quest()9, 8, quest()8, quest()8, quest()7; sn n=76, k >=40: quest1()17, quest1()16, quest1()16, quest1()16, quest1()15, quest1()14, quest1()14, quest1()13, quest1()12, quest1()12, quest1()12, quest1()11, quest1()10, quest1()10, quest1()10, quest()9, 8, quest()8, quest()8; sn n=77, k >=40: quest1()18, quest1()17, quest1()16, quest1()16, quest1()16, quest1()15, quest1()14, quest1()14, quest1()13, quest1()12, quest1()12, quest1()12, quest1()11, quest1()10, quest1()10, quest1()10, quest()9, 8, quest()8; sn n=78, k >=40: quest1()18, quest1()18, quest1()17, quest1()16, quest1()16, quest1()16, newdquest1()14, quest1()14, quest1()14, quest1()13, quest1()12, quest1()12, quest1()12, quest1()11, quest1()10, quest1()10, quest1()10, quest()9, 8; pstail pshead(45) // k = 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 psnext n=79, k >=40: quest1()18, quest1()18, quest1()18, quest1()16, quest1()16, quest1()16, newdquest1()15, newdquest1()14, quest1()14, quest1()14, quest1()13, quest1()12, quest1()12, quest1()12, quest1()11, quest1()10, quest1()10, quest1()10, quest()9; sn n=80, k >=40: quest1()19, quest1()18, quest1()18, quest1()17, quest1()16, quest1()16, quest1()16, newdquest1()15, quest1()14, quest1()14, quest1()14, quest1()13, quest1()12, quest1()12, quest1()12, newdquest1()10, quest1()10, quest1()10, quest1()10; sn n=81, k >=40: quest1()20, quest1()19, quest1()18, quest1()18, quest1()17, quest1()16, quest1()16, quest1()16, quest1()15, quest1()14, quest1()14, quest1()14, quest1()13, quest1()12, quest1()12, newdquest1()11, newdquest1()10, quest1()10, quest1()10; pstailx set price refinement count = 2; psheadx(60) // k = 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 psnext n=82, k >=40: quest1()20, quest1()20, newdquest1()18, quest1()18, quest1()18, quest1()17, quest1()16, quest1()16, quest1()16, quest1()15, quest1()14, quest1()14, quest1()14, quest1()13, quest1()12, quest1()12, newdquest1()11, quest1()10, quest1()10; sn n=83, k >=40: quest1()20, quest1()20, newdquest1()19, quest1()18, quest1()18, quest1()18, quest1()17, quest1()16, quest1()16, quest1()16, quest1()15, quest1()14, quest1()14, quest1()14, newdquest1()12, quest1()12, quest1()12, quest1()11, quest1()10; sn n=84, k >=40: quest1()20, quest1()20, quest1()20, quest1()19, quest1()18, quest1()18, quest1()18, quest1()17, quest1()16, quest1()16, quest1()16, quest1()15, quest1()14, quest1()14, newdquest1()13, newdquest1()12, quest1()12, quest1()12, quest1()11; sn n=85, k >=40: quest1()21coderef(brouwer linear programming bound), quest1()20, quest1()20, quest1()20, quest1()19, quest1()18, quest1()18, quest1()18, quest1()17, quest1()16, quest1()16, quest1()16, quest1()15, quest1()14, quest1()14, newdquest1()13, quest1()13, quest1()12, quest1()12; pstailx psheadx(105) // k = 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 psnext n=72, k >=59: quest()6, quest()5, 4, 4, 4, 4, 3, 2, 2, 2, 2, 2, 2; sn n=73, k >=59: 6, quest()6, quest()5, 4, 4, 4, 4, 3, 2, 2, 2, 2, 2, 2; sn n=74, k >=59: 6, 6, quest()6, quest()5, 4, 4, 4, 4, 3, 2, 2, 2, 2, 2, 2; sn n=75, k >=59: 6, 6, 6, quest()6, quest()5, 4, 4, 4, 4, 3, 2, 2, 2, 2, 2, 2; sn n=76, k >=59: quest()7, 6, 6, 6, quest()6, quest()5, 4, 4, 4, 4, 3, 2, 2, 2, 2, 2, 2; sn n=77, k >=59: quest()8, quest()7, 6, 6, 6, quest()6, quest()5, 4, 4, 4, 4, 3, 2, 2, 2, 2, 2, 2; sn n=78, k >=59: quest()8, quest()8, quest()7, 6, 6, 6, quest()6, quest()5, 4, 4, 4, 4, 3, 2, 2, 2, 2, 2, 2; pstail pshead(105) // k = 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 psnext n=79, k >=59: 8, quest()8, quest()8, quest()7, 6, 6, 6, quest()6, quest()5, 4, 4, 4, 4, 3, 2, 2, 2, 2, 2; sn n=80, k >=59: quest()9, 8, quest()8, quest()8, quest()7, 6, 6, 6, quest()6, quest()5, 4, 4, 4, 4, 3, 2, 2, 2, 2; sn n=81, k >=59: quest1()10, newd()8, 8, quest()8, quest()8, quest()7, 6, 6, 6, quest()6, quest()5, 4, 4, 4, 4, 3, 2, 2, 2; sn n=82, k >=59: quest1()10, newdquest()9, newd()8, 8, quest()8, quest()8, quest()7, 6, 6, 6, quest()6, quest()5, 4, 4, 4, 4, 3, 2, 2; sn n=83, k >=59: quest1()10, quest1()10, newdquest()9, 8coderef(brouwer linear programming bound), 8, quest()8, quest()8, quest()7, 6, 6, quest()6, quest()6, quest()5, 4, 4, 4, 4, 3, 2; sn n=84, k >=59: quest1()10, quest1()10, quest1()10, quest()9, 8, 8, quest()8, quest()8, quest()7, 6, 6, quest()6, quest()6, quest()5, 4, 4, 4, 4, 3; sn n=85, k >=59: quest1()11, quest1()10, quest1()10, quest1()10, quest()9, 8, 8, quest()8, quest()8, quest()7, 6, 6, quest()6, quest()6, quest()5, 4, 4, 4, 4; pstail pshead(105) // k = 78 79 80 81 82 83 84 psnext n=79, k >=78: 2; sn n=80, k >=78: 2, 2; sn n=81, k >=78: 2, 2, 2; sn n=82, k >=78: 2, 2, 2, 2; sn n=83, k >=78: 2, 2, 2, 2, 2; sn n=84, k >=78: 2, 2, 2, 2, 2, 2; sn n=85, k >=78: 3, 2, 2, 2, 2, 2, 2; pstailx data_comment( ![ \block{Partial tables for codes of length between $86$ and $200$} For these tables, we have not given references where credit is due, nor have we attached the question mark tag to results which may not be optimal. ]! ) set price refinement count = 1; type [86,5,44_2]; status: weights = {44,48}; type [86,12,38_2]; kill y86 by x_38; status: weights = {38,40,42,44,46,48,50,52,54,56,60,62,64,66,68}; type [87,4,46_2]; status: weights = {46,48}; type [87,7,42_2]; status: weights = {42,44,46,48,50,52,54,56,58,60,62,64,70,72}; type [87,10,40_2]; kill y86,y84,y82,y80,y76,y74,y72,y70; show (joint:5) y66 = 0; kill y58 by (x_22_20, x_24_16); status: weights = {40,42,44,48,50,52,56,60,64,68}; type [87,13,38_2]; status: weights = {38,40,44,46,48,50,52,54,56,60,62,64,66}; kill y66 ; via lp (joint:5) [current] = ; no [87,13,38]; type [88,6,44_2]; status: weights = {44,48,56,60,64}; type [88,8,42_2]; kill y88,y72,y70,y62; via lp (joint:5) [current] = ; no [88,8,42]; type [88,11,40_2]; kill y88,y68,y50,y42,y64,y60; status: weights = {40,44,48,52,56}; type [88,11,40]; status: weights = {40,44,48,52,56}; no [88,11,40]; type [89,8,42_2]; kill y88, y84 by x_42_0; kill y82 by x_41_1 ; kill y86 ; status: weights = 42_2 - {82..89}; type [89,11,40_2]; kill y88, y86, y84, y82 by (x_33_7, x_34_6, x_35_5, x_35_7, x_36_4), y80 by (x_31_9, x_32_8, x_33_7, x_33_9, x_34_6, x_34_8), y78, y76 by (x_27_13, x_28_12, x_29_11, x_29_13, x_30_10, x_30_12, x_31_9, x_31_11, x_31_13, x_32_8), y74 by (x_25_15, x_27_13, x_27_15, x_28_12, x_28_14, x_29_11, x_29_13, x_29_15, x_30_12, x_30_14, x_31_11, x_31_13, x_32_12, x_33_9, x_33_11, x_33_15, x_34_6) ; status: weights = {40,42,44,46,48,50,52,54,56,58,60,62,64,66,68,70,72}; type [89,14,38_2]; status: weights = 38_2 - {82,84,86,88}; kill y80 by (x_30_8, x_37_1, x_38_0, x_39_1) ; kill y78 by (x_27_11, x_28_10, x_29_11, x_32_10, x_33_11, x_36_10, x_37_1, x_37_11, x_38_0); status: weights = 38_2 - {78..89}; psheadx(60) // k = 2 3 4 5 6 7 8 9 10 11 12 13 14 psnext n=86, k >= 2: 57, 48, 45, 44, 42, 41, 40, 40, 39, 38, 38, newd1()36, 36; sn n=87, k >= 2: 58, 49, 46, 44, 43, 42, newd1()40, 40, 40, newd1()38, 38, newd1()37, newd1()36; sn n=88, k >= 2: 58, 50, 46, 44, 44, 42, newd1()41, newd1()40, 40, newd1()39, newd1()38, 38, newd1()37; sn n=89, k >= 2: 59, 50, 47, 45, 44, 43, 42, newd1()41, 40, 40, newd1()39, 38, 38; pstailx type [90,5,46_2]; status: weights = {46,48}; type [90,7,44_2]; status: weights = {44,46,48,52,56,60,64,72}; type [90,7,44]; status: weights = {44,45,46,48,52,56,60,64,72}; type [90,9,42_2]; status: weights = {42,44,46,48,52,54,56,58,60,62,64,68,70,72}; kill y72 by (x_27_15, x_28_16, x_29_13, x_30_12) ; status: weights = 42_2 - {50,66,72..90}; type [90,12,40_2]; kill y90 by x_40; status: weights = {40,42,44,46,48,50,52,54,56,58,60,64,66,68,70,72}; no [91,10,42]; type [91,13,40_2]; kill y70,y42,y66,y58,y54,y50, y72 by (x_22_18, x_24_16); status: weights = {40,44,48,52,56,60,64,68}; type [91,8,44_2]; kill y72, y64; show 28 < y56 < 29; via lp [base] = ; no [91,8,44]; type [92,6,46_2]; kill y92, y76, y68, y60, y52; status: weights = {46,48,62,64}; type [92,8,44_2]; status: weights = {44,46,48,52,56,60,64,68,72,76}; type [92,10,42_2]; status: weights = 42_2 - {86..92}; kill y84 by (x_36_6, x_36_8, x_37_5), y82 by (x_34_8, x_34_10, x_35_7), y80 by (x_32_10, x_33_9, x_33_11, x_34_8) ; status: weights = {42,44,46,48,50,52,54,56,58,60,62,64,66,68,70,72,74,76,78}; type [92,14,40_2]; status: weights = {40,44,48,52,56,60,64}; no [91,6,46]; TYPE_WE(93,7,46,1 + 93t^46 + 31t^48 + 3t^62) type [93,9,44_2]; kill y76,y72; show (joint:0) y46 = 0; kill y64 ; status: weights = {44,48,56,60}; type [93,9,44]; status: weights = {44,48,56,60}; type [93,11,42_2]; kill y78; status: weights = {42,44,46,48,50,52,54,56,58,60,62,64,66,68,70,72,74,76}; kill y76 by (x_27_17, x_28_14, x_28_16, x_29_15, x_29_17, x_30_16, x_31_15, x_31_17, x_32_14, x_32_16, x_33_13, x_33_15, x_34_14, x_35_13, x_35_17, x_36_16, x_37_15, x_37_17, x_38_12, x_38_14) ; status: weights = {42,44,46,48,50,52,54,56,58,60,62,64,66,68,70,72,74}; no [92,11,42]; no [94,10,44]; type [94,12,42_2]; status: weights = {42,44,46,48,50,52,54,56,58,60,62,64,68,70,72,74}; type [95,4,50_2]; status: weights = {50,52,54,56}; TYPE_WE(95,6,48,1 + 62t^48 + t^64) type [95,10,44_2]; kill y94,y92,y90,y88,y86,y84,y82,y80,y78,y74,y66,y50,y58; status: weights = {44,48,52,56,60,64,68,72,76}; no [94,8,46]; type [95,8,46_2]; kill y94, y92, y76, y68, y46; via lp [base] = ; no [95,8,46]; no [94,6,48]; TYPE_WE(96,7,48,1 + 124t^48 + 3t^64) type [96,8,46_2]; kill y96,y94,y88,y84,y80, y92, y78 by x_35_11; status: weights = {46,48,50,52,54,56,62,64,70,72}; type [96,13,42_2]; kill y94 by x_42_0, y92 by x_42_0, y90 by x_42_0; status: weights = 42_2 - {90,92,94}; kill y88 by (x_36_6, x_40_2) ; status: weights = 42_2 - {88..94}; type [97,11,44_2]; kill y96, y94, y92, y90, y86, y84, y82, y88 by x_44_0; status: weights = {44,46,48,50,52,54,56,58,60,62,64,66,68,70,72,74,76,78,80}; type [97,14,42_2]; status: weights = 42_2 - {88,90,92,94,96}; kill y86 by (x_32_10, x_36_10, x_42_0) ; status: weights = 42_2 - {86..97}; type [98,9,46_2]; status: weights = 46_2 - {58,74,82,84,86,88,90,92,94,96,98}; kill y80 by (x_29_17, x_30_18, x_31_15, x_32_14, x_32_16, x_33_13, x_33_15), y78 by (x_28_18, x_31_15, x_31_17, x_32_14, x_32_16, x_32_18, x_33_15, x_33_17, x_34_18, x_35_11, x_35_13, x_35_17, x_36_10, x_36_12, x_36_14, x_37_9, x_37_11, x_37_13, x_37_15, x_38_8) ; status: weights = {46,48,50,52,54,56,60,62,64,66,68,70,72,76}; type [98,12,44_2]; status: weights = {44,46,48,50,52,54,56,58,60,62,64,66,68,72,74,76,78,80}; kill y80 by (x_26_18, x_28_16, x_30_18, x_31_17, x_32_16, x_32_18, x_33_17, x_34_18, x_35_17, x_36_16, x_38_18, x_39_17, x_40_16, x_40_18), y78 by (x_24_20, x_25_19, x_29_19, x_30_20, x_31_19, x_32_20, x_33_19, x_36_20, x_37_19, x_38_20) ; status: weights = {44,46,48,50,52,54,56,58,60,62,64,66,68,72,74,76}; type [99,5,50_2]; status: weights = 50_2 - {66,68,74..99}; status: weights = {50,52,54,56,58,60,62,64}; type [99,8,48]; status: weights = {48,56,64,72}; type [99,10,46_2]; via lp (joint:0) [current] = ; no [99,10,46]; type [99,13,44_2]; kill ndiv4,y76; status: weights = {44,48,52,56,60,64,68,72}; type [100,10,46_2]; kill y100, y98, y96, y94, y92 by (x_38_8, x_40_8, x_44_8, x_45_7, x_46_0), y90 by (x_36_10, x_38_10); status: weights = 46_2 - {90..100}; kill y88 by (x_34_12, x_35_11, x_36_10, x_36_12, x_37_9), y86 by (x_32_14, x_33_13, x_35_11, x_37_9, x_37_11, x_38_10, x_38_12, x_38_14, x_39_7, x_39_9, x_39_11, x_39_13, x_40_6) ; status: weights = 46_2 - {86..100}; type [101,6,50_2]; kill y100, y84 by x_40_12; status: weights = {50,52,54,56,58,60,62,64}; type [101,9,48_2]; kill y100,y98,y96,y92,y88,y84,y82,y80; show (joint:5) y66 = 0; kill y68 ; status: weights = {48,50,52,54,56,64,72}; no [118,8,58]; no [119,8,58]; no [100,6,50]; type [101,11,46_2]; status: weights = 46_2 - {84..101}; type [101,14,44_2]; status: weights = 44_2 - {92,94,96,98,100}; kill y90 by (x_36_10, x_40_10, x_44_0) ; status: weights = 44_2 - {90..101}; type [102,4,54_2]; STATUS_WE(1 + 12t^54 + 3t^56) type [102,5,52_2]; status: weights = {52,56,60,64}; type [102,7,50_2]; status: weights = {50,52,54,56,58,60,64}; psheadx(195) // k = 2 3 4 5 6 7 8 9 10 11 12 13 14 psnext n= 90, k >= 2: 60, 51, 48, 46, 44, 44, 42, 42, newd1()40, 40, 40, 39, 38; sn n= 91, k >= 2: 60, 52, 48, 46, 45, 44, 43, 42, newd1()41, newd1()40, 40, 40, 39; sn n= 92, k >= 2: 61, 52, 48, 47, 46, 45, 44, 43, 42, newd1()41, newd1()40, 40, 40; sn n= 93, k >= 2: 62, 52, 48, 48, 46, 46, 44, 44, 42, 42, newd1()41, 40, 40; sn n= 94, k >= 2: 62, 53, 49, 48, 47, 46, 44, 44, 43, 42, 42, newd1()40, 40; sn n= 95, k >= 2: 63, 54, 50, 48, 48, 47, 45, 44, 44, 42, 42, newd1()41, newd1()40; sn n= 96, k >= 2: 64, 54, 50, 48, 48, 48, 46, newd1()44, 44, 43, 42, 42, newd1()41; sn n= 97, k >= 2: 64, 55, 51, 48, 48, 48, 46, newd1()45, 44, 44, 43, 42, 42; sn n= 98, k >= 2: 65, 56, 52, 49, 48, 48, 47, 46, newd1()44, 44, 44, 43, 42; sn n= 99, k >= 2: 66, 56, 52, 50, 48, 48, 48, 46, newd1()45, newd1()44, 44, 44, newd1()42; sn n=100, k >= 2: 66, 56, 52, 50, 49, 48, 48, 47, 46, newd1()45, newd1()44, 44, newd1()43; sn n=101, k >= 2: 67, 57, 53, 51, 50, 49, 48, 48, 46, 46, newd1()45, newd1()44, 44; sn n=102, k >= 2: 68, 58, 54, 52, 50, 50, 48, 48, 47, 46, 46, newd1()44, 44; pstailx type [102,12,46_2]; kill y82, y102 by x_46; status: weights = {46,48,50,52,54,56,58,60,62,64,66,68,70,72,76,78,80}; kill y80 by (x_24_22, x_25_21, x_26_22, x_28_20, x_30_22, x_31_21, x_32_20, x_32_22, x_33_21, x_34_22, x_35_21, x_36_20, x_38_22, x_39_21, x_40_20, x_40_22) ; status: weights = {46,48,50,52,54,56,58,60,62,64,66,68,70,72,76,78}; type [104,6,52_2]; show (joint:0) y58 = 0, y74 = 0; kill y104,y88; status: weights = {52,56,60,64,72,76,80}; status: weights = {52,56,60,64}; type [104,11,48_2]; kill y104,y102,y100,y98,y96,y94,y92,y90,y88,y84,y82,y80,y76,y74,y72,y66,y58; via lp [current] = ; no [104,11,48]; type [104,13,46_2]; kill y102 by x_46_0, y100 by x_46_0; status: weights = 46_2 - {100,102}; type [103,10,48_2]; status: weights = 48_2 - {54,62,70,78,84..103}; kill y82 ; status: weights = {48,50,52,56,58,60,64,66,68,72,74,76,80}; (* Oops -- this should be combined with the previous type [104,13,46_2]. *); type [104,13,46_2]; kill y98 by x_46_0, y96 by (x_46_0, x_48_0); status: weights = 46_2 - {96,98,100,102}; kill y94 by (x_45_1, x_46_0) ; status: weights = 46_2 - {94..102}; no [103,6,52]; TYPE_WE(105,7,52,1 + 105t^52 + 15t^56 + 7t^60) no [103,13,46]; no [104,8,50]; type [105,11,48_2]; status: weights = 48_2 - {86..105}; type [105,14,46_2]; status: weights = 46_2 - {94,96,98,100,102,104}; type [106,5,54_2]; status: weights = {54,56,60,62,64}; type [106,9,50_2]; status: weights = 50_2 - {66,82,86..106}; kill y84 by (x_30_22, x_32_20, x_33_19, x_33_21, x_34_20, x_34_22, x_35_19, x_35_21, x_36_20, x_36_22, x_37_15, x_37_17, x_37_21, x_38_16, x_38_18, x_38_22, x_39_13, x_39_15, x_39_17, x_39_19, x_40_10, x_40_12, x_40_14, x_40_16, x_40_18, x_40_20, x_41_9) ; kill y80 by (x_33_23, x_34_24, x_35_23), y78 ; status: weights = {50,52,54,56,58,60,62,64,68,70,72,74,76}; type [106,12,48_2]; status: weights = 48_2 - {78,86..106}; kill y84 by (x_26_22, x_28_20, x_29_21, x_30_20, x_30_22, x_31_21, x_32_20, x_34_22, x_35_21, x_36_20, x_36_22, x_37_21, x_38_22, x_39_21, x_40_20, x_42_22) ; status: weights = {48,50,52,54,56,58,60,62,64,66,68,70,72,74,76,80,82}; type [107,13,48_2]; kill y82,y58,y50,y54,ndiv4; status: weights = {48,52,56,60,64,68,72,76,80}; kill y80 by (x_24_24, x_26_22, x_26_26, x_28_20, x_28_24, x_30_18, x_30_22), y76 by (x_24_24, x_26_26, x_28_20, x_28_24, x_28_28, x_30_18, x_30_22, x_30_26, x_30_30, x_32_16) ; status: weights = {48,52,56,60,64,68,72}; type [108,6,54_2]; status: weights = {54,56,62,64,78,80}; status: weights = {54,56,62,64}; type [108,8,52_2]; status: weights = 52_4 - {108}; type [108,10,50_2]; status: weights = 50_2 - {98,100,102,104,106,108}; kill y96 by x_40_10, y94 by (x_38_12, x_38_14, x_39_11, x_39_13) ; status: weights = 50_2 - {94..108}; no [108,14,48]; no [107,6,54]; type [109,7,54]; show (joint:0) y54 = 90, y56 = 30, y60 = 0, y62 = 6, y64 = 1; STATUS_WE(1 + 90t^54 + 30t^56 + 6t^62 + t^64) no [107,8,52]; type [109,9,52]; status: weights = {52,56,60,64,72,76}; kill y76 ; status: weights = {52,56,60,64,72}; type [109,11,50_2]; status: weights = 50_2 - {90..109}; type [109,14,48_2]; status: weights = 48_2 - {100,102,104,108}; kill y106 by x_48_0; kill y98 by (x_37_11, x_39_11, x_40_10, x_41_11, x_44_10, x_45_11, x_47_1, x_48_0) ; status: weights = 48_2 - {98..109}; type [110,4,58_2]; status: weights = {58,60,62,64}; no [107,10,50]; no [110,10,52]; type [110,12,50_2]; status: weights = 50_2 - {82,86..110}; type [111,10,52_2]; status: weights = {52,56,60,64,68,72,76,80,84,88}; show (joint:0) y88 = 0; status: weights = {52,56,60,64,68,72,76,80,84}; no [110,6,56]; TYPE_WE(112,7,56,1 + 120t^56 + 7t^64) type [112,8,54_2]; status: weights = {54,56,60,62,64,66,68,70,72,76,78,80,84,86,88,92,94,96,100, 108,110}; kill y108, y100 by x_44_12, y92 by (x_36_20, x_38_18, x_42_14, x_42_18, x_44_12, x_44_16, x_44_20, x_45_9); status: weights = {54,56,60,62,64,66,68,70,72,76,78,80,84,86,88,94,96,110}; kill y110, y84, y76, y68, y66 ; status: weights = {54,56,60,62,64,70,72,78,80,86,88,94,96}; type [112,11,52_2]; status: weights = {52,56,60,64,68,72}; no [112,11,52]; type [112,13,50_2]; kill y108, y106, y112 by x_50, y110 by x_50_0, y104 by x_50_0; kill y102 by (x_40_10, x_41_9, x_42_8, x_42_10, x_43_9, x_44_8, x_44_10, x_45_7, x_45_9, x_46_8), y100 by (x_38_12, x_42_12, x_44_12, x_46_12, x_48_12, x_50_0), y98 by (x_36_14, x_37_13, x_38_14, x_39_13, x_40_14, x_41_13, x_42_14, x_43_13, x_44_14, x_45_13, x_46_14, x_47_13, x_48_14, x_49_1, x_49_13) ; status: weights = 50_2 - {98..112}; no [111,8,54]; no [113,8,56]; type [113,9,54_2]; status: weights = {54,56,60,62,64}; via lp (joint:0) [current] = ; no [113,9,54]; type [113,11,52_2]; kill y112,y110,y108,y106,y104,y102,y100,y98,y96,y94 ; status: weights = 52_2 - {94..113}; type [113,14,50_2]; status: weights = 50_2 - {98..112}; type [114,5,58_2]; status: weights = {58,60,62,64}; type [114,9,54_2]; status: weights = 54_2 - {74,90,98..114}; kill y96 by (x_36_18, x_37_17, x_38_18, x_39_15), y94 by (x_36_18, x_38_16) ; status: weights = 54_2 - {74,90,94..114}; type [114,12,52_2]; status: weights = 52_2 - {86,90..114}; set auto mu1; type [115,8,56_2]; kill y114,ndiv4,y112; show (joint:0) 204 <= y56 <= 220, 2 <= y64 <= 50, y68 <= 35, y72 <= 18, y80 <= 9, y88 <= 3, y96 <= 2; show (joint:0) y56 <= 217, y64 >= 5, y68 <= 32, y72 <= 15, y80 <= 7, y88 <= 2, y96 <= 1; show (joint:0) div8 > 224; infer div8 = 256; status: weights = {56,64,72,80,88,96}; type [115,8,56]; status: weights = {56,64,72,80,88,96}; unset auto mu1; type [115,10,54_2]; status: weights = {54,56,60,62,64,68,70,72,76,78,80,84,86,88}; kill y86 by x_35_19 ; kill y84, y76 ; status: weights = {54,56,60,62,64,68,70,72,78,80,88}; type [115,13,52_2]; kill y82,y78,y74,y66,y62,y58,y88; status: weights = {52,56,60,64,68,72,76,80,84}; kill y84 by (x_26_26, x_28_24, x_28_28, x_30_22, x_30_26, x_30_30, x_32_20, x_32_24, x_32_28, x_34_18, x_34_22), y80 by (x_26_26, x_28_28, x_30_26, x_30_30, x_32_24, x_32_28, x_32_32, x_34_22, x_34_26, x_34_30, x_34_34, x_36_16) ; status: weights = {52,56,60,64,68,72,76}; type [116,6,58]; status: weights = {58,60,62,64}; no [116,14,52]; no [115,6,58]; type [117,4,62_2]; status: weights = {62,64}; type [117,5,60_2]; status: weights = {60,64}; type [117,7,58_2]; status: weights = {58,60,62,64}; type [117,7,58]; status: weights = {58,60,62,64}; psheadx(205) // k = 2 3 4 5 6 7 8 9 10 11 12 13 14 psnext n=103, k >= 2: 68, 58, 54, 52, 51, 50, 48, 48, 48, newd1()46, 46, newd1()45, newd1()44; sn n=104, k >= 2: 69, 59, 55, 52, 52, 51, 49, 48, 48, newd1()47, newd1()46, 46, newd1()45; sn n=105, k >= 2: 70, 60, 56, 53, 52, 52, 50, 49, 48, 48, newd1()47, 46, 46; sn n=106, k >= 2: 70, 60, 56, 54, 52, 52, 50, 50, newd1()48, 48, 48, 47, 46; sn n=107, k >= 2: 71, 60, 56, 54, 53, 52, 51, 50, newd1()49, 48, 48, 48, newd1()46; sn n=108, k >= 2: 72, 61, 56, 55, 54, 53, 52, 51, 50, 49, 48, 48, newd1()47; sn n=109, k >= 2: 72, 62, 57, 56, 54, 54, 52, 52, newd1()50, 50, 49, 48, 48; sn n=110, k >= 2: 73, 62, 58, 56, 55, 54, 52, 52, newd1()51, 50, 50, newd1()48, 48; sn n=111, k >= 2: 74, 63, 58, 56, 56, 55, 53, 52, 52, newd1()50, 50, newd1()49, newd1()48; sn n=112, k >= 2: 74, 64, 59, 56, 56, 56, 54, newd1()52, 52, newd1()51, 50, 50, newd1()49; sn n=113, k >= 2: 75, 64, 60, 57, 56, 56, 54, newd1()53, 52, 52, 51, 50, 50; sn n=114, k >= 2: 76, 64, 60, 58, 56, 56, 55, 54, 53, 52, 52, 51, 50; sn n=115, k >= 2: 76, 65, 60, 58, 57, 56, 56, 54, 54, newd1()52, 52, 52, newd1()50; sn n=116, k >= 2: 77, 66, 61, 59, 58, 57, 56, 55, 54, newd1()53, 52, 52, newd1()51; sn n=117, k >= 2: 78, 66, 62, 60, 58, 58, 56, 56, 55, 54, 53, 52, 52; pstailx type [117,9,56_2]; status: weights = {56,58,60,64,66,68,70,72,80,84,88}; kill y88 ; show (joint:0) y70 = 0, y84 = 0; status: weights = {56,58,60,64,66,68,72,80}; type [117,11,54_2]; status: weights = 54_2 - {96..117}; type [117,14,52_2]; status: weights = 52_2 - {100,102,106,108,110,112,114}; kill y116 by (x_54_0, x_57_1) ; status: weights = 52_2 - {100,102,106..117}; no [116,9,56]; type [118,10,56_2]; kill y118; show (joint:0) 719 <= y56 <= 722; status: weights = {56,64,72,80}; show (joint:5) 719 <= y56 <= 720, 215 <= y64 <= 219; show (joint:5) y64 <= 218, 85 <= y72 <= 88, y80 <= 1; status: weights = {56,64,72,80}, constraints = {719 <= y56 <= 720, 215 <= y64 <= 218, 85 <= y72 <= 88, y80 <= 1}; type [118,12,54_2]; status: weights = 54_2 - {90..118}; TYPE_WE(119,6,60,1 + 56t^60 + 7t^64) no [116,11,54]; no [116,9,56]; no [119,13,54]; no [118,6,60]; TYPE_WE(120,7,60,1 + 112t^60 + 15t^64) type [120,8,58_2]; kill y116, y112, y108, y104 by x_44_16, y102 by (x_42_16, x_45_15), y100 by (x_41_17, x_42_18, x_44_14, x_44_20, x_45_17, x_46_14, x_46_18, x_48_10, x_48_20); status: weights = 58_2 - {66,82,90,98,100,102,104,106,108,110,112,114,116}; kill y120, y96, y94 by x_38_20, y88 by (x_34_26, x_36_24, x_36_26, x_38_22), y84 ; status: weights = 58_2 - {66,82,84,88,90,94..116,120}; type [120,11,56_2]; status: weights = {56,60,64,68,72,76,80,84}; kill y84 ; status: weights = {56,60,64,68,72,76,80}; type [120,13,54_2]; kill y118,y116,y114,y112,y106,y104, y120 by x_54, y110 by (x_44_10, x_46_10); status: weights = 54_2 - {104,106,110,112,114,116,118,120}; kill y108 by x_54_0; status: weights = 54_2 - {104..120}; type [121,5,62_2]; status: weights = {62,64}; type [121,14,54_2]; status: weights = 54_2 - {102..121}; type [122,9,58_2]; status: weights = 58_2 - {82,98,102..122}; type [122,12,56_2]; status: weights = 56_2 - {90,94..122}; TYPE_WE(123,6,62,1 + 48t^62 + 15t^64) no [122,8,60]; type [123,8,60]; status: weights = {60,64,76}; no [121,9,58]; type [123,10,58_2]; status: weights = 58_2 - {66,74,82,90,94..123}; kill y88, y84 ; status: weights = {58,60,62,64,68,70,72,76,78,80,86,92}; status: weights = {58,60,62,64,68,70,72,76,78,80}; type [123,13,56_2]; status: weights = {56,60,64,68,72,76,80,84,88,92}; kill y92 by (x_28_28, x_30_30, x_32_28, x_34_30, x_36_28, x_38_30) ; status: weights = {56,60,64,68,72,76,80,84,88}; TYPE_WE(124,7,62,1 + 96t^62 + 31t^64) no [121,12,56]; no [124,14,56]; type [125,4,66_2]; status: weights = {66,68,70,72}; set auto mu1; type [125,9,60_2]; status: weights = {60,64,68,72,76,80,88,92,96}; kill y96 by (x_40_20, x_40_24); show (joint:0) y92 = 0; status: weights = {60,64,68,72,76,80,88}; unset auto mu1; type [125,11,58_2]; status: weights = 58_2 - {102..125}; type [125,14,56_2]; status: weights = 56_2 - {102..122}; kill y124 ; status: weights = 56_2 - {102..125}; TYPE_WE(126,6,64,1 + 63t^64) type [126,8,62_2]; kill y124,y76; show (joint:5) y62 = 127, y64 = 127, y126 = 1; STATUS_WE(1 + 127t^62 + 127t^64 + t^126) type [126,8,62]; status: weights = {62,63,64,126}; no [124,9,60]; type [126,10,60_2]; set dual constraint bound = 0; kill y126,y88,y72; via lp [current] = ; no [126,10,60]; set dual constraint bound = 3; no [124,9,60]; no [124,11,58]; type [126,12,58_2]; kill y126,y100,y94,y90,y86,y96,y92,y82,y78,y74,y66,y58; via lp [current] = ; no [126,12,58]; TYPE_WE(127,7,64,1 + 127t^64) type [127,10,60_2]; status: weights = 60_2 - {70,78,86,94,98,102..127}; kill y90 ; status: weights = {60,62,64,66,68,72,74,76,80,82,84,88,92,96,100}; type [127,12,58_2]; kill y126, y124, y122, y120, y114, y112, y110, y118 by x_58_0, y116 by x_58_0; status: weights = 58_2 - {110..127}; TYPE_WE(128,8,64,1 + 254t^64 + t^128) type [128,11,60_2]; kill y128,ndiv4,y100,y96; status: weights = {60,64,68,72,76,80,84,88,92}; kill y92 ; status: weights = {60,64,68,72,76,80,84,88}; type [128,13,58_2]; status: weights = 58_2 - {108..128}; type [129,9,62_2]; status: weights = {62,64,68,70,72,76,78,80,82,84,92}; kill y92 by (x_34_34, x_38_30) ; kill y76 ; status: weights = {62,64,68,70,72,78,80,82,84}; type [129,14,58_2]; status: weights = 58_2 - {106..129}; type [130,5,66_2]; status: weights = {66,68,70,72,74,76,78,80}; type [130,12,60_2]; kill y130,y128,y126,y124,y122,y120,y118,y116,y114,y112,y110,y108,y106,y104, y100,y98,y94,y90,y86,y62,y66,y82,y78,y74,y70; status: weights = {60,64,68,72,76,80,84,88,92,96}; type [131,10,62_2]; status: weights = 62_2 - {74,82,90,98,102..131}; kill y100, y92 ; status: weights = {62,64,66,68,70,72,76,78,80,84,86,88,94,96}; type [132,4,70_2]; status: weights = {70,72}; no [131,9,64]; type [132,9,64]; status: weights = {64,72,80}; no [129,12,60]; type [132,14,60_2]; { kill y96,y92,y88,y84,y80,y76; show y132 = 1; config from x_132|x_60|x_24_36; via lp [current] = }; no [132,14,60]; type [133,5,68_2]; status: weights = {68,72,76,80}; type [133,6,66_2]; kill y132, y116 by x_56_12; status: weights = 66_2 - {98,114,116,120..133}; kill y100 ; status: weights = 66_2 - {98,100,114,116,120..133}; status: weights = 66_2 - {98..133}; type [133,11,62_2]; status: weights = 62_2 - {108..133}; type [133,14,60_2]; status: weights = 60_2 - {108..130}; type [134,10,64_2]; status: weights = {64,68,72,80,88}; type [134,10,64]; show (joint:5) y65 = 0; status: weights = {64,68,72,80,88}; type [135,7,66_2]; kill y132; status: weights = 66_2 - {114,122,126,130,132}; kill y134 ; kill y124, y116 ; status: weights = 66_2 - {114,116,122..126,130..135}; type [135,12,62_2]; status: weights = 62_2 - {114..122,126..135}; kill y124 by x_62_0 ; status: weights = 62_2 - {114..135}; type [136,6,68_2]; kill y106,ndiv4,y136,y120; status: weights = {68,72,76,80,84,88,92,96,104,108,112}; status: weights = {68,72,76,80,84,88,92,96}; no [134,7,66]; type [136,8,66_2]; status: weights = 66_2 - {82,98,106,114,116,122,124,126,130..136}; kill y120,y118,y112,y110,y108,y104,y102,y100,y96,y94,y92,y90,y88,y86, y84,y80,y78,y76,y74; status: weights = {66,68,70,72,128}; type [136,11,64_2]; status: weights = {64,68,72,76,80,84,88,92,96,100}; kill y100 ; status: weights = {64,68,72,76,80,84,88,92,96}; type [136,13,62_2]; status: weights = 62_2 - {114..136}; type [137,5,70_2]; status: weights = {70,72,76,78,80}; type [137,14,62_2]; status: weights = 62_2 - {110..137}; psheadx(275) // k = 2 3 4 5 6 7 8 9 10 11 12 13 14 psnext n=118, k >= 2: 78, 67, 62, 60, 59, 58, 56, 56, 56, 54, 54, newd1()52, 52; sn n=119, k >= 2: 79, 68, 63, 60, 60, 59, 57, newd1()56, 56, 55, 54, newd1()53, newd1()52; sn n=120, k >= 2: 80, 68, 64, 61, 60, 60, 58, newd1()56, 56, 56, 54, 54, newd1()53; sn n=121, k >= 2: 80, 68, 64, 62, 60, 60, 58, 57, 56, 56, 55, 54, 54; sn n=122, k >= 2: 81, 69, 64, 62, 61, 60, 59, 58, 57, 56, 56, 55, 54; sn n=123, k >= 2: 82, 70, 64, 63, 62, 61, 60, 58, 58, newd1()56, 56, 56, newd1()54; sn n=124, k >= 2: 82, 70, 65, 64, 62, 62, 60, 59, 58, newd1()57, 56, 56, newd1()55; sn n=125, k >= 2: 83, 71, 66, 64, 63, 62, 61, 60, newd1()58, 58, newd1()56, 56, 56; sn n=126, k >= 2: 84, 72, 66, 64, 64, 63, 62, 60, newd1()59, 58, newd1()57, newd1()56, 56; sn n=127, k >= 2: 84, 72, 67, 64, 64, 64, 63, 60, 60, 59, 58, newd1()57, newd1()56; sn n=128, k >= 2: 85, 72, 68, 64, 64, 64, 64, 61, 60, 60, 58, 58, newd1()57; sn n=129, k >= 2: 86, 73, 68, 65, 64, 64, 64, 62, newd1()60, 60, 59, 58, 58; sn n=130, k >= 2: 86, 74, 68, 66, 64, 64, 64, 62, newd1()61, 60, 60, 59, 58; sn n=131, k >= 2: 87, 74, 69, 66, 64, 64, 64, 63, 62, newd1()60, 60, 60, newd1()58; sn n=132, k >= 2: 88, 75, 70, 67, 65, 64, 64, 64, newd1()62, newd1()61, 60, 60, newd1()59; sn n=133, k >= 2: 88, 76, 70, 68, 66, 64, 64, 64, newd1()63, 62, newd1()60, 60, 60; sn n=134, k >= 2: 89, 76, 71, 68, 66, 65, 64, 64, 64, 62, newd1()61, newd1()60, 60; sn n=135, k >= 2: 90, 76, 72, 68, 67, 66, 65, 64, 64, 63, 62, newd1()61, newd1()60; sn n=136, k >= 2: 90, 77, 72, 69, 68, 66, 66, 64, 64, 64, 62, 62, newd1()61; sn n=137, k >= 2: 91, 78, 72, 70, 68, 67, 66, 65, 64, 64, 63, 62, 62; pstailx type [138,7,68_2]; kill y106,y94,y90,y86,y82,y78,y74,y138; status: weights = {68,72,76,80,84,88,92,96,100,104,108,112,120,136}; show (joint:0) y136 = 0; status: weights = {68,72,76,80,84,88,92,96,100,104,108,112,120}; type [138,9,66_2]; status: weights = 66_2 - {98,114,118..138}; kill y116 by (x_47_21, x_48_20, x_48_22, x_49_21, x_50_20, x_50_22, x_51_19, x_51_21, x_52_20) ; status: weights = 66_2 - {98,114..138}; status: weights = 66_2 - {98,110..138}; type [138,12,64_2]; kill y138,y136,y134,y132,y130,y128,y126,y124,y122,y120,y118,y116,y114,y112, y108,y106,y102,y98,y94,y90,y86,y82,y78,y74,ndiv4; status: weights = {64,68,72,76,80,84,88,92,96,100,104}; type [139,8,68_2]; kill y120 by (x_56_16, x_56_12), y112, y104 by (x_52_28, x_44_28), y96 by (x_36_36, x_44_36); via lp (joint) [current] = ; no [139,8,68]; type [140,4,74_2]; status: weights = {74,76,78,80}; set auto mu1; type [140,6,70_2]; status: weights = 70_2 - {74,90,98..106,114..140}; show (joint:0) y76 = 0, y92 = 0, y108 = 0; status: weights = {70,72,78,80,82,84,86,88,94,96,110,112}; status: weights = {70,72,78,80,82,84,86,88,94,96}; type [140,8,68_2]; kill y138,y122,y114,y106,y98,y94,y90,y82 ; status: weights = 68_2 - {82,86,90,94,98,102,106,110,114,118,122,126,130,134, 138}; type [140,10,66_2]; status: weights = 66_2 - {122..140}; kill y120,y118 ; status: weights = 66_2 - {118..140}; type [139,13,64_2]; status: weights = 64_4 - {104..139}; type [140,14,64_2]; kill y100,y96,y92,y88,y84,y80; kill current by x_140, x_64, x_26_38; no [140,14,64]; type [141,9,68_2]; status: weights = 68_4 - {100..141}; type [141,11,66_2]; status: weights = 66_2 - {114..141}; type [141,14,64_2]; kill y138,y136,y134,y132,y130,y128,y124,y122,y120,y118,y116,y114,y112,y126; status: weights = 64_2 - {112..138}; type [142,7,70_2]; status: weights = 70_2 - {74,102,106,114,118..122,126..140}; kill y142,y124,y116,y98,y90,y100,y108,y92,y82,y84,y76; ??kill y112 by (x_48_30, x_56_30), y104 by x_52_20 ; status: weights = {70,72,78,80,86,88,94,96,110}; type [143,6,72_2]; status: weights = {72,80,84,88,96,112}; type [143,6,72]; status: weights = {72,80,84,88,96,112}; kill y84 ; status: weights = {72,80,88,96,112}; status: weights = {72,80,88,96}; type [143,10,68_2]; status: weights = 68_4 - {116..143}; type [143,12,66_2]; status: weights = 66_2 - {120..143}; type [144,8,70_2]; status: weights = 70_2 - {90,106,114,122,130,134,138,140}; kill y144,y142,y132,y124,y116,y108,y100,y98,y92 ; status: weights = {70,72,74,76,78,80,82,84,86,88,94,96,102,104,110,112,118,120,126,128,136}; type [144,11,68_2]; status: weights = 68_4 - {112..144}; kill y108 ; status: weights = {68,72,76,80,84,88,92,96,100,104}; type [144,13,66_2]; status: weights = 66_2 - {118..144}; type [145,5,74_2]; status: weights = {74,76,78,80}; type [145,7,72_2]; kill y144,ndiv4,y112; show (joint:0) y92 = 0, y100 = 0; show div8 > 112; infer div8 = 128; status: weights = {72,80,88,96}; type [145,7,72]; status: weights = {72,80,88,96}; type [147,10,70_2]; kill y116,y112,y110,y108,y100,y92,y84,y82,y76 ; status: weights = {70,72,78,80,86,88,94,96,102,104}; no [143,8,70]; type [145,9,70_2]; status: weights = {70,72,76,78,80,84,86,88,94,96}; kill y84,y76 ; status: weights = {70,72,78,80,86,88,94,96}; type [145,14,66_2]; status: weights = 66_2 - {114..145}; type [146,12,68_2]; kill y146,y144,y142,y140,y138,y136,y134,y132,y130,y128,y126,y124,y122,y120, y116,y114,y112,y110,y106,y102,y98,y94,y90,y86,y82,ndiv4; status: weights = 68_4 - {112..146}; type [147,4,78_2]; status: weights = {78,80}; type [147,8,72_2]; kill y146,ndiv4; status: weights = 72_4 - {92,108,116,124,132..140}; show (joint:0) y100 = 0, y144 = 0; status: weights = {72,76,80,84,88,96,104,112,120,128}; type [147,13,68_2]; status: weights = 68_4 - {112..147}; type [148,5,76_2]; status: weights = {76,80}; type [148,6,74_2]; status: weights = 74_2 - {82,98,106..114,122..148}; kill y116, y100 ; status: weights = {74,76,78,80,84,86,88,90,92,94,96,102,104,118,120}; status: weights = {74,76,78,80,84,86,88,90,92,94,96}; type [148,9,72]; show (joint:5) y72 = 429, y80 = 27, y88 = 55; STATUS_WE(1 + 429t^72 + 27t^80 + 55t^88) type [149,11,70_2]; status: weights = 70_2 - {122..149}; type [149,14,68_2]; status: weights = 68_2 - {118..146}; type [150,7,74_2]; kill y148; status: weights = 74_2 - {82,110,114,122,126..130,134..148}; kill y150,y132,y120,y118,y116,y104,y102,y100,y98,y88,y86,y84,y124 ; status: weights = {74,76,78,80,90,92,94,96,106,108,112}; type [150,10,72_2]; status: weights = {72,80,88,96}; type [151,6,76_2]; kill y90,y120,y104; status: weights = {76,80,88,92,96}; type [151,6,76]; status: weights = {76,80,88,92,96}; type [151,12,70_2]; status: weights = 70_2 - {126..151}; type [152,5,78_2]; status: weights = {78,80}; type [152,8,74_2]; kill y148; status: weights = 74_2 - {98,114,122,130,138,142,146,148}; kill y152,y150,y144,y140,y136,y134,y132,y120,y118,y116; status: weights = {74,76,78,80,82,84,86,88,90,92,94,96,100,102,104,106,108,110,112,124,126,128}; type [152,11,72_2]; status: weights = {72,76,80,84,88,92,96,100,104,108,112}; type [152,13,70_2]; status: weights = 70_2 - {122..152}; type [153,7,76]; status: weights = {76,80,92,96,108}; type [153,9,74_2]; status: weights = 74_2 - {82,90,98,110..153}; kill y108 by (x_44_40, x_46_38), y106, y104, y102, y100, y96 ; kill y88,y86,y84,y80 ; status: weights = {74,76,78,92,94}; type [153,14,70_2]; status: weights = 70_2 - {118..153}; type [154,12,72_2]; kill y154,y152,y150,y148,y146,y144,y142,y140,y138,y136,y134,y132,y130,y128, y124,y122,y120,y118,y116,y114,y110,y106,y102,y98,y94,y90,y86,ndiv4; status: weights = {72,76,80,84,88,92,96,100,104,108,112}; type [155,4,82_2]; status: weights = {82,84,86,88}; type [155,6,78]; status: weights = {78,80,94,96}; type [155,8,76_2]; kill y154,ndiv4; status: weights = {76,80,84,88,92,96,104,108,112,120,128,136,152}; show (joint:0) y120 = 0, y136 = 0, y152 = 0; show (joint:5) y104 = 0; status: weights = {76,80,84,88,92,96,108,112,128}; type [155,10,74_2]; status: weights = 74_2 - {82,98,106,114,122..155}; kill y120,y118,y116; status: weights = 74_2 - {82,98,106,114..155}; type [156,13,72_2]; status: weights = 72_2 - {126..156}; type [157,7,78]; status: weights = {78,80,94,96,110,112,126}; type [157,9,76_2]; status: weights = 76_2 - {86,94,102,114..118,122,126..157}; kill y124 ; kill y106,y90 ; status: weights = {76,78,80,82,84,88,92,96,98,100,104,108,110,112,120}; type [157,11,74_2]; status: weights = 74_2 - {128..157}; no [155,13,72]; type [157,14,72_2]; status: weights = 72_2 - {122..157} ; unset auto mu1; psheadx(280) // k = 2 3 4 5 6 7 8 9 10 11 12 13 14 psnext n =138, k >= 2: 92, 78, 72, 70, 68, 68, 66, 66, newd1()64, 64, 64, 63, 62; sn n =139, k >= 2: 92, 79, 73, 71, 69, 68, 67, 66, newd1()65, 64, 64, 64, newd1()62; sn n =140, k >= 2: 93, 80, 74, 72, 70, 68, 68, 67, 66, 65, 64, 64, newd1()63; sn n =141, k >= 2: 94, 80, 74, 72, 70, 69, 68, 68, newd1()66, 66, newd1()64, 64, 64; sn n =142, k >= 2: 94, 80, 75, 72, 71, 70, 68, 68, newd1()67, 66, newd1()65, newd1()64, 64; sn n =143, k >= 2: 95, 81, 76, 72, 72, 70, 69, 68, 68, 67, 66, newd1()65, newd1()64; sn n =144, k >= 2: 96, 82, 76, 73, 72, 71, 70, 69, 68, 68, 66, 66, newd1()65; sn n =145, k >= 2: 96, 82, 76, 74, 72, 72, 70, 70, newd1()68, 68, 67, 66, 66; sn n =146, k >= 2: 97, 83, 77, 74, 72, 72, 71, 70, newd1()69, 68, 68, 67, 66; sn n =147, k >= 2: 98, 84, 78, 75, 73, 72, 72, 71, 70, newd1()68, 68, 68, newd1()66; sn n =148, k >= 2: 98, 84, 78, 76, 74, 72, 72, 72, newd1()70, newd1()69, 68, 68, newd1()67; sn n =149, k >= 2: 99, 84, 79, 76, 74, 73, 72, 72, newd1()71, 70, newd1()68, 68, 68; sn n =150, k >= 2: 100, 85, 80, 76, 75, 74, 72, 72, 72, 70, newd1()69, newd1()68, 68; sn n =151, k >= 2: 100, 86, 80, 77, 76, 74, 73, 72, 72, 71, 70, newd1()69, newd1()68; sn n =152, k >= 2: 101, 86, 80, 78, 76, 75, 74, 73, 72, 72, 70, 70, newd1()69; sn n =153, k >= 2: 102, 87, 80, 78, 76, 76, 74, 74, 72, 72, 71, 70, 70; sn n =154, k >= 2: 102, 88, 81, 79, 77, 76, 75, 74, 73, 72, 72, 70, 70; sn n =155, k >= 2: 103, 88, 82, 80, 78, 76, 76, newd1()74, 74, newd1()72, 72, 71, 70; sn n =156, k >= 2: 104, 88, 82, 80, 78, 77, 76, newd1()75, 74, newd1()73, 72, 72, 71; sn n =157, k >= 2: 104, 89, 83, 80, 79, 78, 76, 76, 75, 74, newd1()72, 72, 72; pstailx set auto mu1; TYPE_WE(158,6,80,1 + 62t^80 + t^96) type [158,10,76]; status: weights = {76,80,88,92,96}; type [159,8,78_2]; kill y158, y156; kill y88 ; status: weights = {78,80,84,92,94,96,98,100,108,110,112,116,124,132,140}; show (joint:0) y84 = 0, y92 = 0, y98 = 0, y100 = 0, y108 = 0, y116 = 0, y124 = 0, y132 = 0, y140 = 0; status: weights = {78,80,94,96,110,112}; type [159,8,78]; status: weights = {78,80,94,96,110,112}; type [159,12,74_2]; status: weights = 74_2 - {130..159}; type [160,7,80]; status: weights = {80,96,112,128}; type [160,11,76_2]; status: weights = {76,80,84,88,92,96,100,104,108,112,116}; type [160,13,74_2]; status: weights = 74_2 - {126..160}; type [161,5,82_2]; status: weights = {82,84,86,88,90,92,94,96}; psheadx(55) // k = 2 3 4 5 6 7 8 9 10 11 12 13 14 psnext n =158, k >= 2: 105, 90, 84, 80, 80, 78, 77, 76, 76, 74, newd1()73, 72, 72; sn n =159, k >= 2: 106, 90, 84, 80, 80, 79, 78, 76, 76, 75, 74, 73, 72; sn n =160, k >= 2: 106, 91, 84, 81, 80, 80, 78, 77, 76, 76, 74, 74, 73; sn n =161, k >= 2: 107, 92, 85, 82, 80, 80, 79, 78, 77, 76, 75, 74, 74; pstailx type [161,9,78_2]; status: weights = 78_2 - {90,98,106,118..161}; kill y116 by (x_40_40, x_44_40), y114; kill y108, y92 ; status: weights = {78,80,82,84,86,88,94,96,100,102,104,110,112}; type [161,14,74_2]; status: weights = 74_2 - {112,116..161}; type [162,4,86_2]; status: weights = {86,88}; type [162,8,80_2]; kill y162,ndiv4,y160,y100; status: weights = {80,96,112}; type [162,8,80]; status: weights = {80,96,112}; TYPE_WE(162,10,78,1 + 624t^78 + 234t^80 + 144t^94 + 21t^96) type [162,12,76_2]; kill y162,y160,y158,y156,y154,y152,y150,y148,y146,y144,y142,y140,y138,y136,y132, y130,y128,y126,y124,y122,y120,y118,y114,y110,y106,y102,y98,y94,y90,ndiv4; status: weights = {76,80,84,88,92,96,100,104,108,112,116}; type [164,5,84_2]; status: weights = {84,88,92,96}; type [164,6,82_2]; status: weights = 82_2 - {98,114,122..130,138..164}; kill y132, y116 ; status: weights = 82_2 - {98,114,116,122..132,138..164}; status: weights = 82_2 - {98..164}; type [164,9,80_2]; kill y164, ndiv4, y160, y144, y128, y116; status: weights = {80,84,88,96,104,112}; type [164,9,80]; status: weights = {80,84,88,96,104,112}; type [164,11,78_2]; status: weights = {78,80,84,88,92,94,96,100,104,108,112,116}; kill y94,y92,y88; via lp [current] = ; no [164,11,78]; type [164,13,76_2]; status: weights = 76_2 - {130..164}; TYPE_WE(165,10,80,1 + 858t^80 + 165t^96) type [165,11,78_2]; status: weights = 78_2 - {134..165}; type [165,14,76_2]; status: weights = 76_2 - {126..165}; type [166,7,82_2]; kill y166,y164,y148,y140,y136,y134,y132,y102,y100 ; status: weights = 82_2 - {98,100,102,126,130..166}; type [167,6,84_2]; kill y106,ndiv4,y136,y120; status: weights = {84,88,92,96,104,108,112}; type [167,6,84]; status: weights = {84,88,92,96,104,108,112}; type [167,6,84]; status: weights = {84,88,92,96}; type [167,12,78_2]; status: weights = 78_2 - {134..167}; type [168,5,86_2]; status: weights = {86,88,92,94,96}; type [168,8,82_2]; kill y168,y166,y164,y160,y156,y152,y150,y148,y136,y134,y132 ; status: weights = 82_2 - {114,130..138,146..168}; type [168,11,80_2]; status: weights = 80_4 - {128..168}; type [168,13,78_2]; status: weights = 78_2 - {132..168}; type [169,7,84_2]; kill y168,ndiv4; status: weights = {84,88,92,96,104,108,112,116,120,124,136}; show (joint:0) y104 = 0, y136 = 0; status: weights = {84,88,92,96,108,112,116,120,124}; type [169,7,84]; status: weights = {84,88,92,96,108,112,116,120,124}; type [170,4,90_2]; status: weights = {90,92,94,96}; type [170,9,82_2]; status: weights = 82_2 - {130,146,150..162,166..170}; kill y164 ; status: weights = 82_2 - {130,146,150..170}; no [167,8,82]; no [169,9,82]; type [170,12,80_2]; kill y170,y168,y166,y164,y162,y160,y158,y156,y154,y152,y150,y148,y146,y144, y140,y138,y136,y134,y132,y130,y128,y126,y124,y122,y118,y114,y110,y106, y102,y98,y94,ndiv4,y120; status: weights = {80,84,88,92,96,100,104,108,112,116}; type [170,14,78_2]; status: weights = 78_2 - {142..168} ; type [171,6,86_2]; status: weights = {86,88,92,94,96,108,110,112}; show (joint:0) y92 = 0, y108 = 0; status: weights = {86,88,94,96,110,112}; type [171,6,86]; status: weights = {86,88,94,96,110,112}; type [171,6,86]; status: weights = {86,88,94,96}; type [171,8,84_2]; status: weights = 84_4 - {116,132,140,148,156..164}; show (joint:0) y136 = 0, y152 = 0, y168 = 0; status: weights = {84,88,92,96,100,104,108,112,120,124,128,144}; type [171,10,82_2]; status: weights = 82_2 - {98,114,122..171}; no [172,9,84]; no [172,9,84]; type [172,11,82_2]; kill y172,y118,y116,y110,y102,y86,y120,y112,y100; via lp [current] = ; no [172,11,82]; type [172,13,80_2]; kill y172,y170,y168,y166,y164,y162,y160,y158,y156,y154,y152,y150,y148,y146; kill y144 ; kill y142,y140,y138,y136,y134,y82,y130; kill y126 ; kill y118,y114,y110,y106,y122,y102,y94,ndiv4; status: weights = 80_4 - {136..172}; type [173,7,86_2]; kill y172; show (joint:0) y92 = 0, y100 = 0, y108 = 0, y114 = 0, y116 = 0, y124 = 0, y140 = 0, y142 = 0; status: weights = {86,88,94,96,110,112,118,120,126,128}; type [173,9,84_2]; status: weights = 84_4 - {132,144..173}; kill y140 ; status: weights = {84,88,92,96,100,104,108,112,116,120,124,128,136}; type [173,11,82_2]; status: weights = 82_2 - {140..173}; type [173,14,80_2]; status: weights = 80_4 - {132..173}; type [174,6,88_2]; status: weights = {88,96}; type [174,10,84_2]; status: weights = {84,88,92,96,104,108,112}; show (joint:0) y112 = 0; status: weights = {84,88,92,96,104,108}; type [174,10,84]; status: weights = {84,88,92,96,104,108}; type [175,8,86_2]; kill y172, y174; status: weights = {86,88,92,94,96,100,104,108,110,112,114,116,124,126,128,132, 140,148,156}; kill y156,y148,y140,y132; kill y124,y116,y114,y108,y104,y100 ; status: weights = {86,88,92,94,96,110,112,126,128}; type [175,12,82_2]; status: weights = 82_2 - {140..175}; type [176,5,90_2]; status: weights = {90,92,94,96}; type [176,7,88_2]; status: weights = {88,96,112,120,128}; type [176,11,84_2]; status: weights = 84_4 - {132..176}; type [176,13,82_2]; kill y176,y138,y136,y134,y102,y98,y96; via lp [current] = ; no [176,13,82]; psheadx(195) // k = 2 3 4 5 6 7 8 9 10 11 12 13 14 psnext n =162, k >= 2: 108, 92, 86, 82, 80, 80, 80, 78, 78, 76, 76, 74, 74; sn n =163, k >= 2: 108, 92, 86, 83, 81, 80, 80, 79, 78, newd1()76, 76, 75, 74; sn n =164, k >= 2: 109, 93, 87, 84, 82, 80, 80, 80, 79, newd1()77, 76, 76, 75; sn n =165, k >= 2: 110, 94, 88, 84, 82, 81, 80, 80, 80, 78, newd1()76, 76, 76; sn n =166, k >= 2: 110, 94, 88, 84, 83, 82, 80, 80, 80, newd1()78, newd1()77, newd1()76, 76; sn n =167, k >= 2: 111, 95, 88, 85, 84, 82, 81, 80, 80, newd1()79, newd1()78, newd1()77, newd1()76; sn n =168, k >= 2: 112, 96, 88, 86, 84, 83, 82, newd1()80, 80, 80, newd1()78, 78, newd1()76; sn n =169, k >= 2: 112, 96, 89, 86, 84, 84, 82, newd1()81, newd1()80, 80, newd1()79, 78, newd1()77; sn n =170, k >= 2: 113, 96, 90, 87, 85, 84, 83, 82, newd1()81, 80, 80, 78, 78; sn n =171, k >= 2: 114, 97, 90, 88, 86, 84, 84, newd1()82, 82, newd1()80, 80, 79, 78; sn n =172, k >= 2: 114, 98, 91, 88, 86, 85, 84, newd1()83, newd1()82, newd1()81, 80, 80, 79; sn n =173, k >= 2: 115, 98, 92, 88, 87, 86, 84, 84, newd1()83, 82, newd1()80, 80, 80; sn n =174, k >= 2: 116, 99, 92, 88, 88, 86, 85, 84, 84, newd1()82, newd1()81, 80, 80; sn n =175, k >= 2: 116, 100, 92, 89, 88, 87, 86, 84, 84, newd1()83, 82, newd1()80, 80; sn n =176, k >= 2: 117, 100, 93, 90, 88, 88, 86, 85, 84, 84, newd1()82, newd1()81, newd1()80; pstailx type [177,4,94_2]; status: weights = {94,96}; type [177,9,86_2]; status: weights = 86_2 - {90,106,114,122,134..138,142..177}; kill y140,y132,y130,y124,y116,y108,y100,y98 ; status: weights = {86,88,92,94,96,102,104,110,112,118,120,126,128}; type [177,13,82_2]; kill y176,y174,y172,y170,y168,y166,y160,y158,y156,y154,y150,y162; status: weights = 82_2 - {150,154..162,166,168,170,172,174,176}; type [178,8,88]; kill y178,ndiv4,y176; show x_88 >= 216, x_88 <= 246, x_96 <= 38, x_112 <= 14, x_116 <= 12, x_128 <= 8; show (joint:5) 216 <= y88 <= 231, 14 <= y96 <= 38, y112 <= 9, y116 <= 6, y128 <= 2; kill y116, y112 by x_48_48; show (joint:5) 216 <= y88 <= 220, 33 <= y96 <= 38, 1 <= y128 <= 2; config from x_128|x_64_32; show y88 <= 218, y96 >= 35, y128 = 1; show (joint:5) y88 = 216, y96 = 38, y128 = 1; STATUS_WE(1 + 216t^88 + 38t^96 + t^128) type [178,10,86_2]; kill y178,y112,y110; no [178,10,86]; type [178,12,84_2]; kill y178,y176,y174,y172,y170,y168,y166,y164,y162,y160,y158,y156,y154,y152, y148,y146,y144,y142,y140,y138,y136,y134,y132,y130,y128,y126,y124,y122, y118,y114,y110,y106,y102,y98,ndiv4,y120; status: weights = {84,88,92,96,100,104,108,112,116}; type [178,14,82_2]; kill y178 by x_82,y164,y152,y148; status: weights = 82_2 - {148..178}; type [179,5,92_2]; status: weights = {92,96}; type [179,6,90_2]; status: weights = {90,92,94,96,100,102,104,116,118,120}; show (joint:0) y100 = 0, y116 = 0; status: weights = {90,92,94,96,102,104,118,120}; type [179,6,90]; status: weights = {90,92,94,96,102,104,118,120}; type [179,6,90]; status: weights = {90,92,94,96}; type [179,10,86_2]; status: weights = 86_2 - {106,122,130,136,138,142..179}; kill y140 ; status: weights = 86_2 - {106,122,130,136..179}; no [178,10,86]; type [180,11,86_2]; status: weights = 86_2 - {90,98,106,114,122,130..178}; kill y180,y128,y126,y124,y116,y108,y100,y92 ; status: weights = {86,88,94,96,102,104,110,112,118,120}; psheadx(40) // k = 2 3 4 5 6 7 8 9 10 11 12 13 14 psnext n =177, k >= 2: 118, 100, 94, 90, 88, 88, 87, 86, newd1()84, 84, newd1()83, 82, newd1()81; sn n =178, k >= 2: 118, 101, 94, 91, 89, 88, 88, 86, newd1()85, 84, 84, 82, 82; sn n =179, k >= 2: 119, 102, 95, 92, 90, 88, 88, 87, 86, 85, 84, 83, 82; pstailx type [180,9,88_2]; kill y180,ndiv4,y176,y160,y144; kill y132,y100 ; status: weights = 88_8 - {136..180}; type [180,9,88]; status: weights = {88,96,104,112,120,128}; type [180,13,84_2]; kill y180,y178,y176,y174,y172,y170,y168,y166,y164,y162,y160,y158,y156; kill y154 ; kill y152,y150,y148; kill y146 ; kill y144,y142,y140,y138,y134,y130,y126,y122,y118,y114, y110,y106,y102,y98,ndiv4,y136; status: weights = {84,88,92,96,100,104,108,112,116,120,124,128,132}; type [181,7,90_2]; kill y180,y150,y148,y136,y134,y132,y120,y118,y116,y108,y104,y102,y100 ; status: weights = {90,92,94,96,122,124,126,128}; type [181,14,84_2]; status: weights = 84_4 - {128..181}; TYPE_WE(182,6,92,1 + 56t^92 + 7t^96) no [180,7,90]; no [182,8,90]; type [182,10,88_2]; status: weights = {88,90,92,96,98,100,104,112,116,120,128}; type [183,5,94_2]; status: weights = {94,96}; type [183,8,90_2]; kill y180,y182,y164,y156,y148,y140,y132,y116,y112,y108 ; status: weights = {90,92,94,96,100,102,104,118,120,122,124,134,136}; type [183,11,88_2]; kill y128,y120 ; kill y104 ; via lp [current] = ; no [183,11,88]; type [183,12,86_2]; status: weights = 86_2 - {146..183}; type [184,7,92]; status: weights = {92,96,124,128}; type [184,11,88_2]; kill y184,y182,y180,y178,y176,y174,y172,y170,y168,y164,y162,y160,y156,y154, y152,y148,y146,y144,y140,y138 ; status: weights = {88,90,92,96,98,100,104,106,108,112,114,116,120,122,124, 128,130,132,136}; type [185,4,98_2]; status: weights = {98,100,102,104}; type [185,9,90_2]; kill y148,y140,y138,y136,y134,y132,y120,y118,y116 ; status: weights = {90,92,94,96,100,102,104,106,108,110,112,124,126,128}; type [185,13,86_2]; status: weights = 86_2 - {156..185}; TYPE_WE(186,6,94,1 + 48t^94 + 15t^96) type [186,8,92_2]; show (joint:0) y104 = 0, y122 = 0, y136 = 0, y184 = 0, y186 = 0; status: weights = {92,94,96,120,124}; type [186,12,88_2]; kill y186,y184,y182,y180,y178,y176,y174,y172,y170,y168,y166,y164,y162,y160, y156,y154,y152,y150,y148,y146,y144,y142,y140,y138,y136,y134,y132,y130, y128,y126,y122,y118,y114,y110,y106,y102,ndiv4,y124; status: weights = 88_4 - {124..186}; no [184,13,86]; type [186,14,86_2]; kill y186 by x_86; kill y154 ; status: weights = 86_2 - {154..186}; type [187,10,90_2]; status: weights = 90_2 - {114,130,138,142..187}; kill y140 ; status: weights = 90_2 - {114,130,138..187}; type [188,7,94_2]; status: weights = {94,96,124,126,128}; show (joint:0) y124 = 0; status: weights = {94,96,126,128}; type [188,7,94]; status: weights = {94,96,126,128}; type [188,9,92_2]; kill y188,ndiv4,y184,y168,y152,y140,y128; status: weights = {92,96,104,108,112,120,136}; no [188,9,92]; no [188,11,90]; type [188,13,88_2]; kill y188,y186,y184,y182,y180,y178,y176,y174,y172,y170,y168,y166; kill y164 ; kill y160,y158,y156,y152,y150,y148,y146,y144,y142,y140,y138,y136,y134,y130, y126,y122,y118,y114,y110,y106,y102,y98,y94,ndiv4,y132,y128,y124; status: weights = {88,92,96,100,104,108,112,116,120}; TYPE_WE(189,6,96, 1 + 63t^96) TYPE_WE(189,8,94,1 + 189t^94 + 63t^96 + 3t^126) type [189,9,92_2]; status: weights = {92,94,96,98,100,104,106,108,110,112, 114,116,120,122,124,128,130,132,136,138,140,142,144,152,156}; type [189,11,90_2]; kill y188,y186,y184,y182,y180,y178,y176,y174,y172,y170,y168,y166,y164,y162, y160,y158,y156,y154,y152 ; status: weights = 90_2 - {152..189}; type [190,10,92_2]; status: weights = {92,96,100,104,108,112,120,124}; type [190,14,88_2]; kill y190 by x_88,y188,y186,y184,y182,y180,y178,y174,y172,y170,y168,y164, y162,y160,y158,y156; kill y176,y166 ; status: weights = 88_2 - {156..190}; TYPE_WE(191,7,96, 1 + 126t^96 + t^128) type [191,12,90_2]; status: weights = 90_2 - {152..191}; no [190,7,96]; TYPE_WE(192,8,96,1 + 252t^96 + 3t^128) type [192,4,102_2]; status: weights = {102,104}; type [192,5,98_2]; status: weights = {98,100,102,104,106,108,110,112}; type [192,9,94_2]; status: weights = {94,96,100,108,112,116,124}; no [192,9,94]; type [192,11,92_2]; status: weights = 92_2 - {94,102,110,114,118,126,130,134,138,142,146..192}; type [193,9,94_2]; kill y192,y190,y188,y184,y180,y176,y174,y172,y164,y160,y158,y156,y140 ; status: weights = 94_2 - {106,122,130,138,140,150..193}; type [193,13,90_2]; status: weights = 90_2 - {160..193}; type [194,10,94_2]; status: weights = 94_2 - {98,106,114,118..122,128..194}; type [194,12,92_2]; kill y194,y192,y190,y188,y186,y184,y182,y180,y178,y176,y174,y172,y170,y168, y164,y162,y160,y158,y156,y154,y152,y150,y148,y146,y144,y142,y140,y138, y136,y134,y130,y126,y122,y118,y114,y110,y106,ndiv4; status: weights = 92_4 - {136..194}; type [194,14,90_2]; kill y194 by x_90, y158; status: weights = 90_2 - {158..194}; type [195,5,100_2]; status: weights = {100,104,108,112}; type [195,10,94_2]; kill y194,y192,y190,y188,y186,y184,y182,y180,y178,y176,y174,y172,y168,y166, y164,y160,y158,y156,y152,y150 ; status: weights = 94_2 - {122,138,146,150..195}; type [196,6,98_2]; status: weights = 98_2 - {130,146,154..162,170..196}; kill y164,y148 ; status: weights = 98_2 - {130,146,148,154..164,170..196}; status: weights = 98_2 - {130..196}; type [196,9,96_2]; status: weights = {96,98,100,104,112,116,120,128,136,144,148}; show (joint:0) y148 = 0; status: weights = {96,98,100,104,112,116,120,128,136,144}; type [196,11,94_2]; kill y144,y142,y140,y132,y124 ; status: weights = {94,96,100,102,104,108,110,112,116,118,120,126,128,134,136}; type [197,13,92_2]; kill y196,y194,y192,y190,y188,y186,y184,y182,y180,y178; kill y176 ; kill y174,y172,y170,y168,y166,y164,y162; status: weights = 92_2 - {162..197}; type [198,7,98_2]; kill y196 ; kill y198, y180, y172 by (x_80_20, x_84_20), y168, y164, y166 ; status: weights = 98_2 - {130,158,162..198}; status: weights = 98_2 - {130..198}; type [198,10,96_2]; status: weights = {96,98,100,104,106,108,112,114,116,120,128,130,132,136}; type [198,14,92_2]; kill y198 by x_92; status: weights = 92_2 - {162..198}; type [199,5,102_2]; status: weights = {102,104,108,110,112}; type [199,6,100_2]; kill y138,ndiv4,y168,y152; status: weights = {100,104,108,112,116,120,124,128,136,140,144}; status: weights = {100,104,108,112,116,120,124,128}; no [197,7,98]; type [199,8,98_2]; status: weights = 98_2 - {114,122,126,130..199}; kill y124 ; status: weights = {98,100,102,104,106,108,110,112,116,118,120,128}; type [199,11,96_2]; status: weights = {96,104,112,120,128}; type [199,12,94_2]; status: weights = 94_2 - {158..199}; type [200,4,106_2]; status: weights = {106,108,110,112}; unset auto mu1; psheadx(250) // k = 2 3 4 5 6 7 8 9 10 11 12 13 14 psnext n =180, k >= 2: 120, 102, 96, 92, 90, 89, 88, 88, newd1()86, 86, 84, 84, 83; sn n =181, k >= 2: 120, 103, 96, 92, 91, 90, newd1()88, 88, newd1()87, 86, newd1()84, 84, 84; sn n =182, k >= 2: 121, 104, 96, 93, 92, 90, newd1()89, 88, 88, newd1()86, newd1()85, 84, 84; sn n =183, k >= 2: 122, 104, 96, 94, 92, 91, 90, 88, 88, newd1()87, 86, newd1()84, 84; sn n =184, k >= 2: 122, 104, 97, 94, 92, 92, newd1()90, 89, 88, 88, 86, newd1()85, newd1()84; sn n =185, k >= 2: 123, 105, 98, 95, 93, 92, newd1()91, 90, newd1()88, 88, 87, 86, newd1()85; sn n =186, k >= 2: 124, 106, 98, 96, 94, 92, 92, 90, newd1()89, 88, 88, 86, 86; sn n =187, k >= 2: 124, 106, 99, 96, 94, 93, 92, newd1()90, 90, newd1()88, 88, 87, 86; sn n =188, k >= 2: 125, 107, 100, 96, 95, 94, 93, newd1()91, newd1()90, newd1()89, 88, 88, newd1()86; sn n =189, k >= 2: 126, 108, 100, 96, 96, 94, 94, 92, newd1()91, 90, newd1()88, 88, newd1()87; sn n =190, k >= 2: 126, 108, 100, 96, 96, 95, 94, 92, 92, newd1()90, newd1()89, 88, 88; sn n =191, k >= 2: 127, 108, 101, 97, 96, 96, 95, newd1()92, 92, newd1()91, 90, newd1()88, 88; sn n =192, k >= 2: 128, 109, 102, 98, 96, 96, 96, newd1()93, 92, 92, 90, newd1()89, newd1()88; sn n =193, k >= 2: 128, 110, 102, 98, 96, 96, 96, 94, newd1()92, 92, 91, 90, newd1()89; sn n =194, k >= 2: 129, 110, 103, 99, 96, 96, 96, 94, newd1()93, 92, 92, 90, 90; sn n =195, k >= 2: 130, 111, 104, 100, 97, 96, 96, 95, 94, 93, 92, newd1()90, 90; sn n =196, k >= 2: 130, 112, 104, 100, 98, 96, 96, 96, newd1()94, 94, 92, newd1()91, newd1()90; sn n =197, k >= 2: 131, 112, 104, 100, 98, 97, 96, 96, newd1()95, 94, newd1()92, 92, newd1()91; sn n =198, k >= 2: 132, 112, 104, 101, 99, 98, 97, 96, 96, 95, newd1()93, 92, 92; sn n =199, k >= 2: 132, 113, 105, 102, 100, 98, 98, 96, 96, 96, 94, newd1()92, 92; sn n =200, k >= 2: 133, 114, 106, 102, 100, 99, 98, 96, 96, 96, 94, newd1()93, 93; pstailx data_comment( ![ \block{A menagerie of codes}\label{menagerie-section} This section contains a huge list of codes, including a few with previously unknown parameters. The whole list is in transition, as I try to find simpler (or better) descriptions of the codes. Because many of the codes are derived from other codes in the list, the list has gotten to be a bit of a tangle. It will in due course be cleaned up! In particular, I barely started the project of replacing many of the codes by codes described with the {\tt cyclic} command. Some codes have been replaced by generator matrices, which has the advantage of reducing interdependency, but the disadvantage that pages and pages are now filled with matrices. Hopefully better descriptions of these codes will be found. Note also that there is a certain amount of nonsense in this section resulting from uniqueness statements that should be proved by the methods of van Tilborg [.tilborg griesmer.]. These have not yet been formalized in the {\tt Split} language. ]! ) DHIDE( ![ (* "done" notations for the following. Always use "nonprojective search" and look for all isomorphism types C: LAST column deleted E: each column deleted suffix P: done with "double column pairs" option suffix G: done with "double column groups" option Versions: suffix S: done after code shortening added suffix *: semifinal version suffix #: "final" version *); ]! ) unset auto joint list; [2_1_1] type [2,1,1]; [a] := {10}; DHIDE( ![ (* Some good seed codes: *); (* D1# run on everything in DATA_F2_1 except [31,13,9] *); (* D2#: [31,13,9] and [28_10_10.c-g2] skipped *); (* D3#: the above, [16,11,4], the [21,8,8]'s, the [24,14,6], and all the [28,10,10]'s skipped, [28,14,8], [29,8,12] --> end *); (* O(28)# done for the [28,14,8] *); (* DC1#, D2#, D3#(6.1% of orbit 1) done for [17,8,6.a] *); (* DC1P#, D2PG#, O(30)#, DC1.7# done for *); ]! ) [18_9_6x] type [18,9,6]; [a] := 2-cyclic {000101010000001101}; (* isomorphic to [18_9_6.a] *); DHIDE( ![ (* DC2#, O(26)#, DC1.7# done for [20_8_8.a] *); (* DC1#, D3#, O(30)# done for [21_9_8.a] *); (* D3#, DC2P#, D1G, O(24)#, DC1.7# done for [21_8_8.g] *); (* DC4S(26/5,12), D4S(38/5,11)(stopped after 560 minutes), DC1# done for [24,12,8] *); ]! ) DHIDE( ![ (* DC1P#, D2#, O(29/5,10)# done *); (* DE2(26).7(only 4 orbits checked)# *); (* OE(28).7#(allowing length up to 495) *); (* for [35_9_14.a] *); (* DC1P#, D3G#, O(29/5,10)# done for [32_11_12.a] *); (* DC1P#, D3#, DC1.7# done for [48_8_22.a] *); (* DC1#, OE(26)#, DC1.7# done for *); ]! ) [45_8_20] type [45,8,20_2]; DUAL_TRANSFORM([a], [48_8_22.a], ![30_{1,-17},30_{17}]!) status: realizable; DHIDE( ![ (* DC2#, D3#, O(26)#, DC1.7# *); ]! ) [178_8_88] type [178,8,88_2]; (* Bierbrauer-Edel *); DUAL_TRANSFORM_CH([a], [20_8_8.a-1], ![7,11,12,15,16]!) status: realizable; DHIDE( ![ (* DE1.7# done for [12,7,4] *); ]! ) (* ****************** SOME SIX-DIMENSIONAL CODES ************************** *); [45_6_22] type [45,6,22]; (* WE known *); [a] := Simp(4) # Simp(2); [53_6_26] type [53,6,26]; (* weights known to be in {26,28,30,32} *); [a] := P( [21_5_10.a] ); [b] := P( [21_5_10.b] ); disjoint [a], [b]; type [53,6,{26,28,30,32}]; config from x_26; show y32 != 0; (* This implies that [a], [b] is a complete list. *); (* **************** JUNK TO AVOID RE-ENTERING A CODE TYPE. **************** *); [71_7_34x] type [71,7,34]; [a] := P( Even(7) ); [75_7_36x] type [75,7,36]; DUAL_TRANSFORM([a], [178_8_88.a-1], ![88_{41},96]!) (* the above iso. to [75_7_36.a], but not equal *); DUAL_TRANSFORM([b], [178_8_88.a-1], ![88_{49},96]!) (* the above iso. to [75_7_36.b], but not equal *); [79_7_38x] type [79,7,38]; [a] := P( [15_6_6.a] ); [c] := P( [15_6_6.c] ); [82_7_40x] type [82,7,40]; [a] := P( [18_6_8.a] ); [117_7_58x] type [117,7,58]; [a] := P( [53_6_26.a] ); [87_7_42x] type [87,7,42]; DUAL_TRANSFORM([c], [75_7_36x.a-2], ![35_{5},36_{5},37,38_{5},39,40,41_{5},42_{-5},63_{5}]!) (* the above is iso. to d10 *); DUAL_TRANSFORM_PLUS([d], [75_7_36x.a-2], ![35_{10},36_{10},37,38_{10},39,40,41_{-10},42_{10},63_{10}]!, ![+ column 65]!) (* the above is iso. to c3 *); [59_7_28x] type [59,7,28]; DUAL_TRANSFORM([a], [48_8_22.a-1], ![22_{3},24_{3},30_{-3},32_{-3}]!) [105_8_50x] type [105,8,50_2]; DUAL_ORBIT_PLUS([b], [21_9_8.a], ![$2,$3,$4]!, ![000000110,000010001,001111101,010001011,010101111]!, ![- column 3 - column 40]!) [140_8_68y] type [140,8,68_2]; [d] := [21_8_8.g]^T using {$1,$2,$3 : 00001001,00010001,00011101,00100000, 00100011,00110000,00110100,01101000,01101010,01111000,01111110,10110101}; [42_8_18y] type [42,8,18_2]; DUAL_ORBIT([d], [140_8_68y.d], ![$2,$5]!, ![00000111,00001100,00101010,01101011]!) [147_8_72y] type [147,8,72_4]; DUAL_ORBIT([b], [21_8_8.g], ![$1, $2, $3]!, ![00000101,00001001,00001101,00010001,00011101,00100011,00110100,01101000, 01101010]!) (* ************** PUTATIVELY OPTIMAL SEVEN-DIMENSIONAL CODES *************** *); DHIDE( ![ (* DE1.7#, O(26).7# done for [24_7_10.*] *); (* DE1.7#, O(26).7# done for [a]--[g] *); ]! ) (* Note that P of these yields [168,8,82] codes. *); [40_7_18] type [40,7,18]; DUAL_TRANSFORM_PLUS([a], [87_7_42x.d-1], ![42_{85},43_{-85},45_{-85},47_{-85},48_{-85},49_{85},63_{85}]!, ![+ column 38]!) DUAL_ORBIT([b], [24_7_10.a], ![$2,$3]!, ![0000001,0000111,0001100,0010010,0011101,0101110,1111110,1111111]!) DUAL_ORBIT([c], [24_7_10.f], ![$1,$3]!, ![0000001,0001001,0001111,0010011,1001001,1001010]!) DUAL_ORBIT([d], [40_7_18.a], ![$3,$4]!, ![0001000,0010100,0011010,0011110,0100100,0111101]!) DUAL_ORBIT([e], [75_7_36x.b], ![$6]!, ![0000110,0001100,0001110,0100100,0100101, 0101000,0101111,0110110]!) [f] := (6,6,6,6,6,2,6)-cyclic {111110110100010110001010000010010110001, 0110100100001100101101010000100110011101}; [g] := (12,12,6,6,3)-cyclic {1011101011100000010000011100010111101101, 0011011100100101111010000001110111011}; disjoint [a], [b], [c], [d], [e], [f], [g]; DHIDE( ![ (* O(26).7# done for [a], [b] *); ]! ) type [43,7,20]; (* Note that P of these yields [171,8,84] codes. *); DUAL_ORBIT([a], [40_7_18.a], ![$3,$4]!, ![0001000,0010100,0011010,0011110, 0100011,0100100,0111101,1011111,1111100]!) [b] := {1000000100101110001000111011111101001000101, 0100001001101100010101011101011100101101000, 0010000011001110011011101000101110100011100, 0001001110001010111001110010010111000110010, 0000100101010110110110111000000101001111001, 0000011111111110000000000000011111111111111, 0000000000000001111111111111111111111111111}; disjoint [a], [b]; DHIDE( ![ (* O(26).7# done for [a] -- [f] *); ]! ) type [48,7,22]; DUAL_ORBIT([a], [24_7_10.a], ![$3,$4,$5]!, ![0001010,0001011,0001100,0001111, 0011010,0011110,0101101,0111011,1001010,1001011,1011110]!) DUAL_ORBIT([b], [24_7_10.a], ![$3,$4,$5]!, ![0001010,0001011,0001100,0001110, 0011010,0011110,0101101,0111011,1001010,1001011,1011110]!) DUAL_ORBIT([c], [24_7_10.a], ![$3,$4,$5]!, ![0001010,0001011,0001100,0001110, 0011010,0011110,0101100,0111010,1001010,1001011,1011110]!) DUAL_ORBIT([d], [24_7_10.a], ![$2,$3]!, ![0001011,0001101,0010010,0010011,0011101,0101110,0101111,1111111]!) DUAL_ORBIT([e], [24_7_10.a], ![$2,$3]!, ![0001011,0001101,0010010,0010011,0011101,0101110,0101111,1111110]!) DUAL_ORBIT([f], [24_7_10.a], ![$2,$3]!, ![0001010,0001101,0010010,0010011,0011101,0101110,0101111,1111111]!) disjoint [a], [b], [c], [d], [e], [f]; type [51,7,24]; DUAL_ORBIT([a], [24_7_10.a], ![$3,$4,$5]!, ![0001010,0001011,0001100,0001111, 0010111,0011010,0011110,0101101,0111010,1001010,1001011,1011110]!) DUAL_ORBIT([b], [24_7_10.a], ![$3,$4,$5]!, ![0001010,0001011,0001100,0001110, 0010111,0011010,0011110,0101101,0111011,1001010,1001011,1011110]!) DUAL_ORBIT_PLUS([c], [24_7_10.a], ![$3,$4,$5]!, ![0001010,0001011,0001100, 0001110,0010111,0011010,0011110,0101101,0111010,0111011,1001010,1001011, 1011110]!, ![- column 19 - column 29 - column 47]!) DUAL_ORBIT([d], [24_7_10.a], ![$3,$4,$5]!, ![0001010,0001011,0001100,0001110, 0010110,0011010,0011110,0101100,0111010,1001010,1001011,1011110]!) DUAL_ORBIT_PLUS([e], [24_7_10.a], ![$2,$3]!, ![0001011,0001100,0001101,0010010, 0010011,0011101,0101110,0101111,1111111]!, ![+ column 50]!) DUAL_ORBIT_PLUS([f], [59_7_28x.a], ![$2,$4]!, ![0001101,0001111,0011100,0100111, 0101100,0101101,0101111,1000011,1011111]!, ![+ column 32]!) DUAL_ORBIT([g], [59_7_28x.a], ![$2,$4]!, ![0000010,0100010,0100111,0101100, 0101101,0101111,1000011,1011111,1101110]!) DUAL_ORBIT_PLUS([h], [71_7_34x.a], ![$3,$4,$5,$6]!, ![0011111,0111110,0111111, 1000001,1000110,1001110,1001111,1011110,1011111,1111110,1111111]!, ![+ column 8]!) DUAL_ORBIT_PLUS([i], [71_7_34x.a], ![$3,$4,$5,$6]!, ![0001111,0011111,0111110, 0111111,1001110,1001111,1011110,1011111,1111110,1111111]!, ![+ column 16 + column 16]!) DUAL_ORBIT_PLUS([j], [75_7_36x.a], ![$2,$3,$4]!, ![0010101,0100011,0100100, 0100110,0100111,1001101,1011110,1101100,1101101,1111101]!, ![+ column 48]!) DUAL_ORBIT_PLUS([k], [75_7_36x.a], ![$2,$3,$4]!, ![0010101,0100001,0100011, 0100101,0100111,0110110,1011110,1101100,1101101,1111101]!, ![+ column 48]!) DUAL_ORBIT([l], [75_7_36x.a], ![$2,$3,$4]!, ![0010101,0100001,0100011, 0100101,0100111,0110110,1001101,1011110,1101101,1111101]!) DUAL_ORBIT([m], [75_7_36x.b], ![$6]!, ![0001110,0010100,0010110,0100000,0100100, 0100111,0101100,0110100,0110101,0110110]!) DUAL_ORBIT([n], [75_7_36x.b], ![$6]!, ![0000101,0000110,0001001,0001101,0001110, 0100110,0100111,0101100,0101111]!) DUAL_ORBIT_PLUS([o], [75_7_36x.b], ![$6]!, ![0000011,0001100,0001110,0010100, 0100000,0100001,0100100,0100101,0100111,0110100,0110110]!, ![+ column 5 + column 32]!) DUAL_ORBIT([p], [75_7_36x.b], ![$6]!, ![0000011,0000110,0001001,0001110,0010101, 0100100,0101000,0101111,0110110]!) DUAL_ORBIT_PLUS([q], [40_7_18.b], ![$1,$2]!, ![0000111,0010000,1000000,1001000, 1010001,1010010,1011011,1100111]!, ![+ column 37 + column 37]!) disjoint [a], [b], [c], [d], [e], [f], [g], [h], [i], [j], [k], [l], [m], [n], [o], [p], [q]; DHIDE( ![ (* DE1.7# for [a] -- [f], O(26).7# done for [a] -- [c] *); ]! ) [56_7_26] type [56,7,26]; DUAL_TRANSFORM_PLUS([a], [21_8_8.g-1], ![7_{3},11_{3}]!, ![- column 2]!) DUAL_TRANSFORM_PLUS([b], [12_7_4.a-3], ![5_{-4},6_{4},7_{-4},8,9_{4}]!, ![- column 38]!) [c] := (9,9,9,9,9,9)-cyclic {00101110100010001101010000100011100000111100110110011011}; DUAL_TRANSFORM_PLUS([d], [24_7_10.c-1], ![9_{2},10_{2},11_{2},12_{2},13_{2},16,17]!, ![- column 35]!) DUAL_TRANSFORM_PLUS([e], [24_7_10.f-2], ![9_{19},10_{19},11_{19},12_{19},14_{19},15,18_{19}]!, ![- column 33]!) DUAL_TRANSFORM_PLUS([f], [24_7_10.f-2], ![9,11,13_{-21},14_{21},16_{21},18_{-21}]!, ![- column 55]!) DUAL_TRANSFORM_PLUS([g], [24_7_10.f-7], ![9,11,13_{-12},14_{12},16]!, ![- column 56]!) DUAL_TRANSFORM([h], [87_7_42x.c-1], ![41_{80},43,44_{80},46_{80},48_{80},49_{80}]!) DUAL_TRANSFORM_PLUS([i], [87_7_42x.d-1], ![41_{57},43_{57},44_{57},45_{-57},46_{57},48_{57},49_{-57}]!, ![- column 44]!) DUAL_TRANSFORM_PLUS([j], [40_7_18.a-1], ![17_{2},18_{2},19_{2},20_{2},22_{2},23,27]!, ![- column 56]!) DUAL_TRANSFORM_PLUS([k], [40_7_18.a-2], ![17,19_{-33},20_{33},21_{33},28_{-33},32_{33}]!, ![+ column 13 + column 54]!) DUAL_TRANSFORM_PLUS([l], [56_7_26.e-22], ![25_{25},26_{25},27_{25},28_{25},29_{25},31_{-25}]!, ![+ column 40]!) DUAL_TRANSFORM_PLUS([m], [56_7_26.f-12], ![25_{34},26_{34},27_{34},30_{34},31_{34},32_{34},33_{-34},34_{-34}, 37_{34},45_{34}]!, ![+ column 13]!) DUAL_TRANSFORM_PLUS([n], [56_7_26.g-1], ![25_{-45},26_{45},27_{-45},28_{45},30_{-45}]!, ![+ column 22 + column 52]!) DUAL_ORBIT_PLUS([o], [24_7_10.a], ![$2,$3]!, ![0000111,0001101,0010010,0010011, 0011101,0101110,0101111,1111110,1111111]!, ![+ column 54 + column 54]!) DUAL_ORBIT_PLUS([p], [24_7_10.a], ![$2,$3]!, ![0000111,0001100,0010010,0010011, 0011101,0101110,0101111,1111110,1111111]!, ![+ column 54 + column 54]!) DUAL_ORBIT([q], [24_7_10.a], ![$2,$3]!, ![0000111,0001010,0010010,0010011,0011101,0101110,0101111,1111111]!) DUAL_ORBIT([r], [24_7_10.a], ![$2,$3]!, ![0000110,0000111,0001011,0010010,0010011,0011101,0101111,1111110]!) DUAL_ORBIT([t], [24_7_10.b], ![$2,$5]!, ![0000111,0001101,0001110,0010011, 0100111,0101101,0101111,0110010,1001011]!) DUAL_ORBIT([u], [24_7_10.b], ![$2,$5]!, ![0000110,0001001,0001100,0001101, 0001110,0010011,0101111,0110010,1001011]!) DUAL_ORBIT_PLUS([v], [24_7_10.f], ![$1,$3]!, ![0000001,0000111,0001001,0001010,0001111,0101100,1001010,1011101, 1011111]!, ![+ column 32]!) DUAL_ORBIT_PLUS([w], [24_7_10.f], ![$1,$3]!, ![0000001,0000111,0001001,0001010,0001111,0010011,1001001,1001010, 1011111]!, ![+ column 35]!) DUAL_ORBIT_PLUS([x], [24_7_10.f], ![$1,$3]!, ![0000001,0000111,0001001,0001010,0001111,0010011,1001001,1001010, 1011101]!, ![+ column 35]!) DUAL_ORBIT_PLUS([y], [40_7_18.a], ![$3,$4]!, ![0001000,0001101,0010000,0010001, 0010100,0011010,0011110,0100100,0111101,1011111,1111100]!, ![+ column 53]!) DUAL_ORBIT_PLUS([z], [40_7_18.a], ![$3,$4]!, ![0000101,0001000,0010100,0011000, 0011001,0011010,0100011,0100100,0111101,1011111]!, ![+ column 42]!) DUAL_ORBIT([aa], [75_7_36x.b], ![$6]!, ![0000110,0001110,0010101,0010110, 0100000,0100100,0100101,0101000,0101111,0110100,0110110]!) [bb] := {10000001010101111010010010101001010110101010010110110100,0100000101010100010110 1101010110101001011010010110110100,001000010110010100110110011100001100110000110 01101100111,00010000010011101001110100100110100101100110100111010011,00001000101 011110101101010101010101010101010101001010100,0000010011010000101010101011010110 1010101010101010101011,00000011111111111111111111111111111111111111111111111111} ; [cc] := {10000000010010100010101011001011010101010111010110010111,0100000001001001110101 0100110100101010100111010110010111,001000011101101101100110100001101001001111011 00100110000,00010001101011010100101110110010010001100101001010100111,00001000101 100100101010111001010101001010110101001010111,0000010010001101101011011101010100 1001010110101110101000,00000011111111111111111111111111111111111111111111111111} ; [dd] := {10000001001011010101010111001011010001001011010101001011,0100000100101100101010 1000110100101110101011010101001011,001000011110011111001100100001101001001110011 00110011000,00010000110101001001011010110010010101101101001011010011,00001001010 100011010101011001010101101001010101010101011,0000010101001110010110101101010100 1101001010101101010100,00000011111111111111111111111111111111111111111111111111} ; [ee] := {10000011100100111110000000111000011110001110000000111111,0100001110100011000111 1000111111100110001110000111000000,001000111100000011000001111111111110000011111 11000000000,00010000111101100010110011101011011100110101001101011000,00001001011 100011010101101001010110011010111010001101000,0000011001110111100001111010011001 0000011101100011001111,00000000000011111111111111111111111111111111111111111111} ; [ff] := {10000011100100111111100000011110000011111001110000001111,0100001110100011100001 1100011111111100011001110001110000,001000111100000001100000111111111111111000011 11110000000,00010000111101010001101001110010011010110010100011010110,00001001011 100001101101110101010010111001110110100011010,0000011001110101110000011101100111 0010000011101000110011,00000000000011111111111111111111111111111111111111111111} ; [gg] := {10000011100100111110100000011110000111110011100000011111,0100001110100011100101 1100011111111000110011100011100000,001000111100000001110000111111111111110000111 11100000000,00010000111101010001101001110010110101100101000110101100,00001001011 100001101101110101010101110011101101000110100,0000011001110101110000011101100110 0100000111010001100111,00000000000011111111111111111111111111111111111111111111} ; [hh] := {10000000011100101011001110001011011111110001001100110000,0100010110010001001100 1001110011011000110110001100001111,001001000110111100110101100100110110110010011 10000001111,00010100101101001001010101001001101010010011101010010111,00001001010 101010110001101010110101001101011101001101000,0000001111111111111100000000000011 1111111111111111111111,00000000000000000000111111111111111111111111111111111111} ; [ii] := {10000100010110110101001110010100110001111011011000011000,0100010111000001110111 0000011111000001111100000001111111,001001011001110001010110011011001100100110001 11000000111,00010100110011101001101011000010011010110001010011010011,00001101011 011010000111101010001101000101010010100101011,0000001111111111110000000000000011 1111111111111111111111,00000000000000000011111111111111111111111111111111111111} ; [jj] := {10001000111010011011011101010011001100011110110110001000,0100101100101110010001 1110010111001010100110110001111000,001010011100010101011011000011101010010010101 00101010011,00011010100001001001110101000101101101110011010100110100,00000111111 000000111111111000011111110000000111111111111,0000000000011111111111111100000000 0001111111111111111111,00000000000000000000000000111111111111111111111111111111} ; [kk] := {10001000111010011011011101010010010100110011011001010000,0100101100101110010001 1110010001101100101100111001001110,001010011100010101011011000001111001101000010 01010011011,00011010100001001001110101001001101010110110001101010110,00000111111 000000111111111000000011111111000000001111111,0000000000011111111111111100000000 0000000111111111111111,00000000000000000000000000111111111111111111111111111111} ; [ll] := {10000101001001101100100100110110010011010100010011011011,0100011001101101100110 1001100101010100110101011010101100,001000110011100000111111001100001111000111110 00000011111,00010011011100111010001101011100100110011001110001111000,00001100011 101000101110001010011011010011001001110000111,0000000011111111111111110000000000 0011111111111111111111,00000000000000000000000011111111111111111111111111111111} ; [mm] := {10000101100100111011001001011110001011100010000100110011,0100011000110101011001 1010011010100010100101011000101011,001000111001111000001111110110001111100001111 00001111111,00010011001110001110100011001011011001001011001100000111,00001100101 110010001011100001100100111001011010011111000,0000000001111111111111111100000000 0001111111111111111111,00000000000000000000000000111111111111111111111111111111} ; [nn] := {10000111000111111000001111010100011010100010001001011010,0100011100011100011100 1100001111110000011111000001111111,001001000110011011000010001101101111000101100 10010110011,00010101010101100010010101101100100110010011101010011001,00001110001 100110001011110100101101010000101000111010101,0000000011111111111100000000000000 1111111111111111111111,00000000000000000000111111111111111111111111111111111111} ; [oo] := {10000110010010111100011001001001111011100100100001110111,0100000111000111110000 0111000111111000010011100000001111,001000111000111010101010010010100111101010100 01010101001,00010110100101100100110101011010100101100011010011000101,00001010110 110001101100011010000111100111001000110010011,0000000000111111111111111100000000 0000001111111111111111,00000000000000000000000000111111111111111111111111111111} ; DUAL_ORBIT_PLUS([pp], [82_7_40x.a], ![$6,$7]!, ![0000110,1000001,1000011, 1000110,1000111,1001000,1111110,1111111]!, ![+ column 54 + column 54]!) DUAL_ORBIT_PLUS([qq], [82_7_40x.a], ![$6,$7]!, ![0000110,0111110,0111111, 1000001,1000011,1000110,1000111,1001000,1111111]!, ![+ column 55]!) DUAL_ORBIT([rr], [75_7_36x.b], ![$6]!, ![0001110,0100000,0100001,0100100, 0100101,0100111,0101000,0101111,0110100,0110101,0110110]!) DUAL_ORBIT([ss], [56_7_26.b], ![$4]!, ![0000110,0000111,0001001,0001010,0001111,0011001,0011011]!) DUAL_ORBIT_PLUS([tt], [105_8_50x.b], ![$1,$4]!, ![00000110,00010011,00011100,00011101,01111010]!, ![- column 26 - column 26]!) DUAL_ORBIT_PLUS([uu], [105_8_50x.b], ![$1,$4]!, ![00000001,00000110,00010011,00011101,00100111,01110010,01111010]!, ![- column 26 - column 26]!) DUAL_ORBIT_PLUS([vv], [105_8_50x.b], ![$1,$4]!, ![00000001,00000110,00010011,00011101,00100111,01011010,01110010]!, ![- column 19 - column 19]!) DUAL_ORBIT_PLUS([ww], [105_8_50x.b], ![$1,$4]!, ![00000001,00000110,00010001,00100111,00111000,01110010,01111010]!, ![- column 26 - column 26]!) DUAL_ORBIT_PLUS([xx], [105_8_50x.b], ![$1,$4]!, ![00000001,00000011,00000101,00000111,00001011,00001100,00100111,01110010, 01111010]!, ![- column 25 - column 25]!) disjoint [a], [b], [c], [d], [e], [f], [g], [h], [i], [j], [k], [l], [m], [n], [o], [p], [q], [r], [t], [u], [v], [w], [x], [y], [z], [aa], [bb], [cc], [dd], [ee], [ff], [gg], [hh], [ii], [jj], [kk], [ll], [mm], [nn], [oo], [pp], [qq], [rr], [ss], [tt], [uu], [vv], [ww], [xx]; DHIDE( ![ (* DE1.7#, O(26).7# for [a], [b] *); ]! ) type [59,7,28]; DUAL_TRANSFORM([a], [48_8_22.a-1], ![22_{3},24_{3},30_{-3},32_{-3}]!) DUAL_TRANSFORM_PLUS([b], [75_7_36x.a-2], ![35_{10},36_{10},37_{-10},38_{10},39_{-10},40_{-10},41_{-10}]!, ![+ column 42]!) DUAL_ORBIT([c], [24_7_10.a], ![$2,$3]!, ![0000111,0001010,0001100,0010010, 0010011,0011101,0101110,0101111,1111110,1111111]!) DUAL_ORBIT([d], [24_7_10.b], ![$2,$4,$5]!, ![0000111,0001101,0001110,0011000, 0100111,0101101,0101111,0110010,1100111,1111111]!) DUAL_ORBIT_PLUS([e], [40_7_18.a], ![$3,$4]!, ![0000101,0001000,0010000,0010100, 0011010,0011110,0100100,0111101,1011111,1111100]!, ![+ column 41 + column 41]!) DUAL_ORBIT_PLUS([f], [40_7_18.a], ![$3,$4]!, ![0000100,0001000,0001010,0001101, 0011001,0011010,0100011,0100100,0111101,1111100]!, ![+ column 12 + column 12]!) [g] := {10000001001011100011011010110100100101100110101110100011010, 01000010011011001011100011001101000110000101110110011011001, 00100000110011101111000001111010011100100000111011000110011, 00010011100010100110000111100011100000110011100011110001111, 00001001010101100010111010101011011010010110110001010011010, 00000111111111100000000000000000011111111111111111111111111, 00000000000000011111111111111111111111111111111111111111111}; disjoint [a], [b], [c], [d], [e], [f], [g]; DHIDE( ![ (* DE1.7# for [a] *); ]! ) (* Note that P of this is a [192,8,96] code. *); type [64,7,32]; DUAL_TRANSFORM([a], [20_8_8.a-1], ![8_{4},12_{4},16_{4}]!) ??status: unique; (* justify! *); DHIDE( ![ (* DE1.7#, O(26).7# for [a] *); ]! ) (* Note that P of these yields [199,8,98] codes. *); [71_7_34] type [71,7,34]; [a] := P( Even(7) ); DHIDE( ![ (* DE1.7# for [a], [b], [c], O(26).7# for [a] -- [d] *); ]! ) [75_7_36] type [75,7,36]; [a] := P( [11_6_4.a] ); [b] := P( [11_6_4.b] ); DUAL_TRANSFORM_PLUS([c], [75_7_36x.a-2], ![35,36_{10},37_{-10},38_{10},39_{-10},40]!, ![- column 1 - column 26]!) DUAL_TRANSFORM_PLUS([d], [40_7_18.a-5], ![17_{8},18_{8},19,20_{8},21_{8},22,24_{-8}]!, ![- column 23]!) DUAL_ORBIT([e], [24_7_10.a], ![$3,$4,$5]!, ![0001000,0001011,0001100,0001110, 0001111,0010011,0011010,0011110,0101100,0101110,1001011,1011110]!) DUAL_ORBIT([f], [24_7_10.f], ![$1,$3]!, ![0000001,0000111,0001001,0001010, 0001110,0001111,0010011,0010101,0101100,1011101,1011111]!) DUAL_ORBIT([g], [24_7_10.f], ![$1,$3]!, ![0000001,0000101,0001001,0001100, 0001111,0010011,0010101,0101100,0101101,1001001,1011101]!) DUAL_ORBIT([h], [24_7_10.f], ![$1,$3]!, ![0000001,0000111,0001001,0001010, 0001110,0001111,0010011,0010101,0101101,1001001,1011101]!) DUAL_ORBIT_PLUS([i], [40_7_18.a], ![$3,$4]!, ![0000100,0000101,0001000,0001101,0010100,0011000,0011001,0011010,0011110, 0100011,0100100,0111101,1011111,1111100]!, ![+ column 54]!) DUAL_ORBIT([j], [40_7_18.a], ![$3,$4]!, ![0000100,0000101,0001000,0001010,0001101,0010001,0011000,0011010,0100011, 0100100,0111101,1011111,1111100]!) DUAL_ORBIT([k], [75_7_36x.b], ![$6]!, ![0000011,0000100,0000110,0001110,0010100, 0010101,0010110,0100000,0100110,0101100,0101111,0110100,0110101,0110110]!) DUAL_ORBIT([l], [75_7_36.c], ![$3,$4]!, ![0001011,0001101,0010010,0010111, 0100011,1000000,1000001,1000010,1000100,1000110,1000111,1010000,1011010, 1100011,1100110]!) DUAL_ORBIT([m], [75_7_36.c], ![$3,$4]!, ![0001011,0001101,0010000,0010010, 0010111,1000000,1000001,1000010,1000100,1000110,1000111,1010000,1011010, 1100011,1100110]!) DUAL_ORBIT([n], [75_7_36.c], ![$3,$4]!, ![0001001,0001011,0001100,0001101, 0010000,0010010,0010111,0100011,1000000,1000010,1000100,1000110,1010100, 1011010,1100011,1100110]!) DUAL_ORBIT([o], [75_7_36.c], ![$3,$4]!, ![0001001,0001010,0001011,0001100, 0001101,0010000,0010010,0010111,1000010,1000100,1000110,1000111,1010000, 1010010,1011010]!) DUAL_ORBIT([p], [75_7_36.c], ![$3,$4]!, ![0000100,0001010,0001011,0001100, 0001101,0010010,0010111,0100011,1000000,1000010,1000100,1000111,1010000, 1010010,1010100]!) [q] := {100000010010111010101001011010010110100101110010011101001011010010110100101, 010000100110110011011001100110000110011001101001101100110010110011001100110, 001000001100111001101111001100001100111100100100110001100111100110000110011, 000100111000101000011100001111100011110000111000111000011110000111100001111, 000010010101011010101010100101110110101010001101100101001010101101010100101, 000001111111111000000000000000000000000000000111111111111111111111111111111, 000000000000000111111111111111111111111111111111111111111111111111111111111}; [r] := {100000011010010011101100000111000110111100001110001110001110000111100001111,010 001101100111110010010011011110101001111001000110011101100011001111001100,0010011 01010110001110000011011001011001100110110110010010010011001100110011,00010010011 0101010110100110110010010100110011010011011011000110011001100110,000011011000101 010101010110110010011011001100100011011011001001100110011001,0000000000011111111 11110000000000000000000000001111111111111111111111111111,00000000000000000000000 1111111111111111111111111111111111111111111111111111}; [s] := {100000011001100100111110001100100110000111100011100110110000111000011100111,010 001101100001111110000110010001011100110001100110101011100100001101110100,0010011 01011101100001110110001101010011001101100101011010011011001101101011,00010010010 1101010100111100101001100110011000110101100011001101011011010010,000011011010001 010100110011010101100110011011001010010011001101100100101101,0000000000000111111 11111111111100000000000000000000001111111111111111111111,00000000000000000000000 0000000011111111111111111111111111111111111111111111}; [t] := {100011000111000100110011100001111000110010111100011100010011001110001101100,010 000100100110110101010011001100110101001110010011011001010101001100011011,0010101 01101011100011010101101010100011011101010101101011110010010111001001,00010100110 1010010011101010101010101100011010100101101100110001101011000110,000000011111111 110000000000111111111111000000001111111111000000000011111111,0000000000000000011 11111111111111111111000000000000000000111111111111111111,00000000000000000000000 0000000000000000111111111111111111111111111111111111}; [u] := {100010011100110011000110000111100011100010110011000110000111001100110111100,010 010100110100011011100110011001001001010001011101101010010101001101011001,0010101 10100011001101101010101011011010011100001011000110100001011100101010,00011000000 1111000001111100000001111111000111000001111100000011110000111111,000001111111111 000000000011111111111111000000111111111100000000001111111111,0000000000000001111 11111111111111111111000000000000000011111111111111111111,00000000000000000000000 0000000000000000111111111111111111111111111111111111}; DUAL_ORBIT_PLUS([v], [82_7_40x.a], ![$6,$7]!, ![0000010,0000110,0001001, 0010111,0111111,1000000,1000001,1000011,1000110,1000111,1010110,1111110, 1111111]!, ![+ column 74]!) DUAL_ORBIT([w], [105_8_50x.b], ![$1,$4]!, ![00000001,00000110,00001000,00010011, 00011100,00011101,00100111,01111010]!) DUAL_ORBIT([x], [105_8_50x.b], ![$1,$4]!, ![00000001,00000110,00001000,00010011, 00011100,00011101,00100110,01111010]!) disjoint [a], [b], [c], [d], [e], [f], [g], [h], [i], [j], [k], [l], [m], [n], [o], [p], [q], [r], [s], [t], [u], [v], [w], [x]; DHIDE( ![ (* DE1.7# for [a] -- [g], O(26).7# done for [a] -- [h] *); ]! ) (* Note that P of these yields [207,8,102] codes. *); [79_7_38] type [79,7,38]; [a] := P( [15_6_6.a] ); [b] := P( [15_6_6.b] ); [c] := P( [15_6_6.c] ); [d] := P( [15_6_6.d] ); [e] := P( [15_6_6.e] ); DUAL_TRANSFORM_PLUS([f], [71_7_34.a-1], ![33,34_{33},35_{-33},36_{33},38]!, ![+ column 23]!) [g] := {1001011001100100101011010011001100110100101100110011001011001101001010100 111011,010101010101001010101010101000101010101010101110101010101010101010 1001010101010,00110011001010011000011001101001100110011001101001100110011 00110011011001101001,0000111100000111111000000001111110000111100000011110 000111100001111100000011111,000000001111111111100000000000000111111110000 0000001111111100000000011111111111,00000000000000000001111111111111111111 11100000000000000000011111111111111111111,0000000000000000000000000000000 000000000011111111111111111111111111111111111111}; DUAL_TRANSFORM([h], [87_7_42x.d-1], ![41_{-85},42_{85},43,44_{85},45_{-85},46_{85},48_{-85},49_{85},50_{-85}]!) disjoint [a], [b], [c], [d], [e], [f], [g], [h]; DHIDE( ![ (* DE1.7# for [a], [b] *); ]! ) (* Note that P of these yields [210,8,104] codes. *); [82_7_40] type [82,7,40]; (* weights are known to be in {40,44,48,56,64} *); [a] := P( [18_6_8.a] ); [b] := P( [18_6_8.b] ); DUAL_ORBIT_PLUS([c], [42_8_18y.d], ![$1,$2,$3]!, ![00000010,00000011,00000101,00001001,00001010,00001011,00001110,00110110, 00111111,01001101]!, ![+ column 32 + column 58 + column 66]!) DUAL_ORBIT_PLUS([d], [147_8_72y.b-6], ![$1,$2,$3]!, ![00001110,00010000,00010100,00011000,00011010,00110000,00111010,01001110, 01011010,10111011]!, ![+ column 24 + column 47 + column 58]!) disjoint [a], [b], [c], [d]; DHIDE( ![ (* DE1.7# for [d1], [d6], [d9], [c3], [c6], [d2], [d12], [d10], [d21], [d17] *); ]! ) [87_7_42] type [87,7,42]; [c1] := P( [23_6_10.c1] ); [c2] := P( [23_6_10.c2] ); [c3] := P( [23_6_10.c3] ); [c4] := P( [23_6_10.c4] ); [c5] := P( [23_6_10.c5] ); [c6] := P( [23_6_10.c6] ); [c7] := P( [23_6_10.c7] ); [c8] := P( [23_6_10.c8] ); [d1] := P( [23_6_10.d1] ); [d2] := P( [23_6_10.d2] ); [d3] := P( [23_6_10.d3] ); [d4] := P( [23_6_10.d4] ); [d5] := P( [23_6_10.d5] ); [d6] := P( [23_6_10.d6] ); [d7] := P( [23_6_10.d7] ); [d8] := P( [23_6_10.d8] ); [d9] := P( [23_6_10.d9] ); [d10] := P( [23_6_10.d10] ); [d11] := P( [23_6_10.d11] ); [d12] := P( [23_6_10.d12] ); [d13] := P( [23_6_10.d13] ); [d14] := P( [23_6_10.d14] ); [d15] := P( [23_6_10.d15] ); [d16] := P( [23_6_10.d16] ); [d17] := P( [23_6_10.d17] ); [d18] := P( [23_6_10.d18] ); [d19] := P( [23_6_10.d19] ); [d20] := P( [23_6_10.d20] ); [d21] := P( [23_6_10.d21] ); DUAL_TRANSFORM([e], [79_7_38.b-1], ![37,38_{38},39_{-38},40_{38},41_{-38},42,63_{38}]!) DUAL_TRANSFORM([f], [117_7_58x.a-1], ![57,58_{32},59,60_{32},63,64_{32}]!) DUAL_TRANSFORM([g], [117_7_58x.a-1], ![57,58,62_{32}]!) DUAL_TRANSFORM_PLUS([q], [87_7_42x.d-1], ![41,42_{85},43_{-85},44_{85},45_{-85},46_{85},47_{85},48]!, ![- column 14]!) DUAL_TRANSFORM_PLUS([r], [87_7_42.e-2], ![41,42_{39},43,44_{39},45,46_{39}]!, ![- column 84]!) [s] := {1001010110010010011010110100100111011001001010110010011101010010111001001011101 00101101,01000010110101101100100101101100101100100101100110110010110001011011001 0010100101101001,001100011100111000111000111000111000111000111000100011100010001 110001110001100011100111,0000111111000001111110000001111110000001111110000111111 00001111110000001111100000011111,00000000001111111111100000000000011111111111100 0000000011111111110000000000011111111111,000000000000000000000111111111111111111 111111000000000000000000001111111111111111111111,0000000000000000000000000000000 00000000000000111111111111111111111111111111111111111111}; DUAL_TRANSFORM_PLUS([t], [56_7_26.f-3], ![25,26_{7},27,28_{7},29_{7},30_{7},31,33]!, ![- column 60]!) DUAL_TRANSFORM([u], [56_7_26.f-8], ![25,26_{26},27_{-26},28_{26},29_{26},31,32_{26},33_{-26},34_{26}, 37_{26},45_{26}]!) DUAL_TRANSFORM_PLUS([v], [56_7_26.g-6], ![25,26_{33},27,28_{33},29_{33},31_{-33},32_{33},33_{-33},45_{33}]!, ![+ column 80]!) DUAL_TRANSFORM_PLUS([w], [56_7_26.g-17], ![25,26_{26},27,28_{26},29_{26},30_{26},31,45_{26}]!, ![+ column 80]!) DUAL_ORBIT_PLUS([x], [105_8_50x.b-64], ![$1,$2,$3]!, ![00000111,00001001,00010010,00010011,00011101,00100110,00111010, 00111011,01110010]!, ![- column 10 - column 11 + column 17]!) DUAL_ORBIT_PLUS([y], [105_8_50x.b-64], ![$1,$2,$3]!, ![00000111,00001001,00010010,00010011,00011101,00100110,00111010,00111011, 01110010]!, ![- column 12 - column 30 + column 39]!) disjoint [c1], [c2], [c3], [c4], [c5], [c6], [c7], [c8], [d1], [d2], [d3], [d4], [d5], [d6], [d7], [d8], [d9], [d10], [d11], [d12], [d13], [d14], [d15], [d16], [d17], [d18], [d19], [d20], [d21], [e], [f], [g], [q], [r], [s], [t], [u], [v], [w], [x], [y]; DHIDE( ![ (* DE1.7# for [a], [b], [c], [d] *); ]! ) (* Also get from [26_6_12.{a,b}] by P. *); type [90,7,44]; DUAL_TRANSFORM([a], [21_8_8.g-1], ![8_{3},12,16_{3}]!) DUAL_TRANSFORM_PLUS([b], [21_8_8.g-1], ![8_{7},12,16_{-7}]!, ![+ column 88]!) DUAL_TRANSFORM_PLUS([c], [71_7_34.a-1], ![33,34_{33},35,36_{33},37_{33}]!, ![- column 38]!) DUAL_TRANSFORM_PLUS([d], [79_7_38.d-1], ![37,38_{41},39,40_{41},43_{-41},44_{41}]!, ![+ column 33]!) DUAL_TRANSFORM_PLUS([e], [24_7_10.b-1], ![9,10_{10},11,12_{10},13,14_{10},17_{10}]!, ![- column 39]!) disjoint [a], [b], [c], [d], [e]; DHIDE( ![ (* DE1.7# for [a] *); ]! ) [93_7_46] type [93,7,46]; (* WE is known to be unique -- see CODE *); [a] := Simp(5) # Simp(2); DHIDE( ![ (* DE1.7# for [a] *); ]! ) (* I think there is a unique [32,6,16], and this code should come from it by construction P. *); (* Note that P of this yields a [224,8,112] code. *); type [96,7,48]; DUAL_TRANSFORM([a], [48_8_22.a], ![22_{-24},30_{-24}]!) ??status: unique; (* justify! *); DHIDE( ![ (* DE1.7# for [a], [b] *); ]! ) (* Note that P of these yields [230,8,114] codes. *); [102_7_50] type [102,7,50]; [a] := P( [38_6_18.x] ); DUAL_TRANSFORM([b], [117_7_58x.a-1], ![57,58,59_{32},60_{32},62_{32},63_{32}]!) DUAL_ORBIT([c], [24_7_10.f], ![$1,$3]!, ![0000001,0000100,0000101,0000111, 0001001,0001010,0001101,0001110,0001111,0010011,0101101,1001000,1011101, 1011111]!) disjoint [a], [b], [c]; DHIDE( ![ (* DE1.7# for [a] *); ]! ) [105_7_52] type [105,7,52]; (* WE known to be unique *); [a] := Simp(3) # Simp(4); DHIDE( ![ (* DE1.7# for [a] *); ]! ) (* Note that P of these yields [237,8,118] codes. *); [109_7_54] type [109,7,54]; [a] := P( [45_6_22.a] ); DHIDE( ![ (* DE1.7# for [a] *); ]! ) (* Note that P of this yields a [240,8,120] code. *); (* P of the presumably unique [48,6,24] must be this *); type [112,7,56]; DUAL_TRANSFORM([a], [48_8_22.a-1], ![22,24_{3},30]!) ??status: unique; (* justify! *); DHIDE( ![ (* DE1.7# for [a], [b] *); ]! ) [117_7_58] type [117,7,58]; (* The weights are known to be in {58,60,62,64}. One can then show y64 != 0, so the following is a complete list: *); [a] := P( [53_6_26.a] ); [b] := P( [53_6_26.b] ); disjoint [a], [b]; ??status: classified, realizable; DHIDE( ![ (* DE1.7# for [a] *); ]! ) type [120,7,60]; (* P of the presumably unique [56,6,28] is presumably this *); DUAL_TRANSFORM([a], [45_8_20.a], ![20_{-3},22_{-3},28_{-3},30_{-3}]!) ??status: unique; (* justify! *); DHIDE( ![ (* DE1.7# for [a] *); ]! ) (* P of the presumably unique [60,6,30] is presumably this *); type [124,7,62]; DUAL_TRANSFORM_PLUS([a], [21_8_8.g-1], ![7_{-7},8_{-7},11_{-7},12_{-7},16_{-7}]!, ![- column 42]!) ??status: unique; (* justify! *); (* ********************* DIMENSION EIGHT AND HIGHER ********************* *); type [96,8,46]; [a] := 12-cyclic {0000110101011110010101110101111100011111010110110100111011111 10011101101111111101011001111100110}; DHIDE( ![ OE(28).7#(length <= 255) ]! ) type [99,8,48_8]; DUAL_ORBIT([a], [21_9_8.a], ![$1,$3,$5,$6]!, ![000000001,000000110,011000110,011001010,011001100,011011110]!) (* [a] := (8,2,8,8,8,8,8,8,8,8,8,8,8)-cyclic {000001010101000111010100110101010 000010110010101110101001000000111011000110111011001110011010111101} *); DHIDE( ![ (* DE1# done for [a] *); (* O(32)#, OE(28).7#(allowing length up to 495) done for [a], [b] *); ]! ) [238_9_116] type [238,9,116_2]; (* Gulliver *); DUAL_TRANSFORM([a], [35_9_14.a], ![14_{35},16_{35},20_{35},22_{35}]!) (* [a] := 14-cyclic {000000001001110010000001111010111100001000011011011000010 1100100110100001110111110111000100010111111010001001000110101100010100101 0001110001100110001111100100101110011101001010111010100110010110100111111 10011011101100111101010101101111011} *); DUAL_ORBIT([b], [35_9_14.a], ![$1,$2]!, ![000001010,000010000,000010110, 000011101,000100010,000101101,000110111,001001011,001011010]!) (* [b] := 14-cyclic {000001100110000010101011010100010001011100000000111010011 1011110111001110110100001011011111000010010000110010001110001000101110011 1010000011010010110011101111110101101101000101111101000110101010111100111 10111111101100001101110100111111001} *); disjoint [a], [b]; status: realizable; DHIDE( ![ (* OE(28).7#(allowing length up to 495) *); D2.7#(allowing length up to 495) ]! ) [80_9_36] type [80,9,36]; DUAL_ORBIT([a], [238_9_116.a-1], ![$1,$2]!, ![000010011,000011001,000101001,001000001,001000100]!) DUAL_ORBIT([b], [238_9_116.a-1], ![$1,$2]!, ![000001110,000010010,000101001,001010011,001101010]!) disjoint [a], [b]; DHIDE( ![ (* DC1P#, DC2#, DC1.7#, OE(28.7)#(length <= 255) ]! ) [115_8_56] type [115,8,56_8]; DUAL_TRANSFORM([a], [48_8_22.a], ![22_{2},24_{2},30_{-2},32_{-1,-2}]!) (* [a] := (8,8,2,8,8,8,8,8,8,8,8,8,8,8,8)-cyclic {0010111001111110010001000000 1111100100110001010010000011100111101001010100011001000110100001110110010 11110010101111} *); status: realizable; (* The following are extra -- to avoid reentering a code type. *); [42_8_18x] type [42,8,18_2]; DUAL_TRANSFORM([a], [45_8_20.a-45], ![27,28_{10}]!) [168_8_82x] type [168,8,82_2]; [b] := [20_8_8.a]^T using {$1,$4,$5 : 00001100,00100000,00100011,00100101, 00100111,00101000,01100011,01100100,01111101,11100000,11100011,11100100, 11110111}; [58_8_26x] type [58,8,26_2]; DUAL_TRANSFORM_PLUS([a], [42_8_18x.a-42], ![22_{-1,2},23_{-1,2},24_{1,2},25,26,27_{1,-2},27_{2},28_{1,-2},28_{2}]!, ![- column 38]!) DHIDE( ![ (* DC1# done for both [a] and [b], D2# done for [a], [b], [c] *); O(26)# done for [c], [d], [e], [f] OE(26).7#(allowing length up to 511) done for [g] ]! ) [140_8_68] type [140,8,68_2]; [a] := P( [12_7_4.b] ); DUAL_TRANSFORM([b], [178_8_88.a], ![88_{172},96_{1,-172},96_{-1,172}]!) [c] := P( [12_7_4.a] ); [d] := [21_8_8.g]^T using {$1,$2,$3 : 00001001,00010001,00011101,00100000, 00100011,00110000,00110100,01101000,01101010,01111000,01111110,10110101}; (* [d] := (15,15,15,15,15,15,15,15,15,5)-cyclic {00111110010111101011111011010 101111111100001100101100000001001110101000110101001000011111101110011011011101 010110110011001001111000111001111} *); [e] := [178_8_88.a]^T using {$5,$6,$7 : 00001010,00001011,00100001,00100011, 00110011,01100000,01100001,01100010,01100011,11101000}; (* [e] := (14,14,14,14,7,7,14,14,7,14,14,7)-cyclic {0111101100001000101101101001011100 01000111000000111111100000001001001110100010101110100001101111000010110100011001 11001010100110101101111001} *); [f] := [178_8_88.a]^T using {$5,$6,$7 : 00000111,00001010,00001011,00100011, 00110011,01100000,01100001,01100010,01100011,11101001,11101010}; DUAL_TRANSFORM_PLUS([g], [168_8_82x.b-168], ![81_{54},82_{54},83_{54},84_{54},85,86_{54},87_{-54},88_{54},91,92]!, ![+ column 48 + column 57]!) disjoint [a], [b], [c], [d], [e], [f], [g]; status: realizable; (* The following code is new *); DHIDE( ![ (* D2#, O(30)# done for [a] *); OE(28).7#(length <= 255) done for [a], [b] ]! ) [105_8_50] type [105,8,50_2]; DUAL_ORBIT([a], [48_8_22.a], ![$5]!, ![00000101,00000111,00001000,00001110,00010100,00111000,00111001]!) DUAL_ORBIT_PLUS([b], [21_9_8.a], ![$2,$3,$4]!, ![000000110,000010001,001111101,010001011,010101111]!, ![- column 3 - column 40]!) DUAL_ORBIT_PLUS([c], [140_8_68.d], ![$1,$2,$3,$4]!, ![00000010, 00000011,00000100,00000101,00001011,00010101,01101001]!, ![+ column 1]!) disjoint [a], [b], [c]; status: realizable; DHIDE( ![ (* D2# done for [a], [b] *); (* O(26).7#(length <= 255) done for [a], [b], [c], [d] *); ]! ) [42_8_18] type [42,8,18_2]; DUAL_TRANSFORM([a], [45_8_20.a-45], ![27,28_{10}]!) (* [a] := (12,12,6,12)-cyclic {001010100000001110110001011110000001101011} *); DUAL_TRANSFORM_PLUS([b], [58_8_26x.a], ![32_{2},34_{-2},34_{1,2},36,38_{1,-2},38_{-1,2}]!, ![- column 38]!) (* [b] := (8,8,8,8,8,2)-cyclic {001111100111010100110100011101000000001101} *); DUAL_ORBIT([c], [42_8_18.a], ![$1,$3]!, ![00010011,00011111,00101111,01001000]!) (* [c] := (12,12,12,6)-cyclic {011000110010010011101100000110101100110000} *); DUAL_ORBIT([d], [140_8_68.d], ![$2,$5]!, ![00000111,00001100,00101010,01101011]!) disjoint [a], [b], [c], [d]; status: realizable; DHIDE( ![ (* DC1#, D2# done for [a] *); (* O(26)# done for *); ]! ) type [112,8,54_2]; [a] := 14-cyclic {000010110001010101000000010010100001111101001111000110100101 1011011101100010001101100010101110100100110101101111}; DUAL_TRANSFORM_PLUS([b], [42_8_18.a], ![18_{5},20_{5},22_{5},24_{1,5},26_{-5},28_{1,-5}]!, ![- column 30]!) disjoint [a], [b]; status: realizable; DHIDE( ![ (* D2S(5 orbits only), DC1#, OE(26), O(29/5,10)#, D3(28).7#(only 4 orbits checked) done for *); ]! ) [222_9_108] type [222,9,108_2]; (* Gulliver *); DUAL_TRANSFORM_CH([a], [18_9_6x.a-18], ![5,7,9,12]!) status: realizable; (* The existence of a code with the following parameters is new: *); DHIDE( ![ (* D2S, DC1#, OE(26)# done for *); ]! ) [245_9_120] type [245,9,120_2]; DUAL_TRANSFORM([a], [21_9_8.a-21], ![7,11,16]!) (* [a] := (15,15,5,15,15,15,15,15,15,15,15,15,15,15,5,15,15,5,5)-cyclic {0000100111100000011110110100000000100010010011000100111011001010000010101010010 00011101010001010011000010110000010101100110010001111101110010011011000111000001 10011111101001011011011101001101111001101001110001011110101110011010101111100110 101111} *); status: realizable; DHIDE( ![ (* DC1#, O(32)#, OE(26)# done for *); ]! ) [186_10_88] type [186,10,88_8]; DUAL_TRANSFORM([a], [32_11_12.a], ![20_{-1}]!) status: realizable; (* The following code is new. *); DHIDE( ![ (* D2#, OE(26)#, D3(28).7#(only 4 orbits checked) done for *); ]! ) [242_9_118] type [242,9,118_2]; DUAL_TRANSFORM_PLUS([a], [186_10_88.a-186], ![87_{3},95_{3}]!, ![- column 237 + column 113]!) (* [a] := (15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15)-cyclic {001001000101010010101011000011001110010111101011001001100000 000010000011110011110011110111010011011100001001000010011111 010100001110110001111111000110011000100011011001110101110011 01001011001101000001011101000000010110100011110101001010111111} *); status: realizable; DHIDE( ![ (* D2#, DC1#, O(28).7#(length <= 255) done for [a] *); (* OE(28).7#(allowing length up to 255) for [b], [c], [d] *); ]! ) [147_8_72] type [147,8,72_4]; DUAL_TRANSFORM([a], [178_8_88.a], ![88_{2},96,128_{1,2}]!) DUAL_ORBIT([b], [21_8_8.g], ![$1, $2, $3]!, ![00000101,00001001,00001101,00010001,00011101,00100011,00110100,01101000, 01101010]!) DUAL_ORBIT([c], [242_9_118.a], ![$4,$5]!, ![000001010,000001011,000010000,000010110,000011010,000011011,000100000]!) DUAL_ORBIT([d], [147_8_72.c], ![$6]!, ![00000111,00001001,00001101,00010000,00010001,00010100,00010101,00011000, 00101010,00101011,00110011,01101000,01101001]!) disjoint [a], [b], [c], [d]; status: realizable; DHIDE( ![ (* DC1#, D2# done for [a] *); (* OE(28).7#(allowing length up to 255) done for [a] *); (* O(28).7#(allowing length up to 255) done for [b] *); ]! ) (* The existence of a code with the following parameters is due to Bierbrauer and Edel. *); [175_8_86] type [175,8,86]; DUAL_TRANSFORM_CH([a], [147_8_72.a], ![72_{12},76]!) DUAL_ORBIT_PLUS([b], [105_8_50.a], ![$2,$3]!, ![00000001, 00000011,00000111,00001011,00001101,00010010,00010011,01101000,11111111]!, ![+ column 174]!) DUAL_ORBIT_PLUS([c], [147_8_72.a], ![$2,$4,$5]!, ![00000011,00000111,00001010,00001110,00010100,00010110,00011001,00011010, 00011011,00110101,00110111,01000111,11111000,11111010]!, ![+ column 167]!) disjoint [a], [b], [c]; status: realizable; DHIDE( ![ (* D1#, OE(28).7#(allowing length up to 495) *); ]! ) type [250,10,120_8]; DUAL_TRANSFORM([a], [32_11_12.a-32], ![19_{1,-2},19_{-1,2},20_{-1,-2},20_{1,2}]!) status: realizable; DHIDE( ![ (* D2P#, DC1#, O(26)# done for *); ]! ) [155_8_76] type [155,8,76_4]; DUAL_TRANSFORM_CH([a], [48_8_22.a], ![22_{2,-3},22_{-2,3}, 24_{2,-3},24_{-2,3},30,32_{1,2,3}]!) status: realizable; DHIDE( ![ (* D2P#, DC1#, O(26)# done for *); ]! ) [172_8_84] type [172,8,84_4]; DUAL_TRANSFORM_PLUS([a], [155_8_76.a], ![76_{3,-11},76_{11},80_{3,-11},80_{-3,11},84_{-11},84_{-3,11}]!, ![+ column 77 + check]!) DUAL_TRANSFORM([b], [178_8_88.a], ![88_{1,-172},88_{172},96_{-1,172}]!) disjoint [a], [b]; status: realizable; (* It would be desirable to eliminate this because there is a [108,8,52] *); DHIDE( ![ (* O(26)# done for [a], [b], [e] *); (* DC1# done for [a] -- [e] *); ]! ) [109_8_52] type [109,8,52]; DUAL_ORBIT([a], [105_8_50.a], ![$1,$3]!, ![00001101,00010010,00010011,00011010,00011011,00011110,00100001,00101111, 10010111]!) DUAL_ORBIT([b], [105_8_50.a], ![$1,$3]!, ![00001101,00010010,00010011,00011010,00011011,00011110,00100001,00101111, 01101000]!) DUAL_ORBIT_PLUS([c], [147_8_72.a], ![$5,$6]!, ![00001100,00001110,00011001,00011011,00111010,11111010]!, ![+ column 102 + column 102]!) DUAL_ORBIT_PLUS([d], [147_8_72.a], ![$5,$6]!, ![00001100,00001110,00011001,00011011,00111010,11111000,11111010]!, ![+ column 103]!) DUAL_ORBIT([e], [140_8_68.d], ![$2,$3,$4]!, ![00000011,00000100,00000101,00001010,00001011,00011011,00011110,01011011, 01101001,01110001]!) disjoint [a], [b], [c], [d], [e]; status: realizable; DHIDE( ![ (* DC1# done for [a] -- [e] *); ]! ) [168_8_82] type [168,8,82_2]; DUAL_ORBIT([a], [105_8_50.a], ![$2,$3]!, ![00000001,00000011,00000111,00001101,00010010,00010011,01101000, 11111111]!) DUAL_ORBIT([b], [20_8_8.a], ![$1,$4,$5]!, ![00001100,00100000,00100011,00100101,00100111,00101000,01100011,01100100, 01111101,11100000,11100011,11100100,11110111]!) DUAL_ORBIT_PLUS([c], [172_8_84.b], ![$2,$5,$7]!, ![00000010,00000011,00000110,00000111,00010000,00010001,00110101,00110110, 00110111,00111011,01001110,01001111,11111110,11111111]!, ![+ column 166]!) DUAL_ORBIT([d], [140_8_68.e], ![$4,$6]!, ![00000111,00001000,00001001,01000000,01000001,01000010,01001000,01001001, 01001100,01011001,10100001]!) DUAL_ORBIT([e], [109_8_52.c], ![$5,$6,$7]!, ![00000010,00000011,00000111,00110101,00110111,01000000,01000001,01000010, 01000011,01000100,01000101,11000011,11001111,11010111]!) DUAL_TRANSFORM([f], [168_8_82.b-168], ![81_{50},82_{50},83,84_{50},85,86_{50},87_{50},88,89,90_{50},91_{-50}, 92_{50},127_{50}]!) DUAL_ORBIT([g], [109_8_52.e], ![$2,$4,$5]!, ![00000001,00000011,00010011,00100000,00100001,00100010,00100011,00100101, 00100111,00101001,00101110,00110011,00111010]!) disjoint [a], [b], [c], [d], [e], [f], [g]; status: realizable; DHIDE( ![ (* D2P#, DC1# done for *); ]! ) [136_8_66] type [136,8,66_2]; (* unique -- Tilborg type III *); DUAL_TRANSFORM_CH([a], [155_8_76.a], ![76_{3,-29},76_{-3,29},80_{3,-29}, 80_{-3,29},84_{3,29},128_{3,29}]!) (* Simpler description: P( Even(8) ) *); status: realizable; (* I would like to REMOVE the following code, as it is superceded by the [92,8,44]. *); DHIDE( ![ (* D2P#, DC2S(unfinished!), DC1# done for *); ]! ) [93_8_44] type [93,8,44_4]; DUAL_TRANSFORM_CH([a], [136_8_66.a], ![68_{1,28},70,72_{-1,28}]!) status: realizable; DHIDE( ![ (* D6 (only 1 orbit) for [a], DC5 (only one orbit) for [a], DC2 done for [a] *); (* DC1# done for [a], [b], [c] *); (* D3#, DC2# done for [b] *); (* D2# done for [c] *); (* O(26)# done for [b], [c] *); ]! ) [68_8_32] type [68,8,32_2]; DUAL_TRANSFORM_PLUS([a], [93_8_44.a], ![48_{1},64_{-2},64_{1,2}]!, ![+ column 1 + column 1 + column 1]!) DUAL_TRANSFORM([b], [35_9_14.a], ![16_{-35}]!) DUAL_TRANSFORM([c], [68_8_32.b], ![32_{2,14,27},40_{-27},40_{-14,27},40_{-2,14,27}]!) disjoint [a], [b], [c]; status: realizable; DHIDE( ![ (* D2#, O(26)# done for *); ]! ) [65_8_30] type [65,8,30_2]; DUAL_TRANSFORM_PLUS([a], [68_8_32.b-68], ![39,40_{-1,-2,-3},40_{2,-3},40_{3}]!, ![- column 5]!) status: realizable; DHIDE( ![ (* D2#, DC1# done for [a], [b], [c] *); (* O(26)# done for [b] -- [g] *); ]! ) [144_8_70] type [144,8,70_2]; DUAL_TRANSFORM_CH([a], [178_8_88.a], ![88_{172},96_{1,-172},96_{172}]!) DUAL_TRANSFORM([b], [48_8_22.a], ![22_{2},24_{2},30]!) DUAL_TRANSFORM([c], [175_8_86.a], ![86_{1},88_{1},94,126_{1}]!) DUAL_ORBIT([d], [242_9_118.a], ![$4,$5]!, ![000001011,000010000,000010110,000011010,000011011,000100000]!) DUAL_ORBIT([e], [65_8_30.a], ![$3]!, ![00000011,00000100,00001101,00100000,00100010,00100100,00100101,00100110, 00101001,00101011,00110101,00110111,00111001,01110111]!) DUAL_ORBIT([f], [147_8_72.b], ![$1,$2,$4]!, ![00000111,00001101,00010001,00011001,00100001,00101011,00111111]!) DUAL_ORBIT([g], [147_8_72.c], ![$6]!, ![00000111,00001001,00001101,00010000,00010001,00010100,00010101,00101010, 00101011,00110011,01101000,01101001]!) DUAL_TRANSFORM([h], [168_8_82.b-168], ![81_{7},82_{7},83_{7},84_{7},85,86_{7},87,88_{7},89_{7},90_{7},91, 92,127_{7}]!) disjoint [a], [b], [c], [d], [e], [f], [g], [h]; status: realizable; DHIDE( ![ (* D2P#, DC1# done for *); ]! ) type [199,8,98_2]; [a] := P( [71_7_34.a] ); status: realizable; DHIDE( ![ (* DC2, DC1# done for *); ]! ) [189_8_94] type [189,8,94_2]; (* unique -- Tilborg type II *); DUAL_TRANSFORM([a], [155_8_76.a], ![76_{3,-14},76_{14},80_{3,-14},80_{14}, 84_{3,14}]!) (* [a] := Even(3) # Simp(6) *); status: realizable; (* The following three types are extra -- to avoid reentering a code type. *); [245_8_122x] type [245,8,122_2]; DUAL_TRANSFORM([a], [189_8_94.a-189], ![93,94,95,96_{1,-2},96_{2}]!) [207_8_102x] type [207,8,102_2]; DUAL_TRANSFORM_CH([a], [136_8_66.a], ![66_{1,-17},66_{17},68_{1,-17},68_{17},70,72_{-1,17},128_{1,17}]!) DUAL_ORBIT([n], [147_8_72.b], ![$1,$3,$4]!, ![00000111,00001011,00001101,00001111,00010001,00011000,00011101,00101001, 00101101,00110000,00110010,00111000,00111111,01110000]!) [183_8_90x] type [183,8,90]; DUAL_TRANSFORM([b], [207_8_102x.a-207], ![101,102_{1},103,104_{1},107,108_{1},127,128_{1}]!) DHIDE( ![ (* D2 done for [a], DC1# done for [a] -- [d] *); ]! ) [210_8_104] type [210,8,104]; DUAL_TRANSFORM([a], [20_8_8.a], ![8_{1,-2},8_{2},12,16_{1,-2},16_{2}]!) (* [a] := P( [82_7_40.b] ) *); DUAL_TRANSFORM([b], [136_8_66.a], ![66_{1,28},68,70_{-28},70_{-1,28}]!) DUAL_TRANSFORM_PLUS([c], [68_8_32.a-68], ![31_{-6},31_{-5,6},32_{5,-6},32_{6},39,40,63_{5,6}]!, ![+ column 97]!) (* [c] := P( [82_7_40.a] ) *); DUAL_TRANSFORM([d], [245_8_122x.a], ![122,124_{6},126_{1,-6},126_{1,6},128_{1,6}]!) DUAL_TRANSFORM_PLUS([e], [183_8_90x.b], ![90_{2,-3},90_{3},90_{-2,-3,90},92_{2,-3},92_{3},92_{-2,-3,90}, 122_{-2,-3,90},122_{2,3,90}]!, ![+ column 182]!) DUAL_TRANSFORM_PLUS([f], [21_8_8.g-21], ![7_{-2,-15},7_{2,15},8_{2,-15},8_{-2,15},11,12,15_{2},15_{-2,15}, 16_{2,15}]!, ![+ column 140 + column 198 + column 190 + column 205 + column 207]!) DUAL_ORBIT([g], [242_9_118.a], ![$4,$5]!, ![000000001,000000110,000001011,000010110,000011010,000011011,000110111, 001000010]!) DUAL_ORBIT([h], [20_8_8.a], ![$2,$3,$5]!, ![00000011,00000110,00001101,01000000,01000010,01000111,01001110,01010000, 01010100,01111101,11000000,11000011,11000111,11001000,11011110]!) DUAL_ORBIT_PLUS([i], [207_8_102x.n], ![$1,$6]!, ![00000011,00000100,00000110,00001000,00010000,00010001,00010010,00010011, 00010111,00011110,00011111,01110011,10010001,10111011]!, ![+ column 122]!) [j] := P( [82_7_40.c] ); [k] := P( [82_7_40.d] ); disjoint [a], [b], [c], [d], [e], [f], [g], [h], [i], [j], [k]; status: realizable; (* The following are extra -- to avoid reentering a code type. *); [121_8_58x] type [121,8,58_2]; DUAL_TRANSFORM([b], [21_9_8.a], ![8_{-1,-2,3},8_{1,2,3},12_{-1,-2,3},12_{1,2,3},16_{1,2,-3}]!) [214_8_106x] type [214,8,106_2]; [a] := {1010001010011011010010101010101010101001010101010100110110100110100100110101010 10101010101010101010101010101010101010101010101010101010101001101101001101001001 1011010100101001010101010101010110100100110100110110101,011010111011011011011001 10011001100110110011001011011011011011011011011011001100110011001100110011001100 11001100110011001100110011001100110110110110110110110110110110010011011001100110 011001101101101101101101101111,0001100110001110001110000111100001111000111100011 10001110001110001110001110000111100001111000011110000111100001111000011110000111 10000111100011100011100011100011100011100001110000111100001111000111000111000111 00011,00000111100000011111100000000111111110000000111111000000111111000000111111 00000000111111110000000011111111000000001111111100000000111111110000001111110000 001111110000001111111000000001111111100000011111100000011111,0000000001111111111 11000000000000000011111111111110000000000001111111111110000000000000000111111111 11111110000000000000000111111111111111100000000000011111111111100000000000001111 11111111111100000000000011111111111,00000000000000000000011111111111111111111111 11111100000000000000000000000011111111111111111111111111111111000000000000000000 00000000000000111111111111111111111111000000000000000000000000000001111111111111 1111111111,000000000000000000000000000000000000000000000000001111111111111111111 11111111111111111111111111111111111110000000000000000000000000000000000000000000 00000000000001111111111111111111111111111111111111111111111111111,00000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000011111111111111111111111111111111111111111111111111111111111111111111 1111111111111111111111111111111111111111}; DHIDE( ![ (* DC1# done for [a] -- [e] *); (* D2# done for [a] -- [g] *); (* O(26)# done for [j], [n], [o] *); ]! ) [207_8_102] type [207,8,102]; DUAL_TRANSFORM_CH([a], [136_8_66.a], ![66_{1,-17},66_{17},68_{1,-17},68_{17},70,72_{-1,17},128_{1,17}]!) (* = [a] := P( [79_7_38.d] ) *); DUAL_TRANSFORM([b], [210_8_104.a], ![104_{19,-83},104_{83},108]!) [c] := P( [79_7_38.g] ); [d] := P( [79_7_38.a] ); [e] := P( [79_7_38.b] ); DUAL_TRANSFORM_PLUS([f], [210_8_104.c-210], ![103,104_{17},107,108,112,127]!, ![+ column 201]!) [g] := P( [79_7_38.e] ); DUAL_TRANSFORM([h], [183_8_90x.b], ![90_{2},90_{-2,3},90_{-2,-3,90},92_{2,-3},92_{3},92_{-2,-3,90}]!) DUAL_TRANSFORM_PLUS([i], [183_8_90x.b], ![90_{2,-3},90_{3},90_{-2,-3,90},92_{2,-3},92_{3},92_{-2,-3,90}, 122_{2,3,90}]!, ![- column 180]!) DUAL_ORBIT([j], [21_8_8.g], ![$2,$3,$4]!, ![00000101,00001101,00010001,00010101,00011101,01010011,01010100]!) [k] := P( [79_7_38.c] ); [l] := P( [79_7_38.h] ); [m] := P( [79_7_38.f] ); DUAL_ORBIT([n], [147_8_72.b], ![$1,$3,$4]!, ![00000111,00001011,00001101,00001111,00010001,00011000,00011101,00101001, 00101101,00110000,00110010,00111000,00111111,01110000]!) DUAL_ORBIT([o], [147_8_72.c], ![$1,$5]!, ![00000001,00000010,00000101,00000111,00001000,00001010,00001100,00010001, 00011000,01100010,01110001,01110111,10000000,10000001,10001010,10010011, 11110011]!) DUAL_ORBIT([p], [214_8_106x.a], ![$9,$10,$12]!, ![00000110,00000111,00001000,00001001,00010000,00010001,00110000,00110001, 01000001,01000011,01000110]!) disjoint [a],[b],[c],[d],[e],[f],[g],[h],[i],[j],[k],[l],[m],[n],[o],[p]; status: realizable; DHIDE( ![ (* DC1# done for [a],[b],[c], D1# done for [d], O(26)# done for [a] -- [d], [f] *); ]! ) [121_8_58] type [121,8,58_2]; DUAL_TRANSFORM([a], [20_8_8.a-20], ![7_{-1,2},8_{2},11_{2},12_{2},15_{1}]!) DUAL_TRANSFORM([b], [21_9_8.a], ![8_{-1,-2,3},8_{1,2,3},12_{-1,-2,3},12_{1,2,3},16_{1,2,-3}]!) DUAL_TRANSFORM_PLUS([c], [207_8_102.a], ![102_{80},104_{80},106_{1,80},108_{1,80},128_{1,-80},128_{-1,80}]!, ![+ column 1]!) DUAL_TRANSFORM([d], [35_9_14.a-35], ![14_{1},16_{1},18_{1},20_{1},24_{-1}]!) DUAL_TRANSFORM_PLUS([e], [245_9_120.a-245], ![120_{7},124_{7},128_{-7}]!, ![+ column 1 + column 1]!) DUAL_TRANSFORM_PLUS([f], [42_8_18.a], ![18_{17},20_{17},22_{4,17},24_{-4,17},26_{17},28_{4,-17},28_{17}]!, ![+ column 34 + column 77]!) DUAL_TRANSFORM_PLUS([g], [222_9_108.a], ![108_{1,4},112_{1,4},116_{1,4},128_{-1,-4}]!, ![- column 2 - column 19 + column 4]!) DUAL_ORBIT_PLUS([h], [21_8_8.g], ![$1,$2,$3]!, ![00001001,00010001,00011101,00100011,00110000,00110100,01101010,01111000, 10110101]!, ![+ column 43 + column 107]!) DUAL_TRANSFORM_PLUS([i], [109_8_52.e-109], ![51_{-73},52_{73},55_{-73},56_{73},59_{73},60_{73}]!, ![+ column 18 + column 68]!) DUAL_TRANSFORM_PLUS([j], [168_8_82.b-168], ![81_{37},82_{37},83_{37},84_{37},85_{-37},86_{37},87_{37},88_{37}, 89_{-37},90_{37}]!, ![- column 113]!) DUAL_TRANSFORM_PLUS([k], [168_8_82.b-168], ![81_{54},82_{54},83_{54},84_{54},85,86_{54},88_{54},127_{54}]!, ![+ column 111]!) [l] := {1001001011100010110010110010110101100101011011100010010110101100110011001011010 010100110100011001110101010001110101000101,0101101011010001101011111001010010101 01001100110110010101010000010101011111101110110110110010101001001000001001010100 1010,001110000110000001111001100111110000001111001100000011111100001001111001100 1000011011001111110000111100011000000111100011,000001100101101110011010000110001 10000111011110001110011110001000111000101110001110000011100011001000111110001110 01101100,00000001111110000001111110000000001111111111000000000011111111100000011 11110000011111000000000011111111100000000001111111,00000000000001111111111110000 00000000000000011111111111111111110000000000001111111111000000000000000000011111 111111111111,0000000000000000000000000111111111111111111111111111111111111110000 000000000000000000111111111111111111111111111111111111,0000000000000000000000000 00000000000000000000000000000000000000111111111111111111111111111111111111111111 1111111111111111}; (* [l] := [245_9_120.a-123]^T using {...:...} -- data lost *); DUAL_TRANSFORM_PLUS([m], [80_9_36.a], ![36_{6,15},40_{6,15},44_{6,15},52_{-6,-15},52_{6,15}]!, ![- column 10 - column 52 + column 3]!) DUAL_TRANSFORM_PLUS([n], [80_9_36.a], ![36_{6,15},40_{6,15},44_{6,15},52_{-6,-15},52_{6,15}]!, ![- column 41 - column 52 + column 33]!) disjoint [a], [b], [c], [d], [e], [f], [g], [h], [i], [j], [k], [l], [m], [n]; status: realizable; (* type [245,8,122_2] show y148 = 0, y150 = 0, y152 = 0, y180 = 0, y182 = 0, y244 = 0 kill y134, y140, y136, y132 type [245,8,122] show y128 != 0 so the following is a complete classification [a] terminal P( [117_7_58.a] ) [b] terminal P( [117_7_58.b] ) disjoint [a], [b] *); DHIDE( ![ (* DC1#, D2# done for *); ]! ) [245_8_122] type [245,8,122]; DUAL_TRANSFORM([a], [189_8_94.a-189], ![93,94,95,96_{1,-2},96_{2}]!) DUAL_TRANSFORM([b], [207_8_102.a-207], ![101,102,103,104,106_{1},107,108,127]!) disjoint [a], [b]; ??classification of [base]: [a], [b]; status: classified, realizable; DHIDE( ![ (* D2 done for both [pa] and [pb], DC1# done for [pa], [pb], [c] *); (* D1G# done for [pa], [pb], [c], [pc] *); ]! ) type [203,8,100]; [pa] := P( [75_7_36.a] ); [pb] := P( [75_7_36.b] ); [pc] := P( [75_7_36.c] ); [pd] := P( [75_7_36.d] ); [pe] := P( [75_7_36.e] ); [pf] := P( [75_7_36.f] ); [pg] := P( [75_7_36.g] ); [ph] := P( [75_7_36.h] ); [pi] := P( [75_7_36.i] ); [pj] := P( [75_7_36.j] ); [pk] := P( [75_7_36.k] ); [pl] := P( [75_7_36.l] ); [pm] := P( [75_7_36.m] ); [pn] := P( [75_7_36.n] ); [po] := P( [75_7_36.o] ); [pp] := P( [75_7_36.p] ); [pq] := P( [75_7_36.q] ); [pr] := P( [75_7_36.r] ); [ps] := P( [75_7_36.s] ); [pt] := P( [75_7_36.t] ); [pu] := P( [75_7_36.u] ); [pv] := P( [75_7_36.v] ); DUAL_TRANSFORM([c], [210_8_104.c-210], ![103,104_{17},107,108,112_{-17}]!) DUAL_ORBIT_PLUS([f], [121_8_58.a], ![$4,$7]!, ![00000010,00000100,00000101,00000110,00000111,00001000,00001001,00001010, 00001011,00001101,00011101,01010111,11111110]!, ![+ column 201]!) DUAL_ORBIT([g], [147_8_72.b], ![$1,$2,$4]!, ![00000111,00001011,00001101,00010001,00011001,00011101,00100001,00101011, 00110000,00110010,00111000,00111111]!) DUAL_ORBIT([i], [147_8_72.c], ![$1,$5]!, ![00000001,00000010,00000101,00000111,00001000,00001010,00001100,00010001, 00011000,01100010,01110001,01110111,10000001,10001010,10010011,11110011]!) DUAL_ORBIT([j], [175_8_86.b], ![$2,$3,$6]!, ![00000100,00000111,00001000,00001001,00001011,00001100,00001101,00010010, 00011000,00011001,00011010,01011101,10001000,10001001,10001010,10001011, 10001110,10011011,10101000,10111011]!) DUAL_ORBIT([k], [140_8_68.c], ![$2,$4,$5,$6]!, ![00000001,00000101,00001000,00001010,00010011,00011101,00101001,00101011, 00111111,01100101,11101001,11111101]!) DUAL_ORBIT([l], [140_8_68.c], ![$2,$4,$5,$6]!, ![00000001,00000010,00000101,00001000,00001010,00010011,00011101,00101001, 00101011,00111111,01100101,11101001]!) DUAL_ORBIT([n], [140_8_68.e], ![$4,$6]!, ![00000111,00001000,00001100,00011001,01000000,01000001,01001000,01001001, 01011001,10100001,11100001]!) DUAL_ORBIT([o], [140_8_68.e], ![$4,$6]!, ![00000111,00001000,00001001,00001100,00011001,01000001,01000010,01001000, 01001001,01001100,01011001]!) DUAL_ORBIT([p], [105_8_50.b], ![$1,$4]!, ![00000001,00000010,00000011,00000100,00000101,00000110,00001000,00001010, 00001011,00001100,00001101,00010000,00010001,00010011,00011100,00011101, 00100111,00111000,00111001,01111010]!) DUAL_ORBIT([q], [105_8_50.b], ![$1,$4]!, ![00000001,00000010,00000011,00000100,00000101,00000110,00001000,00001010, 00001011,00001100,00001101,00010000,00010001,00010011,00011100,00011101, 00100110,00111000,00111001,01111010]!) DUAL_ORBIT([r], [105_8_50.b-64], ![$1,$2,$3]!, ![00000010,00000011,00000101,00000110,00000111,00001010,00001011,00010000, 00010001,00010010,00010011,00011101,00011110,00011111,00100111,00111010, 00111011,11001110,11001111]!) disjoint [c],[f],[g],[i],[j],[k],[l],[n],[o],[pa],[pb],[pc],[pd],[pe],[pf], [pg],[ph],[pi],[pj],[pk],[pl],[pm],[pn],[po],[pp],[pq],[pr],[ps],[pt], [pu],[pv],[p],[q],[r]; status: realizable; DHIDE( ![ (* DC1# done for [a], [b] *); (* D2# done for [a], [c] *); (* D3# done for [b] *); ]! ) [183_8_90] type [183,8,90]; DUAL_TRANSFORM([a], [207_8_102.b], ![102,106_{1,-41},106_{41}]!) DUAL_TRANSFORM([b], [207_8_102.a-207], ![101,102_{1},103,104_{1},107,108_{1},127,128_{1}]!) DUAL_TRANSFORM([c], [42_8_18.a], ![18_{1,-3},18_{3},20_{1,-3},20_{3},22_{1,-3},22_{3},24_{1,-3},26_{1,-3}, 26_{3}]!) DUAL_TRANSFORM([d], [183_8_90.b], ![90_{3},90_{-3,90},92_{3},92_{-3,90},96_{2,3},96_{2,-3,90}]!) DUAL_TRANSFORM_PLUS([e], [183_8_90.b], ![90_{3},90_{-3,90},92_{3},92_{-3,90},96_{2,3},96_{2,-3,90},122_{2,3,90}]!, ![- column 156]!) DUAL_ORBIT([f], [144_8_70.f], ![$1,$3]!, ![00000011,00000111,00001000,00001010,00001100,00010001,00010011,00010101, 00011000,00011001,00011111,00100111,00110001,00111010,01110110]!) DUAL_TRANSFORM_PLUS2([g], [168_8_82.b-168], ![81,82_{54},83,84_{54},85_{54},87_{-54},88_{54},89_{-54},90_{54}, 91,92_{54}]!, ![+ column 35]!) DUAL_TRANSFORM_PLUS([h], [168_8_82.d-168], ![81,82_{31},83,84_{31},85,86_{31},89,91]!, ![+ column 86]!) disjoint [a], [b], [c], [d], [e], [f], [g], [h]; status: realizable; DHIDE( ![ (* DC1#, DC2S (but on column deletion, only 1 column checked, and for it, only 9 orbits checked) *); (* D2# *); ]! ) [221_8_110] type [221,8,110_2]; DUAL_TRANSFORM([a], [189_8_94.a], ![94,96_{2}]!) (* = [a] := P( [93_7_46.a] ) *); (* P( Simp(5) * Simp(2) ) *); status: realizable; DHIDE( ![ (* DC1#, D2# done for *); ]! ) type [217,8,108]; (* unique -- Tilborg type II *); [a] := Simp(5) # Simp(3); status: realizable; DHIDE( ![ (* DC1#, D2# done for *); ]! ) type [233,8,116_4]; [a] := P( Simp(3) # Simp(4) ); status: realizable; DHIDE( ![ (* DC1# for [a], D1# for [b] *); (* O(26)# done for [a], [b], [c], [pa], [pb] *); ]! ) [152_8_74] type [152,8,74_2]; DUAL_TRANSFORM([a], [48_8_22.a], ![22_{1,-2},22_{-1,2},24_{1,-2},24_{-1,2},30]!) (* isomorphic to [pd] := P( [24_7_10.d] *); DUAL_TRANSFORM([b], [48_8_22.a], ![22_{1,-18},22_{-1,18},24_{1,-18},24_{-1,18},30]!) DUAL_TRANSFORM_PLUS([c], [45_8_20.a-45], ![19_{-1},20_{1},21_{-1},22_{1},23_{-1},24_{1},27,28,29_{1},30_{1}]!, ![- column 33]!) [pa] := P( [24_7_10.a] ); [pb] := P( [24_7_10.b] ); [pc] := P( [24_7_10.c] ); [pe] := P( [24_7_10.e] ); [pf] := P( [24_7_10.f] ); disjoint [a], [b], [c], [pa], [pb], [pc], [pe], [pf]; status: realizable; DHIDE( ![ (* DC1G# done for *); ]! ) [186_8_92] type [186,8,92]; DUAL_TRANSFORM([a], [221_8_110.a], ![110]!) (* [a] = [6_3_3.a] * Simp(5) =(presumably) [93_7_46.unique?] * Proj(1) *); DUAL_TRANSFORM_PLUS([b], [152_8_74.a-152], ![73,74_{15},75,76_{15},77,78_{15},81]!, ![+ column 84]!) DUAL_TRANSFORM([c], [45_8_20.a-45], ![19,20_{3},21,22_{3},23,24_{3},27,28_{3}]!) disjoint [a], [b], [c]; status: realizable; DHIDE( ![ (* DC1# done for *); ]! ) [237_8_118] type [237,8,118_2]; DUAL_TRANSFORM([a], [186_8_92.a-186], ![91,92,93,95]!) (* [a] := P( [109_7_54.a] ) *); status: realizable; DHIDE( ![ (* D2# done for *); ]! ) [214_8_106] type [214,8,106_2]; DUAL_TRANSFORM([a], [237_8_118.a-237], ![117,118,119_{60},120_{60},126_{60},127_{60}]!) status: realizable; DHIDE( ![ (* D2, DC1# done for [a] *); ]! ) type [230,8,114_2]; [a] := P(P(P(Even(6)))); DUAL_TRANSFORM([b], [237_8_118.a-237], ![117,118,119,120_{60},126_{60},127]!) [c] := P( [102_7_50.b] ); DUAL_ORBIT([d], [214_8_106.a], ![$9,$10,$12]!, ![00000100,00000101,00000110,00000111,00001000,00001001,00001101,00010000, 00010001,00110000,00110001,01000010,01000011,01000100,01000110]!) [e] := P( [102_7_50.c] ); disjoint [a], [b], [c], [d], [e]; status: realizable; DHIDE( ![ (* D1# done for [a], O(26)# done for [a], [b] *); ]! ) [58_8_26] type [58,8,26_2]; DUAL_TRANSFORM_PLUS([a], [42_8_18.a-42], ![22_{-1,2},23_{-1,2},24_{1,2},25,26,27_{1,-2},27_{2},28_{1,-2},28_{2}]!, ![- column 38]!) DUAL_ORBIT([b], [42_8_18.a], ![$1,$3]!, ![00000001,00000111,00001101,00011111,00101111,00110101,01001000]!) disjoint [a], [b]; status: realizable; DHIDE( ![ (* DC1G# *); ]! ) type [162,8,80_16]; DUAL_TRANSFORM_PLUS([a], [21_8_8.g], ![12_{-1},12_{1},16_{-1},16_{1},16_{1}]!, ![+ column 64]!) status: realizable; DHIDE( ![ (* D2#, OE(26)# done for *); ]! ) type [81,8,38_2]; DUAL_ORBIT([a], [21_8_8.g], ![$2,$3,$4]!, ![00011101,01010011,01111110]!) status: realizable; DHIDE( ![ (* The following code is new: *); (* OE(26)#, DC1# done for *); ]! ) type [92,8,44_4]; DUAL_ORBIT([a], [21_8_8.g], ![$1,$2,$3]!, ![00011101, 00100000,00110000,00110100,01101010,01111000,01111110,10110101]!) status: realizable; DHIDE( ![ (* OE(26)#, D1# done for *); ]! ) type [204,9,98_2]; DUAL_ORBIT([a], [35_9_14.a], ![$1,$2]!, ![000001010, 000010000,000011101,000100010,000101101,001001011,001011010,001111101]!) status: realizable; DHIDE( ![ (* DC1#, O(26)# done for [a], [b] *); ]! ) type [171,8,84_4]; DUAL_ORBIT_PLUS([a], [105_8_50.a], ![$1,$3]!, ![00000111,00001100,00001101,00010001,00010010,00010011,00010101,00011010, 00011011,00011110,00100001,00101111,01101000,10010111]!, ![+ column 100]!) DUAL_ORBIT([b], [140_8_68.e], ![$4,$6]!, ![00000111,00001000,00001001,01000000,01000001,01000010,01000101,01001000, 01001001,01001100,01011001,10100001,10111111,11111010]!) disjoint [a], [b]; status: realizable; DHIDE( ![ (* OE(26).7#, DC1# done for [a] *); ]! ) type [144,9,68_4]; DUAL_ORBIT([a], [242_9_118.a], ![$4,$5]!, ![000000101,000001111,000100011,000100100,001000000,001000010,001110000]!) status: realizable; DHIDE( ![ (* OE(26)#, DC1# done for [a], [b] *); ]! ) [167_9_80] type [167,9,80_4]; DUAL_ORBIT_PLUS([a], [242_9_118.a], ![$4,$5]!, ![000000010,000001010,000001111,000011010,000011011,000100011,000100100, 001000010,001110000,111111111]!, ![+ column 166]!) DUAL_ORBIT_PLUS([b], [242_9_118.a], ![$4,$5]!, ![000000010,000000101,000001010,000001111,000100000,000100011,000101001, 001000000,001110000,111111111]!, ![+ column 166]!) disjoint [a], [b]; status: realizable; DHIDE( ![ (* OE(26)#, D1# done for [a] *); (* D3(28).7#(but only 1 orbit checked) *); ]! ) type [76,9,34_2]; DUAL_ORBIT([a], [167_9_80.b], ![$3,$5]!, ![000001101,000001111,001110111,111110110]!) status: realizable; DHIDE( ![ (* OE(26)# done for *); ]! ) type [160,9,76_4]; DUAL_ORBIT([a], [242_9_118.a], ![$1,$2,$3,$4]!, ![000000001,000000010,000000011,000001001,000010010,000101001]!) DUAL_ORBIT([b], [242_9_118.a], ![$1,$2,$3,$4]!, ![000000001,000000010,000000011,000001001,000010000,000101001]!) DUAL_ORBIT([c], [21_9_8.a], ![$1,$4,$5,$6]!, ![000000010,000000110,000100111,000101111,001100011,001101010,001101101, 011100011,111100001]!) disjoint [a], [b], [c]; status: realizable; DHIDE( ![ (* O(26)# done for *); ]! ) [84_8_40] type [84,8,40_2]; DUAL_ORBIT([a], [140_8_68.f], ![$2,$4]!, ![00000111,00001100,00001110,00100111,00101010,00101110,10101000,10101001, 10111000,10111001]!) status: realizable; (* The following code is new: *); DHIDE( ![ (* O(26)# done for *); ]! ) type [108,8,52_4]; DUAL_ORBIT_PLUS([a], [84_8_40.a], ![$2,$4]!, ![00000001,00000011,00000110,00001010,00011111]!, ![+ column 4]!) status: realizable; data_comment( ![ More {\bf nine-dimensional codes} are given below. Except for the first one, they are in order by length. ]! ) [307_9_152] type [307,9,152]; DUAL_ORBIT([a], [18_9_6x.a], ![$1,$2]!, ![000001000,000011011,100000000, 100000010,100001011,100001111,100101011,111111111]!) status: realizable; DHIDE( ![ (* O(26).7#(allowing length up to 511) done for [b], [c] *); ]! ) [96_9_44] type [96,9,44]; DUAL_ORBIT([a], [307_9_152.a], ![$6,$7]!, 000000100) DUAL_ORBIT([b], [96_9_44.a], ![$10,$12]!, ![000011100,001010111,010000110, 010010010,010011100,010110110]!) DUAL_ORBIT([c], [96_9_44.a], ![$10,$12]!, ![000011100,001010111,010000101, 010011100,011001100]!) DUAL_ORBIT_PLUS2([d], [96_9_44.b], ![$3,$4]!, ![000000001,000000010,000110001, 000110010,010101101,010101110,111101010]!, ![+ column 85 + column 87 + column 91 + column 93]!) disjoint [a], [b], [c], [d]; status: realizable; type [99,9,46]; DUAL_ORBIT([a], [307_9_152.a], ![$5,$7]!, ![000000101,000000110]!) DUAL_ORBIT([b], [307_9_152.a], ![$5,$7]!, ![000000100,000000110]!) disjoint [a], [b]; status: realizable; DHIDE( ![ (* D2#, DC1#, OE(26).7# done for [a] *); ]! ) type [102,9,48]; DUAL_TRANSFORM([a], [18_9_6x.a], 12) [b] := [51_8_24.a] # Proj(1); DUAL_ORBIT_PLUS([c], [307_9_152.a], ![$6,$7]!, ![000000011,000000100,111110100]!, ![+ column 1]!) disjoint [a], [b], [c]; status: realizable; data_comment( ![ The parameters of the following code are new: ]! ) DHIDE( ![ (* OE(28).7#(allowing length up to 495) *); ]! ) type [176,9,84]; DUAL_ORBIT([a], [238_9_116.a-1], ![$1,$2]!, ![000010010,000010011,000011001,000011101,000101001,000101010,001000000, 001000001,001000111,001001100,001101010]!) type [265,9,130]; DUAL_TRANSFORM_PLUS([a], [80_9_36.a], ![36_{1,-19},36_{-1,19},40_{1,-19},40_{-1,19},44_{1,-19},44_{-1,19}, 48,52_{-1},52_{1,-19}]!, ![- column 88 - column 262]!) status: realizable; type [269,9,132]; DUAL_TRANSFORM_PLUS([a], [80_9_36.a], ![36_{2,-20},36_{-2,20},40_{2,-20},40_{-2,20},44_{2,-20},44_{-2,20}, 48_{-2},48_{2,-20},52]!, ![- column 38]!) status: realizable; DHIDE( ![ (* O(26).7#(allowing length up to 511) *); ]! ) type [273,9,134]; DUAL_ORBIT([a], [18_9_6x.a], ![$1,$2]!, ![000001000,100000000,100000010,100001011,100001111,100101011,111111111]!) status: realizable; type [300,9,148]; DUAL_ORBIT([a], [307_9_152.a], ![$4,$6]!, ![000000100,000000101,000000111,000001001,000010101]!) status: realizable; type [304,9,150]; DUAL_ORBIT([a], [307_9_152.a], ![$4,$6]!, ![000000100,000000101,000000111,000001001,000010101,111110100,111110101]!) DUAL_ORBIT([b], [307_9_152.a], ![$4,$6]!, ![000000001,000000011,000000100, 000000101,000000111,000001001,000010101,111110101]!) disjoint [a], [b]; status: realizable; DHIDE( ![ (* O(26).7#(allowing length up to 511) *); ]! ) [324_9_160] type [324,9,160]; DUAL_ORBIT([a], [18_9_6x.a], ![$1,$2]!, ![000000101,100000000,100000010,100001011,100001111,100101011,111111111]!) status: realizable; [372_9_184] type [372,9,184]; DUAL_ORBIT([a], [96_9_44.a], ![$10,$12]!, ![000000100,000000101,000001101, 000010010,000110110,001001100,001010111,010000100,010000101,010000110, 010001101,010010010,010110110,011001100,011010111]!) DUAL_ORBIT([b], [372_9_184.a], ![$16,$17]!, ![000000001,000001000,000001001, 000010000,000010001,000010101,000100001]!) DUAL_ORBIT([c], [238_9_116.a-1], ![$1,$2]!, ![000000010,000000011,000000110,000001001,000001110,000010010,000010011, 000011001,000101010,001000001,001000010,001000100,001000111,001001011, 001001100,001010011,001010111,001011100,001101010]!) disjoint [a], [b], [c]; status: realizable; type [375,9,186]; DUAL_ORBIT([a], [372_9_184.a], ![$16,$17]!, ![000000001,000001000,000001001, 000010000,000010001,000010101,000100001,000111010]!) DUAL_ORBIT([b], [372_9_184.a], ![$16,$17]!, ![000000001,000001000,000001001, 000010000,000010001,000010101,000100001,000111001]!) disjoint [a], [b]; status: realizable; type [378,9,188]; DUAL_ORBIT([a], [372_9_184.a], ![$16,$17]!, ![000000001,000001000,000001001, 000010000,000010001,000010101,000100001,010011001]!) status: realizable; type [381,9,190]; DUAL_ORBIT([a], [372_9_184.a], ![$16,$17]!, ![000000001,000001000,000001001, 000010000,000010001,000010101,000100001,000111010,010011001]!) status: realizable; type [384,9,192]; DUAL_ORBIT([a], [307_9_152.a], ![$6,$7]!, ![000000100,000000110,000001000]!) status: realizable; type [396,9,196]; DUAL_ORBIT([a], [96_9_44.a], ![$10,$12]!, ![000000001,000000100,000001101, 000010010,000011100,000011101,001001100,001010111,010000001,010000100, 010001101,010010010,010011100,010011101,010110110,011001100,011010111]!) DUAL_TRANSFORM_PLUS([b], [80_9_36.a], ![36_{1},36_{-1,22},40_{1},40_{-1,22},44,48_{1},48_{-1,22},52_{1}, 52_{-1,22}]!, ![- column 57 - column 87 - column 97 - column 108]!) disjoint [a], [b]; status: realizable; type [448,9,224]; DUAL_ORBIT([a], [324_9_160.a], ![$3,$4]!, ![000000001,000000010,000000011, 000000101,000000110,000000111,000001010,000001011,000010010,000010011, 000011011,001000011,011011011]!) status: realizable; type [459,9,228]; DUAL_ORBIT([a], [324_9_160.a], ![$2,$3,$6]!, ![000000010,000000011,000000100, 000000101,000000110,000000111,000001011,000001100,000001101,000001111, 000010011,000010100,000010101,001000000,001000010,001000100,001001010, 001001100,001010000,001011110,001100000]!) status: realizable; type [463,9,230]; DUAL_ORBIT([a], [96_9_44.a], ![$10,$11,$12]!, ![000000100,000000101,000000110, 000001101,000010010,000011100,000110110,001001100,001010111,001110111, 010000000,010000001,111001101]!) status: realizable; type [480,9,240]; DUAL_ORBIT([a], [96_9_44.a], ![$10,$12]!, ![000000001,000000100,000000101, 000000110,000001101,000010010,000011100,000011101,000110110,001001100, 001010111,010000001,010000100,010000101,010000110,010001101,010010010, 010011100,010011101,010110110,011001100,011010111]!) status: realizable; type [486,9,242]; DUAL_ORBIT([a], [96_9_44.b], ![$3,$4]!, ![000000001,000000010,000000101, 000000110,000001000,000001011,000100000,000100001,000100010,000100011, 000100100,000100101,000100110,000100111,000101000,000101011,000110001, 000110010,001101000,010101001,010101010,010101101,010101110,111101001, 111101010]!) status: realizable; type [504,9,252]; DUAL_ORBIT([a], [307_9_152.a], ![$6,$7]!, ![000000100,000000110,000001000,000010100]!) status: realizable; type [508,9,254]; DUAL_ORBIT([a], [307_9_152.a], ![$6,$7]!, ![000000100,000000110,000001000,000010100,111110100]!) status: realizable; data_comment( ![ Now we give some {\bf codes of lengths 10, 11, and 12} ]! ) type [496,11,240]; DUAL_ORBIT([a], [32_11_12.a], ![$2,$3]!, 00000010011) DUAL_ORBIT([b], [32_11_12.a], ![$1,$2]!, ![10000000110,10000001000,10000001001,10000001010]!) disjoint [a], [b]; status: realizable; [341_11_162] type [341,11,162]; DUAL_ORBIT([a], [32_11_12.a], ![$1,$2]!, ![00000001101,10000000110,10000001000]!) status: realizable; DHIDE( ![ (* OE(26).7#(allowing length up to 495) *); ]! ) type [310,10,148]; DUAL_ORBIT([a], [341_11_162.a], ![$1,$2]!, ![00000001010,00000010011]!) status: realizable; DHIDE( ![ (* OE(26).7#(allowing length up to 495) *); ]! ) type [341,10,164]; DUAL_ORBIT([a], [341_11_162.a], ![$1,$2]!, ![00000000011,00000000110,00000001010]!) status: realizable; DHIDE( ![ (* O(28).7#(allowing length up to 495) *); ]! ) type [371,11,176]; DUAL_ORBIT_PLUS([a], [341_11_162.a], ![$1,$2]!, ![00000000010,00000000111,00000001010,00001100010]!, ![- column 19]!) DUAL_ORBIT_PLUS([b], [341_11_162.a], ![$1,$2]!, ![00000000010,00000000111,00000001010,00000111010]! ,![- column 13]!) DUAL_ORBIT_PLUS([c], [341_11_162.a], ![$1,$2]!, ![00000000001,00000000010,00000000111,00000001010,00001100010]!, ![- column 20 - column 29]!) DUAL_ORBIT_PLUS([d], [341_11_162.a], ![$1,$2]!, ![00000000001,00000000010,00000000111,00000001010,00001100010]!, ![- column 20 - column 34]!) DUAL_ORBIT_PLUS([e], [341_11_162.a], ![$1,$2]!, ![00000000001,00000000010,00000000111,00000001010,00001100010]!, ![- column 20 - column 59]!) disjoint [a], [b], [c], [d], [e]; status: realizable; type [343,11,164]; DUAL_ORBIT_PLUS([a], [32_11_12.a], ![$1,$2]!, ![00000001101,10000000110,10000001000,11111111111]!, ![+ column 342]!) status: realizable; type [324,12,144]; DUAL_ORBIT([a], [24_12_8.a], ![$6,$7,$9,$10]!, ![001001000101,001011000011,011001000110]!) DUAL_ORBIT([b], [24_12_8.a], ![$6,$7,$9,$10]!, ![001001000000,001011000000,011001000010]!) disjoint [a], [b]; status: realizable; type [490,10,240]; DUAL_ORBIT([a], [24_12_8.a], ![$4,$6,$9,$10]!, ![111000000001,111000001101,111100000001,111100000110,111100101101]!) status: realizable; (* ********* The following codes may be optimal but are not needed: ******** *); DHIDE( ![ (* DC2S, DC1# done for *); ]! ) type [128,8,64_64]; DUAL_TRANSFORM([a], [20_8_8.a], ![8_{2},12_{2},16_{2}]!) set auto joint list; DHIDE( ![ (* DC2S, DC1# done for *); ]! ) type [192,8,96_32]; DUAL_TRANSFORM([a], [20_8_8.a], ![8_{1,-2},8_{2},12_{1,-2},12_{2},16_{1,-2}, 16_{2}]!) DHIDE( ![ (* DC2S, DC1# done for *); ]! ) type [224,8,112_16]; DUAL_TRANSFORM([a], [20_8_8.a-20], ![7,8_{1,-2},8_{2},11,12_{1,-2},12_{2}, 15_{1,-2},15_{2},16_{1,2}]!) DHIDE( ![ (* DC2S (but only one column deleted, and only 4 orbits checked for it) for *); (* DC1# done for *); ]! ) type [240,8,120_8]; DUAL_TRANSFORM_CH([a], [189_8_94.a], ![94,96_{1,-2},96_{2},126_{1,2}]!) DHIDE( ![ (* DC1# done for *); ]! ) type [248,8,124_2]; DUAL_TRANSFORM([a], [155_8_76.a], ![76,80_{1,-73},80_{73},84_{1,-73},84_{73}]!) DHIDE( ![ (* DC1# done for *); ]! ) type [252,8,126_2]; DUAL_TRANSFORM([a], [155_8_76.a], ![76,80,84_{1,-2},84_{2}]!) DHIDE( ![ (* DC1# done for *); ]! ) type [255,8,128_128]; DUAL_TRANSFORM([a], [20_8_8.a], ![8,12,16_{1,-2},16_{2}]!) DHIDE( ![ (* The following lines are temporary. *); type [47,7,22]; ??status: realizable; type [60,8,27]; ??status: realizable; type [74,8,34]; ??status: realizable; type [77,8,36]; ??status: realizable; type [89,8,42]; ??status: realizable; type [38,9,16]; ??status: realizable; type [47,9,20]; ??status: realizable; type [55,9,24]; ??status: realizable; type [63,9,28_2]; ??status: realizable; type [67,9,30]; ??status: realizable; type [70,9,32]; ??status: realizable; type [83,9,38]; ??status: realizable; type [108,9,50]; ??status: realizable; type [111,9,52]; ??status: realizable; type [118,9,56_2]; ??status: realizable; type [124,9,58]; ??status: realizable; type [135,9,64_2]; ??status: realizable; type [140,9,66]; ??status: realizable; type [150,9,72_2]; ??status: realizable; type [163,9,78_2]; ??status: realizable; type [172,9,82]; ??status: realizable; type [181,9,88_2]; ??status: realizable; type [187,9,90]; ??status: realizable; type [189,9,92]; ??status: realizable; type [207,9,100_2]; ??status: realizable; type [214,9,104_2]; ??status: realizable; type [243,9,118_2]; ??status: realizable; type [40,10,16]; ??status: realizable; type [49,10,20]; ??status: realizable; type [53,10,22]; ??status: realizable; type [56,10,24]; ??status: realizable; type [71,10,32]; ??status: realizable; type [87,10,40]; ??status: realizable; type [96,10,44]; ??status: realizable; type [117,10,54]; ??status: realizable; type [128,10,60]; ??status: realizable; type [133,10,62_2]; ??status: realizable; type [136,10,64]; ??status: realizable; type [154,10,72]; ??status: realizable; type [195,10,94]; ??status: realizable; type [228,10,110]; ??status: realizable; type [231,10,112]; ??status: realizable; type [239,10,114_2]; ??status: realizable; type [165,10,76_2]; ??status: realizable; type [42,11,16]; ??status: realizable; type [66,11,28]; ??status: realizable; type [74,11,32]; ??status: realizable; type [106,11,48]; ??status: realizable; type [154,11,69]; ??status: realizable; type [199,11,96]; ??status: realizable; type [217,11,104]; ??status: realizable; type [60,12,24]; ??status: realizable; type [84,12,34]; ??status: realizable; type [186,12,86]; ??status: realizable; type [104,13,44]; ??status: realizable; type [114,13,48]; ??status: realizable; type [156,13,68]; ??status: realizable; type [180,14,80]; ??status: realizable; type [183,14,82]; ??status: realizable; type [115,15,46]; ??status: realizable; type [231,15,102]; ??status: realizable; type [241,16,106]; ??status: realizable; type [249,17,110]; ??status: realizable; type [128,8,64]; ??status: unique; type [192,8,96]; ??status: unique; type [224,8,112]; ??status: unique; type [240,8,120]; ??status: unique; type [127,8,63]; ??status: unique; type [191,8,95]; ??status: unique; type [223,8,111]; ??status: unique; type [239,8,119]; ??status: unique; type [255,8,128]; ??status: unique; type [254,8,127]; ??status: unique; type [252,8,126]; ??status: unique; type [248,8,124]; ??status: unique; type [189,8,94]; ??status: unique; (* Tilborg type II *); type [136,8,66]; ??status: unique; (* Tilborg type III *); type [256,9,128]; ??status: unique; type [384,9,192]; ??status: unique; type [511,9,256]; ??status: unique; ]! ) type [255,8,128]; DUAL_TRANSFORM([a], [20_8_8.a], ![8,12,16_{1,-2},16_{2}]!) at [base]; show y128 = 255; via unique wordtypes [base] implies [a]; classification of [base]: [a]; STATUS_UNIQUE_WE(1 + 255t^128) (* The following codes have parameters [2^8 - 2^r, 8, 2^7 - 2^(r-1)] for r = 7,6,5,4. They are all two-weight codes, which obviously form a series, no doubt admitting a simpler description. Presumably their uniqueness follows from something else. *); type [128,8,64]; DUAL_TRANSFORM([a], [20_8_8.a], ![8_{2},12_{2},16_{2}]!) at [base]; show y64 = 254, y128 = 1; =config 128 : {1}; via configuration search [a] implies [current]; via unique wordtypes [current] implies [a]; classification of [base]: [a]; STATUS_UNIQUE_WE(1 + 254t^64 + t^128) type [192,8,96]; DUAL_TRANSFORM([a], [20_8_8.a], ![8_{1,-2},8_{2},12_{1,-2},12_{2},16_{1,-2}, 16_{2}]!) at [base]; show y96 = 252, y128 = 3; config from x_128|x_64_64; via configuration search [a] implies [current]; via unique wordtypes [current] implies [a]; classification of [base]: [a]; STATUS_UNIQUE_WE(1 + 252t^96 + 3t^128) type [224,8,112]; DUAL_TRANSFORM([a], [20_8_8.a-20], ![7,8_{1,-2},8_{2},11,12_{1,-2},12_{2}, 15_{1,-2},15_{2},16_{1,2}]!) at [base]; show y112 = 248, y128 = 7; config from x_128|x_64_64|x_32_32_32_32; via configuration search [a] implies [current]; via unique wordtypes [current] implies [a]; classification of [base]: [a]; STATUS_UNIQUE_WE(1 + 248t^112 + 7t^128) type [240,8,120]; DUAL_TRANSFORM_CH([a], [189_8_94.a], ![94,96_{1,-2},96_{2},126_{1,2}]!) at [base]; show y120 = 240, y128 = 15; (* Now one can show that jy128y128y120 = 0: in fact the variable itself isn't in the list of joint variables. This implies that the words of weight 0 and 128 comprise a subcode. Since the latter is a one-weight code, it is uniquely determined. Hence since the code has only two weights, it is uniquely determined. *); ??classification of [base]: [a]; STATUS_UNIQUE_WE(1 + 240t^120 + 15t^128) (* Justify the following lines, which follow by "print punctured codes": *); type [127,8,63]; ??status: unique; type [191,8,95]; ??status: unique; type [223,8,111]; ??status: unique; type [239,8,119]; ??status: unique; type [254,8,127]; ??status: unique; (* Justify the following lines: *); type [252,8,126]; ??status: unique; type [248,8,124]; ??status: unique; type [256,9,128]; ??status: unique; type [384,9,192]; ??status: unique; type [511,9,256]; ??status: unique; set dual constraint bound = 0; (* In case code.data is inputted via accept. *); |-> tex/code.tex \end{svb} \catcode`\@=11 \def\setlabel#1#2#3{\@bsphack\if@filesw {\let\thepage\relax \def\protect{\noexpand\noexpand\noexpand}% \edef\@tempa{\write\@auxout{\string \newlabel{#1}{{#2}{#3}}}}% \expandafter}\@tempa \if@nobreak \ifvmode\nobreak\fi\fi\fi\@esphack} \setlabel{NewResultCount}{newresultcounter}{0} \catcode`\@=12 \newpage \part{The program} This printed document includes most (but not all) of the lines of code from the actual program. Lines of code relating to debugging, internal errors, and template instantiation are hidden, as are lines of code pertaining to or resulting from the splitting of code into multiple files. We do not show ``friend'' or {\tt extern "C"}$\ldots$ declarations. \block{Definitions, string tools, list of classes, miscellanea} The following \verb|#define| directives should be adjusted to match your computer. \begin{svb} set_include_file(macros.h) #define LINCOLN #ifdef LINCOLN HIDE( ![ #ifndef DEMO #define CPLEX "cplex" #endif ]! ) #define CPLEX_VERSION "4.0.7" #endif #ifdef DELFT #define CPLEX "cplex" #define CPLEX_VERSION "4.0.4" #define ABSOLUTE_PATH_FOR_CPLEX #endif HIDE( ![ #ifdef DEMO #define CPLEX "/usr/local/cplex/cplex" #endif ]! ) index_method(test) template inline bool test(const T& a, const T& b, char sense) { if ( sense == '=' ) return a == b; if ( sense == '<' ) return a <= b; return a >= b; } TEX(We make a macro for an iteration syntax which gets used zillions of times.) index_method(forPix) index_method(forPixDef) #define forPix( pix, list ) for ( pix = (list).first( ); pix != 0; \ (list).next(pix) ) #define forPixDef( pix, list ) Pix pix; for ( pix = (list).first( ); \ pix != 0; (list).next(pix) ) index_method(if_match) index_method(if_no_match) TEX( ![ \verb|if_match( |{\it string}\verb|, |{\it pattern}\verb| )|: \ Convert {\it pattern\/} to a {\tt Regex} (regular expression) and test to see if {\it string\/} matches it. The macro code for \verb|if_match| is visible only in the source file. There is also a macro \verb|if_no_match|. ]! ) HIDE( ![ #define if_match( string, pattern ) ]! ) DEFINE(if_mat_ctr,0) DEFINE(if_match,![DEFINE(![if_mat_ctr]!,incr(if_mat_ctr))![if_match]!( $1, $2 ) |-> current_compile_file static Regex ![if_match]!if_mat_ctr ($2); if ( $1.matches( ![if_match]!if_mat_ctr ) ) |-> current_compile_file, tex/code.tex ]! ) HIDE( ![ #define if_no_match( string, pattern ) ]! ) DEFINE(if_no_mat_ctr,0) DEFINE(if_no_match,![DEFINE(![if_no_mat_ctr]!,incr(if_no_mat_ctr))![if_no_match]!( $1, $2 ) |-> current_compile_file static Regex ![if_no_match]!if_no_mat_ctr ($2); if ( !$1.matches( ![if_no_match]!if_no_mat_ctr ) ) |-> current_compile_file, tex/code.tex ]! ) HIDE( ![ // #define DEBUG ]! ) #define ERROR(MSG) { cerr << "\nError: " << MSG << "\n"; exit(1); } #define INTERNAL_ERROR(MSG) { \ cerr << "\n---Internal Error---: " << MSG << "\n"; \ cerr << "Please send a copy of your program file to\n"; \ cerr << "jaffe@cpthree.unl.edu. "; \ cerr << "Please include the version number: VERSION.\n"; \ cerr << "Also please describe your hardware and operating system.\n"; \ exit(1); } #define WARNING(MSG) { cerr << "\nWarning: " << MSG << "\n"; \ if (warnings_are_fatal) exit(1); } #define WARNRET(MSG) { cerr << "\nWarning: " << MSG << " Command ignored.\n"; \ if (warnings_are_fatal) exit(1); return; } index_method(swap) template inline void swap(T& a, T& b) { static T temp; temp = a; a = b; b = temp; } TEX(![ For both {\tt min} and {\tt max}, I tried to use a conditional expression, but it didn't work. Perhaps this is a compiler bug. ]!) index_method(abs) template T inline abs(const T& x) { return (x >= 0) ? x : -x; } index_method(min) template T inline min(const T& a, const T& b) { if ( a < b ) return a; return b; } index_method(max) template T inline max(const T& a, const T& b) { if ( b < a ) return a; return b; } index_method(require_char) inline void require_char(String& s, char c) { if ( c == 0 && s.length() == 0 ) return; if ( s.length() == 0 || s[0] != c ) ERROR("Syntax of string \"" << s << "\" is incorrect."); s.del(c); } index_method(minus1_to_the) inline Integer minus1_to_the(int j) { if ( even(j) ) return 1; else return -1; } index_method(operator*(Integer, Rational)) inline Rational operator*(const Integer& a, const Rational& b) { return Rational(a) * b; } index_method(operator*(Rational, Integer)) inline Rational operator*(const Rational& a, const Integer& b) { return a * Rational(b); } TEX( \verb|as_int(s)|: Convert the {\tt String} object \verb|s| into an {\tt int} object. The assumption is that \verb|s| is a string of digits which defines a nonnegative integer small enough to fit into an {\tt int} object. The implementation is goofy and should be replaced. ) index_method(as_int) inline int as_int(const String& s) { return int( atoI(s).as_long( ) ); } inline int as_int(const Integer& n) { return int( n.as_long( ) ); } // If s is a string, and n is an integer, we want "s + n" to yield a string // obtained by concatenating s with the decimal expansion of n. inline String operator+(const String& s, int n) { return s + dec(n); } index_method(yno) inline int yno( String var ) { var.del('y'); var.del('x'); var.del('_'); return as_int(var); } #include index_method(make_list) template inline SLList make_list(const T& x) { SLList l; l.append(x); return l; } index_method(global_var) inline bool global_var(const String& v) { return v[0] == 'y' || v[0] == 'm' || v[0] == 'd'; } index_method(local_var) inline bool local_var(const String& v) { return v[0] == 'x' || v[0] == 's' || v[0] == 'z' || v[0] == 'q'; } index_method(joint_var) inline bool joint_var(const String& v) { return v[0] == 'j' || v[0] == 'c'; } set_include_file(gnutypes.h) #include #include #include #include #include #include set_compile_file(code.c) HIDE(![#include "gnutypes.h" #include "macros.h" ]!) #include #ifdef NeXT #include #else #include #endif #include #include #include #include TEX( Set up global variables. ) int homebrew = 0, use_quad = 0; String homebrew_status; int refactorization_rate = 0; long time_used_by_CPLEX = 0; long time_used_by_subdivide = 0; long time_used_generating_Krawtchouk_table = 0; long time_used_by_list_extensions = 0; long time_used_by_build = 0; long time_used_by_igs; long time_used_by_smallcode_we; long time_used_by_Isomorphic; long time_used_presolving = 0; long time_used_by_check_infeasible = 0; long time_used_by_simple_simplex = 0; long time_used_setting_up_simplex_problem = 0; long time_used_generating_constraints = 0; int gullible = 0, optimal = 0, secondary_echo = 1, show_terminals_only = 1; int quiet_build = 1, depth_first = 0, alternate_extension_method = 0; int tables_only = 0, partial_pricing = 50, gullible_silent = 0; int secondary_plus = 0, auto_group_computation = 0; int smart_dual = 0, homebrew_full_report = 0, silent = 0; int residual_check_for_kill = 0, auto_projection = 0, save_bounds = 0; int auto_macaulay = 0, auto_round = 0, limited_secondary_kill = 0; int sort_flag = 1, full_secondary_kill = 0, lower_bound_check = 1; int dual_constraint_bound = 0, secondary_kill_maxvars = 0, homebrew_speedy = 1; int vars, create_con_file_only = 0, show_variables = 0; int auto_dual_transform = 0, dual_transform_length_limit = 255; int dual_transform_dim_low = 1, dual_transform_dim_high = 1000; int auto_orbit_transform = 0, auto_transform_depth = 0, tuple_orbit_max = 5; int auto_dual_column_deletion = 0, nzv_length_max = 18; int price_refinement_count = 1, generate_noneven_bounds = 0; int dcb_depth_limit = 0, doubly_even_test = 0, fill_weight = 0; int show_config_creation = 1, auto_joint_search = 0, auto_joint_test = 0; int use_dual_dual_for_joint = 0, no_test_if_classified = 0; int nzv_length_max2 = 0, transform_pass_level = 5, auto_joint_list = 1; int matrix_isomorphism_silent = 1, nonprojective_search = 0; int allowed_failures = 2, iteration_limit = 50000, auto_mu1 = 0, debug = 0; int double_column_pairs = 0, starting_tuple_orbit = 1; int double_column_triples = 0, double_column_groups = 0; int show_even_if_known = 0; char* PATH_PREFIX = ""; HIDE( ![ extern "C" long random( ); extern "C" int isspace(int); extern "C" int isdigit(int); ]! ) set_compile_file(code.c) String orsign = "\\|"; String left = "\\("; String right = "\\)"; String leftbracket = "\\["; String rightbracket = "\\]"; String number_pat = left + "0" + orsign + "[1-9][0-9]*" + right; String signed_number = "[+-]?" + number_pat; String pos_number = "[1-9][0-9]*"; String var = "[a-zA-Z][a-zA-Z_0-9]*"; String pos_term = left + pos_number + var + orsign + var + right; String op = left + "=" + orsign + "<=" + orsign + "<" + orsign + ">" + orsign + ">=" + right; String LHS_pat = "[-]?" + pos_term + left + "[+-]" + pos_term + right + "*"; String constraint_pat = left + LHS_pat + op + "[-]?" + number_pat + orsign + op + "[-]?" + number_pat + right; String label_pat = "\\[[a-zA-Z_0-9]+\\]"; String bang_label_pat = left + label_pat + orsign + "\\[[a-zA-Z_0-9]+!\\]" + right; String gen_label_pat = "\\[[a-z.:A-Z_0-9!]+\\]"; index_method(list_of) String list_of(const String& s, const String& delim = ",") { return left + left + s + right + delim + right + "*" + left + s + right; } index_method(zero_or_more) String zero_or_more(const String& s, const String& delim = ",") { return left + orsign + left + s + delim + right + "*" + s + right; } String config_list_piece = "\\[[*{}a-z.,:A-Z_0-9!]+\\]"; String config_list = zero_or_more(config_list_piece); String pos_list = list_of(pos_number); TEX(![ If {\tt s} is a string and {\tt x} is a regular expression, {\tt take(s, x)} equals the largest part of {\tt s} which matches {\tt x}; {\tt s} is replaced s by what is left. ]!) String take(String& s, const Regex& x) { String y = s.at(x); s.del(x); return y; } index_method(take) inline String take(String& s, const String& t) { return take(s, Regex(t)); } inline String take(String& s, char* t) { return take(s, Regex(t)); } index_method(str) String str(Rational x) { if ( x.denominator( ) == 1 ) return dec( x.numerator( ) ); else { return String("(") + dec( x.numerator( ) ) + "/" + dec( x.denominator( ) ) + ")"; } } index_method(take_int) int take_int(String& s, const Regex& x) { return as_int( take(s,x) ); } index_method(even) inline int even(int i) { return !(i % 2); } index_method(odd) inline int odd(int i) { return i % 2; } TEX( ![ \verb|log2(n, low, high)|: For $n \in \N$, set \verb|low| $= \floor{\log_2(n)}$, \verb|high| $ = \ceiling{\log_2(n)}$. ]! ) index_method(log2) void log2( const Integer& n, Integer& low, Integer& high ) { low = Integer( lg(n) ); high = low; if ( n != Ipow(2, low.as_long( )) ) ++high; } index_method(round_down_to_power_of_2) Integer round_down_to_power_of_2( Integer n ) { return Ipow( 2, lg(n) ); } index_method(round_up_to_power_of_2) Integer round_up_to_power_of_2( Integer n ) { Integer low, high; log2( n, low, high ); return Ipow( 2, high.as_long( ) ); } TEX( The following routine {\tt choose} for computing binomial coefficients is intended for occasional use only. \mindex{choose} ) Integer choose(int n, int k) BHIDE1( ![ if (debug) if ( n < 0 || k < 0 || k > n ) INTERNAL_ERROR( "Trying to calculate choose(" << n << "," << k << ")." ); ]!, ![ Integer prod = 1; ]! ) if ( 2 * k > n ) k = n - k; for ( int i = n - k + 1; i <= n; i++ ) prod *= i; for ( int i = 2; i <= k; i++ ) prod /= i; return prod; } TEX(![ \verb|class OSLList: | This is the GNU single-linked list ({\tt SLList}) class, templated over an ``ordered'' class, meaning a class with operators {\tt==} and {\tt>}. The list is supposed to be an ordered list, without repetition, and may be regarded as a set of T objects. \mindex{add}\mindex{contains}\mindex{intersection} ]!) set_include_file(OSLList.h) index_class(OSLList) index_method(Min) index_method(Max) index_method(del) index_method(element) index_method(diff) index_method(intersection) template class OSLList : public SLList { public: T element(int k) const { Pix g = first( ); for ( int i = 0; i < k; i++ ) next(g); return (*this)(g); } T Min( ) { return front( ); } T Max( ) const { Pix prev; forPixDef( p, *this ) prev = p; return (*this)(prev); } void add( T x ) { Pix prev = 0; forPixDef( p, *this ) { if ( (*this)(p) == x ) return; if ( (*this)(p) > x ) { ins_after( prev, x ); return; } prev = p; } append(x); } bool contains( T x ) const { forPixDef( p, *this ) { if ( (*this)(p) == x ) return true; if ( (*this)(p) > x ) return false; } return false; } void del( T x ) { Pix prev = 0; forPixDef( p, *this ) { if ( (*this)(p) > x ) return; if ( (*this)(p) == x ) { del_after(prev); return; } prev = p; } } friend bool operator==(const OSLList& a1, const OSLList& a2) { Pix p1 = a1.first( ), p2 = a2.first( ); while( p1 != 0 && p2 != 0 ) { if ( a1(p1) != a2(p2) ) return false; a1.next(p1); a2.next(p2); } return ( p1 == 0 && p2 == 0 ); } friend bool operator!=(const OSLList& a1, const OSLList& a2) { return !(a1 == a2); } friend bool operator<=(const OSLList& a1, const OSLList& a2) // subset? { Pix p1 = a1.first( ), p2 = a2.first( ); while( p1 != 0 && p2 != 0 ) { if ( a1(p1) == a2(p2) ) { a1.next(p1); a2.next(p2); } else if ( a2(p2) > a1(p1) ) return false; else a2.next(p2); } return p1 == 0; } friend OSLList intersection( const OSLList& a, const OSLList& b ) { OSLList c = a; forPixDef( p, a ) if ( !b.contains( a(p) ) ) c.del( a(p) ); return c; } friend OSLList diff( const OSLList& a, const OSLList& b ) { OSLList c = a; forPixDef( p, a ) if ( b.contains( a(p) ) ) c.del( a(p) ); return c; } HIDE(![ friend bool operator !=(OSLList< vector >, OSLList< vector >) { INTERNAL_ERROR( "operator!= for OSLList< vector > not defined"); } ]!) }; TEX(![ The following definitions of {\tt pair} and \verb|make_pair| are taken from [.stepanov lee.]. The {\tt pair} class has been modified by adding a default constructor. (Otherwise we would just include \verb|pair.h| from the gnu {\tt libstdc++} distribution.) We give similar versions of {\tt triple} and \verb|make_triple|. The following copyright and permission statements apply to the definitions of \verb|pair| and \verb|make_pair|: {\footnotesize \begin{quote} Copyright(c) 1994 Hewlett-Packard Company\\ \ \\ Permission to use, copy, modify, distribute and sell this document for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation. \end{quote} } \indexz{pair} ]!) set_include_file(pair_.h) template class pair { public: T1 first; T2 second; pair(const T1& x, const T2& y) : first(x), second(y) { } pair( ) { } }; index_method(make_pair) template inline pair make_pair(const T1& x, const T2& y) { return pair(x, y); } template inline bool operator==( const pair& p1, const pair& p2 ) { return ( p1.first == p2.first && p1.second == p2.second ); } template inline bool operator!=( const pair& p1, const pair& p2 ) { return ( p1.first != p2.first || p1.second != p2.second ); } index_class(triple) template class triple { public: T1 first; T2 second; T3 third; triple(const T1& x, const T2& y, const T3& z) : first(x), second(y), third(z) { } triple( ) { } friend bool operator==(const triple& t1, const triple& t2) { return t1.first == t2.first && t1.second == t2.second && t1.third == t2.third; } friend bool operator!=(const triple& t1, const triple& t2) { return !(t1 == t2); } }; index_method(make_triple) template inline triple make_triple(const T1& x, const T2& y, const T3& z) { return triple(x, y, z); } set_compile_file(code.c) HIDE(![ #include "OSLList.h" #include "pair_.h" template class matrix; template class ShareGraph; template class Map; class EquivRelIntList; class Permutation; class Permutationlist; class term; class term_sum; class constraint; class qvconstraint; class vconstraint; class constraintlist; class opt_card; class opt_table; class code; class partition; class wordtype; class mawhome; class mawhometable; class config; class config_share; class config_active; class weightlist; class codebase; class codehome; class codetable; ]! ) TEX(![ \block{Number, gf2, prevector, and vector classes} We give ``{\tt vector}'' and ``{\tt matrix}'' template classes with values in a class {\tt T}. Elements of vectors [resp.\ matrices] {\tt x} are accessed via expressions of the form {\tt x(}$i${\tt)} [resp.\ {\tt x(}$i${\tt,}$j${\tt)}] where $i,j \geq 0$. Also for a matrix, {\tt x(}$i${\tt)} will return the \th{i} row, viewed as a vector. Implementations of these classes are given (as needed in this program) for the cases {\tt T }$=${\tt\ number} and {\tt T }$=${\tt\ gf2}, where a {\tt number} represents a small nonnegative integer $(< 2^{15})$ and a ``{\tt gf2}'' object corresponds to an element of $\F_2$, represented here by a ``{\tt char}''. \indexz{number}\mindex{operator*(number, number)} ]!) set_include_file(numgf2.h) class number { public: short int x; number(const String&); number(int a) { x = a; } number( ) { x = 0; } operator int( ) { return x; } operator Rational( ) { return Rational(x); } operator++( ) { x++; } #define number_op(op) \ friend int operator op(number a, number b) { return a.x op b.x; } number_op(==) number_op(>=) number_op(<=) number_op(>) number_op(<) number_op(!=) number_op(+) number_op(-) number_op(*) friend int operator-(number a) { return -a.x; } number operator+=(number a) { x += a.x; } number operator/=(number a) { x /= a.x; } friend ostream& operator<<(ostream& s, number n) { return s << n.x; } }; set_compile_file(code.c) HIDE(![#include "numgf2.h"]!) number::number(const String& s) { if ( s.length( ) > 4 ) ERROR( "The string " << s << " is being processed as a small " << "integer. Either it is not an integer at all or else it is " << "too big." ); x = 0; for ( int i = 0; i < s.length( ); i++ ) { x *= 10; if ( s[i] < '0' || s[i] > '9' ) ERROR("non-digit encountered where not allowed"); x += s[i] - '0'; } } set_include_file(numgf2.h) index_method(operator*(gf2, gf2)) index_class(gf2) class gf2 { public: char x; gf2(int i = 0) { x = i; } friend gf2 operator+(gf2 a, gf2 b) { return a.x ^ b.x; } friend gf2 operator*(gf2 a, gf2 b) { return a.x & b.x; } friend int operator==(gf2 a, gf2 b) { return a.x == b.x; } friend int operator!=(gf2 a, gf2 b) { return a.x != b.x; } friend int operator<(gf2 a, gf2 b) { return a.x < b.x; } friend int operator>(gf2 a, gf2 b) { return a.x > b.x; } operator int( ) { return x; } gf2 operator+=(gf2 a) { x ^= a.x; } friend gf2 operator-(gf2 a) { return a; } gf2(char c) { x = c - '0'; } gf2(String s) { x = s[0]; } friend ostream& operator<<(ostream& s, gf2 a) { return s << char(a.x + '0'); } }; TEX( ![ The following template class {\tt extend} is intended to encapsulate a notion of {\it extended real number}, where {\tt R} is some class of real numbers. ]! ) index_class(extend) index_method(MinusInfinity) index_method(PlusInfinity) index_method(SetMinusInfinity) index_method(SetPlusInfinity) template class extend { public: R x; // value if finite // "inf" is -1 for -infinity, 0 for ordinary number, 1 for +infinity signed char inf; extend( ) { inf = 0; } extend(R a) : x(a), inf(0) { } extend(int a) : x(a), inf(0) { } bool MinusInfinity( ) const { return inf == -1; } bool PlusInfinity( ) const { return inf == 1; } void SetMinusInfinity( ) { x = 0; inf = -1; } void SetPlusInfinity( ) { x = 0; inf = 1; } operator R( ) { return x; } extend operator+=(R a) { x += a; } friend bool operator==(extend a, extend b) { return a.x == b.x && a.inf == b.inf; } friend bool operator==(R a, extend b) { return b.inf == 0 && a == b.x; } friend bool operator!=(extend a, R b) { return a.inf != 0 || a.x != b; } friend bool operator<(extend a, extend b) { if ( a.inf == 0 && b.inf == 0 ) return a.x < b.x; return a.inf < b.inf; } friend bool operator<(R a, extend b) { return (b.inf == 0) ? (a < b.x) : (b.inf == 1); } friend bool operator>(R a, extend b) { return (b.inf == 0) ? (a > b.x) : (b.inf == -1); } friend ostream& operator<<(ostream& s, extend a) { if ( a.inf == 0 ) return s << a.x; if ( a.inf == -1 ) return s << "MinusInfinity"; return s << "PlusInfinity"; } }; TEX(![ The template class ``{\tt prevector}'' is for vectors over any class. Later we give a template class ``{\tt vector}'', for which one needs a base class equipped with operators ``{\tt+}'', ``{\tt==}'', ``\verb|!=|'', and as well a zero object. The elements of a {\tt prevector} are pointed to by its {\tt x} member. If {\tt x} $= 0$, the {\tt prevector} is said to be {\it uninitialized}. In that case its {\tt length} member is undefined, and the {\tt prevector} is usable only as an operand to {\tt operator=}, \verb|set_size|, the copy constructor, and the destructor. \indexz{prevector} ]!) index_method(set_size) index_method(merge) index_method(diff) index_method(resize) index_method(set_and_take) index_method(member) index_method(subset) index_method(intersection_size) index_method(pos) index_method(make_listv) set_include_file(prevector.h) template class prevector { public: // the data T* x; // the elements int length; // number of elements // constructors, the destructor, and a resizer prevector( ) { x = 0; } prevector(int n) // Construct prevector with n default elements. { x = new T[n]; length = n; } prevector(String, char = ','); // constructor from String, using char // as delim prevector(const prevector& v) { if ( v.x == 0 ) x = 0; else { length = v.length; x = new T[length]; for ( int i = 0; i < length; i++ ) x[i] = v(i); } } prevector(const SLList& list) { length = list.length( ); x = new T[length]; int j = 0; forPixDef( i, list ) x[j++] = list(i); } prevector(const DLList&); prevector(int length, T* x) : length(length), x(x) { } ~prevector( ) { if ( x != 0 ) delete [ ] x; } void set_size(int n) // resize, destroying contents { if ( x != 0 && length == n ) return; if ( x != 0 ) delete [ ] x; x = new T[n]; length = n; } void resize(int n) // Boy is this inefficient! { T* x_new = new T[n]; for ( int i = 0; i < min( n, length ); i++ ) x_new[i] = x[i]; delete [ ] x; x = x_new; length = n; } // other methods void set_and_take( const prevector& v, int M ) { set_size(M); for ( int i = 0; i < M; i++ ) (*this)(i) = v(i); } prevector& operator=(const prevector& v) { if ( v.x == 0 ) { if ( x != 0 ) delete [ ] x; x = 0; } else { if ( x == 0 ) { length = v.length; x = new T[length]; } else if ( length != v.length ) { delete [ ] x; length = v.length; x = new T[length]; } for ( int i = 0; i < v.length; i++ ) (*this).x[i] = v(i); } } bool member( const T& t ) const { for ( int i = 0; i < length; i++ ) if ( (*this)(i) == t ) return true; return false; } friend bool subset( const prevector& v, const prevector& w ) { for ( int i = 0; i < v.length; i++ ) if ( !w.member( v(i) ) ) return false; return true; } friend SLList make_listv(const prevector& v) { SLList l; for ( int i = 0; i < v.length; i++ ) l.append( v(i) ); return l; } friend number intersection_size( const prevector& v, const prevector& w ) { number count; for ( int i = 0; i < v.length; i++ ) if ( w.member( v(i) ) ) ++count; return count; } int find(const T& t) const { for ( int i = 0; i < length; i++ ) if ( (*this)(i) == t ) return i; return -1; } // Do binary search to return position in sorted vector, else -1. int pos( const T& t, int (*cmp)(const T&, const T&) ) const { if ( length == 0 ) return -1; int first = 0, last = length - 1, next, relationship; while (1) { if ( first == last ) return (t == (*this)(last)) ? last : -1; next = first + (last - first) / 2; relationship = cmp( t, (*this)(next) ); if ( relationship == 0 ) return next; if ( relationship > 0 ) first = next + 1; else last = next; } } prevector complement( ) const; T& operator( )(int i) const BHIDE2( ![ #ifdef DEBUG if ( x == 0 || i < 0 || i >= length ) INTERNAL_ERROR("illegal vector reference"); #endif ]!, ![ return x[i]; } ]! ) T& operator[ ](int i) { if ( i >= length ) resize( max( (length * 6)/5, length + 5 ) ); return x[i]; } friend bool operator==(const prevector& v1, const prevector& v2) BHIDE2( ![ #ifdef DEBUG if ( v1.x == 0 || v2.x == 0 ) INTERNAL_ERROR("== invoked on uninitialized vector(s)"); #endif ]!, ![ if ( v1.length != v2.length ) return false; ]! ) for ( int i = 0; i < v1.length; i++ ) if ( v1(i) != v2(i) ) return false; return true; } friend bool operator!=(const prevector& v1, const prevector& v2) { return !(v1 == v2); } HIDE( ![ friend ostream& operator<<(ostream&, const prevector&); ]! ) void sort( int (*cmp)(const T&, const T&) ); void sort( int (*cmp)(const T&, const T&), Permutation& ); void unique_sort( int (*cmp)(const T&, const T&) ); TEX( \begin{quote} Merge two unique-sorted {\tt prevector}s having no overlap. \end{quote} ) friend void merge( const prevector& Xa, const prevector& Xb, prevector& Xt, int (*cmp)(const T&, const T&) ) { int i = 0, j = 0; Xt.set_size(Xa.length + Xb.length); while(1) { if ( i == Xa.length && j == Xb.length ) break; if ( i == Xa.length ) goto grab_b; if ( j == Xb.length ) goto grab_a; if ( (*cmp)( Xa(i), Xb(j) ) > 0 ) goto grab_b; grab_a: Xt( i + j ) = Xa(i); i++; continue; grab_b: Xt( i + j ) = Xb(j); j++; } return; } TEX(![ \begin{quote} Set $Xb = Xc - Xa$, where $Xc$, $Xa$ are unique-sorted {\tt prevector}s. \end{quote} ]!) friend void diff( const prevector& Xc, const prevector& Xa, prevector& Xb, int (*cmp)(const T&, const T&) ) { int i = 0, j = 0, k = 0, c; prevector Xt(Xc.length); while(1) { if ( j == Xc.length ) break; if ( i == Xa.length ) { Xt(k++) = Xc(j++); continue; } c = (*cmp)( Xa(i), Xc(j) ); if ( c == 0 ) { i++; j++; } else if ( c > 0 ) Xt(k++) = Xc(j++); else i++; } Xb.set_size(k); for ( i = 0; i < k; i++ ) Xb(i) = Xt(i); } }; set_compile_file(code.c) HIDE(![#include "prevector.h"]!) template prevector::prevector(const DLList& list) { length = list.length( ); x = new T[length]; int j = 0; forPixDef( i, list ) x[j++] = list(i); } set_compile_file(sort.cc) TEX(![ The following material, up through the routine ``\verb|prevector::sort|'' is taken essentially verbatim from the {\tt Vec} implementation in the GNU C++ Class Library. The only changes made are that comments have been deleted, spacing has been changed, the routine name and argument names have been changed. This material is covered by the GNU General Public License [.FSF general public license.]. { \footnotesize ]!) HIDE(![#include "homedefs.h"]!) index_method(SWAP) template static inline void SWAP(T* A, T* B) { T tmp = *A; *A = *B; *B = tmp; } #define BYTES_PER_WORD 8 #define BYTES_PER_LONG 4 #define STACK_SIZE (BYTES_PER_WORD * BYTES_PER_LONG) #define PUSH(LOW,HIGH) do {top->lo = LOW;top++->hi = HIGH;} while (0) #define POP(LOW,HIGH) do {LOW = (--top)->lo;HIGH = top->hi;} while (0) #define STACK_NOT_EMPTY (stack < top) #define MAX_THRESH 4 index_method(sort) template void prevector::sort( int (*cmp)(const T&, const T&) ) { struct stack_node { T *lo; T *hi; }; T pivot_buffer; int max_thresh = MAX_THRESH; if (length > MAX_THRESH) { T *lo = x; T *hi = lo + (length - 1); T *left_ptr; T *right_ptr; stack_node stack[STACK_SIZE]; stack_node *top = stack + 1; while (STACK_NOT_EMPTY) { { T *pivot = &pivot_buffer; { T *mid = lo + ((hi - lo) >> 1); if ((*cmp) (*mid, *lo) < 0) SWAP (mid, lo); if ((*cmp) (*hi, *mid) < 0) { SWAP (mid, hi); if ((*cmp) (*mid, *lo) < 0) SWAP (mid, lo); } *pivot = *mid; pivot = &pivot_buffer; } left_ptr = lo + 1; right_ptr = hi - 1; do { while ((*cmp) (*left_ptr, *pivot) < 0) left_ptr += 1; while ((*cmp) (*pivot, *right_ptr) < 0) right_ptr -= 1; if (left_ptr < right_ptr) { SWAP (left_ptr, right_ptr); left_ptr += 1; right_ptr -= 1; } else if (left_ptr == right_ptr) { left_ptr += 1; right_ptr -= 1; break; } } while (left_ptr <= right_ptr); } if ((right_ptr - lo) <= max_thresh) { if ((hi - left_ptr) <= max_thresh) POP (lo, hi); else lo = left_ptr; } else if ((hi - left_ptr) <= max_thresh) hi = right_ptr; else if ((right_ptr - lo) > (hi - left_ptr)) { PUSH (lo, right_ptr); lo = left_ptr; } else { PUSH (left_ptr, hi); hi = right_ptr; } } } { T *end_ptr = x + 1 * (length - 1); T *run_ptr; T *tmp_ptr = x; T *thresh = (end_ptr < (x + max_thresh))? end_ptr : (x + max_thresh); for (run_ptr = tmp_ptr + 1; run_ptr <= thresh; run_ptr += 1) if ((*cmp) (*run_ptr, *tmp_ptr) < 0) tmp_ptr = run_ptr; if (tmp_ptr != x) SWAP (tmp_ptr, x); for (run_ptr = x + 1; (tmp_ptr = run_ptr += 1) <= end_ptr; ) { while ((*cmp) (*run_ptr, *(tmp_ptr -= 1)) < 0); if ((tmp_ptr += 1) != run_ptr) { T *trav; for (trav = run_ptr + 1; --trav >= run_ptr;) { T c = *trav; T *hi, *lo; for (hi = lo = trav; (lo -= 1) >= tmp_ptr; hi = lo) *hi = *lo; *hi = c; } } } } } TEX( } ) DEFINE(![INSTANTIATE0]!, ![ ifelse($#,2, ,$3, , , patsubst(template $1;, $2, ![ $3 ]!) ![INSTANTIATE0($1,$2,SHIFT(SHIFT(SHIFT($@))))]! ) ]!) DEFINE(![INSTANTIATE]!, ![ |-> current_compile_file INSTANTIATE0($@) |-> tex/code.tex, current_compile_file ]!) INSTANTIATE( ![class prevector]!, T, number, String, wordtype, Permutation, vector, vector, int, ![![pair]!]!, ![![pair]!]!, ![![pair< pair< matrix, int >, int >]!]! ) INSTANTIATE( ![void prevector::sort( int (*cmp)(const T&, const T&) )]!, T, number, String, wordtype, Permutation, vector, vector, int, ![![pair]!]!, ![![pair]!]!, ![![pair< pair< matrix, int >, int >]!]! ) TEX( ![ The following sort routine returns a permutation which if applied to the original vector would cause it to be sorted. The implementation is a stupid bubble sort. ]! ) index_method(sort) template void prevector::sort( int (*cmp)(const T&, const T&), Permutation& p ) { bool no_change; p = Permutation(length); do { no_change = true; for ( int i = 1; i < length; i++ ) if ( (*cmp)( (*this)(i-1), (*this)(i) ) > 0 ) { swap( (*this)(i-1), (*this)(i) ); p.transpose( i, i+1 ); no_change = false; } } while( !no_change ); } INSTANTIATE( ![class prevector]!, T, number ) INSTANTIATE( ![void prevector::sort( int (*cmp)(const T&, const T&), Permutation& )]!, T, number ) index_method(unique_sort) template void prevector::unique_sort( int (*cmp)(const T&, const T&) ) { if ( length <= 1 ) return; sort(cmp); prevector G = *this; int i, j = 0; for ( i = 1; i < length; i++ ) if ( G(i) != G(j) ) G(++j) = G(i); set_size(j + 1); for ( i = 0; i < j + 1; i++ ) (*this)(i) = G(i); } INSTANTIATE( ![class prevector]!, T, String, wordtype, vector, vector, Permutation ) INSTANTIATE( ![void prevector::unique_sort(int (*cmp)(const T&, const T&))]!, T, vector, vector, wordtype, String, Permutation ) index_method(cmp_second) template int cmp_second( const pair& a, const pair& b ) { return a.second - b.second; } template int cmp_secondI( const pair& a, const pair& b ) { return sign(a.second - b.second); } |-> current_compile_file template class pair; template int cmp_secondI( const pair&, const pair& ); |-> tex/code.tex, current_compile_file index_method(sort_by_second) template void sort_by_second( prevector< pair >& p ) { p.sort( &cmp_second ); } |-> current_compile_file template class pair; template class pair, int>; template class pair< pair, int>, int>; template class prevector< pair >; template class prevector< pair, int> >; template class prevector< pair< pair, int>, int> >; template void sort_by_second( prevector< pair,int> >& ); template void sort_by_second( prevector< pair,int> >& ); template void sort_by_second( prevector< pair,int>,int> >& ); template void sort_by_second( prevector< pair >& ); |-> tex/code.tex, current_compile_file set_compile_file(code.c) index_method(String_cmp) int String_cmp(const String& a, const String& b) { return compare(a, b); } index_method(rcmp) int rcmp(const number& a, const number& b) { return a - b; } index_method(rcmp) int rcmp(const int& a, const int& b) { return a - b; } set_compile_file(prevec1.cc) HIDE(![#include "basedefs.h"]!) index_method(complement) prevector prevector::complement( ) const { prevector answer(*this); for ( int i = 0; i < length; i++ ) if ( answer(i) ) answer(i) = 0; else answer(i) = 1; return answer; } TEX(![ {\tt prevector(string, delimiter)}:\ Construct a prevector from a string, consisting of string representations of {\tt T} objects, separated by the given delimiter, which defaults to a comma. If the delimiter is $0$, the string representations of {\tt T} objects are assumed to be single characters. For efficiency reasons and also because there is no uniform way to handle conversions from strings to {\tt T} objects, we give a separate implementation for each type. Note also that {\tt unpack} (given later) could also be handled as a constructor; this would be more consistent. ]!) prevector::prevector(String s, char delim) { if ( delim == 0 ) { length = s.length( ); x = new gf2[length]; for ( int i = 0; i < length; i++ ) { if ( s[i] != '0' && s[i] != '1' ) ERROR( s << " is not a string of 0's and 1's" ); x[i] = s[i] - '0'; } } else if ( s.length( ) == 0 ) { length = 0; x = new gf2[0]; } else { if ( s.length( )/2 * 2 != s.length( ) ) ERROR( s << " is not a " << delim << "-separated string of 0's and 1's" ); length = (s.length( ) + 1)/2; x = new gf2[length]; for ( int i = 0; i < length; i++ ) { if ( (s[2*i] != '0' && s[2*i] != '1') || (i > 0 && s[2*i-1] != delim) ) ERROR( s << " is not a " << delim << "-separated string of 0's and 1's" ); x[i] = s[2*i] - '0'; } } } prevector::prevector(String s, char delim) { static Regex any_char("."); static Regex signed_number_pat(signed_number); if ( delim == 0 ) length = s.length( ); else if ( s.length( ) == 0 ) length = 0; else length = s.freq(delim) + 1; x = new Integer[length]; for ( int i = 0; i < length; i++ ) { if ( delim == 0 ) x[i] = take(s, any_char)[0] - '0'; else { x[i] = atoI( take(s, signed_number_pat) ); if ( i < length - 1 ) require_char(s, delim); } } if ( s.length( ) > 0 ) ERROR("trailing junk?"); } HIDE( ![ prevector::prevector(String s, char delim) { INTERNAL_ERROR( "prevector constructor from String " << "does not exist" ); } ]! ) prevector::prevector(String s, char delim) { if ( delim == 0 ) length = s.length( ); else { if ( s.length( ) == 0 ) length = 0; else length = s.freq(delim) + 1; } x = new number[length]; int where = 0; for ( int i = 0; i < length; i++ ) { if ( delim == 0 ) { if ( !isdigit(s[where]) ) ERROR( "\"" << s << "\" is not a string of digits" ); x[i] = s[where] - '0'; } else { x[i] = 0; while ( where != s.length( ) && s[where] != delim ) { if ( !isdigit(s[where]) ) ERROR( "\"" << s << "\" is not a \"" << delim << "\"-separated list of numbers" ); x[i] = (10 * x[i]) + (s[where] - '0'); if ( x[i] > 10000 ) ERROR( "large integer encountered where not allowed"); where++; } } where++; } } index_method(set_zero) index_method(weight) index_method(as_poly) index_method(divides_as_poly) set_include_file(vector_.h) index_class(vector) template class vector : public prevector { public: TEX( ![ \classtextt{Constructors} ]! ) vector(const SLList& l) : prevector(l) { } vector(const DLList& l) : prevector(l) { } vector(const prevector& v) : prevector(v) { } vector( ) { x = 0; } vector(int n) { x = new T[n]; length = n; } // construct default vector vector(String s, char c = ',') : prevector(s, c) { } TEX( ![ \classtextt{Other methods} ]! ) vector& vector::operator+=(const vector& v) { for ( int i = 0; i < v.length; i++ ) (*this).x[i] = (*this)(i) + v(i); } vector& vector::operator-=(const vector& v) { for ( int i = 0; i < v.length; i++ ) (*this).x[i] = (*this)(i) - v(i); } vector& vector::operator*=(const T&); bool if_zero( ) const; bool if_nonzero( ) const; void set_zero( ) { for ( int i = 0; i < length; i++ ) (*this)(i) = 0; } int weight( ) const; void set_random( ); bool advance( ); // get lexicographically next vector operator String( ) const; friend vector operator+(const vector& a, const vector& b) BHIDE2( ![ #ifdef DEBUG if ( a.x == 0 || b.x == 0 ) INTERNAL_ERROR("operator+ invoked on uninitialized vector(s)"); #endif ]!, ![ vector c(a.length); ]! ) for ( int i = 0; i < a.length; i++ ) c(i) = a(i) + b(i); return c; } friend vector operator-(const vector& a, const vector& b) BHIDE2( ![ #ifdef DEBUG if ( a.x == 0 || b.x == 0 ) INTERNAL_ERROR("operator- invoked on uninitialized vector(s)"); #endif ]!, ![ vector c(a.length); ]! ) for ( int i = 0; i < a.length; i++ ) c(i) = a(i) - b(i); return c; } friend vector operator-(const vector& a) { vector b(a.length); for ( int i = 0; i < b.length; i++ ) b(i) = -a(i); return b; } HIDE( ![ friend int operator<(const vector&, const vector&); friend int cmp(const vector&, const vector&); ]! ) friend int operator>(const vector& a, const vector& b) { return b < a; } friend String as_poly(const vector& v) { String p = "1"; for ( int i = 1; i < v.length; i++ ) if ( v(i) != 0 ) { p += " + "; if ( v(i) != 1 ) p += dec(v(i)); p += (String("t^") + dec(i)); } return p; } friend bool divides_as_poly( const vector& f, vector g ) { int i, dg = g.length-1; for ( i = f.length-1; i >= 0; i-- ) if ( f(i) != 0 ) break; int df = i; // degree of f while (1) { for ( i = dg; i >= 0; i-- ) if ( g(i) != 0 ) break; dg = i; // degree of g if ( dg == -1 ) return true; if ( df > dg ) return false; for ( i = 0; i <= df; i++ ) g(i + dg - df) += f(i); } } }; set_compile_file(code.c) HIDE(![#include "vector_.h"]!) template vector& vector::operator*=(const T& m) { for ( int i = 0; i < length; i++ ) (*this).x[i] *= m; } HIDE( ![ template vector& vector::operator*=(const Integer& m); ]! ) HIDE( ![ prevector< vector >::prevector(const DLList< vector >& list) { length = list.length( ); x = new vector[length]; int j = 0; forPixDef( i, list ) x[j++] = list(i); } ]! ) TEX(![ Lexicographically compare two vectors, which are supposed to be of the same length. The ``cmp'' routine returns $1$ if the first argument is bigger, $-1$ if it is smaller, $0$ if both arguments are equal. The cmp code is instantiated to {\tt T} = {\tt number} since otherwise the compiler forgets to instantiate it. Cmp moved lower in code. ]!) template int operator<(const vector& a, const vector& b) BHIDE1( ![ #ifdef DEBUG if ( a.x == 0 || b.x == 0 ) INTERNAL_ERROR("operator< invoked on uninitialized vector(s)"); #endif ]!, ![ for ( int i = 0; i < a.length; i++ ) ]! ) { if ( a(i) < b(i) ) return 1; if ( a(i) > b(i) ) return 0; } return 0; } HIDE( ![ int operator<(const vector& a, const vector& b) { #ifdef DEBUG if ( a.x == 0 || b.x == 0 ) INTERNAL_ERROR("operator< invoked on uninitialized vector(s)"); #endif for ( int i = 0; i < a.length; i++ ) { if ( a(i) < b(i) ) return 1; if ( a(i) > b(i) ) return 0; } return 0; } int operator<(const vector& a, const vector& b) { #ifdef DEBUG if ( a.x == 0 || b.x == 0 ) INTERNAL_ERROR("operator< invoked on uninitialized vector(s)"); #endif for ( int i = 0; i < a.length; i++ ) { if ( a(i) < b(i) ) return 1; if ( a(i) > b(i) ) return 0; } return 0; } ]! ) index_method(if_zero) template bool vector::if_zero( ) const { for ( int i = 0; i < length; i++ ) if ( (*this)(i) != 0 ) return false; return true; } index_method(if_nonzero) template bool vector::if_nonzero( ) const { for ( int i = 0; i < length; i++ ) if ( (*this)(i) == 0 ) return false; return true; } HIDE( ![ bool vector::if_zero( ) const { for ( int i = 0; i < length; i++ ) if ( (*this)(i) != 0 ) return false; return true; } bool vector::if_nonzero( ) const { for ( int i = 0; i < length; i++ ) if ( (*this)(i) == 0 ) return false; return true; } bool vector::if_zero( ) const { for ( int i = 0; i < length; i++ ) if ( (*this)(i) != 0 ) return false; return true; } bool vector::if_zero( ) const { for ( int i = 0; i < length; i++ ) if ( (*this)(i) != 0 ) return false; return true; } bool vector::if_zero( ) const { for ( int i = 0; i < length; i++ ) if ( (*this)(i) != 0 ) return false; return true; } bool vector::if_zero( ) const { for ( int i = 0; i < length; i++ ) if ( (*this)(i) != 0 ) return false; return true; } ]! ) TEX( There appears to be duplication of what follows with {\tt ycmp}. ) set_include_file(cmp.h) index_method(cmp) template inline int cmp(const vector& a, const vector& b) BHIDE1( ![ #ifdef DEBUG if ( a.x == 0 || b.x == 0 ) INTERNAL_ERROR("cmp invoked on uninitialized vector(s)"); #endif ]!, ![ register int i, n = a.length; ]! ) for ( i = 0; i < n; i++ ) { if ( a(i) > b(i) ) return 1; if ( a(i) < b(i) ) return -1; } return 0; } inline int cmp(const vector< vector >& a, const vector< vector >& b) BHIDE1( ![ #ifdef DEBUG if ( a.x == 0 || b.x == 0 ) INTERNAL_ERROR("cmp invoked on uninitialized vector(s)"); #endif ]!, ![ register int i, n = a.length, c; ]! ) for ( i = 0; i < n; i++ ) { c = cmp( a(i), b(i) ); if ( c > 0 ) return 1; if ( c < 0 ) return -1; } return 0; } HIDE( ![ inline int cmp(const vector& a, const vector& b) { #ifdef DEBUG if ( a.x == 0 || b.x == 0 ) INTERNAL_ERROR("cmp invoked on uninitialized vector(s)"); #endif register int i, n = a.length; for ( i = 0; i < n; i++ ) { if ( a(i) > b(i) ) return 1; if ( a(i) < b(i) ) return -1; } return 0; } ]! ) set_compile_file(misc.cc) HIDE(![#include "basedefs.h"]!) index_method(weight) int vector::weight( ) const { int sum = 0; for ( int i = 0; i < length; i++ ) sum += x[i].x; return sum; } int vector::weight( ) const { int sum = 0; for ( int i = 0; i < length; i++ ) sum += x[i].x; return sum; } index_method(set_random) void vector::set_random( ) { for ( int i = 0; i < length; i++ ) x[i] = char(random( )) & 01; } #include "quad.h" template ostream& operator<<(ostream& s, const prevector& v) { s << "{"; for ( int i = 0; i < v.length; i++ ) { s << v(i); if ( i != v.length - 1 ) s << ","; } return s << "}"; } ostream& operator<<(ostream& s, const prevector& v) { for ( int i = 0; i < v.length; i++ ) s << v(i); return s; } HIDE( ![ ostream& operator<<(ostream& s, const prevector& v) { s << "{"; for ( int i = 0; i < v.length; i++ ) { s << v(i); if ( i != v.length - 1 ) s << ","; } return s << "}"; } ostream& operator<<(ostream& s, const prevector& v) { s << "{"; for ( int i = 0; i < v.length; i++ ) { s << v(i); if ( i != v.length - 1 ) s << ","; } return s << "}"; } ostream& operator<<(ostream& s, const prevector& v) { s << "{"; for ( int i = 0; i < v.length; i++ ) { s << v(i); if ( i != v.length - 1 ) s << ","; } return s << "}"; } ostream& operator<<(ostream& s, const prevector& v) { s << "{"; for ( int i = 0; i < v.length; i++ ) { s << v(i); if ( i != v.length - 1 ) s << ","; } return s << "}"; } ostream& operator<<(ostream& s, const prevector& v) { s << "{"; for ( int i = 0; i < v.length; i++ ) { s << v(i); if ( i != v.length - 1 ) s << ","; } return s << "}"; } ostream& operator<<(ostream& s, const prevector& v) { s << "{"; for ( int i = 0; i < v.length; i++ ) { s << v(i); if ( i != v.length - 1 ) s << ","; } return s << "}"; } ostream& operator<<(ostream& s, const prevector& v) { s << "{"; for ( int i = 0; i < v.length; i++ ) { s << v(i); if ( i != v.length - 1 ) s << ","; } return s << "}"; } ]! ) vector::operator String( ) const { String s; for ( int i = 0; i < length; i++ ) s += char( (*this)(i).x + '0' ); return s; } vector::operator String( ) const { String s = "{"; for ( int i = 0; i < length; i++ ) { s += String((*this)(i)); if ( i != length - 1 ) s += ","; } s += "}"; return s; } HIDE( ![ vector::operator String( ) const { INTERNAL_ERROR("String(double) not implemented"); } vector::operator String( ) const { INTERNAL_ERROR("String(Quad) not implemented"); } vector::operator String( ) const { INTERNAL_ERROR("String(Rational) not implemented"); } ]! ) vector::operator String( ) const { String s = "{"; for ( int i = 0; i < length; i++ ) { s += dec((*this)(i)); if ( i != length - 1 ) s += ","; } s += "}"; return s; } TEX( ![ Change a vector over {\tt gf2} to the vector which is lexicographically next. Return {\tt false} upon failure, i.e.\ if we're at the last vector $(11\ldots1)$; otherwise return {\tt true}. ]! ) index_method(advance) bool vector::advance( ) { int i, j; for ( i = length-1; i >= 0; i-- ) if ( x[i] == 0 ) break; if ( i == -1 ) return false; for ( j = length-1; j > i; j-- ) x[j] = 0; x[i] = 1; return true; } TEX(![ Dot product. I've replaced {\tt v(i)} with {\tt v.x[i]} and likewise for {\tt w(i)}, but I haven't checked to see if this really speeds up the code. ]!) set_include_file(dot.h) index_method(operator*(vector$<$gf2$>$, vector$<$number$>$)) inline int operator*(const vector& v, const vector& w) { static int i, sum; sum = 0; for ( i = 0; i < v.length; i++ ) if ( v.x[i] ) sum += w.x[i]; return sum; } index_method(operator*(vector$<$T$>$, vector$<$T$>$)) template inline T operator*(const vector&v, const vector& w) { T dot = 0; for ( int i = 0; i < v.length; i++ ) dot += v(i) * w(i); return dot; } HIDE( ![ inline gf2 operator*(const vector&v, const vector& w) { gf2 dot = 0; for ( int i = 0; i < v.length; i++ ) dot += v(i) * w(i); return dot; } inline double operator*(const vector&v, const vector& w) { double dot = 0; for ( int i = 0; i < v.length; i++ ) dot += v(i) * w(i); return dot; } inline Quad operator*(const vector&v, const vector& w) { Quad dot = 0; for ( int i = 0; i < v.length; i++ ) dot += v(i) * w(i); return dot; } inline Rational operator*(const vector&v, const vector& w) { Rational dot = 0; for ( int i = 0; i < v.length; i++ ) dot += v(i) * w(i); return dot; } ]! ) index_method(idot) inline int idot(const vector& v, const vector& w) { static int i, sum; sum = 0; for ( i = 0; i < v.length; i++ ) sum += v.x[i].x & w.x[i].x; return sum; } set_compile_file(code.c) HIDE(![#include "quad.h"]!) HIDE(![#include "dot.h"]!) TEX(![ {\tt unpack(}{\it string}{\tt,}$d${\tt)}:\ Break a string up into pieces, using the given string $d$ as a delimiter. Return a prevector of strings. The default delimiter is a comma. If the delimiter is the null string, then the pieces will be single characters. ]!) index_method(unpack) prevector unpack(String s, String delim = ",") { SLList list; if ( s.length( ) == 0 ) return prevector(list); if ( delim.length( ) != 0 ) { String part; while( s.length( ) != 0 ) { if ( s.contains( delim, 0 ) ) { s.del(delim); list.append(part); part = ""; } else { part += s[0]; s.del( s[0] ); } } list.append(part); } else { for ( int i = 0; i < s.length( ); i++ ) list.append(s[i]); } return prevector(list); } TEX(![ \block{EquivRelIntList class} The class ``{\tt EquivRelIntList}'' manages an equivalence relation on the set $0,\ldots,n-1$. In essence, this is kept track of internally via a digraph which is a disjoint union of cycles. \indexz{EquivRelIntList} ]! ) set_include_file(permutation.h) class EquivRelIntList : public vector { public: EquivRelIntList(int n) : vector(n) // construct discrete ~ relation { for ( int i = 0; i < length; i++ ) (*this)(i) = i; } EquivRelIntList(const vector&, bool); // use equality as the // relation on a given list bool equiv(int,int) const; // test for equivalence void join(int,int); // make two integers equivalent int size(int) const; // compute size of an equivalence class int orbit_count( ) const; // compute number of orbits bool minimal(number x) // Is x the minimal element of its class? { number i = x; while ( (i = (*this)(i)) > x ); return x <= i; } }; set_include_file(somedefs.h) HIDE( ![ extern "C" long random( ); #include #include #include #include "macros.h" #include "numgf2.h" #include "prevector.h" #include "vector_.h" #include "cmp.h" #include "quad.h" ]! ) set_compile_file(permutation.cc) HIDE( ![ // #define DEBUG class Permutation; #include "somedefs.h" #include "permutation.h" ]! ) TEX(![ For the following routine, the {\tt bool} argument is not used -- it is just there to prevent the compiler from getting confused. ]!) EquivRelIntList::EquivRelIntList(const vector& v, bool b) : vector(v.length) { for ( int i = 0; i < length; i++ ) { int j; for ( j = i+1; j < length; j++ ) if ( v(j) == v(i) ) { (*this)(i) = j; break; } if ( j == length ) for ( j = 0; j <= i; j++ ) if ( v(j) == v(i) ) { (*this)(i) = j; break; } } } index_method(equiv) bool EquivRelIntList::equiv(int a, int b) const { if ( a == b ) return true; int c = a; while ( (c = (*this)(c)) != a ) if ( c == b ) return true; return false; } index_method(join) void EquivRelIntList::join(int a, int b) { if ( a == b ) return; // Determine if a is already equivalent to b. // Also, find out what comes before a. int c = (*this)(a), before_a = a; while( c != a ) { if ( c == b ) return; // a ~ b already before_a = c; c = (*this)(c); } // Make a equivalent to b. (*this)(before_a) = (*this)(b); (*this)(b) = a; } index_method(size) int EquivRelIntList::size(int a) const { int s = 1, b = a; while( (b = (*this)(b)) != a ) s++; return s; } index_method(orbit_count) int EquivRelIntList::orbit_count( ) const { int count = 0; for ( int i = 0; i < length; i++ ) { int a = (*this)(i); int b = a; while ( (b = (*this)(b)) != a ) if ( b < a ) break; if ( a == b ) count++; } return count; } TEX(![ \block{Permutation, Permutationlist classes} The {\tt Permutation} class we define is inefficient for a number of reasons, including the fact that for our implementation, a Permutation of $n$ requires (on most machines) $2n$ bytes to store, yet if $n < 256$, certainly $n$ bytes are sufficient. \indexz{Permutation}\mindex{mul} ]!) set_include_file(permutation.h) index_method(inverse) class Permutation : public vector { public: Permutation(const String&); Permutation(int); // construct the identity Permutation Permutation(const EquivRelIntList&); Permutation( ) { } Permutation(const Permutation& p) : vector(p) { } Permutation(const vector& v) : vector(v) { } Permutation inverse( ) const { Permutation p(length); for ( int i = 0; i < length; i++ ) p( (*this)(i) - 1 ) = i + 1; return p; } void act(prevector&) const; void act(prevector&) const; void act(prevector&) const; void act(prevector&) const; void act(prevector&) const; void transpose(int,int); // p |--> transpose(i,j) o p String as_cycle_product( ) const; HIDE( ![ friend Permutation operator*(const Permutation&, const Permutation&); ]! ) int order( ) const { Permutation p(*this), id(length); int o = 1; while(1) { if ( p == id ) return o; o++; p = p * (*this); } } friend void pmul(const Permutation& p1, const Permutation& p2, Permutation& q) { q.set_size( p1.length ); for ( int i = 0; i < p1.length; i++ ) q(i) = p1( p2(i) - 1 ); } HIDE( ![ friend ostream& operator<<(ostream&, const Permutation&); ]! ) }; set_compile_file(permutation.cc) Permutation::Permutation(const String& s) : vector(s) { for ( int i = 1; i <= length; i++ ) { int j; for ( j = 0; j < length; j++ ) if ( (*this)(j) == i ) break; if ( j == length ) ERROR("invalid Permutation"); } } Permutation::Permutation(int n) : vector(n) { for ( int i = 0; i < n; i++ ) (*this)(i) = i+1; } index_method(act) #define PERMUTATION_ACT(TYPE) \ void Permutation::act(prevector& v) const \ { TYPE* x_new = new TYPE[v.length]; \ for ( int i = 0; i < v.length; i++ ) \ x_new[(*this)(i) - 1] = v(i); \ delete [ ] v.x; \ v.x = x_new; } PERMUTATION_ACT(gf2) PERMUTATION_ACT(number) PERMUTATION_ACT(Rational) PERMUTATION_ACT(double) PERMUTATION_ACT(Quad) TEX(![ There are two routines to compose two Permutations, using function composition order. The first is invoked by {\tt*}, whereas the second (see class definition) is a three-argument function {\tt pmul}, whose third argument is the result. These routines do no validity checking whatsoever. The second routine should be used where efficiency is critical. \mindex{operator*(Permutation, Permutation)} ]!) Permutation operator*(const Permutation& p1, const Permutation& p2) { Permutation p = Permutation(p1.length); for ( int i = 0; i < p1.length; i++ ) p(i) = p1( p2(i) - 1 ); return p; } index_method(transpose) void Permutation::transpose(int i, int j) { for ( int k = 0; k < length; k++ ) { if ( (*this)(k) == i ) (*this)(k) = j; else if ( (*this)(k) == j ) (*this)(k) = i; } } ostream& operator<<(ostream& s, const Permutation& p) { for ( int i = 0; i < p.length; i++ ) { s << p(i); if ( i < p.length-1 ) s << ","; } return s; } TEX( Construct a random Permutation which is subordinate to the given equivalence relation. The implementation is very inefficient. ) Permutation::Permutation(const EquivRelIntList& e) : vector(e.length) { int y, i, j; for ( i = 0; i < e.length; i++ ) { while(1) { y = (random( ) % length) + 1; for ( j = 0; j < i; j++ ) if ( y == (*this)(j) ) break; if ( j != i ) continue; if ( e.equiv(i, y-1) ) break; } (*this)(i) = y; } } index_method(as_cycle_product) String Permutation::as_cycle_product( ) const { String ans; vector used(length); for ( int i = 0; i < length; i++ ) { if ( used(i) || (*this)(i) == i+1 ) continue; used(i) = 1; ans += String("(") + dec(i+1); int j = i; while(1) { j = (*this)(j) - 1; if ( j == i ) break; used(j) = 1; ans += String(",") + dec(j+1); } ans += ")"; } return ans; } TEX(![ {\tt orbit}:\ Let a group $G = \inn{\VEC g1n}$ act on an ordered set $S$. Let $x \in S$. Compute $Gx$, or else an $M$-element subset of $Gx$ if $M \geq 0$. The method is very similar to that of {\tt minimal}, p.\ \pageref{bool-minimal}. ]!) set_compile_file(code.c) index_method(orbit) template void orbit( const prevector& Q, const S& x, prevector& X, int (*cmp)(const S&, const S&), void (*act)(const G&, const S&, S&), int M = -1 ) { prevector Xa(0), Xb(1), Xc, Xt; Xb(0) = x; int i, j, k, c, n = Q.length; while(1) { Xc.set_size( n * Xb.length ); for ( i = 0; i < n; i++ ) for ( j = 0; j < Xb.length; j++ ) act( Q(i), Xb(j), Xc( i + n * j) ); Xc.unique_sort(cmp); merge( Xa, Xb, Xt, cmp ); // Merge Xa and Xb to get if ( M < 0 || Xt.length < M ) // new Xa, then set Xb = Xc - Xa. Xa = Xt; else { X.set_and_take(Xt, M); return; } diff( Xc, Xa, Xb, cmp ); if ( Xb.length == 0 ) { X = Xa; return; } } } set_compile_file(permutation.cc) index_method(pcmp) int pcmp( const Permutation& a, const Permutation& b ) { register int i, n = a.length; for ( i = 0; i < n; i++ ) { if ( a(i).x > b(i).x ) return 1; if ( a(i).x < b(i).x ) return -1; } return 0; } HIDE( ![ template void orbit( const prevector&, const S&, prevector&, int (*cmp)(const S&, const S&), void (*act)(const G&, const S&, S&), int = -1 ); ]! ) TEX( \indexz{Permutationlist} \mindex{clear} \mindex{generate} \mindex{append} ) set_include_file(permutationlist.h) class Permutationlist : public vector { public: int n; // length of the Permutation // generate -- see documentation given below void generate( const Permutationlist& S, int M = -1 ) { Permutation x(n); prevector& me = *this; orbit( prevector(S), x, me, pcmp, pmul, M ); } Permutationlist( int n = 0 ) : n(n) { set_size(0); } void append( const Permutation& p ) { Permutationlist l(n); l.set_size( length + 1 ); for ( int i = 0; i < length; i++ ) l(i) = (*this)(i); l(length) = p; *this = l; } void clear( ) { set_size(0); } bool minimal( const vector& ) const; }; set_compile_file(permutation.cc) HIDE(![#include "permutationlist.h"]!) TEX(![ {\tt Permutationlist::generate(S, M)} -- {\tt S} is to be an arbitrary list of Permutations, and {\tt M} is to be a positive integer (or $-1$, which is treated as $+\infty$). Replace {\tt*this} by the group generated by {\tt S}; upon exit it is sorted. However, if during the generation process more than {\tt M} elements are encountered, the ``group'' will consist only of the first {\tt M} elements generated. We use a primitive algorithm. A much better algorithm is due to Sims ([.sims 1970.]\ \S4) and there have been improvements since then due to Leon [.leon strong generating set.], [.leon finding order.] and others. There are implementations in the GAP [.groups algorithms programming.] and MAGMA packages, and others. More recent approaches are given in [.leon permutation group algorithms 1991.] and [.sims book 1994.]. The book [.butler fundamental algorithms.] has a very readable discussion. ]!) TEX(![ {\tt Permutationlist::minimal(vector v)} -- The {\tt Permutationlist} (call it {\tt G}) acts on the vector {\tt v}, which should be sorted. If {\tt sort(gv)} $\geq$ {\tt v} for all {\tt g} $\in$ {\tt G}, return {\tt true}. Otherwise, return {\tt false}. The action is not by permuting the entries of the vector, but rather via the action on the individual elements of the vector. \mindex{minimal} ]!) bool Permutationlist::minimal(const vector& v) const { static vector w; w = v; register int i, j, k, n = w.length, best; for ( i = 0; i < length; i++ ) { for ( j = 0; j < n; j++ ) w(j) = (*this)(i)(v(j) - 1); // Determine if after sorting, w would be smaller than v. for ( j = 0; j < n; j++ ) { best = j; for ( k = j + 1; k < n; k++ ) if ( w(k) < w(best) ) best = k; if ( w(best) < v(j) ) return false; if ( w(best) > v(j) ) break; if ( best != j ) w(best) = w(j); } } return true; } set_compile_file(code.c) HIDE(![ #include "permutation.h" template void orbit( const prevector&, const Permutation&, prevector&, int (*)(const Permutation&, const Permutation&), void (*)(const Permutation&, const Permutation&, Permutation&), int ); int pcmp( const Permutation&, const Permutation& ); #include "permutationlist.h" ]! ) TEX( \block{Matrix class} ) index_class(matrix) index_method(transpose_columns) index_method(mul) index_method(set_size) index_method(leading_ones) index_method(set_col) set_include_file(matrix.h) template class matrix { public: TEX( ![ \classtextt{Data items} ]! ) vector* x; // the elements int nrows, ncols; TEX( ![ \classtext{ Constructors, the assigner, a resizer, and the destructor. A ``null matrix'' is one with $\verb|x| = 0$.} ]! ) matrix(int, int); matrix(int, String); matrix(String); matrix( ) { x = 0; } matrix(const matrix& ); matrix(const vector&); // make a row vector matrix(int, const SLList< vector >&); matrix& operator=(const matrix&); void set_size(int r, int c) { if ( x != 0 && nrows == r && ncols == c ) return; if ( x != 0 ) delete [ ] x; x = new vector[r]; nrows = r; ncols = c; for ( int i = 0; i < r; i++ ) { x[i].x = new T[c]; x[i].length = c; } } void resize(int r, int c) // Very inefficient. { matrix M(r, c); for ( int i = 0; i < min( r, nrows ); i++ ) for ( int j = 0; j < min( c, ncols ); j++ ) M(i, j) = (*this)(i, j); (*this) = M; } ~matrix( ) { if ( x != 0 ) delete [ ] x; } TEX( ![ \classtextt{Access to elements, rows, and columns} ]! ) T& operator( )(int i, int j) const { return x[i].x[j]; } vector& operator( )(int i) const { return x[i]; } void set_col(int c, vector v) { for ( int i = 0; i < nrows; i++ ) (*this)(i,c) = v(i); } matrix select_col(vector w) { matrix A( nrows, w.weight( ) ); int col_ptr = 0; for ( int i = 0; i < ncols; i++ ) if ( w(i) ) { for ( int j = 0; j < nrows; j++ ) A(j, col_ptr) = (*this)(j, i); col_ptr++; } return A; } TEX( ![ \classtextt{Permute entries} ]! ) void permute_columns(const Permutation&); void transpose_columns(int i, int j) { for ( int k = 0; k < nrows; k++ ) swap( (*this)(k,i), (*this)(k,j) ); } Permutation* column_fix( ); void transpose_equals(matrix&) const; TEX( ![ \classtextt{Arithmetic} ]! ) friend void mul(const matrix& M, const vector& v, vector& prod) { prod.set_size(M.nrows); for ( int i = 0; i < M.nrows; i++ ) { T sum = 0; for ( int j = 0; j < v.length; j++ ) sum += M(i,j) * v(j); prod(i) = sum; } } HIDE( ![ friend void mul(const matrix&, const matrix&, matrix&); friend void mul(const vector&, const matrix&, vector&); friend void xA_minus_c_eq(const vector&, const matrix&, const vector&, vector&); ]! ) friend matrix operator+(const matrix& A, const matrix& B) { HIDE( ![ if (A.x == 0 || B.x == 0 || A.nrows != B.nrows || A.ncols != B.ncols) INTERNAL_ERROR("matrix addition"); ]! ) matrix M(A.nrows, A.ncols); for ( int i = 0; i < A.nrows; i++ ) for ( int j = 0; j < A.nrows; j++ ) M(i,j) = A(i,j) + B(i,j); return M; } TEX( ![ \classtextt{Other methods} ]! ) void set_zero( ) { int i, j; for ( i = 0; i < nrows; i++ ) for ( j = 0; j < ncols; j++ ) (*this)(i,j) = 0; } void delete_column(int r) { matrix B( nrows, ncols-1 ); for ( int j = 0; j < r; j++ ) for ( int l = 0; l < nrows; l++ ) B(l,j) = (*this)(l,j); for ( int j = r+1; j < ncols; j++ ) for ( int l = 0; l < nrows; l++ ) B(l,j-1) = (*this)(l,j); *this = B; } vector leading_ones( ) const { vector leading1s = vector(nrows); for ( int i = 0; i < nrows; i++ ) for ( int j = i; j < ncols; j++ ) if ( (*this)(i,j) != 0 ) { leading1s(i) = j; break; } return leading1s; } bool orthogonal_to(const vector&) const; bool lu_decompose(Permutation&); HIDE( ![ friend void update(matrix&, Permutation&, Permutation&, const vector&, int); ]! ) void solve_from_lu(const Permutation&, const vector&, vector&); void solve_from_lu_t(const Permutation&, const vector&, vector&); HIDE( ![ friend void solve_Ax_eq_b(const matrix&, vector&, const vector&); friend bool operator==(const matrix&, const matrix&); ]! ) friend inline bool operator!=(const matrix& m1, const matrix& m2) { return !(m1 == m2); } HIDE( ![ friend void hcat(const matrix&, const matrix&, matrix&); friend void rowspace_intersection(const matrix&, const matrix&, matrix&); friend void intersect_dual(const matrix&, matrix&); ]! ) int reduce( ); // in place conversion to reduced row echelon form void reduce_i(matrix&); // same but the argument is set equal to an // invertible matrix which does it void remove_zero_rows_at_bottom( ); void reduce_nz( ); // nullspace_equals(D) -- The matrix "this" should be in RREF and have no // zero rows. Set D to a matrix whose rows form a basis for // nullspace(*this). void nullspace_equals(matrix&) const; vector enumerate_weights( ) const; HIDE( ![ friend int rank_of_rowspace_sum(const matrix&, matrix&); friend ostream& operator<<(ostream&, const matrix&); ]! ) bool rowspace_member(vector) const; vector coord_vector(vector) const; operator String( ) const { String s = "{"; for ( int i = 0; i < nrows; i++ ) { s += (*this)(i); if ( i < nrows - 1 ) s += ","; } return s + "}"; } }; set_compile_file(matreal.cc) HIDE( ![ // #define DEBUG class Permutation; #include "somedefs.h" #include "permutation.h" template void orbit( const prevector&, const S&, prevector&, int (*cmp)(const S&, const S&), void (*act)(const G&, const S&, S&), int = -1 ); int pcmp( const Permutation&, const Permutation& ); #include "permutationlist.h" #include "matrix.h" ]! ) TEX( ![ \verb|lu_decompose|:\ Compute the $LU$ decomposition of an $n \times n$ invertible matrix $A$ using row-oriented partial pivoting. We find a unit lower triangular matrix $L$, an upper triangular matrix $U$, and a permutation matrix $P$ such that $A = PLU$. Upon entry {\tt *this} is to be $A$. Upon exit it is replaced by $L - I + U$. If in the process of computation it is found that $A$ is not invertible, {\tt false} is returned; otherwise {\tt true} is returned. We start with $P = I$. As we proceed through the proof, $P$ changes, and for expository purposes, we let $M$ denote the matrix product $P^{-1} \cdot (\verb|*this|)$. ]! ) index_method(lu_decompose) template bool matrix::lu_decompose(Permutation& P) { matrix& me = *this; HIDE( ![ if ( nrows != ncols ) INTERNAL_ERROR( "lu_decompose called with non-square matrix" ); ]! ) int& n = nrows; static vector pivotindices; pivotindices.set_size(n-1); P = Permutation(n); int i, j, k, m, pivotindex; T x, biggest, pivot, mult; TEX( ![ \begin{quote} The current column is $k$. \end{quote} ]! ) for ( k = 0; k < n-1; k++ ) { TEX( ![ \begin{quoteaneg} Find the entry of $M$ in the current column (on or below the diagonal) which has the largest absolute value. Let {\tt pivotindex} be its row index. \end{quoteaneg} ]! ) biggest = 0; for ( i = k; i < n; i++ ) { x = abs( me( P(i)-1, k ) ); if ( x > biggest ) { biggest = x; pivotindex = i; } } if ( biggest == 0 ) return false; TEX( ![ \begin{quotea} Replace $P$ by $P \circ (k \leftrightarrow \verb|pivotindex|)$, thereby in effect swapping rows $k$ and {\tt pivotindex} of $M$. \end{quotea} ]! ) if ( pivotindex != k ) swap( P(k), P(pivotindex) ); pivotindices(k) = pivotindex; TEX( ![ \begin{quotea} In effect execute the following code: \begin{classboxedquotefour} \verb|for ( i = k + 1; i < n; i++ )|\\ \verb|{ M(i,k) /= M(k,k);|\\ \verb| for ( j = k + 1; j < n; j++ )|\\ \verb| M(i,j) -= M(i,k) * M(k,j); }| \end{classboxedquotefour} \end{quotea} ]! ) pivot = me( P(k)-1, k ); m = P(k)-1; T* v = me(m).x; for ( i = k+1; i < n; i++ ) { T* w = me( P(i)-1 ).x; mult = w[k] / pivot; w[k] = mult; if ( mult != 0 ) { for ( j = k + 1; j < n; j++ ) w[j] -= mult * v[j]; } } } TEX( ![ \begin{quote} At this point, {\tt *this} is $P(L - I + U)$. We change it into $L - I + U$. \end{quote} ]! ) for ( i = 0; i <= n-2; i++ ) if ( i != pivotindices(i) ) swap( me(i), me(pivotindices(i)) ); return me( n-1, n-1 ) != 0; } HIDE( ![ template bool matrix::lu_decompose(Permutation&); template bool matrix::lu_decompose(Permutation&); template bool matrix::lu_decompose(Permutation&); ]! ) set_compile_file(woof.cc) HIDE(![#include "basedefs.h"]!) TEX( ![ \verb|solve_from_lu|:\ Start with an invertible matrix $A$ and a vector $b$. Solve $Ax = b$ for $x$. Upon entry {\tt *this} and {\tt P} are to be the $LU$-decomposition of $A$ coming from \verb|lu_decompose|. The code is based on the code given in [.forsythe moler.]\ pp.\ 59--60. ]! ) index_method(solve_from_lu) template void matrix::solve_from_lu(const Permutation& P, const vector& b, vector& x ) { matrix& lu = *this; int i, j, n = nrows; x.set_size(n); T dot; T* xx = x.x; for ( i = 0; i < n; i++ ) { dot = 0; T* v = lu(i).x; for ( j = 0; j < i; j++ ) dot += v[j] * xx[j]; xx[i] = b(P(i)-1) - dot; } for ( i = n-1; i >= 0; i-- ) { dot = 0; T* v = lu(i).x; for ( j = i+1; j < n; j++ ) dot += v[j] * xx[j]; xx[i] = (xx[i] - dot) / v[i]; } } INSTANTIATE( ![class matrix]!, T, double, Quad, Rational ) INSTANTIATE( ![matrix::solve_from_lu(const Permutation&, const vector&, vector&) ]!, T, double, Quad, Rational ) TEX( ![ \verb|solve_from_lu_t|:\ Start with an invertible matrix $A$ and a vector $c$. Solve $y^T A = c^T$ for $y$. Upon entry {\tt *this} and {\tt P} are to be the $LU$-decomposition of $A$ coming from \verb|lu_decompose|. ]! ) index_method(solve_from_lu_t) template void matrix::solve_from_lu_t(const Permutation& P, const vector& c, vector& y ) { matrix& lu = *this; static vector z; z.set_size(nrows); y.set_size(nrows); int i, j; T dot; T* zx = z.x; for ( i = 0; i < nrows; i++ ) { dot = 0; for ( j = 0; j < i; j++ ) dot += lu(j, i) * zx[j]; zx[i] = (c(i) - dot) / lu( i, i ); } for ( i = nrows-1; i >= 0; i-- ) for ( j = i+1; j < nrows; j++ ) zx[i] -= lu(j, i) * zx[j]; for ( i = 0; i < nrows; i++ ) y( P(i)-1 ) = z( i ); } INSTANTIATE( ![class matrix]!, T, double, Quad, Rational ) INSTANTIATE( ![matrix::solve_from_lu_t(const Permutation&, const vector&, vector&) ]!, T, double, Quad, Rational ) set_compile_file(matreal.cc) index_method(solve_Ax_eq_b) template void solve_Ax_eq_b(const matrix& A, vector& x, const vector& b) BHIDE1( ![ if ( A.nrows != A.ncols ) INTERNAL_ERROR( "solve_Ax_eq_b is only defined for square matrices A" ); ]!, ![ matrix LU = A; ]! ) Permutation P( A.nrows ); LU.lu_decompose(P); LU.solve_from_lu(P, b, x); } HIDE( ![ template void solve_Ax_eq_b(const matrix&, vector&, const vector&); template void solve_Ax_eq_b(const matrix&, vector&, const vector&); template void solve_Ax_eq_b(const matrix&, vector&, const vector&); ]! ) TEX( ![ {\tt update}:\ Let $A$ be an $n \times n$ invertible matrix, and suppose one has an equation $AQ = PLU$, in which $P,Q$ are permutation matrices, $L$ is unit lower triangular, and $U$ is upper triangular. Let $v$ be an $n$-vector, let $k$ ($0 \leq k < n$) be given, and (using superscripts to denote columns) let $B = [A^0 \cdots A^{k-1} \kern2.5pt v \kern2.5pt A^{k+1} \cdots A^{n-1}]$, which we assume is invertible. Find $\oP$, $\oQ$, $\oL$, and $\oU$ (of the same types as $P$, $Q$, $L$, and $U$) such that $B \oQ = \oP \kern1.5pt \oL \kern1.5pt \oU$. Upon entry, {\tt LU} is to be $L - I + U$; it is replaced by $\oL - I + \oU$. The method we use is outlined in [.nazareth updating.] (also in [.nazareth book.]\ \S6.5), which presents a reformulation of the Fletcher-Matthews update [.fletcher matthews.]. (Regarding the role of $Q$, see [.nazareth book.]\ p.\ 118.) Let $R$ be the permutation matrix associated to the cycle $(n-1 \kern5pt n-2 \kern5pt \cdots \kern5pt Q^{-1}(k) \kern5pt Q^{-1}(k)-1)$.% \footnote{Note the probably unfortunate convention made in the {\tt Permutation} class that if $\sigma$ is a permutation of $n$, then $\setof{\sigma(0),\ldots,\sigma(n-1)} = \setof{1,\ldots,n}$. Also, we have identified permutations with permutation matrices.} The starting point for the update is that the matrix $H := L^{-1}P^{-1}BQR^{-1}$ is upper Hessenberg, i.e.\ it would be upper triangular except that it has nonzero entries on the diagonal below the main diagonal, starting in column $Q^{-1}(k)-1$. We work from that column rightward to clear these subdiagonal elements. The running time for this algorithm is $O(n^2)$; its raison d'\^etre is that refactorization of $B$ from scratch costs $O(n^3)$. ]! ) template void update(matrix& LU, Permutation& P, Permutation& Q, const vector& v, int k) { int n = LU.nrows, i, j; R* U_i; // to represent ith row of U R* U_ip; // to represent (i+1)st row of U R* L_j; // to represent jth row of L static Permutation Qi; // inverse of Q Qi = Q.inverse( ); TEX( ![ \begin{quote} The first task is to set up $H$, which is $UR^{-1}$ with the last column replaced by the solution $x$ to the equation $Lx = P^{-1}v$. We put the entries of $H$ on or above the diagonal into the existing space for $U$ (the upper half of $\verb|LU|$), and put the subdiagonal entries of $H$ into a separate vector $\verb|h|$. \end{quote} ]! ) static vector h, x; h.set_size(n-1); x.set_size(n); R dot; R* xx = x.x; for ( i = 0; i < n; i++ ) // i is row { U_i = LU.x[i].x; dot = 0; for ( j = 0; j < i; j++ ) dot += U_i[j] * xx[j]; xx[i] = v(P(i)-1) - dot; if ( i >= Qi(k) ) h(i-1) = U_i[i]; for ( j = max(i + 1, int(Qi(k))); j < n; j++ ) U_i[j-1] = U_i[j]; } for ( i = 0; i < n; i++ ) LU(i, n-1) = xx[i]; TEX( ![ \begin{quote} We have $BQR^{-1} = PLH$. Our job is to progressively modify $P$, $L$, and $H$ so that the subdiagonal entries of $H$ are cleared one by one, while maintaining the equation. \end{quote} ]! ) for ( i = Qi(k)-1; i < n-1; i++ ) { TEX( ![ \begin{quoteaneg} At this point $\verb|h|(j) = 0$ for $j < i$. Since $U$ was invertible, its diagonal entries were nonzero, and so the entries of $\verb|h|$ (for $j \geq Q^{-1}(k)-1$) were nonzero. As $\verb|h|(i)$ has not been changed, it is still nonzero. Note that $\verb|h|(i) = H(i+1, i)$. The current $H(i,i)$ may be smaller (in absolute value), in which case one would think that a row exchange is called for. However, we shall see that this is not always the case. Supposing that $H(i,i) \not= 0$, let $E$ be the elementary matrix corresponding to subtracting $\alpha := H(i+1,i)/H(i,i)$ times row $i$ from row $i+1$, and let $F$ be the elementary matrix corresponding to subtracting $\alpha^{-1}$ times row $i$ from row $i+1$. Let $T$ be the permutation matrix which exchanges rows $i$ and $i+1$, so $T = T^{-1}$. If we were to do a row exchange on $H$, we would be led to the equation $LH = (LTF^{-1})(FTH)$. Now $FTH$ is upper Hessenberg, but $LTF^{-1}$ is $$\bordermatrix{&&&&i&i+1\cr &1&&&0&0\cr &&\ddots&&\vdots&\vdots\cr &&&1&0&0\cr i&&&&\alpha^{-1}&1\cr i+1&&&&1+\alpha^{-1} L_{i+1,i} & L_{i+1,i}\cr &&&&L_{i+2,i+1}+ \alpha^{-1} L_{i+2,i} & L_{i+2,i}&1\cr &&&&\vdots&\vdots&&\ddots\cr &&&&\vdots&\vdots&&&1\cr},$$% which is not unit lower triangular. (Unmarked entries agree with those of $L$.) One has to in turn do an $LU$ factorization of this matrix. Again one has a choice as to whether to do a row exchange. If $\abs{\alpha^{-1}} \geq \abs{1 + \alpha^{-1} L_{i+1,i}}$ (or equivalently $\abs{\alpha + L_{i+1,i}} \leq 1$), one should not do a row exchange. But then after one does the $LU$ factorization of $LTF^{-1}$ (say as $\oL\kern1.5pt\oU$), then in fact $\oL(\oU FTH)$ is exactly the $LU$ factorization one would have obtained if one had never done a row exchange at all! This follows from the uniqueness of $LU$ factorizations. \end{quoteaneg} ]! ) static R alpha, alpha_inv, li; if ( LU(i,i) != 0 ) alpha = h(i) / LU(i,i); alpha_inv = LU(i,i) / h(i); U_i = LU.x[i].x; U_ip = LU.x[i+1].x; li = U_ip[i]; if ( abs(h(i)) <= abs(LU(i,i)) || (LU(i,i) != 0 && abs( alpha + li ) <= 1) ) { TEX( ![ \begin{quotebneg} This is the easy case. We have $LH = (LE^{-1})(EH)$. Replace $L$ by $LE^{-1}$ (still unit lower triangular) and replace $H$ by $EH$ (still upper Hessenberg, but with one more zero subdiagonal entry). Note that the action on $L$ (of multiplying on the right by $E^{-1}$) is to add $\alpha$ times column $i+1$ to column $i$. \end{quotebneg} ]! ) // h(i) = 0; // Not necessary to actually do it. for ( j = i+1; j < n; j++ ) U_ip[j] -= alpha * U_i[j]; LU(i+1, i) += alpha; for ( j = i+2; j < n; j++ ) // row j LU(j, i) += alpha * LU(j, i+1); } else { TEX( ![ \begin{quotebneg} This is the hard case. We have $LH = (LTF^{-1})(FTH)$. Whereas $FTH$ is upper Hessenberg and improved as before, $LTF^{-1}$ is (as noted above) not unit lower triangular. What we have to do is define the needed operations which would in principle bring about the $LU$ factorization (say as $\oP \kern1.5pt\oL\kern1.5pt\oU$) of this matrix. To understand this one should focus on the \th{i} and $(i+1)^{\operatoratfont st}$ rows and columns, defining a $2 \times 2$ submatrix. Then there are two subcases. The first subcase $\abs{\alpha^{-1}} \geq \abs{1 + \alpha^{-1} L_{i+1,i}}$ has already been dealt with. In the second subcase, $\abs{\alpha^{-1}} < \abs{1 + \alpha^{-1} L_{i+1,i}}$. Let $\ell = L_{i+1,i}$, $\lambda = \alpha + \ell$. The defining $2 \times 2$ factorization is $$\brmat{\alpha^{-1}&1\cr 1+\alpha^{-1} \ell & \ell} = \brmat{0&1\cr1&0} \brmat{1&0\cr \lambda^{-1} & 1} \brmat{1+\alpha^{-1} \ell&\ell\cr 0 & \alpha \lambda^{-1} }.$$% Now $\oP$ is the permutation matrix associated to transposing $i$ and $i+1$. We have $$\oL = \bordermatrix{&&&&i&i+1\cr &1&&&0&0\cr &&\ddots&&\vdots&\vdots\cr &&&1&0&0\cr &L_{i+1,0}&\cdots&L_{i+1,i-1}&1&0\cr &L_{i,0}&\cdots&L_{i,i-1}&\lambda^{-1}&1\cr &&&&{\alpha\lambda^{-1} L_{i+2,i+1} \atop + \lambda^{-1} L_{i+2,i}} & {L_{i+2,i} - \atop \ell L_{i+2,i+1}} & 1 \cr &&&&\vdots&\vdots&&\ddots\cr &&&&\vdots&\vdots&&&1\cr},$$ where those entries not marked agree with those of $L$, and $$\oU = I_i \o+ \brmat{\alpha^{-1}\lambda & \ell\cr 0 & \alpha\lambda^{-1}} \o+ I_{n-i-2} \hbox{\ \ (block diagonal decomposition).}$$% From this one calculates that $$\oU F T = I_i \o+ \brmat{ \ell & 1\cr \alpha\lambda^{-1} & -\lambda^{-1} } \o+ I_{n-i-2}.$$ \end{quotebneg} ]! ) static R M11, M21, M22neg; M11 = li; M22neg = alpha_inv / (1 + li * alpha_inv); M21 = 1 / (1 + li * alpha_inv); // M12 = 1; TEX( ![ \begin{quoteb} We are thinking of {\tt M} as the $2 \times 2$ matrix which appears in $\oU F T$. We let it act on rows $i$ and $i+1$ of $H$, thereby updating $H$. \end{quoteb} ]! ) R temp; for ( j = i; j < n; j++ ) { if ( j == i ) temp = M11 * U_i[j] + h(i); else temp = M11 * U_i[j] + U_ip[j]; if ( j > i ) U_ip[j] = M21 * U_i[j] - M22neg * U_ip[j]; U_i[j] = temp; } // h(i) = 0; // Not necessary to actually do it. TEX( ![ \begin{quoteb} Update $L$, by letting a $2 \times 2$ matrix $N$ act on columns $i$ and $i+1$ of $L$. The entry in spot $(i+1,i)$ has to be separately set. Also exchange rows $i$ and $i+1$, for columns less than $i$. \end{quoteb} ]! ) for ( j = 0; j < i; j++ ) swap( LU(i,j), LU(i+1,j) ); #define N11 M22neg #define N22neg M11 #define N21 M21 // N12 = 1; for ( j = i+1; j < n; j++ ) { L_j = LU.x[j].x; if ( j == i + 1 ) L_j[i] = N11; else { temp = N11 * L_j[i] + N21 * L_j[i+1]; L_j[i+1] = L_j[i] - N22neg * L_j[i+1]; L_j[i] = temp; } } TEX( ![ \begin{quoteb} Update $P$, by multiplying it on the right by the permutation of $i$ and $i+1$. \end{quoteb} ]! ) swap( P(i), P(i+1) ); } } TEX( ![ \begin{quote} Update $Q$, by replacing it by $QR^{-1}$. \end{quote} ]! ) number t = Q( Qi(k)-1 ); for ( i = Qi(k)-1; i < n-1; i++ ) Q(i) = Q(i+1); Q(n-1) = t; } HIDE( ![ template void update(matrix&, Permutation&, Permutation&, const vector&, int); template void update(matrix&, Permutation&, Permutation&, const vector&, int); template void update(matrix&, Permutation&, Permutation&, const vector&, int); ]! ) set_include_file(simplex.h) TEX( ![ \block{A provisional implementation of the simplex method} The class \verb|exact_lp_problem| encodes the following notion of a \LP\ problem. It is a list of linear constraints, equality or inequality, involving variables $\verb|v|1,\ldots\verb|v|n$ with integer coefficients (and an integer \RHS), together with a list of linear objectives (having $\Q$ coefficients), to be maximized or minimized over $(\Q^{\geq 0})^n$. The constraints ({\tt vconstraint}'s) are at present stored on a single file. It would be nice to later reimplement with a ``virtual prevector'' class, which would allow for multiple files (or pipes) or in-memory storage, transparent to the ``user''. We define the optimum value of an objective function as an extended real number. We regard two \verb|exact_lp_problem|s as being {\it equivalent\/} if they have the same number of objectives (= {\tt obj.length}) and those objectives have the same optimum value. ]! ) index_class(exact_lp_problem) class exact_lp_problem { public: TEX( ![ \classtext{ The first entry signals that the problem is infeasible (if it is). In that case, everything else is to be ignored.} ]! ) bool known_to_be_infeasible; int n; // number of variables int m; // total number of constraints int m_eq; // number of constraints which are equality constraints TEX( ![ \classtext{ The first part of the objective vector entry is its constant component. The second part contains the coefficients of the variables in the objective function. The third part is ``{\tt max}'' or ``{\tt min}''.} ]! ) prevector< triple< Rational, vector, String > > obj; String con_file; // constraint file exact_lp_problem( ) : known_to_be_infeasible(false), obj(0) { } void presolve( ); String show_infeasible_by_primal_simplex(int, const vconstraint&); String show_infeasible_by_primal_simplex_on_dual(int, const vconstraint&); }; TEX( ![ The class \verb|canonical_lp_problem| encodes the following notion of a \LP\ problem in canonical form, as given e.g.\ in ([.nazareth book.]\ p.\ 5). For $A$ an $m \times n$ matrix over $\R$ (with $m \leq n$), $x, c \in \R^n$, $b \in \R^m$, and $l, u$ vectors, each of $n$ extended real numbers ($l \leq u$), we are to minimize $c^T x$, subject to the constraints $Ax = b$ and $l \leq x \leq u$. Moreover, we assume given a choice (the {\it basis}) of $m$ columns of $A$, preferably independent columns. The number {\tt slacks} gives the number of variables which are regarded as slack variables. (The first $\verb|n|-\verb|slacks|$ variables are to be regarded as non-slack variables.) This is at present used only by the input ({\tt istream}) routine, to facilitate the reading in of noncanonical lp problems. The class is templated over a class {\tt R} which is to be an exact or approximate real number class. For computational efficiency, we store the transpose of $A$ rather than $A$ itself. \def\AsubB{\verb|A|_{\tiny\verb|B|}}\def\AsubN{\verb|A|_{\tiny\verb|N|}} \def\ysubB{\verb|y|_{\tiny\verb|B|}}\def\ysubN{\verb|y|_{\tiny\verb|N|}} \def\xsubB{\verb|x|_{\tiny\verb|B|}}\def\xsubN{\verb|x|_{\tiny\verb|N|}} \def\csubB{\verb|c|_{\tiny\verb|B|}}\def\csubN{\verb|c|_{\tiny\verb|N|}} \def\ssubB{\verb|s|_{\tiny\verb|B|}}\def\ssubN{\verb|s|_{\tiny\verb|N|}} ]! ) index_class(canonical_lp_problem) index_method(valid) template class canonical_lp_problem { public: int m; // number of rows in A int n; // number of columns in A (number of variables) int slacks; // number of variables which are slack variables matrix At; // transpose of A vector b, c, x; vector< extend > l, u; TEX( ![ \classtextt{ To find the actual matrix {\tt A}, multiply row $i$ of it by {\tt row\string_dividers}$(i)$, for each $i$. } ]! ) vector row_dividers; TEX( ![ \classtextt{ The {\tt basis} is an unordered list of $m$ distinct integers between $0$ and $n-1$. } ]! ) prevector basis; prevector if_basis; TEX( ![ \classtext{The routine {\tt simple\string_simplex} maintains a factorization of the form $\AsubB \verb|Q| = \verb|PLU|$, where $P$ and $Q$ are permutation matrices. Here $\AsubB$ is the matrix whose columns are the basis rows of {\tt At}. } ]! ) matrix LU; Permutation P, Q; matrix A_B; vector x_B; vector b_minus; TEX( ![ \classtextt{Routine to recompute {\tt x}.} ]! ) void recompute_x( ) { b_minus = b; for ( int i = 0; i < n; i++ ) { if ( !if_basis(i) && x(i) != 0 ) for ( int k = 0; k < m; k++ ) b_minus(k) -= At(i,k) * x(i); } LU.solve_from_lu( P, b_minus, x_B ); Q.act(x_B); for ( int i = 0; i < m; i++ ) x(basis(i)) = x_B(i); } TEX( ![ \classtextt{Routine to randomly perturb {\tt b}.} ]! ) void perturb(double pert_factor) { R max_random; assign(max_random, Ipow(2,31) - 1); for ( int i = 0; i < b.length; i++ ) { R bmult; assign( bmult, 1.0 + pert_factor * random( ) / max_random ); b(i) = bmult * b(i); } } canonical_lp_problem(int m, int n) : m(m), n(n), At(n,m), b(m), b_minus(m), c(n), x(n), l(n), u(n), basis(m), if_basis(n), A_B(m,m), LU(m,m), P(m), Q(m), x_B(m), row_dividers(m) { } HIDE( ![ friend istream& operator>>(istream&, canonical_lp_problem&); ]! ) R objective( ) { R obj = 0; for ( int i = 0; i < n; i++ ) if ( if_basis(i) || l(i) != 0 ) obj += c.x[i] * x.x[i]; return obj; } static R tolx; R infeasibility( ) { R infeas = 0; for ( int i = 0; i < n; i++ ) if ( x(i) + tolx < l(i) ) infeas += R(l(i)) - x(i); return infeas; } pair status( ) { R inf = infeasibility( ); if ( inf > 0 ) return make_pair(false, inf); else return make_pair(true, objective( )); } TEX( ![ \classtextt{Check if problem is correctly posed. } ]! ) bool valid( ) const { if ( m > n || At.x == 0 || b.x == 0 || c.x == 0 || l.x == 0 || u.x == 0 || basis.x == 0 ) return false; if ( At.nrows != n || At.ncols != m || b.length != m || c.length != n || l.length != n || u.length != n || basis.length != m ) return false; for ( int i = 0; i < m; i++ ) { if ( basis(i) < 0 || basis(i) >= n ) return false; for ( int j = i+1; j < m; j++ ) if ( basis(i) == basis(j) ) return false; } return true; } extend simple_simplex(vector&, vector&, bool&, bool = false); HIDE( ![ friend bool check_infeasible(istream&, canonical_lp_problem&, vector&, const vconstraint&); ]! ) }; // Assignment operators ( x := y ). index_method(assign) template inline void assign(S& x, const T& y) { x = y; } inline void assign( double& x, const Integer& y ) { x = y.as_double( ); } inline void assign( Quad& x, const Integer& y ) { x = atoq(dec(y)); } inline void assign( double& x, const Rational& y ) { x = double(y); } inline void assign( Quad& x, const Rational& y ) { x = atoq(dec(y.numerator( ))) / atoq(dec(y.denominator( ))); } inline void assign( Rational& x, const Quad& y ) { x = Rational(y.h( )) + Rational(y.l( )); } inline void assign( double& x, const Quad& y ) { x = y.h( ); } set_compile_file(simplex.cc) #include HIDE( ![ #include "homedefs.h" #include "simplex.h" #include "math.h" #include extern long time_used_presolving; extern long time_used_by_check_infeasible; extern long time_used_by_simple_simplex; extern long time_used_setting_up_simplex_problem; extern int refactorization_rate, partial_pricing; extern int homebrew_full_report, homebrew_speedy, iteration_limit; extern int price_refinement_count; extern "C" long random( ); void log2( const Integer&, Integer&, Integer& ); Integer round_down_to_power_of_2(Integer); inline bool test(const Rational& a, const Rational& b, char sense) { if ( sense == '=' ) return a == b; if ( sense == '<' ) return a <= b; return a >= b; } ]! ) TEX( ![ \verb|presolve|:\ Create a new problem, equivalent to the given problem, but which has no $\leq$ constraints, and for which (more importantly) the equality constraints are independent. ]! ) index_method(presolve) void exact_lp_problem::presolve( ) { int i, j, k; if ( known_to_be_infeasible ) return; time_used_presolving -= time(0); vconstraint v(n); SLList vs; ofstream out1("elim_eq_temp"); ifstream in1(con_file); while( in1.peek( ) != EOF ) { in1 >> v; if ( v.sense == '=' ) vs.append(v); if ( v.sense == '<' ) { for ( i = 0; i < n; i++ ) v.LHS(i) = -v.LHS(i); v.RHS = -v.RHS; v.sense = '>'; } if ( v.sense == '>' ) out1 << v; } in1.close( ); TEX( ![ \begin{quote} Now put the equality constraints into a matrix and reduce it. \end{quote} ]! ) matrix eqs( vs.length( ), n+1 ); int current_row = 0; forPixDef( p, vs ) { for ( i = 0; i < n; i++ ) eqs( current_row, i ) = vs(p).LHS(i); eqs( current_row++, n ) = vs(p).RHS; } eqs.reduce_nz( ); m_eq = eqs.nrows; m -= vs.length( ) - m_eq; TEX( ![ \begin{quote} Check for inconsistency of equality constraints. \end{quote} ]! ) if ( eqs.nrows != 0 ) { for ( i = 0; i < n; i++ ) if ( eqs( eqs.nrows-1, i ) != 0 ) break; if ( i == n ) { known_to_be_infeasible = true; time_used_presolving += time(0); return; } } TEX( ![ \begin{quote} The included {\tt reduce} routine for {\tt Integer} matrices does not clear entries above the leading elements, so we do that here. Also make the leading elements positive. \end{quote} ]! ) int current_col = 0; Integer a, b, mm; for ( i = 0; i < eqs.nrows; i++ ) { while(1) { if ( eqs( i, current_col ) != 0 ) break; current_col++; } if ( eqs(i, current_col) < 0 ) for ( j = current_col; j < eqs.ncols; j++ ) eqs(i,j) = -eqs(i,j); for ( j = 0; j < i; j++ ) { a = eqs(i, current_col); b = eqs(j, current_col); if ( b != 0 ) { // Force b to be divisible by a. mm = a / gcd(a,b); eqs(j) *= mm; // Clear. mm = eqs(j, current_col) / a; for ( k = 0; k < eqs.ncols; k++ ) eqs(j, k) -= mm * eqs(i, k); // Reduce. mm = abs(eqs(j, 0)); for ( k = 1; k < eqs.ncols; k++ ) mm = gcd(mm, eqs(j, k)); for ( k = 0; k < eqs.ncols; k++ ) eqs(j, k) /= mm; } } } TEX( ![ \begin{quote} Reduce each row of the matrix. (Is this necessary?) \end{quote} ]! ) for ( i = 0; i < eqs.nrows; i++ ) { Integer g = 1; for ( j = 0; j <= n; j++ ) g = gcd( g, eqs(i, j) ); if ( g != 1 ) for ( j = 0; j <= n; j++ ) eqs(i, j) /= g; } v.sense = '='; for ( i = 0; i < eqs.nrows; i++ ) { for ( j = 0; j < n; j++ ) v.LHS(j) = eqs(i,j); v.RHS = eqs(i,n); out1 << v; } out1.close( ); rename( "elim_eq_temp", con_file ); time_used_presolving += time(0); } TEX( ![ \verb|show_infeasible_by_primal_simplex|:\ First use floating-point arithmetic to try to show that the given problem is ``numerically infeasible''. If this step fails, return ``{\tt feasible}'', meaning that the problem may be feasible. Otherwise, use the output of the floating-point calculation, together with the given constraint \verb|bounding_con| to attempt to show that the problem (including \verb|bounding_con|) has no solution. Return ``{\tt infeasible}'' if the process shows that the given problem is infeasible. Otherwise return ``{\tt confused}''. Normally \verb|bounding_con| has the form $a_1 v_1 \many+ a_n v_n \leq r$, where the $a_i$ are all positive. Normally it would be a constraint included in or implied by the given problem, but this is not checked. The objective functions for the problem are ignored. The floating-point calculation is done with {\tt precision}-byte arithmetic. At this point the only allowed values for {\tt precision} are $8$ and $16$. ]! ) index_method(show_infeasible_by_primal_simplex) String exact_lp_problem::show_infeasible_by_primal_simplex( int precision, const vconstraint& bounding_con ) { if ( m == 0 ) return "feasible"; int i; ifstream con(con_file); #define SHOW_INFEASIBLE(PRECISION, TYPE) \ if ( precision == PRECISION ) \ { canonical_lp_problem prob(m, n + m - m_eq); \ prob.slacks = m - m_eq; \ con >> prob; \ con.seekg(0, ios::beg); /* rewind */ \ prob.c.set_zero( ); \ vector cost(n), improve; \ bool confused; \ extend obj = prob.simple_simplex( cost, \ improve, confused, false ); \ if (confused) return "confused"; \ if ( !obj.PlusInfinity( ) ) \ { con.close( ); \ return "feasible"; } \ if ( check_infeasible(con, prob, cost, bounding_con) ) \ { con.close( ); \ return "infeasible"; } \ else \ { con.close( ); \ return "confused"; } } SHOW_INFEASIBLE(8, double) else SHOW_INFEASIBLE(16, Quad) else INTERNAL_ERROR( "show_infeasible_by_primal_simplex called with " << "illegal precision value." ); } index_method(show_infeasible_by_primal_simplex_on_dual) String exact_lp_problem::show_infeasible_by_primal_simplex_on_dual( int precision, const vconstraint& bounding_con ) { if ( m == 0 ) return "feasible"; int i, j; ifstream con(con_file); TEX( ![ \begin{quote} I don't know exactly how the right hand sides {\tt b} should be chosen. At first I tried making them all $1$, and encountered severe cycling. Then I tried making them random numbers, uniformly distributed on $[0.5, 1.5]$. Again cycling was encountered. Then I tried random numbers from $[0.5, 100.5]$. That worked, so that's what is used here. I originally used {\tt drand48} to get random numbers, but switched to {\tt random} to make this code more portable. \end{quote} ]! ) #define SHOW_INFEASIBLE_D(PRECISION, TYPE) \ if ( precision == PRECISION ) \ { canonical_lp_problem prob(n, n + m); \ prob.row_dividers.set_size(m); \ prob.slacks = n; \ vconstraint v(n); \ for ( i = 0; i < m; i++ ) \ { con >> v; \ if ( v.sense == '<' ) INTERNAL_ERROR( \ "show_infeasible_by_primal_simplex_on_dual " \ << "may not be invoked on <= constraints." ) \ if ( v.sense == '=' ) prob.l(i).SetMinusInfinity( ); \ else prob.l(i) = 0; \ prob.u(i).SetPlusInfinity( ); \ Integer rowmax = abs(v.RHS); \ for ( j = 0; j < n; j++ ) \ rowmax = max( rowmax, abs( v.LHS(j) ) ); \ if ( rowmax == 0 ) \ INTERNAL_ERROR("The linear programming problem " << \ "has a zero constraint."); \ rowmax = round_down_to_power_of_2(rowmax); \ for ( j = 0; j < n; j++ ) \ assign( prob.At(i,j), \ Rational(v.LHS(j)) / Rational(rowmax) ); \ assign( prob.c(i), -Rational(v.RHS)/Rational(rowmax) ); \ prob.row_dividers(i) = Rational(rowmax); } \ for ( i = 0; i < n; i++ ) \ for ( j = m; j < m + n; j++ ) \ prob.At(j,i) = (j == i + m); \ for ( i = m; i < m + n; i++ ) \ { prob.c(i) = 0; \ prob.l(i) = 0; \ prob.u(i).SetPlusInfinity( ); } \ TYPE max_random; \ assign(max_random, Ipow(2,31) - 1); \ for ( i = 0; i < n; i++ ) \ prob.b(i) = 0.5 + 100.0 * random( ) / max_random; \ /* Form the crash basis. */ \ for ( i = 0; i < n; i++ ) \ prob.basis(i) = i + m; \ con.seekg(0, ios::beg); /* rewind */ \ vector cost(n), improve; \ bool confused; \ extend obj = prob.simple_simplex( \ cost, improve, confused, true ); \ if ( !confused && !obj.MinusInfinity( ) ) \ { con.close( ); \ return "feasible"; } \ prob.slacks = prob.m = m; /* kluge */ \ if ( !confused && \ check_infeasible(con, prob, improve, bounding_con) ) \ { con.close( ); \ return "infeasible"; } \ else \ { if ( PRECISION == 16 ) \ { con.close( ); \ return "confused"; } \ else \ { ofstream homebrew_log( \ "calculations/homebrew.log", ios::app ); \ homebrew_log << \ "Double precision calculation failed." \ << " Redoing at quad precision.\n"; \ homebrew_log.close( ); \ con.seekg(0, ios::beg); /* rewind */ \ precision = 16; } } } SHOW_INFEASIBLE_D(8, double) SHOW_INFEASIBLE_D(16, Quad) else INTERNAL_ERROR( "show_infeasible_by_primal_simplex_on_dual called " << "with illegal precision value." ); } TEX( ![ \verb|bits_in_significand|:\ Return number of bits in significand (0 means infinity). ]! ) index_method(bits_in_significand) int bits_in_significand( double& x ) { return 53; } int bits_in_significand( Quad& x ) { return 106; } int bits_in_significand( Rational& x ) { return 0; } TEX( ![ The following input operator for class \verb|canonical_lp_problem| is a preliminary version; the file structure will likely change later. First, you have to know $m$ and $n$ in advance and you should have used the \verb|canonical_lp_problem(int m, int n)| constructor. Now a problem to be inputted consists of a sequence of $m$ vconstraints. These need not be equality constraints; slack variables will be added as needed. But you have to have preset $n$ to the total number of variables, including the slacks. By assumption, all variables are nonnegative. All constraints are normalized so that the maximum absolute value of an element is one. This improves the conditioning of the problem. (Cf.{\ }[.tomlin scaling.].) The member {\tt c} has to be separately set, except that the slack members are automatically set to zero. The input operator finds a {\it crash basis}, according to the following scheme. First, all the columns of $A$ containing slack variables are included. Second, we consider all the rows of $A$ coming from equations in the file, we form a matrix $M$ consisting of their left hand sides, and reduce it to row echelon form. (This is done exactly. For a problem with many equality constraints, this may be too time-consuming.) If $M$ then has a zero row we exit with error. (This is a temporary ``feature''.) Otherwise, adjoin to the chosen columns of $A$ those columns in the positions of the leadings ones of $M$. This method is perhaps counter to the advice in ([.nazareth book.]\ p.\ 163). ]! ) template istream& operator>>(istream& s, canonical_lp_problem& p) { time_used_setting_up_simplex_problem -= time(0); int n0 = p.n - p.slacks, slack_count = 0; vconstraint v(n0); int i, j, eq_rows_ctr = 0; matrix eq(p.m - p.slacks, n0); for ( i = 0; i < p.m; i++ ) { s >> v; Integer rowmax = abs(v.RHS); for ( j = 0; j < n0; j++ ) rowmax = max( rowmax, abs( v.LHS(j) ) ); HIDE( ![ if ( rowmax == 0 ) INTERNAL_ERROR( "The linear programming problem has a zero constraint." ); ]! ) rowmax = round_down_to_power_of_2(rowmax); for ( j = 0; j < n0; j++ ) assign( p.At(j,i), Rational(v.LHS(j))/Rational(rowmax) ); for ( j = n0; j < p.n; j++ ) p.At(j,i) = 0; assign( p.b(i), Rational(v.RHS)/Rational(rowmax) ); p.row_dividers(i) = Rational(rowmax); if ( v.sense == '<' ) p.At( n0 + slack_count++, i ) = 1; else if ( v.sense == '>' ) p.At( n0 + slack_count++, i ) = -1; else { for ( j = 0; j < eq.ncols; j++ ) eq( eq_rows_ctr, j ) = v.LHS(j); eq_rows_ctr++; } } for ( i = 0; i < p.n; i++ ) { p.l(i) = 0; p.u(i).SetPlusInfinity( ); } for ( i = n0; i < p.n; i++ ) p.c(i) = 0; // Form the crash basis. HIDE( ![ if ( eq.reduce( ) != eq.nrows ) INTERNAL_ERROR( "The linear programming problem has some dependent" << " or inconsistent equality constraints." ); ]! ) int basis_ctr = 0, col_ctr = 0; for ( i = 0; i < eq.nrows; i++ ) for ( j = col_ctr; j < eq.ncols; j++ ) if ( eq(i,j) != 0 ) { p.basis( basis_ctr++ ) = j; col_ctr = j + 1; break; } for ( i = n0; i < p.n; i++ ) p.basis( basis_ctr++ ) = i; time_used_setting_up_simplex_problem += time(0); return s; } TEX( ![ \verb|check_infeasible|( vconstraint file, \verb|canonical_lp_problem|, cost vector, key ) \vspace{0.1in} \par\noindent The \verb|canonical_lp_problem| should have been previously read from the vconstraint file. This program verifies that the linear program (defined over $\Z$) given by the vconstraint file is infeasible. To do this, the cost vector should be the cost vector produced by \verb|simple_simplex| when it found that \verb|canonical_lp_problem| was numerically infeasible. We form the associated exact linear combination of constraints by reading the vconstraint file again. By adding to this a small multiple of the constraint key, we obtain (hopefully) a self-contradictory constraint. ]! ) index_method(check_infeasible) template bool check_infeasible(istream& s, canonical_lp_problem& p, vector& cost, const vconstraint& key) { time_used_by_check_infeasible -= time(0); int n0 = p.n - p.slacks; HIDE( ![ if ( cost.length != p.m ) INTERNAL_ERROR("check_infeasible: cost length wrong"); ]! ) vconstraint v(n0); qvconstraint qv(n0); qv.LHS.set_zero( ); qv.RHS = 0; qv.sense = '>'; Rational multiplier; int i, j; Integer mul_top, mul_bot; for ( i = 0; i < p.m; i++ ) { assign( multiplier, cost(i) ); s >> v; if ( (multiplier < 0 && v.sense == '>') || (multiplier > 0 && v.sense == '<') ) continue; multiplier /= p.row_dividers(i); mul_top = multiplier.numerator( ); mul_bot = multiplier.denominator( ); for ( j = 0; j < n0; j++ ) qv.LHS(j) += Rational( mul_top * v.LHS(j), mul_bot ); qv.RHS += multiplier * Rational(v.RHS); } HIDE( ![ if ( key.sense == '>' ) INTERNAL_ERROR( "check_infeasible: sense of key cannot be >" ); ]! ) Rational key_multiplier = 0; for ( i = 0; i < n0; i++ ) if ( qv.LHS(i) > 0 ) { if ( key.LHS(i) <= 0 ) { time_used_by_check_infeasible += time(0); return false; } key_multiplier = min( key_multiplier, -qv.LHS(i) / Rational(key.LHS(i)) ); } time_used_by_check_infeasible += time(0); return qv.RHS + key_multiplier * Rational(key.RHS) > 0; } #ifdef NeXT #include #else #include #endif index_method(finite) bool finite(Quad x) { return finite( x.h( ) ) && finite( x.l( ) ); } bool finite(Rational x) { return true; } index_method(dot) template T dot( T* x, T* y, int length ) { register T answer = 0; register int i; for ( i = 0; i < length; i++ ) answer += *(x+i) * *(y+i); return answer; } index_method(dot_plus) template T dot_plus( T* x, T* y, int length, T z ) { register T answer = z; register int i; for ( i = 0; i < length; i++ ) answer += *(x+i) * *(y+i); return answer; } index_class(finite_stack) template class finite_stack : public prevector { public: int depth; finite_stack(int n) : prevector(n), depth(0) { } void push(const T& t) { for ( int i = 0; i < min(depth-1, length-2); i++ ) (*this)(i+1) = (*this)(i); (*this)(0) = t; depth = min( depth+1, length ); } void clear( ) { depth = 0; } }; TEX( ![ The following routine \verb|simple_simplex| is a primitive solver (primal simplex) for a canonical \LP\ problem whose variables are not bounded above. Return the minimum value of the objective function ($c^T x$). If the objective is unbounded, return $-\infty$. If the feasible region is empty, return $+\infty$. If the solver fails, the variable {\tt confused} is set to true, in which case no meaningful objective function value is returned. For any $n$-vector {\tt y} we let \verb|y_B| (or $\ysubB$) denote the $m$-vector obtained from {\tt y} by selecting the entries defined by {\tt basis}. Similarly, for an $r \times n$ matrix {\tt C}, we let \verb|C_B| be the the corresponding $r \times m$ matrix. We likewise use the notation \verb|_N| to denote the selection of entries which are not defined by {\tt basis}. This is for expository purposes only. If the boolean argument \verb|b_any_pos| is set to {\tt true}, the program will proceed under the assumption that {\tt b} may be changed to any positive vector. This allows for perturbation in the event of cycling. One would presumably only want to use this option if the only goal of the calculation is to determine whether the objective is unbounded. The outline was originally based on [.nazareth book.]\ pp.\ 37--38. ]! ) index_method(REFACTOR) #define REFACTOR \ { refcount = -1; \ goto end_of_iteration; } index_method(simple_simplex) template extend canonical_lp_problem::simple_simplex( vector& cost, vector& improve, bool& confused, bool b_any_pos ) { time_used_by_simple_simplex -= time(0); ofstream homebrew_log("calculations/homebrew.log", ios::app); homebrew_log.setf(homebrew_log.unitbuf); confused = false; int i, j, k, ll, nn; prevector basis_save = basis; HIDE( ![ if ( !valid( ) ) INTERNAL_ERROR( "simple_simplex invoked on invalid lp problem" ); ]! ) int candidate_count = 0; int partial_pricing0 = min( partial_pricing, n-m ); prevector candidates(partial_pricing0); double pert_factor = 0.001; HIDE( ![ if (homebrew_full_report) { for ( i = 0; i < n; i++ ) for ( j = i+1; j < n; j++ ) { if ( At(i) == At(j) ) homebrew_log << "column " << i << " equals column " << j << "\n"; } } ]! ) TEX( ![ \begin{quote} The global variable \verb|homebrew_speedy| (if set) will cause some internal error checking to be turned off. This checking is expensive. When an anomaly is encountered, we turn the error checking back on and restart the calculation. (There must be a better way.) Upon normal exit, we turn off \verb|speedy| and refactor to make sure we are really done. Sometimes an anomaly is then encountered, in which case we turn the error checking back on and restart the calculation. \end{quote} ]! ) bool speedy = homebrew_speedy; // local version bool speedy_toggled_because_apparently_done = false; TEX( ![ \begin{quote} When we think we are done, we do some things (such as refactor) to make sure. First set the following to the believed optimum: \end{quote} ]! ) extend preliminary_opt; TEX( ![ \begin{quote} The object \verb|objective_history| keeps track of how the simplex iterations are progressing. It is a stack, each entry of which is a pair ({\it feasible?}, {\it value}), where ``{\it feasible?}'' is {\tt true} if we are at a feasible point, else {\tt false}, and {\it value\/} is the value of the objective function (in the first case), and the total infeasibility (in the second case). Stack entries are only made immediately after refactorization. Whenever we introduce or remove a perturbation, or rebuild the basis from scratch, the stack is cleared. \end{quote} ]! ) finite_stack< pair > objective_history(20); finite_stack loop_count_at_refactorization(50); OSLList entering_avoid; // variables to be avoided as entering // variables if possible bool normal_iteration = false; HIDE( ![ for ( i = 0; i < n; i++ ) if ( !u(i).PlusInfinity( ) ) INTERNAL_ERROR( "simple_simplex requires that variables be unbounded above" ); ]! ) for ( i = 0; i < m; i++ ) for ( j = 0; j < m; j++ ) A_B(i,j) = At( basis(j), i ); for ( i = 0; i < n; i++ ) if_basis(i) = false; for ( i = 0; i < m; i++ ) if_basis( basis(i) ) = true; vector x_save(n), x_save2(n); for ( i = 0; i < n; i++ ) x(i) = ( l(i).MinusInfinity( ) ? 0 : R(l(i)) ); vector b_save = b; bool b_perturbed = false; int j_save, k_save, basis_k_save; Permutation P_save(m); prevector< pair > history(1000); bool cycling_detected = false; vector cycle_test(n); TEX( ![ \begin{quote} Imagining that the columns of \verb|A| and \verb|x| are permuted, write $\verb|A| = [\AsubB \kern4pt \AsubN]$, $\verb|x| = [\xsubB, \xsubN]$, $\verb|Ax| = \verb|b|$. Then $\AsubB\xsubB = \verb|b| - \AsubN\xsubN$. The values in $\xsubN$ come from {\tt l}, so we compute the \RHS\ and then solve for $\xsubB$. \end{quote} ]! ) b_minus = b; for ( i = 0; i < n; i++ ) { if ( !if_basis(i) && x(i) != 0 ) for ( k = 0; k < m; k++ ) b_minus(k) -= At(i,k) * x(i); } solve_Ax_eq_b( A_B, x_B, b_minus ); Permutation Qi(m); vector pi(m), pi_err(m); for ( i = 0; i < n; i++ ) x(i) = ( l(i).MinusInfinity( ) ? 0 : R(l(i)) ); for ( i = 0; i < m; i++ ) x(basis(i)) = x_B(i); vector c_curr(n); // current cost vector vector c_B(m); // part of current cost vector vector c_B_err(m); // error in part of current cost vector vector c_BQi(m); // result of Q^(-1) acting on c_B vector y(m); // improvement direction vector bool backwards; // set if improving by moving backwards int itcount = 0, loopcount = 0, itcount_floor = 0; int refcount = -1; // iterations since last refactorization // setting to -1 forces refactorization R theta, theta_best, infeas = 0, err, lu_err, errx, abserr, s, s_best; extend opt; bool infeasible; // set if current x is outside feasible region int catastrophe_count = 0; static R tolpiv = ( bits_in_significand(theta) == 0 ? 0 : pow( 2, -bits_in_significand(theta) * 0.87 ) ); static R toldj = ( bits_in_significand(s) == 0 ? 0 : pow( 2, -bits_in_significand(s) * 0.70 ) ); tolx = ( bits_in_significand(b(0)) == 0 ? 0 : pow( 2, -bits_in_significand(infeas) * 0.55) ); R tolerr = ( bits_in_significand(infeas) == 0 ? 0 : pow( 2, -bits_in_significand(infeas) * 0.3) ); static R tol_refactor = ( bits_in_significand(infeas) == 0 ? 0 : pow( 2, -bits_in_significand(infeas) * 1.00) ); static R abserr_max; while(1) { if ( homebrew_full_report || (itcount+1) % 100 == 0 ) homebrew_log << "\nIteration " << itcount+1 << ": "; for ( i = 0; i < n; i++ ) if ( !finite(x(i)) ) goto catastrophe; if ( loopcount > iteration_limit ) { homebrew_log << "simple_simplex giving up after " << loopcount << " loops\n"; homebrew_log.close( ); confused = true; time_used_by_simple_simplex += time(0); return opt; } TEX( ![ \begin{quotea} Factor the basis matrix. Although we use only partial pivoting (and not complete pivoting), we still maintain a factorization of the form $\AsubB \verb|Q| = \verb|PLU|$, where $P$ and $Q$ are permutation matrices. For now $Q$ is the identity, but when we update the $LU$ factorization, it will become nontrivial. We refactor the basis matrix whenever any of the pivot elements in the $LU$ factorization get smaller than $10^{-16}$ or so (relative to a double precision type). Also recompute {\tt x}. \end{quotea} ]! ) bool outcome; if (loopcount > 0) { for ( i = 0; i < m; i++ ) if ( abs(LU(i,i)) < tol_refactor ) break; } HIDE( ![ if (loopcount > 0 && i < m && homebrew_full_report) homebrew_log << "There is a pivot element " "of size " << abs(LU(i,i)) << ".\n"; ]! ) if ( loopcount == 0 || i < m || refcount == -1 || (refactorization_rate != 0 && itcount/refactorization_rate*refactorization_rate == itcount) ) { TEX( ![ \begin{quoteb} Check to see if we're stuck in a loop, refactoring over and over. \end{quoteb} ]! ) loop_count_at_refactorization.push(loopcount); if ( !normal_iteration && loop_count_at_refactorization.depth == loop_count_at_refactorization.length ) { if ( loopcount - loop_count_at_refactorization( loop_count_at_refactorization.length - 1 ) < 10 * loop_count_at_refactorization.length ) goto catastrophe; } refactor: refcount = 0; homebrew_log << "\nrefactoring basis matrix\n"; LU = A_B; outcome = LU.lu_decompose(P); TEX( ![ \begin{quoteb} If a basis singularity is detected, we go to a random basis, and start over from scratch. I really doubt this is the ``correct'' strategy. \end{quoteb} ]! ) if (outcome) { for ( i = 0; i < m; i++ ) if ( abs(LU(i,i)) < tol_refactor ) break; HIDE( ![ if (i < m && homebrew_full_report) homebrew_log << "There is a " "pivot element of size " << abs(LU(i,i)) << ".\n"; ]! ) if (i < m) { if (speedy || speedy_toggled_because_apparently_done) goto restart_slowly; if (normal_iteration) { x_save2 = x_save; goto backup; } else goto catastrophe; } } if (!outcome) { if (normal_iteration) { x_save2 = x_save; goto backup; } catastrophe: normal_iteration = false; homebrew_log << "A catastrophic error has been detected" << " (basis singularity, infinite element of x, " << "or some other anomalous behavior). " << "Attempting to restart simplex calculation from " << "scratch with random basis.\n"; catastrophe_count++; objective_history.clear( ); loop_count_at_refactorization.clear( ); for ( i = 0; i < slacks; i++ ) basis(i) = n - slacks + i; for ( i = slacks; i < m; i++ ) { while(1) { basis(i) = random( ) % (n - slacks); for ( j = slacks; j < i; j++ ) if ( basis(i) == basis(j) ) break; if ( j == i ) break; } } for ( i = 0; i < n; i++ ) if_basis(i) = false; for ( i = 0; i < m; i++ ) if_basis( basis(i) ) = true; for ( i = 0; i < m; i++ ) for ( j = 0; j < m; j++ ) A_B(i,j) = At( basis(j), i ); for ( k = 0; k < n; k++ ) x(k) = ( l(k).MinusInfinity( ) ? 0 : R(l(k)) ); if ( catastrophe_count > 12 ) { homebrew_log << "too many catastrophies: I give up\n"; homebrew_log.close( ); confused = true; time_used_by_simple_simplex += time(0); return opt; } if ( catastrophe_count > 5 ) { if (!b_any_pos) b_perturbed = true; b = b_save; perturb( b_any_pos ? 9.0 : 0.01 ); } REFACTOR; } Q = Permutation(m); Qi = Permutation(m); recompute_x( ); } refcount++; TEX( ![ \begin{quotea} We always recompute {\tt x}. This should really only be done when there is evidence that roundoff error is a problem. \end{quotea} ]! ) if (!speedy || catastrophe_count > 0) recompute_x( ); x_save2 = x_save; x_save = x; TEX( ![ \begin{quotea} If we just refactored, update \verb|objective_history|. \end{quotea} ]! ) if ( refcount == 0 ) objective_history.push( status( ) ); TEX( ![ \begin{quotea} Compute the error term $\norm{Ax-b}_1$. \end{quotea} ]! ) if (speedy && catastrophe_count == 0) { entering_avoid.clear( ); goto bypass1; } abserr = 0; for ( ll = 0; ll < m; ll++ ) abserr += abs( dot_plus( A_B(ll).x, x_B.x, m, -b_minus(ll) ) ); if ( abserr > tolerr ) { homebrew_log << "err(Ax-b) = " << abserr << "\n"; assign( abserr_max, pow(10,80) ); if ( abserr > abserr_max ) cerr << "[Caution: Unstable simplex calculation may lead " << "to bus error.]\n"; if ( refcount != 1 ) { homebrew_log << "error in x forces refactorization\n"; TEX( ![ \begin{quotec} Back up over previous iteration. Then refactor the basis matrix. \end{quotec} ]! ) backup: if (normal_iteration) { if (speedy || speedy_toggled_because_apparently_done) goto restart_slowly; homebrew_log << "backing up over previous iteration\n"; entering_avoid.add(j_save); basis(k_save) = basis_k_save; if_basis(basis_k_save) = true; if_basis(j_save) = false; x = x_save2; A_B.set_col( k_save, At(basis_k_save) ); P = P_save; normal_iteration = false; refcount = -1; loopcount++; // Should we test for loopcount too big? goto refactor; } REFACTOR; } } else if (normal_iteration) entering_avoid.clear( ); for ( i = 0; i < m; i++ ) for ( j = 0; j < m; j++ ) if ( !finite(LU(i,j)) ) ERROR("An element of LU is not finite."); TEX( ![ \begin{quotea} If the current lower bound for a variable is very slightly below its given bound, we round up the current lower bound. The tolerance which determines ``very slightly below'' is the {\it primal feasibility tolerance\/} {\tt tolx}, which is discussed in ([.nazareth book.]\ p.\ 163) and ([.advanced orchard.]\ p.\ 130). The latter gives a value of about $10^{-8}$ on a machine with a $48$ bit significand. \end{quotea} ]! ) for ( i = 0; i < n; i++ ) if ( !finite( x(i) ) ) goto catastrophe; bypass1: normal_iteration = false; if (!infeasible && (homebrew_full_report || (itcount+1) % 100 == 0)) homebrew_log << "Objective: " << objective( ); HIDE( ![ if (!infeasible && homebrew_full_report) homebrew_log << "\n"; ]! ) for ( i = 0; i < n; i++ ) if ( x(i) + tolx < l(i) ) break; if ( i == n ) // no variables below their bounds { infeasible = false; infeas = 0; c_curr = c; } else { infeasible = true; infeas = infeasibility( ); for ( i = 0; i < n; i++ ) c_curr(i) = ( (x(i) + tolx < l(i)) ? -1 : 0 ); if ((homebrew_full_report || (itcount+1) % 100 == 0)) homebrew_log << "Infeasibility: " << infeas; HIDE( ![ if (homebrew_full_report) homebrew_log << "\n"; ]! ) } for ( i = 0; i < m; i++ ) c_B(i) = c_curr( basis(i) ); TEX( ![ \begin{quotea} Form the {\it price vector\/} {\tt pi} (also called the {\it vector of simplex multipliers}) by solving $\verb|pi|^T \AsubB = \csubB^T$. Note that {\tt pi} is characterized by the following property ([.nazareth book.]\ p.\ 29): If $x$ is nondegenerate, and we consider what happens as $b$ varies (and accordingly $x$ varies), the \th{i} component of {\tt pi} is $\partial(c^T x) / \partial b_i$. The following explanation is derived from ([.bazaraa jarvis sherali.]\ p.\ 93). For conceptual purposes, imagine that the columns of \verb|A| and \verb|x| are permuted, and write $\verb|A| = [\AsubB \kern4pt \AsubN]$, $\verb|x| = [\xsubB, \xsubN]$. Then $$\verb|b| = \verb|Ax| = \AsubB\kern4pt\xsubB + \AsubN\kern4pt\xsubN,$$% so $\xsubB = \AsubB^{-1} \verb|b| - \AsubB^{-1} \AsubN \kern2pt \xsubN$. Hence \begin{eqnarray*} \verb|c|^T \verb|x| & = & \csubB^T (\AsubB^{-1} \verb|b| - \AsubB^{-1} \AsubN \xsubN) + \csubN^T \xsubN\\ & = & (\csubB^T \AsubB^{-1} \verb|b|) + (\csubN^T - \csubB^T \AsubB^{-1} \AsubN) \xsubN. \end{eqnarray*} Note that the first parenthesized expression on the last line is the value of the objective function provided that $\xsubN = 0$. The second parenthesized expression is the vector $\ssubN$ of reduced costs. Note that $\ssubN \geq 0$ implies that $\verb|x|$ is optimal. We have $\verb|pi| = \csubB^T \AsubB^{-1}$, $\ssubN = \csubN^T - (\verb|pi|)\AsubN$. The \th{j} entry of $\ssubN$ is the rate of change of the objective function \WRT\ the nonbasic variable $\verb|x|_j$, provided that the other nonbasic variables are held at zero. \end{quotea} ]! ) c_BQi = c_B; Qi.act(c_BQi); LU.solve_from_lu_t( P, c_BQi, pi ); for ( i = 0; i < m; i++ ) if ( !finite( pi(i) ) ) ERROR("A price vector element is infinite."); TEX( ![ \begin{quotea} In this version, we always do a one-step ``single precision'' refinement of {\tt pi}. Probably refinement should only be done selectively. I put this step in because I encountered a devastating error, which apparently resulted from dividing a big number by a relatively small number in \verb|solve_from_lu_t|. In turn it is conceivable that this came from degradation of the $LU$ decomposition arising from updating. It is also possible that with proper scaling, the problem would not occur. \end{quotea} ]! ) if ( !speedy || catastrophe_count > 0 ) { for ( i = 0; i < price_refinement_count; i++ ) { xA_minus_c_eq(pi, A_B, c_B, c_B_err); Qi.act(c_B_err); LU.solve_from_lu_t( P, c_B_err, pi_err ); pi -= pi_err; } } TEX( ![ \begin{quotea} Compute the reduced costs $\verb|s|_j$ and choose the entering variable $j$. That is, for each index $j$ corresponding to a nonbasic variable (so $j \notin \verb|basis|$) which is bounded below, we set $\verb|s|_j = \verb|c|_j - \verb|pi|^T \verb|A|^j$, where $\verb|A|^j$ denotes the \th{j} column of $A$. If no $\verb|s|_j$ is negative, and there is no nonbasic free variable $j$ with $\verb|s|_j \not= 0$, $\xsubB$ is optimal and we are done. Otherwise, let $j$ be such that $\abs{\verb|s|_j}$ is maximized. Actually, rather than check to see whether $\verb|s|_j < 0$, we check to see if it is less than $-{\tt toldj}$, where {\tt toldj} is the {\it optimality tolerance}, temporarily defined here to be $2^{-0.7s}$, where $s$ is the number of bits in the significand. For brief comments on {\tt toldj} (also denoted {\tt tol}$\sigma$), see ([.nazareth book.]\ pp.\ 144,163) and ([.murtagh advanced.]\ p.\ 34). We do not compute all reduced costs. Rather we follow a {\it partial pricing\/} scheme whereby we initially choose a pool of candidate entering variables, and try to use those exclusively, until no longer possible, at which time we recompute the pool of candidate entering variables. The size of the pool is controlled by the global variable \verb|partial_pricing|. Also, we always give preference to entering variables which are unbounded. \end{quotea} ]! ) s_best = -toldj; backwards = false; for ( i = 0; i < n; i++ ) { if ( if_basis(i) ) continue; if ( !l(i).MinusInfinity( ) ) continue; if ( entering_avoid.contains(i) ) continue; // s = c_curr(i) - dot( At(i).x, pi.x, m ); s = -dot_plus( At(i).x, pi.x, m, -c_curr(i) ); if ( s < R(-10.0) * toldj && s < s_best ) { s_best = s; backwards = false; j = i; } if ( -s < R(-10.0) * toldj && -s < s_best ) { s_best = -s; backwards = true; j = i; } } if ( s_best != -toldj ) goto found_entering_variable; for ( i = 0; i < candidate_count; i++ ) { if ( if_basis( candidates(i) ) ) continue; if ( entering_avoid.contains( candidates(i) ) ) continue; // s = c_curr( candidates(i) ) - // dot( At( candidates(i) ).x, pi.x, m ); s = -dot_plus( At( candidates(i) ).x, pi.x, m, -c_curr(candidates(i)) ); if ( s < R(-10.0) * toldj && s < s_best ) { s_best = s; backwards = false; j = candidates(i); } if ( l(candidates(i)).MinusInfinity( ) && -s < R(-10.0) * toldj && -s < s_best ) { s_best = -s; backwards = true; j = candidates(i); } } if ( s_best == -toldj ) { candidate_count = 0; for ( i = 0; i < n; i++ ) { if ( entering_avoid.contains(i) ) continue; if ( !if_basis(i) ) { // s = c_curr(i) - dot( At(i).x, pi.x, m ); s = -dot_plus( At(i).x, pi.x, m, -c_curr(i) ); bool good_var = false; if ( s < s_best ) { s_best = s; good_var = true; backwards = false; j = i; } if ( l(i).MinusInfinity( ) && -s < s_best ) { s_best = -s; good_var = true; backwards = true; j = i; } if ( good_var && partial_pricing0 ) { candidates(candidate_count++) = i; if (candidate_count == partial_pricing0) break; } } } } found_entering_variable: if ( s_best == -toldj ) { if (b_perturbed) { b = b_save; homebrew_log << "[Removing perturbation.]"; b_perturbed = false; REFACTOR; } // The following test is clearly weak. if ( infeasible && (b_any_pos || infeas > 1) ) opt.SetPlusInfinity( ); else opt = objective( ); if ( speedy_toggled_because_apparently_done && opt.inf != preliminary_opt.inf ) goto restart_slowly; if ( refcount != 1 && (b_any_pos || !speedy || catastrophe_count > 0) ) { HIDE( ![ if ( homebrew_full_report ) homebrew_log << "Optimum apparently " << "found. Refactor and test again to make sure.\n"; ]! ) if (speedy) speedy_toggled_because_apparently_done = true; speedy = false; preliminary_opt = opt; REFACTOR; } if (b_any_pos) { // Do an extra refinement of the price vector. xA_minus_c_eq(pi, A_B, c_B, c_B_err); Qi.act(c_B_err); LU.solve_from_lu_t( P, c_B_err, pi_err ); pi -= pi_err; } cost = pi; time_used_by_simple_simplex += time(0); HIDE( ![ if (homebrew_full_report) homebrew_log << "Leaving simple_simplex, " << "optimum = " << opt << ", basis = " << basis << "\n"; ]! ) homebrew_log.close( ); return opt; } HIDE( ![ if (homebrew_full_report) { homebrew_log << "Entering variable: " << j; if ( l(j).MinusInfinity( ) ) homebrew_log << " (unbounded)"; homebrew_log << ". "; } ]! ) TEX( ![ \begin{quotea} Find the vector {\tt y} defining the direction of improvement, which satisfies $\AsubB \verb|y| = \verb|A|^{\verb|j|}$. \end{quotea} ]! ) LU.solve_from_lu( P, At(j), y ); Q.act(y); if (backwards) y = -y; TEX( ![ \begin{quotea} Determine the exiting variable $\verb|basis|(k)$. This involves looking at those $\verb|y|(i)$ values which are ``positive''. (But free variables are not allowed to exit.) Positive is defined by being greater than a small positive number called the {\it pivot tolerance}, sometimes denoted {\tt tolpiv}. This is touched on in ([.nazareth book.]\ pp.\ 141, 163); a somewhat more detailed discussion may be found in ([.advanced orchard.]\ pp.\ 129--130). There it is stated that many systems employ three pivot tolerances. The smallest of these is about $10^{-12}$, on a machine with a $48$ bit significand. If there are $s$ bits in the significand, this would thus correspond to about $2^{-0.83s}$. For now we use the smaller value $2^{-0.87s}$. \end{quotea} ]! ) if (!infeasible) { k = -1; for ( i = 0; i < m; i++ ) if ( !l(basis(i)).MinusInfinity( ) && y(i) > tolpiv ) { theta = (x(basis(i)) - R(l(basis(i))) ) / y(i); if ( k == -1 || theta < theta_best ) { theta_best = theta; k = i; } } if ( k == -1 ) // objective is unbounded { if (b_perturbed) { b = b_save; homebrew_log << "[Removing perturbation.]"; b_perturbed = false; objective_history.clear( ); REFACTOR; } if ( speedy_toggled_because_apparently_done && preliminary_opt.inf != -1 ) goto restart_slowly; if ( refcount != 1 ) { HIDE( ![ if ( homebrew_full_report ) homebrew_log << "Objective is apparently unbounded. " << "Refactor and test again to make sure.\n"; ]! ) if (speedy) speedy_toggled_because_apparently_done = true; speedy = false; preliminary_opt.SetMinusInfinity( ); REFACTOR; } // Refine y and retest. vector y_err(m), y_add(m); if (backwards) y = -y; for ( ll = 0; ll < m; ll++ ) { errx = -At(j)(ll); for ( int jj = 0; jj < m; jj++ ) errx += A_B(ll,jj) * y(jj); y_err(ll) = errx; } LU.solve_from_lu( P, y_err, y_add ); Q.act(y_add); y -= y_add; if (backwards) y = -y; for ( i = 0; i < m; i++ ) if ( !l(basis(i)).MinusInfinity( ) && y(i) > tolpiv ) { theta = (x(basis(i)) - R(l(basis(i))) ) / y(i); if ( k == -1 || theta < theta_best ) { theta_best = theta; k = i; } } if ( k != -1 ) goto escape_from_here; improve.set_size(n - slacks); improve.set_zero( ); for ( i = 0; i < m; i++ ) if ( basis(i) < n - slacks ) improve(basis(i)) = -y(i); if ( j < n - slacks ) improve(j) = (backwards ? -1 : 1); opt.SetMinusInfinity( ); time_used_by_simple_simplex += time(0); HIDE( ![ if (homebrew_full_report) homebrew_log << "Leaving simple_simplex, " << "optimum = " << opt << ", basis = " << basis << "\n"; ]! ) homebrew_log.close( ); return opt; } escape_from_here: for ( i = 0; i < m; i++ ) if ( i != k ) x(basis(i)) -= y(i) * theta_best; x(basis(k)) = l(basis(k)); x(j) += theta_best; } TEX( ![ \begin{quotea} In the infeasible case (phase 1), the idea is to make theta as big as possible. We push theta up in increments. Each time a basic variable crosses over the lower bound (from above or below), we have to reassess whether increasing theta further will reduce infeasibility. At the point where no improvement can be achieved, we stop. This is probably the scheme given in [.wolfe composite.]. See also ([.fletcher practical.]\ pp.\ 165--166) and ([.nazareth book.]\ Chapter 8). \end{quotea} ]! ) else { R delta_theta, delta_theta_best, infeasibility_sum; k = -1; bool x_j_at_bound = false; while(1) { TEX( ![ \begin{quotecneg} The idea is that \verb|infeasibility_sum| should be the rate of change of infeasibility with respect to {\tt x(j)}, as {\tt x(j)} increases. \end{quotecneg} ]! ) // Is the following line correct?? infeasibility_sum = x(j) < l(j); for ( i = 0; i < m; i++ ) if ( x(basis(i)) < l(basis(i)) || (x(basis(i)) == l(basis(i))) && y(i) > tolpiv) infeasibility_sum -= y(i); if ( infeasibility_sum <= 0 ) { if ( k == -1 && !x_j_at_bound) { // I don't understand this case. homebrew_log << "entering funny case\n"; if (speedy || speedy_toggled_because_apparently_done) goto restart_slowly; for ( i = 0; i < m; i++ ) if ( !l(basis(i)).MinusInfinity( ) && y(i) > tolpiv ) { delta_theta = (x(basis(i)) - R(l(basis(i)))) / y(i); if ( k == -1 || delta_theta < delta_theta_best ) { delta_theta_best = delta_theta; k = i; } } // Note: One can have delta_theta = 0 at this // point. if ( k == -1 ) // It's not clear how this can // happen, but it can. { homebrew_log << "Something screwy happened in " << "phase I.\n"; goto catastrophe; } for ( i = 0; i < m; i++ ) x(basis(i)) -= y(i) * delta_theta_best; x(j) += delta_theta_best; } break; } k = -1; for ( i = 0; i < m; i++ ) { if ( l(basis(i)).MinusInfinity( ) ) continue; if ( (x(basis(i)) < l(basis(i)) && y(i) < -tolpiv) || (x(basis(i)) > l(basis(i)) && y(i) > tolpiv) ) { delta_theta = (x(basis(i)) - R(l(basis(i)))) / y(i); if (k == -1 || delta_theta < delta_theta_best) { delta_theta_best = delta_theta; k = i; } } } x_j_at_bound = false; if ( x(j) < l(j) && R(l(j)) - x(j) < delta_theta_best ) { delta_theta_best = R(l(j)) - x(j); homebrew_log << "x(j) will be at bound\n"; x_j_at_bound = true; } if ( k == -1 ) { if ( refcount != 1 ) { x = x_save; REFACTOR; } // The following code is weak. homebrew_log << "An auxiliary objective function used to " << "reduce infeasibility " << "was found to be unbounded.\n"; goto catastrophe; } for ( i = 0; i < m; i++ ) x(basis(i)) -= y(i) * delta_theta_best; x(j) += delta_theta_best; TEX( ![ \begin{quotec} The following two lines force equalities that would otherwise be equalities only up to roundoff error. \end{quotec} ]! ) x(basis(k)) = R(l(basis(k))); if (x_j_at_bound && !l(j).MinusInfinity( )) x(j) = R(l(j)); } if ( x_j_at_bound ) goto end_of_iteration; } TEX( ![ \begin{quotea} Update iteration history and test for cycling. \end{quotea} ]! ) if ( itcount == history.length ) history.resize( history.length + 1000 ); history(itcount) = make_pair( j, int(basis(k)) ); cycling_detected = false; if ( itcount > itcount_floor ) { cycle_test.set_zero( ); for ( i = itcount; i >= 0; i-- ) { cycle_test( history(i).first )++; cycle_test( history(i).second )--; if ( cycle_test.if_zero( ) ) { cycling_detected = true; homebrew_log << "cycling detected\n"; R max_random; assign(max_random, Ipow(2,31) - 1); TEX( ![ \begin{quoted} If \verb|b_any_pos| is set, the degree of perturbation depends on \verb|objective_history|. If there is evidence that progress has been made, the degree is low. Otherwise (within limits) we double the previous perturbation. One problem with this (as it stands) is that the current status is computed without refactoring first, so it could be highly inaccurate. \end{quoted} ]! ) bool improvement_detected = false; if (b_any_pos) { if ( objective_history.depth > 0 ) { pair oldest = objective_history( objective_history.depth - 1 ); pair current = status( ); if ( current.first && !oldest.first ) improvement_detected = true; else if ( current.first && oldest.first && current.second < R(101)/R(99)*oldest.second ) improvement_detected = true; else if ( !current.first && !oldest.first && current.second < R(99)/R(100)*oldest.second ) improvement_detected = true; } } if (b_any_pos) { if (improvement_detected) pert_factor = 0.001; else pert_factor = min(1.0, 2 * pert_factor); } else pert_factor = 0.01; if ( partial_pricing ) { TEX( ![ \begin{quotee} Here we deal with cycling encountered while in in the midst of partial pricing. First we end the current major iteration. If possible, we will attempt to back up over the current iteration and restart from there. But if there is evidence that we are stuck in an infinite loop, we perturb. This evidence we look for is whether the previous five loop counts (at this stage) constitute an arithmetic sequence. \end{quotee} ]! ) candidate_count = 0; #define LC_SZ 5 static int lc[LC_SZ] = {0,0,0,0,0}; // Does the above line correctly initialize? for ( i = 1; i < LC_SZ; i++ ) lc[i-1] = lc[i]; lc[LC_SZ - 1] = loopcount; int delta_lc = lc[1] - lc[0]; for ( i = 2; i < LC_SZ; i++ ) if ( lc[i] - lc[i-1] != delta_lc ) { x = x_save; homebrew_log << "attempting to back up" << " over previous iteration\n"; goto end_of_iteration; } } homebrew_log << "perturbing RHS, using perturbation " << "factor = " << pert_factor << "\n"; if (!b_any_pos) b_perturbed = true; objective_history.clear( ); refcount = -1; // force refactorization perturb(pert_factor); if ( !b_any_pos ) { itcount_floor = ++itcount; goto end_of_iteration; } break; } } } itcount++; HIDE( ![ if (homebrew_full_report) homebrew_log << "Exiting variable: " << basis(k) << ". "; ]! ) TEX( ![ \begin{quotea} Update the basis, the basis matrix, and the $LU$ decomposition of it. \end{quotea} ]! ) normal_iteration = true; A_B.set_col( k, At(j) ); if_basis( basis(k) ) = false; if_basis(j) = true; j_save = j; k_save = k; basis_k_save = basis(k); P_save = P; basis(k) = j; update( LU, P, Q, At.x[j], k ); Qi = Q.inverse( ); end_of_iteration: loopcount++; continue; restart_slowly: loopcount = 0; refcount = -1; homebrew_log << "Restarting calculation from " << "scratch with \"homebrew speedy\" turned off\n"; speedy = false; speedy_toggled_because_apparently_done = false; candidate_count = 0; objective_history.clear( ); loop_count_at_refactorization.clear( ); entering_avoid.clear( ); basis = basis_save; for ( i = 0; i < n; i++ ) if_basis(i) = false; for ( i = 0; i < m; i++ ) if_basis( basis(i) ) = true; for ( i = 0; i < m; i++ ) for ( j = 0; j < m; j++ ) A_B(i,j) = At( basis(j), i ); for ( k = 0; k < n; k++ ) x(k) = (l(k).MinusInfinity( ) ? 0 : R(l(k))); } } HIDE( ![ template class canonical_lp_problem; template class canonical_lp_problem; template class canonical_lp_problem; template istream& operator>>(istream&, canonical_lp_problem&); template istream& operator>>(istream&, canonical_lp_problem&); template istream& operator>>(istream&, canonical_lp_problem&); template bool check_infeasible(istream&, canonical_lp_problem&, vector&, vconstraint&); template bool check_infeasible(istream&, canonical_lp_problem&, vector&, vconstraint&); template extend canonical_lp_problem ::simple_simplex(vector&, vector&, bool&, bool); template extend canonical_lp_problem ::simple_simplex(vector&, vector&, bool&, bool); template extend canonical_lp_problem ::simple_simplex(vector&, vector&, bool&, bool); ]! ) TEX( ![ \block{More matrix stuff} ]! ) set_compile_file(code.c) HIDE(![#include "matrix.h"]!) template matrix::matrix(const vector& v) : nrows(1), ncols(v.length) { x = new vector[1]; x[0] = v; } set_compile_file(woof2.cc) HIDE(![#include "basedefs.h"]!) template matrix::matrix(int r, int c) : nrows(r), ncols(c) { x = new vector[r]; for ( int i = 0; i < r; i++ ) { x[i].x = new T[c]; x[i].length = c; } } HIDE( ![ matrix::matrix(int r, int c) : nrows(r), ncols(c) { x = new vector[r]; for ( int i = 0; i < r; i++ ) { x[i].x = new gf2[c]; x[i].length = c; } } matrix::matrix(int r, int c) : nrows(r), ncols(c) { x = new vector[r]; for ( int i = 0; i < r; i++ ) { x[i].x = new Quad[c]; x[i].length = c; } } matrix::matrix(int r, int c) : nrows(r), ncols(c) { x = new vector[r]; for ( int i = 0; i < r; i++ ) { x[i].x = new Integer[c]; x[i].length = c; } } matrix::matrix(int r, int c) : nrows(r), ncols(c) { x = new vector[r]; for ( int i = 0; i < r; i++ ) { x[i].x = new double[c]; x[i].length = c; } } matrix::matrix(int r, int c) : nrows(r), ncols(c) { x = new vector[r]; for ( int i = 0; i < r; i++ ) { x[i].x = new Rational[c]; x[i].length = c; } } matrix::matrix(int r, int c) : nrows(r), ncols(c) { x = new vector[r]; for ( int i = 0; i < r; i++ ) { x[i].x = new number[c]; x[i].length = c; } } ]! ) // matrix(nc, vl): make a matrix whose rows are the vectors in the list vl. // The vectors in vl must all have length nc. template matrix::matrix( int nc, const SLList< vector >& vl ) { int i; x = new vector[vl.length( )]; nrows = vl.length( ); ncols = nc; for ( i = 0; i < vl.length( ); i++ ) { x[i].x = new T[nc]; x[i].length = nc; } i = 0; forPixDef( p, vl ) (*this)(i++) = vl(p); } HIDE( ![ matrix::matrix( int nc, const SLList< vector >& vl ) { int i; x = new vector[vl.length( )]; nrows = vl.length( ); ncols = nc; for ( i = 0; i < vl.length( ); i++ ) { x[i].x = new gf2[nc]; x[i].length = nc; } i = 0; forPixDef( p, vl ) (*this)(i++) = vl(p); } ]! ) template matrix::matrix(const matrix& m) : nrows(m.nrows), ncols(m.ncols) { x = new vector[nrows]; for ( int i = 0; i < nrows; i++ ) x[i] = m.x[i]; } HIDE( ![ matrix::matrix(const matrix& m) { nrows = m.nrows; ncols = m.ncols; x = new vector[nrows]; for ( int i = 0; i < nrows; i++ ) x[i] = m.x[i]; } matrix::matrix(const matrix& m) { nrows = m.nrows; ncols = m.ncols; x = new vector[nrows]; for ( int i = 0; i < nrows; i++ ) x[i] = m.x[i]; } matrix::matrix(const matrix& m) { nrows = m.nrows; ncols = m.ncols; x = new vector[nrows]; for ( int i = 0; i < nrows; i++ ) x[i] = m.x[i]; } matrix::matrix(const matrix& m) { nrows = m.nrows; ncols = m.ncols; x = new vector[nrows]; for ( int i = 0; i < nrows; i++ ) x[i] = m.x[i]; } ]! ) set_compile_file(code.c) index_method(operator=(matrix)) template matrix& matrix::operator=(const matrix& m) { if ( m.x == 0 ) { if ( x != 0 ) delete [ ] x; x = 0; } else { if ( x == 0 || nrows != m.nrows || ncols != m.ncols ) { nrows = m.nrows; ncols = m.ncols; if ( x != 0 ) delete [ ] x; x = new vector[nrows]; } for ( int i = 0; i < m.nrows; i++ ) (*this).x[i] = m(i); } } HIDE( ![ matrix& matrix::operator=(const matrix& m) { if ( m.x == 0 ) { if ( x != 0 ) delete [ ] x; x = 0; } else { if ( x == 0 || nrows != m.nrows || ncols != m.ncols ) { nrows = m.nrows; ncols = m.ncols; if ( x != 0 ) delete [ ] x; x = new vector[nrows]; } for ( int i = 0; i < m.nrows; i++ ) (*this).x[i] = m(i); } } matrix& matrix::operator=(const matrix& m) { if ( m.x == 0 ) { if ( x != 0 ) delete [ ] x; x = 0; } else { if ( x == 0 || nrows != m.nrows || ncols != m.ncols ) { nrows = m.nrows; ncols = m.ncols; if ( x != 0 ) delete [ ] x; x = new vector[nrows]; } for ( int i = 0; i < m.nrows; i++ ) (*this).x[i] = m(i); } } matrix& matrix::operator=(const matrix& m) { if ( m.x == 0 ) { if ( x != 0 ) delete [ ] x; x = 0; } else { if ( x == 0 || nrows != m.nrows || ncols != m.ncols ) { nrows = m.nrows; ncols = m.ncols; if ( x != 0 ) delete [ ] x; x = new vector[nrows]; } for ( int i = 0; i < m.nrows; i++ ) (*this).x[i] = m(i); } } matrix& matrix::operator=(const matrix& m) { if ( m.x == 0 ) { if ( x != 0 ) delete [ ] x; x = 0; } else { if ( x == 0 || nrows != m.nrows || ncols != m.ncols ) { nrows = m.nrows; ncols = m.ncols; if ( x != 0 ) delete [ ] x; x = new vector[nrows]; } for ( int i = 0; i < m.nrows; i++ ) (*this).x[i] = m(i); } } ]! ) template bool operator==(const matrix& M1, const matrix& M2) BHIDE1( ![ if ( M1.x == 0 || M2.x == 0 ) INTERNAL_ERROR("operator== invoked on uninitialized matrice(s)"); ]!, ![ if ( M1.nrows != M2.nrows || M1.ncols != M2.ncols ) return false;]!) for ( int i = 0; i < M1.nrows; i++ ) for ( int j = 0; j < M1.ncols; j++ ) if ( M1(i,j) != M2(i,j) ) return false; return true; } HIDE( ![ template bool operator==(const matrix&, const matrix&); ]! ) index_method(remove_zero_rows_at_bottom) template void matrix::remove_zero_rows_at_bottom( ) { int i; for ( i = nrows - 1; i >= 0; i-- ) if ( !(x[i].if_zero( )) ) break; if ( i + 1 != nrows ) { vector* xnew = new vector[ i + 1 ]; for ( int j = 0; j < i + 1; j++ ) xnew[j] = x[j]; delete [ ] x; x = xnew; nrows = i + 1; } } INSTANTIATE( ![class matrix]!, T, gf2, Integer ) INSTANTIATE( ![void matrix::remove_zero_rows_at_bottom( )]!, T, gf2, Integer ) TEX(![ \verb|column_fix|: Let $M$ := {\tt *this} be an $n \times k$ matrix in \RREF, having no zero rows. This routine permutes the columns of $M$ in a special way, and returns a pointer to the permutation $\sigma$ which was used. The most important thing about the new matrix (say $M'$) it that it is still in \RREF, but now moreover $M'_{11},\ldots,M'_{nn}$ are leading ones. Since there is in general more than one way to do this, we describe precisely how $\sigma$ is chosen. Let $\ell_1 < \cdots < \ell_n$ be the columns in which the leading ones of $M$ reside. Then $$ \sigma = (n,\ell_n) \circ (n-1,\ell_{n-1}) \circ \ldots \circ (1,\ell_1).$$% Henceforth in this paper we refer to $\sigma$ as the {\it column fix\/} of $M$. ]!) index_method(column_fix) template Permutation* matrix::column_fix( ) { Permutation* colfix = new Permutation(ncols); for ( int i = 0; i < nrows; i++ ) { for ( int j = i; j < ncols; j++ ) if ( (*this)(i,j) == 1 ) { if ( i != j ) { colfix->transpose(i+1, j+1); transpose_columns(i, j); } break; } } return colfix; } HIDE( ![ Permutation* matrix::column_fix( ) { Permutation* colfix = new Permutation(ncols); for ( int i = 0; i < nrows; i++ ) { for ( int j = i; j < ncols; j++ ) if ( (*this)(i,j) == 1 ) { if ( i != j ) { colfix->transpose(i+1, j+1); transpose_columns(i, j); } break; } } return colfix; } ]! ) index_method(orthogonal_to) bool matrix::orthogonal_to(const vector& v) const { for ( int i = 0; i < nrows; i++ ) if ( odd ( (*this)(i) * v ) ) return false; return true; } index_method(permute_columns) template void matrix::permute_columns(const Permutation& p) { vector new_row = vector(ncols); for ( int i = 0; i < nrows; i++ ) { for ( int j = 0; j < ncols; j++ ) new_row(p(j).x-1) = (*this)(i,j); (*this)(i) = new_row; } } INSTANTIATE( ![class matrix]!, T, gf2 ) INSTANTIATE( ![void matrix::permute_columns(const Permutation&)]!, T, gf2 ) index_method(nullspace_equals) template void matrix::nullspace_equals(matrix& n) const { n.set_size(ncols - nrows, ncols); matrix& M = const_cast< matrix& >(*this); Permutation* colfix = M.column_fix( ); int i, j; for ( i = 0; i < ncols - nrows; i++ ) { for ( j = 0; j < nrows; j++ ) n(i,j) = -M(j, i + nrows); for ( j = 0; j < ncols - nrows; j++ ) n(i, j + nrows) = (i == j); } Permutation colfix_i = colfix->inverse( ); n.permute_columns(colfix_i); M.permute_columns(colfix_i); delete colfix; } INSTANTIATE( ![class matrix]!, T, gf2 ) INSTANTIATE( ![void matrix::nullspace_equals(matrix&) const]!, T, gf2 ) index_method(transpose_equals) template void matrix::transpose_equals(matrix& n) const BHIDE1( ![ if ( x == 0 ) INTERNAL_ERROR("You can't transpose a null matrix."); ]!, ![ n.set_size(ncols, nrows); ]! ) for ( int i = 0; i < nrows; i++ ) for ( int j = 0; j < ncols; j++ ) n(j,i) = (*this)(i,j); } INSTANTIATE( ![class matrix]!, T, gf2 ) INSTANTIATE( ![void matrix::transpose_equals(matrix&) const]!, T, gf2 ) TEX( Compute the weight enumerator of the code having as a basis the rows of the given matrix. This was a template but there was an instantiation problem. ) index_method(enumerate_weights) vector matrix::enumerate_weights( ) const { vector indx(nrows), sum(ncols); vector w(ncols + 1); int i, weight; w.set_zero( ); do { mul( indx, *this, sum ); ++w( sum.weight( ) ); } while( indx.advance( ) != 0 ); return w; } set_compile_file(matgf2.cc) HIDE( ![ // #define DEBUG class Permutation; #include "somedefs.h" #include "permutation.h" template void orbit( const prevector&, const S&, prevector&, int (*cmp)(const S&, const S&), void (*act)(const G&, const S&, S&), int = -1 ); int pcmp( const Permutation&, const Permutation& ); #include "permutationlist.h" #include "matrix.h" #include ]! ) index_method(hcat) // horizontal concatenation template void hcat(const matrix& A, const matrix& B, matrix& C) BHIDE1( ![ if ( A.x == 0 || B.x == 0 || A.nrows != B.nrows ) INTERNAL_ERROR("hcat: input matrices don't make sense"); ]!, ![ C.set_size(A.nrows, A.ncols + B.ncols); ]! ) int i, j; for ( i = 0; i < A.nrows; i++ ) { for ( j = 0; j < A.ncols; j++ ) C(i,j) = A(i,j); for ( j = 0; j < B.ncols; j++ ) C(i,j + A.ncols) = B(i,j); } } HIDE( ![ template void hcat(const matrix&, const matrix&, matrix&); ]! ) index_method(mul) template void mul(const matrix& A, const matrix& B, matrix& P) BHIDE1( ![ if ( A.ncols != B.nrows ) INTERNAL_ERROR("matrix multiplication"); ]!, ![ P.set_size(A.nrows, B.ncols); ]! ) int i, j, k; T sum; for ( i = 0; i < P.nrows; i++ ) for ( j = 0; j < P.ncols; j++ ) { sum = 0; for ( k = 0; k < A.ncols; k++ ) sum += A(i,k) * B(k,j); P(i,j) = sum; } } index_method(mul) template void mul( const vector& v, const matrix& M, vector& prod ) BHIDE1( ![ if ( v.x == 0 || M.x == 0 || v.length != M.nrows ) INTERNAL_ERROR( "Multiplication of vector times matrix." ); ]!, ![ prod.set_size( M.ncols ); ]! ) int i, j; prod.set_zero( ); for ( i = 0; i < M.nrows; i++ ) for ( j = 0; j < M.nrows; j++ ) prod(j) += v(i) * M(i,j); } void mul( const vector& v, const matrix& M, vector& prod ) BHIDE1( ![ if ( v.x == 0 || M.x == 0 || v.length != M.nrows ) INTERNAL_ERROR( "Multiplication of vector times matrix." ); ]!, ![ prod.set_size( M.ncols ); ]! ) prod.set_zero( ); for ( int i = 0; i < v.length; i++ ) if ( v(i) ) prod += M(i); } index_method(xA_minus_c_eq) template void xA_minus_c_eq(const vector& x, const matrix& A, const vector& c, vector& ans) { ans.set_size( A.ncols ); int i, j; for ( i = 0; i < A.ncols; i++ ) ans(i) = -c(i); for ( i = 0; i < A.nrows; i++ ) for ( j = 0; j < A.ncols; j++ ) ans(j) += x(i) * A(i,j); } HIDE( ![ void mul( const vector& v, const matrix& M, vector& prod ) { if ( v.x == 0 || M.x == 0 || v.length != M.nrows ) INTERNAL_ERROR( "Multiplication of vector times matrix." ); prod.set_size( M.ncols ); int i, j; prod.set_zero( ); for ( i = 0; i < M.nrows; i++ ) for ( j = 0; j < M.nrows; j++ ) prod(j) += v(i) * M(i,j); } void mul( const vector& v, const matrix& M, vector& prod ) { if ( v.x == 0 || M.x == 0 || v.length != M.nrows ) INTERNAL_ERROR( "Multiplication of vector times matrix." ); prod.set_size( M.ncols ); int i, j; prod.set_zero( ); for ( i = 0; i < M.nrows; i++ ) for ( j = 0; j < M.nrows; j++ ) prod(j) += v(i) * M(i,j); } void mul( const vector& v, const matrix& M, vector& prod ) { if ( v.x == 0 || M.x == 0 || v.length != M.nrows ) INTERNAL_ERROR( "Multiplication of vector times matrix." ); prod.set_size( M.ncols ); int i, j; prod.set_zero( ); for ( i = 0; i < M.nrows; i++ ) for ( j = 0; j < M.nrows; j++ ) prod(j) += v(i) * M(i,j); } void xA_minus_c_eq(const vector& x, const matrix& A, const vector& c, vector& ans) { ans.set_size( A.ncols ); int i, j; for ( i = 0; i < A.ncols; i++ ) ans(i) = -c(i); for ( i = 0; i < A.nrows; i++ ) for ( j = 0; j < A.nrows; j++ ) ans(j) += x(i) * A(i,j); } void xA_minus_c_eq(const vector& x, const matrix& A, const vector& c, vector& ans) { ans.set_size( A.ncols ); int i, j; for ( i = 0; i < A.ncols; i++ ) ans(i) = -c(i); for ( i = 0; i < A.nrows; i++ ) for ( j = 0; j < A.nrows; j++ ) ans(j) += x(i) * A(i,j); } void xA_minus_c_eq(const vector& x, const matrix& A, const vector& c, vector& ans) { ans.set_size( A.ncols ); int i, j; for ( i = 0; i < A.ncols; i++ ) ans(i) = -c(i); for ( i = 0; i < A.nrows; i++ ) for ( j = 0; j < A.nrows; j++ ) ans(j) += x(i) * A(i,j); } ]! ) index_method(rowspace_intersection) void rowspace_intersection(const matrix& A, const matrix& B, matrix& C) { matrix AT, BT, ATBT, D, CT, DT; HIDE( ![ if ( A.ncols != B.ncols ) INTERNAL_ERROR("rowspace_intersection"); ]! ) A.transpose_equals(AT); B.transpose_equals(BT); hcat(AT, BT, ATBT); ATBT.reduce_nz( ); ATBT.nullspace_equals(D); D.resize( D.nrows, AT.ncols ); D.transpose_equals(DT); mul(AT, DT, CT); CT.transpose_equals(C); C.reduce_nz( ); } TEX(![ If $M$ is a generator matrix for a code C, in \RREF, \verb|intersect_dual|$(M,N)$ will cause $N$ to be set equal to a generator matrix for $C \cap C^\perp$. ]!) index_method(intersect_dual) void intersect_dual(const matrix& M, matrix& N) { matrix nullspace_M; M.nullspace_equals(nullspace_M); rowspace_intersection(M, nullspace_M, N); } TEX(![ \verb|rowspace_member|: Given a matrix over {\tt gf2}, in \RREF\ and having no zero rows at the bottom, test to see if a given vector is in the rowspace. ]!) index_method(rowspace_member) bool matrix::rowspace_member( vector w ) const { int col = 0; for ( int row = 0; row < nrows; row++ ) { while ( (*this)(row, col) == 0 ) col++; if ( w(col) ) w += (*this)(row); } return w.if_zero( ); } index_method(coord_vector) vector matrix::coord_vector( vector w ) const { vector coord(nrows); int col = 0; for ( int row = 0; row < nrows; row++ ) { while ( (*this)(row, col) == 0 ) col++; if ( w(col) ) { w += (*this)(row); coord(row) = 1; } } if ( !w.if_zero( ) ) INTERNAL_ERROR("coord_vector failed" ); return coord; } TEX( ![ Convert (in place) a matrix to reduced row echelon form and return its rank. For the {\tt Integer} case, ``leading ones'' are not required to be one, and we don't clear out above them either. Whenever we subtract a multiple of a row from another, we divide the modified row by its gcd afterwards. But there is no guarantee that every row is reduced at the end of the process. ]! ) index_method(reduce) int matrix::reduce( ) { matrix& M = *this; int r, c, current_row = 0, current_col = 0; do { for ( r = current_row; r < nrows; r++ ) // find 1 in current column if( M(r, current_col) ) break; if ( r > nrows-1 ) // no 1 in current column (at or below current row) { current_col++; continue; } if ( r != current_row ) // have to exchange rows for ( c = current_col; c < ncols; c++ ) swap( M(r, c), M(current_row, c) ); for ( r = 0; r < nrows; r++ ) // clear out the current column if ( r != current_row && M(r, current_col) ) { // The efficiency of the following code is extremely // critical. register gf2* rx = M.x[r].x; register gf2* crx = M.x[current_row].x; for ( c = current_col; c < ncols; c++ ) rx[c] += crx[c]; } current_row++; current_col++; } while(current_row < nrows && current_col < ncols); return current_row; } int matrix::reduce( ) { matrix& M = *this; int current_row = 0, current_col = 0, r, c, pivot_row; Integer pivot; do { // Find nonzero entry in current column with smallest absolute value. pivot = 0; pivot_row = -1; for ( r = current_row; r < nrows; r++ ) if( M(r, current_col) != 0 && (pivot_row == -1 || abs(M(r, current_col)) < pivot) ) { pivot = abs(M(r, current_col)); pivot_row = r; } if ( pivot_row == -1 ) //from current row down, current column is zero { current_col++; continue; } if ( pivot_row != current_row ) // have to exchange rows for ( c = current_col; c < ncols; c++ ) swap( M(pivot_row, c), M(current_row, c) ); // Clear out the current column, below the current row. for ( r = current_row + 1; r < nrows; r++ ) if ( M(r, current_col) != 0 ) { Rational multiplier = Rational(M(r, current_col)) / Rational(M(current_row, current_col)); Integer md = multiplier.denominator( ); Integer mn = multiplier.numerator( ); // Multiply row r by the denominator of the multiplier. for ( c = current_col; c < ncols; c++ ) M(r, c) *= md; // Clear. for ( c = current_col; c < ncols; c++ ) M(r, c) -= M(current_row, c) * mn; // Compute the gcd of row r. Integer g = M(r, current_col); for ( c = current_col + 1; c < ncols; c++ ) g = gcd( g, M(r, c) ); // Divide row r by its gcd. if ( g != 0 ) { for ( c = current_col; c < ncols; c++ ) M(r, c) /= g; } } current_row++; current_col++; } while(current_row < nrows && current_col < ncols); return current_row; } index_method(reduce_nz) template void matrix::reduce_nz( ) { reduce( ); remove_zero_rows_at_bottom( ); } HIDE( ![ void matrix::reduce_nz( ) { reduce( ); remove_zero_rows_at_bottom( ); } void matrix::reduce_nz( ) { reduce( ); remove_zero_rows_at_bottom( ); } ]! ) index_method(reduce_i) void matrix::reduce_i(matrix& Q) { matrix& M = *this; Q.set_size(nrows, nrows); int r, c, current_row = 0, current_col = 0; for ( r = 0; r < nrows; r++ ) for ( c = 0; c < nrows; c++ ) Q(r,c) = (r == c); do { for ( r = current_row; r < nrows; r++ ) // find 1 in current column if( M(r, current_col) ) break; if ( r > nrows-1 ) // no 1 in current column (at or below current row) { current_col++; continue; } if ( r != current_row ) // have to exchange rows { for ( c = current_col; c < ncols; c++ ) swap( M(r, c), M(current_row, c) ); for ( c = 0; c < nrows; c++ ) swap( Q(r, c), Q(current_row, c) ); } for ( r = 0; r < nrows; r++ ) // clear out the current column if ( r != current_row && M(r, current_col) ) { for ( c = current_col; c < ncols; c++ ) M(r, c) += M(current_row, c); Q(r) += Q(current_row); } current_row++; current_col++; } while(current_row < nrows && current_col < ncols); } TEX(![ \verb|rank_of_rowspace_sum(M, N)|: Let \verb|M|, \verb|N| be matrices having the same number of columns. Compute the rank of $\rowspace($\verb|M|$) + \rowspace($\verb|N|$)$. It is assumed that the matrix \verb|M| is in reduced row echelon form, that it has no zero rows, and that it has leading $1$'s in the $(0,0), (1,1), \ldots$ spots. The matrix \verb|N| is modified. The implementation is inefficient in so far as it does row exchanges. ]!) index_method(rank_of_rowspace_sum) int rank_of_rowspace_sum(const matrix& M, matrix& N) { int current_row = 0, current_col = 0, r, rx, c, cx; // First reduce to the case where the first M.nrows columns of N are zero. for ( r = 0; r < M.nrows; r++ ) for ( rx = 0; rx < N.nrows; rx++ ) if ( N(rx, r) ) for ( cx = r; cx < N.ncols; cx++ ) N(rx, cx) += M(r, cx); // Now convert N to row echelon form. The code here is very similar // to that of matrix::reduce. current_col = M.nrows; current_row = 0; int rank = M.nrows; while(current_row < N.nrows && current_col < N.ncols) { for ( r = current_row; r < N.nrows; r++ ) // find 1 in current column if( N(r, current_col) ) break; if ( r > N.nrows-1 ) // no 1 in current col (at or below current row) { current_col++; continue; } if ( r != current_row ) // have to exchange rows for ( c = current_col; c < N.ncols; c++ ) swap( N(r, c), N(current_row, c) ); for ( r = current_row+1; r < N.nrows; r++ ) { // clear out the current column (below current row) if ( N(r, current_col) ) for ( c = current_col; c < N.ncols; c++ ) N(r, c) += N(current_row, c); } rank++; current_row++; current_col++; } return rank; } set_compile_file(code.c) template ostream& operator<<(ostream& s, const matrix& m) { s << "{"; for ( int i = 0; i < m.nrows; i++ ) { s << m(i); if ( i < m.nrows - 1 ) s << ","; } return s << "}"; } HIDE( ![ ostream& operator<<(ostream& s, const matrix& m) { s << "{"; for ( int i = 0; i < m.nrows; i++ ) { s << m(i); if ( i < m.nrows - 1 ) s << ","; } return s << "}"; } ostream& operator<<(ostream& s, const matrix& m) { s << "{"; for ( int i = 0; i < m.nrows; i++ ) { s << m(i); if ( i < m.nrows - 1 ) s << ","; } return s << "}"; } ostream& operator<<(ostream& s, const matrix& m) { s << "{"; for ( int i = 0; i < m.nrows; i++ ) { s << m(i); if ( i < m.nrows - 1 ) s << ","; } return s << "}"; } ostream& operator<<(ostream& s, const matrix& m) { s << "{"; for ( int i = 0; i < m.nrows; i++ ) { s << m(i); if ( i < m.nrows - 1 ) s << ","; } return s << "}"; } ostream& operator<<(ostream& s, const matrix& m) { s << "{"; for ( int i = 0; i < m.nrows; i++ ) { s << m(i); if ( i < m.nrows - 1 ) s << ","; } return s << "}"; } ]! ) TEX(![ Initialize a matrix over {\tt gf2} from an integer (the number of columns), and a white-space-free string, which gives the rows of the matrix. For example, valid arguments would be \par\noindent\kern1.5cm\verb|4, "{1111,1100,1010}"| or \verb|7, "{}"|. The brackets are optional. ]!) matrix::matrix( int nc, String s ) : ncols(nc) { static Regex matrixpat( "" + orsign + "{}" + orsign + list_of("[01]*") + orsign + "{" + list_of("[01]*") + "}" ); static Regex curlybracks( "[{}]" ); static Regex wordpat( "[01]*" ); if( !s.matches(matrixpat) ) ERROR("01 matrix is garbage"); s.gsub(curlybracks, ""); // delete brackets { } nrows = s.empty( ) ? 0 : s.freq(",") + 1; x = new vector[nrows]; for ( int i = 0; i < nrows; i++ ) { (*this)(i) = vector( take(s, wordpat), 0 ); if ( (*this)(i).length != ncols ) ERROR("A row in the matrix " << s << " has the wrong length."); if ( i < nrows - 1 ) require_char(s, ','); } } matrix::matrix(String s) { static Regex matrixpat( list_of("[01]*") + orsign + "{" + list_of("[01]*") + "}" ); static Regex curlybracks( "[{}]" ); static Regex wordpat( "[01]*" ); if( !s.matches(matrixpat) ) ERROR("01 matrix is garbage"); s.gsub(curlybracks, ""); // delete brackets { } nrows = s.empty( ) ? 0 : s.freq(",") + 1; ncols = -1; x = new vector[nrows]; for ( int i = 0; i < nrows; i++ ) { (*this)(i) = vector( take(s, wordpat), 0 ); if ( ncols == -1 ) ncols = (*this)(i).length; else if ( (*this)(i).length != ncols ) ERROR("A row in the matrix " << s << " has the wrong length."); if ( i < nrows - 1 ) require_char(s, ','); } } TEX(![ \block{Bit vector and graph classes} This section contains an interface to Brendan McKay's graph automorphism/isomorphism program nauty. We first give a class {\tt bitvec}, which is a vector of bits, like nauty's {\tt set} structure. Because we are not using {\tt bitvec}'s in any computationally intensive way, the class has not been optimized, but it could be by looking at how {\tt set} is implemented in nauty. I wanted to give an operator so that {\tt b(i)} could be use to set or retrieve the \th{\hbox{\tt i}} bit of a {\tt bitvector} {\tt b}, but I don't know how to do it. The bits are divided into words each having (say) $r$ bits. The bits in the first word are numbered $r-1,r-2,\ldots,1,0$. The bits in the second word are numbered $2r-1,2r-2,\ldots,r+1,r$, and so forth. However, we think of the bits in a {\tt bitvec} as being arranged from left to right: $0,1,2,\ldots$. A {\tt bitvec} can also be regarded as a set of finitely many nonnegative integers, an on bit signifying membership. Then we give a class \verb|vertex_colored_graph|, which contains the interface to nauty. ]! ) set_include_file(bitvec.h) #include index_class(bitvec) index_method(nwords) index_method(set_size) index_method(set) index_method(value) index_method(apply) index_method(weight) index_method(clear) index_method(intersection) index_method(Union) index_method(even_part) index_method(odd_part) index_method(left_shift1) index_method(right_shift1) index_method(set_zero) class bitvec { public: unsigned int* x; int length; // number of bits static int bits_per_int, log2_bpi; static int find_log2_bpi( ); int nwords( ) const { if ( length == 0 ) return 0; else return 1 + ((length - 1) >> log2_bpi); } bitvec(int n = 0) // define a bitvec with n bits, preset to 0 { length = n; int nw = nwords( ); x = new unsigned int[nw]; for ( int i = 0; i < nw; i++ ) x[i] = 0; } bitvec( const bitvec& b ) { length = b.length; int bnw = b.nwords( ); x = new unsigned int[ bnw ]; for ( int i = 0; i < bnw; i++ ) x[i] = b.x[i]; } ~bitvec( ) { delete [ ] x; } void set_size(int n) { if ( n == length ) return; delete [ ] x; length = n; int nw = nwords( ); x = new unsigned int[nw]; for ( int i = 0; i < nw; i++ ) x[i] = 0; } bitvec& operator=(const bitvec& b) { int bnw = b.nwords( ); if ( nwords( ) != bnw ) { delete [ ] x; x = new unsigned int[bnw]; } for ( int i = 0; i < bnw; i++ ) x[i] = b.x[i]; length = b.length; } void set(int i, bool j = true) // set the ith bit to j BHIDE2( ![ if ( i < 0 || i >= length ) INTERNAL_ERROR("set: invalid bit reference."); ]!, ![ int word_no = i >> log2_bpi; ]! ) int bit_no = i % bits_per_int; if (j) x[word_no] |= (1 << bit_no); else x[word_no] &= ~(1 << bit_no); } bitvec( const vector& w ) { if ( w.x == 0 ) { length = 0; x = new unsigned int[0]; } else { length = w.length; int nw = nwords( ); x = new unsigned int[nw]; int i; for ( i = 0; i < nw; i++ ) x[i] = 0; for ( i = 0; i < length; i++ ) if ( w(i) ) set(i); } } bool value(int i) const // return value of ith bit BHIDE2( ![ if ( i < 0 || i >= length ) INTERNAL_ERROR("value: invalid bit reference."); ]!, ![ int word_no = i >> log2_bpi; ]! ) int bit_no = i % bits_per_int; return (x[word_no] & (1 << bit_no)) != 0; } set_zero( ) { int nw = nwords( ); for ( int i = 0; i < nw; i++ ) x[i] = 0; } friend bool operator==(const bitvec& b1, const bitvec& b2) { if ( b1.length != b2.length ) return false; int nw = b1.nwords( ); for ( int i = 0; i < nw; i++ ) if ( b1.x[i] != b2.x[i] ) return false; return true; } friend bool operator!=(const bitvec& b1, const bitvec& b2) { return !(b1 == b2); } bitvec apply(const Permutation&p) const { bitvec ans(length); for ( int i = 0; i < length; i++ ) if ( value(i) ) ans.set( p(i) - 1 ); return ans; } TEX( ![ \begin{quote} If we regard a {\tt bitvec\/} as a set of nonnegative integers, then {\tt intersection} intersects these sets. \end{quote} ]! ) friend bitvec intersection(const bitvec& x, const bitvec& y) { int r = min( x.nwords( ), y.nwords( ) ); bitvec ans( max(x.length, y.length) ); for ( int i = 0; i < r; i++ ) ans.x[i] = x.x[i] & y.x[i]; return ans; } friend bitvec Union(const bitvec& x, const bitvec& y) { int r = min( x.nwords( ), y.nwords( ) ); bitvec ans( max(x.length, y.length) ); for ( int i = 0; i < r; i++ ) ans.x[i] = x.x[i] | y.x[i]; if ( x.nwords( ) > r ) for ( int j = r; j < x.nwords( ); j++ ) ans.x[j] = x.x[j]; else if ( y.nwords( ) > r ) for ( int j = r; j < y.nwords( ); j++ ) ans.x[j] = y.x[j]; return ans; } TEX( ![ \begin{quote} Convert an ordered list of nonnegative integers to a set of nonnegative integers, regarded as a {\tt bitvec}. \end{quote} ]! ) bitvec( const OSLList& l ) { if ( l.length( ) == 0 ) { length = 0; int nw = nwords( ); x = new unsigned int[nw]; for ( int i = 0; i < nw; i++ ) x[i] = 0; return; } length = l.Max( ) + 1; int nw = nwords( ); x = new unsigned int[nw]; for ( int i = 0; i < nw; i++ ) x[i] = 0; forPixDef( p, l ) set( l(p) ); } TEX( ![ \begin{quote} Extract the odd elements from a bitvec. (The first bit is numbered $0$.) \end{quote} ]! ) bitvec odd_part( ) const { bitvec ans(length); HIDE( ![ if (bits_per_int != 32) INTERNAL_ERROR( "Sorry, bitvec::odd_part assumes an int has " << "32 bits in it. The code will need to be rewritten." ); ]! ) static unsigned int odd_bits = 025252525252; int nw = nwords( ); for ( int i = 0; i < nw; i++ ) ans.x[i] = x[i] & odd_bits; return ans; } bitvec even_part( ) const { bitvec ans(length); HIDE( ![ if (bits_per_int != 32) INTERNAL_ERROR( "Sorry, bitvec::even_part assumes an int has " << "32 bits in it. The code will need to be rewritten." ); ]! ) static unsigned int even_bits = 012525252525; int nw = nwords( ); for ( int i = 0; i < nw; i++ ) ans.x[i] = x[i] & even_bits; return ans; } TEX( ![ \begin{quote} Left shift one bit, with the leftmost bit falling off into the bit bucket. \end{quote} ]! ) void left_shift1( ) { int nw = nwords( ); static unsigned int high_bit = 020000000000; HIDE( ![ if (bits_per_int != 32) INTERNAL_ERROR( "Sorry, bitvec::left_shift1 assumes an int has " << "32 bits in it. The code will need to be rewritten." ); ]! ) for ( int i = 0; i < nw; i++ ) { x[i] = x[i] >> 1; if ( i > 0 && even(x[i]) ) x[i-1] |= high_bit; } } TEX( ![ \begin{quote} Right shift one bit, adding a zero bit to fill the hole. \end{quote} ]! ) void right_shift1( ) { length++; int nw = nwords( ); bool high_bit_saved = false; HIDE( ![ if (bits_per_int != 32) INTERNAL_ERROR( "Sorry, bitvec::right_shift1 assumes an int has " << "32 bits in it. The code will need to be rewritten." ); ]! ) for ( int i = 0; i < nw; i++ ) { bool high_bit = x[31]; x[i] = x[i] << 1; if (high_bit_saved) x[i] |= 01; high_bit_saved = high_bit; } if ( length % 32 == 1 ) { bitvec me(length); for ( int j = 0; j < nw; j++ ) me.x[j] = x[j]; me.x[nw] = high_bit_saved; } } friend bitvec operator+(const bitvec& x, const bitvec& y) BHIDE2( ![ if ( x.length != y.length ) INTERNAL_ERROR("bitvec length inconsistency"); ]!, ![ bitvec ans(x.length); ]! ) int nw = x.nwords( ); for ( int i = 0; i < nw; i++ ) ans.x[i] = x.x[i] ^ y.x[i]; return ans; } HIDE( ![ friend bitvec operator-(const bitvec&) { INTERNAL_ERROR("There is no unary bitvec operator-."); } ]! ) friend inline bitvec operator-(const bitvec& x, const bitvec& y) { return x + y; } bitvec& operator+=(const bitvec& v) BHIDE2( ![ if (length != v.length) INTERNAL_ERROR("bitvec length inconsistency"); ]!, ![ int nw = nwords( ); ]! ) for ( int i = 0; i < nw; i++ ) x[i] ^= v.x[i]; } int weight( ) { int wt = 0, nw = nwords( ); static int bw[512]; // weight of each possible byte static bool first_call(true); if (first_call) { first_call = false; HIDE( ![ if (CHAR_BIT != 8) INTERNAL_ERROR("bitvec::weight is designed to work with " << "8 bit bytes. It will need to be rewritten."); if (bits_per_int != 32) INTERNAL_ERROR( "Sorry, bitvec::weight assumes an int has " << "32 bits in it. The code will need to be " << "rewritten." ); ]! ) for ( int i = 0; i < 512; i++ ) { bw[i] = 0; unsigned int z = i; for ( int j = 0; j < 8; j++ ) { if ( z & 1 ) ++bw[i]; z >>= 1; } } } register unsigned char* yp; register int i; for ( i = 0; i < nw; i++ ) { yp = (unsigned char*) &(x[i]); wt += bw[yp[0]] + bw[yp[1]] + bw[yp[2]] + bw[yp[3]]; } return wt; } void clear( ) { int nw = nwords( ); for ( int i = 0; i < nw; i++ ) x[i] = 0; } HIDE( ![ friend bool operator<(const bitvec& a, const bitvec& b) { INTERNAL_ERROR("operator< for bitvec not defined"); } friend bool operator>(const bitvec& a, const bitvec& b) { INTERNAL_ERROR("operator> for bitvec not defined"); } ]! ) friend ostream& operator<<(ostream& s, const bitvec& b) { for ( int i = 0; i < b.length; i++ ) s << b.value(i); return s; } }; set_compile_file(code.c) HIDE( ![ #include "simplex.h" double canonical_lp_problem::tolx; Quad canonical_lp_problem::tolx; Rational canonical_lp_problem::tolx; #include ]! ) int bitvec::bits_per_int = sizeof(unsigned int) * CHAR_BIT; int bitvec::find_log2_bpi( ) { int l = 0, n = bits_per_int; while ( n != 1 ) BHIDE2( ![ if ( odd(n) ) INTERNAL_ERROR( "The number of bits in an int is not a power of 2." << " You will need to redesign the bitvec class." ); ]!, ![ n = n/2; ]! ) l++; } return l; } int bitvec::log2_bpi = find_log2_bpi( ); set_include_file(bitvec.h) index_class(bitmat) class bitmat : public vector { public: bitmat(const matrix& M) : vector(M.nrows) { for ( int i = 0; i < length; i++ ) x[i] = M(i); } bitmat(int nrows, int ncols) : vector(nrows) { for ( int i = 0; i < nrows; i++ ) x[i].set_size(ncols); } }; set_include_file(graph.h) index_class(vertex_colored_graph) class vertex_colored_graph { public: int n; // number of vertices prevector a; // the adjacency matrix prevector c; // c(i) is the "color" of vertex i // The constructor initializes to an n-vertex graph with no edges and // each vertex colored "0". vertex_colored_graph(int n = 0) : n(n), a(n), c(n) { for ( int i = 0; i < n; i++ ) a(i) = bitvec(n); } void apply(const Permutation& p) { // The following is inefficient. p.act(c); vertex_colored_graph g(n); for ( int i = 0; i < n; i++ ) g.a( p(i) - 1 ) = a(i); for ( int i = 0; i < n; i++ ) a(i) = g.a(i).apply(p); } HIDE( ![ friend bool Isomorphic(vertex_colored_graph, vertex_colored_graph); ]! ) pair find_automorphism_group( ) const; }; set_compile_file(graph.cc) HIDE( ![ #include "basedefs.h" int rcmp(const number&, const number&); #include "bitvec.h" #include "graph.h" #include extern long time_used_by_Isomorphic; ]! ) #define MAXN 1024 #include "nauty.h" Integer group_size; Permutationlist generators_for_group; index_method(perm_store) void perm_store(int, permutation *perm, nvector *orbits, int, int, int n) { Permutation p(n); for ( int i = 0; i < n; i++ ) p(i) = perm[i] + 1; generators_for_group.append(p); } index_method(level_store) void level_store( nvector *lab, nvector *ptn, int, nvector *orbits, statsblk *stats, int, int index, int, int, int, int n ) { group_size *= index; } index_method(find_automorphism_group) pair< Permutationlist, Integer > vertex_colored_graph::find_automorphism_group( ) const { if ( n > MAXN ) ERROR("You are trying to find the automorphism group" << " of a graph with > " << MAXN << " vertices."); graph g[n * MAXM]; nvector orbits[n], lab[n], ptn[n]; static DEFAULTOPTIONS(options); statsblk(stats); int m = (n + WORDSIZE - 1) / WORDSIZE; int workroom = 50 * m; // See page 4 of nauty manual. setword workspace[workroom]; options.writemarkers = FALSE; options.writeautoms = FALSE; options.defaultptn = FALSE; options.userautomproc = (void (*)()) &perm_store; options.userlevelproc = (void (*)()) &level_store; // Set up coloring information for nauty. vertex_colored_graph G = *this; int i, j; Permutation p; vector cc = G.c; cc.sort(rcmp, p); Permutation pi = p.inverse( ); G.apply(p); for ( i = 0; i < n; i++ ) { lab[i] = i; ptn[i] = !( i == n - 1 || G.c(i) != G.c(i+1) ); } // Build the graph for nauty. for ( j = 0; j < n; ++j ) { set* gv = GRAPHROW(g, j, m); EMPTYSET(gv, m); for ( i = 0; i < n; i++ ) if ( G.a(i).value(j) ) ADDELEMENT( gv, i ); } // Invoke nauty. group_size = 1; generators_for_group.n = n; generators_for_group.clear( ); nauty( g, lab, ptn, NILSET, orbits, &options, &stats, workspace, workroom, m, n, NILGRAPH); for ( i = 0; i < generators_for_group.length; i++ ) generators_for_group(i) = pi * generators_for_group(i) * p; return make_pair( generators_for_group, group_size ); } index_method(Isomorphic) bool Isomorphic(vertex_colored_graph g1, vertex_colored_graph g2) { time_used_by_Isomorphic -= time(0); if ( g1.n != g2.n ) return false; if ( g1.n > MAXN ) ERROR("You are trying to find the automorphism group" << " of a graph with > " << MAXN << " vertices."); int i, j, k, n = g1.n; Permutation p1, p2; vector c1 = g1.c, c2 = g2.c; c1.sort(rcmp, p1); c2.sort(rcmp, p2); if ( c1 != c2 ) { time_used_by_Isomorphic += time(0); return false; } g1.apply(p1); g2.apply(p2); // Set up for nauty. graph g[n * MAXM], canong[n * MAXM]; nvector orbits[n], lab[n], ptn[n]; static DEFAULTOPTIONS(options); statsblk(stats); int m = (n + WORDSIZE - 1) / WORDSIZE; int workroom = 50 * m; setword workspace[workroom]; options.writemarkers = FALSE; options.writeautoms = FALSE; options.defaultptn = FALSE; options.getcanon = TRUE; // Build the graph for nauty, then invoke it. for ( j = 0; j < 2; j++ ) { // Prepare the graph coloring information for nauty. for ( i = 0; i < n; i++ ) { lab[i] = i; ptn[i] = !( i == n - 1 || g1.c(i) != g1.c(i+1) ); } for ( int col = 0; col < n; ++col ) { set *gv = GRAPHROW(g, col, m); EMPTYSET(gv, m); for ( int row = 0; row < n; row++ ) { if ( j == 0 && g1.a(row).value(col) ) ADDELEMENT( gv, row ); if ( j == 1 && g2.a(row).value(col) ) ADDELEMENT( gv, row ); } } nauty( g, lab, ptn, NILSET, orbits, &options, &stats, workspace, workroom, m, n, canong); Permutation p(n); for ( i = 0; i < n; i++ ) p(i) = lab[i] + 1; Permutation pi = p.inverse( ); if ( j == 0 ) g1.apply(pi); else g2.apply(pi); } bool answer = (g1.a == g2.a); time_used_by_Isomorphic += time(0); return answer; } TEX(![ \block{ShareGraph and multiedge classes} First we consider a rudimentary paradigm for exploratory computations involving abstract mathematical structures. Then we will exhibit a template class {\tt ShareGraph} which partially implements the paradigm. The only purpose of all of this is to clarify what we do in this program. It may be merged into the {\tt codehome} definition at a later date. \begin{center} \begin{tabular}{|c|}\hline node\\ \hline \end{tabular} \kern10pt\lower2pt\hbox{\LARGE$\equiv$}\kern10pt \begin{tabular}{|c|}\hline object\\ \hline facts about\\ the object\\ \hline \end{tabular} \kern40pt \begin{tabular}{|c|}\hline constructive\\ edge\\ \hline \end{tabular} \kern10pt\lower2pt\hbox{\LARGE$\equiv$}\kern10pt \begin{tabular}{|c|}\hline construction method\\ \hline \&node\\ \hline \&node\\ \hline \end{tabular} \end{center} \begin{center} \begin{tabular}{|c|}\hline logical\\ statement\\ \hline \end{tabular} \kern10pt\lower2pt\hbox{\LARGE$\equiv$}\kern10pt \begin{tabular}{|c|}\hline $f(\VEC x1n)$\\ \hline \&(node $1$)\\ \hline $\cdots$\\ \hline \&(node $n$)\\ \hline \end{tabular} \kern40pt \begin{tabular}{|c|}\hline equivalence\\ class\\ \hline \end{tabular} \kern10pt\lower2pt\hbox{\LARGE$\equiv$}\kern10pt \begin{tabular}{|c|}\hline shared facts\\ \hline \&node\\ \hline $\cdots$\\ \hline \&node\\ \hline \end{tabular} \end{center} We describe the paradigm in terms of the above pictures, along the way illustrating the paradigm by means of the coding language in this paper. First, a specific instance of the entities in the above pictures (nodes, constructive edges, logical statements, equivalence classes, and the components of each) comprise a {\it world}. In our usage, a world would correspond to a code type, and the objects (or nodes) would be configurations. A {\it logical statement\/} is just a boolean formula $f$ (without quantifiers) between references to nodes. For example, $x_1$ would mean that node $1$ exists, and $x_1 \rightarrow x_2$ (i.e.\ $(\neg x_1) \vee x_2$) would mean that if node $1$ exists, then so does node $2$. The situation where $x_1 \Longleftrightarrow x_2 \Longleftrightarrow \cdots \Longleftrightarrow x_n$ arises sufficiently frequently that a special entity (equivalence class) is given. The equivalent nodes share facts which are meaningful and known to be true for all of them. One often arrives at a logical statement like $x_1 \Leftrightarrow x_2$ by way of a specific construction which starts with $x_1$ and builds $x_2$. A {\it constructive edge\/} ``remembers'' that the logical statement was gotten in this way. Thereafter, certain facts (obtained after the construction) may flow along the edge from $x_1$ to $x_2$, or perhaps the other way. Thus the constructive edge codifies an active conduit for information flowing between two nodes. Now we turn to a real structure, the template class {\tt ShareGraph}. It is based on a vertex class ({\tt V}), a vertex share class ({\tt VS}), and an edge class ({\tt E}). The idea is that a {\tt ShareGraph} object {\tt G} is a directed multigraph\footnote{Multiple edges and loops are allowed; here we follow the terminology of [.bollobas course.], p.\ 5.} whose vertices are objects of {\tt V}, whose edges are objects of {\tt E}, and such that to each connected component of {\tt G} there is associated an object of {\tt VS}. The vertex class {\tt V} must have a member ``{\tt share}'' of type {\tt VS*}. The vertices are expected to be unequal objects, and so {\tt V} must be provided with an equality operator {\tt ==}. (This should not test the {\tt share} member.) Likewise, given vertices $i$ and $j$, the edges from $i$ to $j$ are expected to be unequal objects, and so {\tt E} must be provided with an equality operator {\tt ==}. The vertex share class must have a {\it merge} operator {\tt +} which is to be invoked whenever (by adding an edge) two connected components of {\tt G} are coalesced. To declare and initialize (to null) a {\tt ShareGraph} {\tt G} one uses the command: \par\noindent\kern0.5in{\tt ShareGraph G;}\par\noindent where {\tt V}, {\tt VS}, and {\tt E} are replaced by the appropriate classes. To create a vertex one uses the command: \par\noindent\kern0.5in% {\tt Pix i = G.add(}{\it vertex object}{\tt );}% \par\noindent which will add the object as a vertex if the vertex object does not already exist. (If it already exists, no action is taken.) To search for a vertex object {\tt x} of {\tt V}, use \par\noindent\kern0.5in{\tt Pix i = G.find(x);} \par\noindent which returns $0$ if {\tt x} is not found. The find function has nothing to do with {\tt VS}. From now on, when we refer to a {\it vertex\/} {\tt i}, we really mean a {\tt Pix} {\tt i} which corresponds to a vertex of {\tt G}. Now if {\tt i} and {\tt j} are vertices, then \par\noindent\kern0.5in% {\tt Pix k = G.join(i, j, }{\it edge object}{\tt);}\par\noindent makes an edge from vertex {\tt i} to vertex {\tt j}, labelled with the given edge object, provided that it does not already exist. The edge object may be omitted. If {\tt i} is a vertex of {\tt G}, {\tt woof} is a member of {\tt V}, and {\tt bark} is a member of {\tt VS}, one may access these members via \par\noindent\kern0.5in{\tt G(i).woof} \par\noindent\kern0.5in{\tt G(i).share->bark}. \par\noindent To search for an edge object {\tt e} of {\tt E}, from vertex {\tt i} to vertex {\tt j}, use \par\noindent\kern0.5in\verb|G.find_edge(i,j,e);| \par\noindent which returns $0$ if {\tt e} is not found. Traversal by pixes of vertices is provided in the usual way: \par\noindent\kern0.5in% {\tt for ( Pix i = G.first( ); i != 0; G.next(i) ) use(G(i));} \par\noindent One can traverse the edges from vertex {\tt i} to vertex {\tt j} via: \par\noindent\kern0.5in% {\tt for ( Pix e = G(i,j).first( ); e != 0; G(i,j).next(e) ) use(G(i,j)(e));} The implementation follows. It is not particularly efficient, and is intended for situations where this does not matter. First we give a primitive {\tt Map} class. \indexz{Map} \mindex{first}\mindex{next} ]!) set_include_file(share.h) template class Map { public: SLList< pair< key, contents > > data; contents Default; Pix first( ) { return data.first( ); } void next(Pix& p) { data.next(p); } key& operator( )(Pix p) { return data(p).first; } contents& take(Pix p) { return data(p).second; } inline contents& operator[ ](const key&); Map(const contents& d) : Default(d) { } Map( ) { } }; template inline contents& Map::operator[ ](const key& k) { forPixDef ( i, data ) if ( k == data(i).first ) return data(i).second; Pix p = data.append( make_pair(k, contents(Default)) ); return data(p).second; } index_class(ShareGraph) template class ShareGraph { public: DLList vertices; Map< pair, SLList > edges; ShareGraph( ) : edges( SLList( ) ) { } // I don't quite understand why the following const_cast is needed. V& operator( )(Pix i) const { return const_cast(vertices(i)); } Pix first( ) { return vertices.first( ); } void next(Pix& i) { vertices.next(i); } V& operator[ ](Pix i) { return (V&) vertices(i); } SLList operator( )(Pix i, Pix j) // Perhaps broken. { return edges[ make_pair(i,j) ]; } index_method(add) Pix add(const V& vert) { forPixDef( i, vertices ) if ( vertices(i) == vert ) return i; return vertices.append(vert); } index_method(del) void del(Pix p) { VS* sh = vertices(p).share; vertices.del(p); forPixDef( i, vertices ) if ( vertices(i).share == sh ) break; if ( i == 0 ) delete sh; } index_method(join) void join(Pix i, Pix j) { if ( vertices(i).share != vertices(j).share ) { VS* merge = *(vertices(i).share) + *(vertices(j).share); delete vertices(i).share; delete vertices(j).share; VS* old_i = vertices(i).share; VS* old_j = vertices(j).share; forPixDef( k, vertices ) if ( vertices(k).share == old_i || vertices(k).share == old_j ) vertices(k).share = merge; } } void join(Pix i, Pix j, const E& e) { if ( find_edge(i, j, e) ) return; edges[ make_pair(i,j) ].append(e); join(i, j); } SLList sharelist( ) { OSLList s; forPixDef( i, vertices ) s.add( vertices(i).share ); return s; } ~ShareGraph( ) { SLList s = sharelist( ); forPixDef( i, s ) delete s(i); } index_method(find) Pix find(const V& x) { forPixDef( i, vertices ) if ( vertices(i) == x ) return i; return 0; } index_method(find_edge) Pix find_edge(Pix i, Pix j, const E& e) { forPixDef( k, (*this)(i,j) ) if ( (*this)(i,j)(k) == e ) return k; return 0; } }; set_compile_file(code.c) HIDE(![#include "share.h"]!) TEX( Objects of class {\tt multiedge} encode logical relationships of the form $a \Longrightarrow (b_1 \kern5pt\hbox{or} \cdots \hbox{or}\kern5pt b_n)$. ) set_include_file(multiedge.h) template class multiedge : public pair< T, OSLList > { }; set_compile_file(code.c) HIDE(![#include "multiedge.h"]!) set_include_file(state.h) template class state_list : public Map { public: void propagate( SLList< multiedge > ); void reverse_propagate( SLList< multiedge > ); }; TEX( Propagate according to the rule $\VEC b1n$ true $\Longrightarrow$ $a$ true. ) index_method(propagate) template inline void state_list::propagate( SLList< multiedge > m ) { state_list& s = *this; Pix p, q; while(1) { forPix( p, m ) { multiedge& me = m(p); forPix( q, me.second ) if ( !s[me.second(q)] ) break; if ( q == 0 && !s[me.first] ) { s[me.first] = true; break; } } if ( p == 0 ) return; } } TEX( Propagate according to the rule $n = 1$ and $a$ true $\Longrightarrow$ $b_1$ true. ) index_method(reverse_propagate) template inline void state_list::reverse_propagate( SLList< multiedge > m ) { state_list& s = *this; Pix p, q; while(1) { forPix( p, m ) { multiedge& me = m(p); if ( me.second.length( ) == 1 && !s[me.second.front( )] && s[me.first] ) { s[me.second.front( )] = true; break; } } if ( p == 0 ) return; } } set_compile_file(code.c) HIDE(![#include "state.h"]!) TEX(![ \block{Terms, term{\tt\_}sums, constraints, qvconstraints, vconstraints, constraintlists, constraint files} Abstractly, a {\it constraint\/} is a relation of the form $$a_1 v_1 \many+ a_n v_n \kern3pt\square\kern3pt k,$$% where $\VEC v1n$ are variables, $\VEC a1n \in \Q$, $k \in \Z$, and $\square$ is either $\leq$, $\geq$, or $=$. Constraints are represented in several different ways, according to what variables and coefficients are allowed: \begin{enumerate} \item When constraints appear in commands, the variables are arbitrary (within the confines of the language), and the coefficients are in $\Z$. \item These constraints are internally represented (using the ``{\tt constraint}'' class) in the same way, except that $\Q$-coefficients are allowed. This is because some internal operations may result in constraints whose coefficients are not integers. (This can happen when the ``{\tt incorporate}'' command is used.) \item For split linear programming calculations, constraints are first converted to constraints involving {\tt v} variables and having coefficients in $\Q$ (class {\tt qvconstraint}). \item Clearing denominators yields constraints having {\tt v} variables and coefficients in $\Z$\\ (class {\tt vconstraint}). The constraints which are generated automatically (for split linear programming) naturally have this form. The raison d'\^etre for the separate class ``{\tt vconstraint}'' is that there are huge numbers of these automatically generated constraints. \end{enumerate} Lists of constraints (class {\tt constraint}) are managed by the class {\tt constraintlist}. The following diagram summarizes some of the conversions which take place in this section, with emphasis on strings and input-output: \diagramx{\hbox{\tt String}& \mapE{} &\hbox{\tt term\string_sum}&&&&&& \hbox{\tt String}\cr &&\mapS{}&&&&&&\mapS{}\cr &&\hbox{\tt String}&\mapE{}&\hbox{\tt term}&&\hbox{input} &&\hbox{\tt constraintlist}\cr &&\mapS{}&&&&\mapS{}&&\mapS{}\cr \hbox{input} & \mapE{} & \hbox{\tt constraint} & \mapE{} & \hbox{\tt qvconstraint} & \mapE{} & \hbox{\tt vconstraint} & \mapE{} & \hbox{output}\cr &&\mapS{}\cr &&\hbox{\tt String}} \indexz{term} ]!) set_include_file(basedefs.h) HIDE( ![ // #define DEBUG class Permutation; extern "C" long random( ); #include "gnutypes.h" #include "macros.h" #include "OSLList.h" #include "pair_.h" #include "numgf2.h" #include "prevector.h" #include "vector_.h" #include "cmp.h" #include "quad.h" #include "dot.h" #include "permutation.h" template void orbit( const prevector&, const S&, prevector&, int (*cmp)(const S&, const S&), void (*act)(const G&, const S&, S&), int = -1 ); int pcmp( const Permutation&, const Permutation& ); #include "permutationlist.h" #include "matrix.h" #include "constraint.h" String take(String&, const Regex&); Integer choose(int, int); String str(Rational); extern String var, pos_term, signed_number, op, constraint_pat, left, right, number_pat, orsign, pos_number, pos_list; inline int even(int i) { return !(i % 2); } prevector unpack(String s, String delim = ","); extern "C" int isspace(int); extern "C" int isdigit(int); ]! ) typedef vector word; set_include_file(constraint.h) class term { public: Rational coeff; // coefficient String var; // variable name term(const Rational& m, const String& s) : coeff(m), var(s) { } // constructor, e.g. from -5, "y3" term(String); // constructor from a white-space-free // string, e.g. from "-5y3" // (coefficient must be an integer) term( ) { } }; set_compile_file(constraint.cc) HIDE(![ #include "homedefs.h" extern int warnings_are_fatal, debug; ]!) term::term(String s) { static Regex signed_number_pat("[+-]?[0-9]*"); String s1 = take(s, signed_number_pat); if ( s1 == "" || s1 == "+" ) coeff = 1; else coeff = (s1 == '-') ? Integer(-1) : atoI(s1); var = s; } TEX(![ A \verb|term_sum| is a list of terms, to be regarded as a sum. ]!) set_include_file(constraint.h) index_class(term_sum) HIDE( ![ extern String pos_term; extern String take(String&, const Regex&); ]! ) class term_sum : public DLList { public: term_sum(String t) { static Regex term_pat( "[+-]?" + pos_term ); while ( !t.empty( ) ) append(term(take(t, term_pat))); } term_sum( ) { } operator String( ) const; merge(const term& t) { forPixDef( p, *this ) if ( (*this)(p).var == t.var ) break; if ( p == 0 ) append(t); else (*this)(p).coeff += t.coeff; } friend ostream& operator<<(ostream&s, const term_sum& t) { return s << String(t); } }; set_compile_file(constraint.cc) term_sum::operator String( ) const { const term_sum& t = *this; String s; bool first_nonzero_term = true; forPixDef( i, t ) { if ( sign ( t(i).coeff ) != 0 ) { if (!first_nonzero_term && sign ( t(i).coeff ) > 0) s += " + "; if ( t(i).coeff == 1 ); else if ( t(i).coeff > 0 ) s += str(t(i).coeff); else { s += first_nonzero_term ? "-" : " - "; if ( t(i).coeff != -1 ) s += str(-t(i).coeff); } s += t(i).var; first_nonzero_term = false; } } return s; } index_class(constraint) index_method(simple) index_method(simple_local) index_method(simple_local_zero) index_method(simple_global) index_method(addterm) index_method(adjoin) index_method(clear_denominators) index_method(global) index_method(local) index_method(joint) set_include_file(constraint.h) class constraint { public: term_sum LHS; // left hand side char sense; // >, <, or =, where > means >=, < means <= Integer RHS; // right hand side void addterm(const Rational& k, const String& s) // add term to LHS { if ( k != 0 ) LHS.append(term(k, s)); } constraint(String); // constructor from white-space-free string constraint( ) { } constraint(char sense, const Integer& RHS) : sense(sense), RHS(RHS) { } operator String( ) const; bool global( ) const { forPixDef( p, LHS ) if ( !global_var( LHS(p).var ) ) return false; return true; } bool local( ) const { forPixDef( p, LHS ) if ( !global_var( LHS(p).var ) && !local_var( LHS(p).var ) ) return false; return true; } bool joint( ) const { forPixDef( p, LHS ) if ( !global_var( LHS(p).var ) && !joint_var( LHS(p).var ) ) return false; return true; } void adjoin(const term_sum& t) { forPixDef( p, t ) LHS.merge( t(p) ); } bool simple( ) const { return LHS.length( ) == 1 && LHS.front( ).coeff == Rational(1); } bool simple_local( ) const { return simple( ) && LHS.front( ).var[0] == 'x'; } bool simple_local_zero( ) const { return simple_local( ) && sense == '=' && RHS == 0; } bool simple_global( ) const { return simple( ) && LHS.front( ).var[0] == 'y'; } HIDE( ![ friend istream& operator>>(istream&, constraint&); ]! ) friend ostream& operator<<(ostream&s, const constraint& t) { return s << String(t); } void clear_denominators( ) { Integer multiplier = 1; forPixDef( p, LHS ) multiplier = lcm( multiplier, LHS(p).coeff.denominator( ) ); forPix( p, LHS ) LHS(p).coeff *= multiplier; RHS *= multiplier; } }; set_compile_file(constraint.cc) constraint::constraint(String t) { static Regex var_pat(var); static Regex beetle( "[+-]?" + pos_term ); static Regex signed_number_pat(signed_number); static Regex op_plus(op + ".*"); if_match( t, var + "!=0" ) { addterm(1, take(t, var_pat)); sense = '>'; RHS = 1; } else { if_no_match( t, constraint_pat ) ERROR( "\"" << t << "\" is not a valid constraint" ); while ( !t.matches(op_plus) ) LHS.append(term(take(t, beetle))); sense = t[0]; t.del(sense); int equals = (t[0] == '='); if (equals) t.del('='); RHS = atoI(take(t, signed_number_pat)); if ( equals == 0 ) { if ( sense == '<' ) --RHS; if ( sense == '>' ) ++RHS; } } } constraint::operator String( ) const { if ( LHS.length( ) > 1000 ) WARNING( "A request has been made to convert a very large " << "constraint into a string. The constraint has " << LHS.length( ) << " terms. It is possible that a string-related " "abortion will result." ); String s = String(LHS); return s + (sense == '=' ? " = " : (sense == '>' ? " >= " : " <= ")) + dec(RHS); } istream& operator>>(istream&s, constraint& t) { String con; char c; do { s.get(c); if ( !isspace(c)) con += c; } while ( c != '=' ); do { s.get(c); if ( !isspace(c) ) con += c; } while ( !isdigit(c) ); do { s.get(c); if ( !isspace(c)) con += c; } while ( c != '\n' ); t = constraint(con); return s; } index_method(eat_constraint) void eat_constraint(istream& s) { char c; do s.get(c); while ( c != '=' ); do s.get(c); while ( !isdigit(c) ); do s.get(c); while ( c != '\n' ); } TEX( The following routine translates constraints for the ``{\tt incorporate}'' command. If the {\tt verbatim} flag is set, the working weight list will not be used to simplify constraints. This is necessary when the constraint is an assumed constraint. \mindex{translate} ) constraint translate( const config& cs, const constraint& c, const String& sub_var, int nparts, int insertion_point, bool verbatim = false ) { constraint new_c( c.sense, c.RHS ); term_sum ts = cs.simplify_global_vars(c.LHS, verbatim); forPixDef( q, ts ) { String v = ts(q).var; Rational cf = ts(q).coeff; if ( v[0] == 'y' ) v.at(0,1) = "sub" + sub_var + "_"; else if ( v[0] == 'x' ) { String zero = (v[1] == '_') ? "_0" : "0"; v.at("x") = "x" + replicate(zero, insertion_point); v += replicate(zero, nparts - insertion_point - 1); } else if ( v[0] == 's' ) { v.at("sub") = "sub" + replicate("0", insertion_point); String zeros = replicate("0", nparts - insertion_point - 1); if ( v.contains("_") ) v.at("_") = zeros + "_"; else v += zeros; } else if ( v[0] == 'z' ) { v.at("z") = "q" + replicate("_z", insertion_point); v += replicate("_z", nparts - insertion_point - 1); cf /= Ipow(2, cs.home->dim); } else /* q variable */ { v.at("q") = "q" + replicate("_z", insertion_point); v += replicate("_z", nparts - insertion_point - 1); } new_c.addterm( cf, v ); } return new_c; } set_compile_file(code.c) HIDE( ![ #include "constraint.h" void eat_constraint(istream&); constraint translate(const config&, const constraint&, const String&, int, int, bool = false); int cmp_secondI( const pair&, const pair&); template void sort_by_second( prevector< pair >&); sort_by_secondx( prevector< pair >& p ) { p.sort( &cmp_secondI ); } ]! ) set_include_file(vconstraint.h) index_method(set) index_class(qvconstraint) class qvconstraint { public: vector LHS; char sense; Rational RHS; qvconstraint(const constraint&, codehome*); qvconstraint(int nvars) : LHS(nvars) { } qvconstraint( ) { } void set(char s, const Rational& R) { sense = s, RHS = R; } }; index_class(vconstraint) index_method(if_zero) class vconstraint { public: vector LHS; char sense; Integer RHS; vconstraint(int nvars) : LHS(nvars) { } vconstraint( ) { } void set(char s, const Integer& I) { sense = s, RHS = I; } bool if_zero( ) { return RHS == 0 && LHS.if_zero( ); } HIDE( ![ friend ostream& operator<<(ostream&, const vconstraint&); friend istream& operator>>(istream&, vconstraint&); friend Rational clear_denom(const qvconstraint&, vconstraint&); friend bool operator==(const vconstraint&, const vconstraint&) { INTERNAL_ERROR("operator== for vconstraint not defined"); } friend bool operator!=(const vconstraint&, const vconstraint&) { INTERNAL_ERROR("operator!= for vconstraint not defined"); } ]! ) void reduce( ); }; set_compile_file(constraint.cc) istream& operator>>(istream& s, vconstraint& vcon) { vcon.LHS.set_zero( ); char c; Integer coeff; int var_no, signx; while(1) // Read left hand side. { s >> c; if ( c == '=' || c == '<' || c == '>' ) break; // Read a coefficient. signx = 1; if ( c == '+' ) s >> c; else if ( c == '-' ) { s >> c; signx = -1; } if ( c == 'v' ) { coeff = signx; s.unget( ); } else { s.unget( ); s >> coeff; if ( signx == -1 ) coeff = -coeff; } // Process variable. s >> c >> var_no; vcon.LHS( var_no - 1 ) = coeff; } // Determine sense and right hand side. vcon.sense = c; if ( vcon.sense != '=' ) s.get(c); s >> vcon.RHS; while( c != '\n' ) s.get(c); } TEX( Divide the coefficients and \RHS\ of a {\tt vconstraint} by their $\gcd$. Do not call with a zero constraint. ) index_method(reduce) void vconstraint::reduce( ) { Integer divider = RHS; for ( int i = 0; i < LHS.length; i++ ) divider = gcd(divider, LHS(i)); if ( divider == 1 ) return; HIDE( ![ if (debug) { if ( divider == 0 ) INTERNAL_ERROR( "Attempting to divide by zero in vconstraint::reduce." ); } ]! ) for ( int i = 0; i < LHS.length; i++ ) LHS(i) /= divider; RHS /= divider; } TEX(![ \verb|clear_denom|:\ Replace a given constraint with rational coefficients by a constraint {\tt c} whose coefficients are integers and relatively prime, returning the rational number which one has to multiply by to accomplish this. In case the constraint is identically zero, return garbage for {\tt c} but a multiplier of zero. ]!) index_method(clear_denom) Rational clear_denom(const qvconstraint& qc, vconstraint& c) { Integer multiplier = qc.RHS.denominator( ); Integer divider = abs(qc.RHS.numerator( )); for ( int i = 0; i < qc.LHS.length; i++ ) { multiplier = lcm( multiplier, qc.LHS(i).denominator( ) ); divider = gcd( divider, qc.LHS(i).numerator( ) ); } if ( divider == 0 ) return 0; for ( int i = 0; i < qc.LHS.length; i++ ) c.LHS(i) = (qc.LHS(i).numerator( ) * multiplier) / (qc.LHS(i).denominator( ) * divider); c.RHS = (qc.RHS.numerator( ) * multiplier) / (qc.RHS.denominator( ) * divider); c.sense = qc.sense; return Rational(multiplier, divider); } ostream& operator<<(ostream& s, const vconstraint& t) { bool first_nonzero = true; for ( int i = 0; i < t.LHS.length; i++ ) if ( t.LHS(i) != 0 ) { if (first_nonzero) { first_nonzero = false; if ( t.LHS(i) == -1 ) s << "-"; else if ( t.LHS(i) != 1 ) s << t.LHS(i); } else { if ( t.LHS(i) > 0 ) { if ( t.LHS(i) != 1 ) s << " + " << t.LHS(i); else s << " + "; } else { if ( t.LHS(i) != -1 ) s << " - " << -t.LHS(i); else s << " - "; } } s << "v" << i + 1; } s << " " << t.sense; return s << ((t.sense == '=') ? " " : "= ") << t.RHS << "\n"; } set_include_file(constraint.h) index_class(constraintlist) index_method(merge) index_method(global) index_method(joint) index_method(local) index_method(intersection) class constraintlist : public DLList { public: constraintlist(const String&); constraintlist( ) { } // The following line was added to circumvent an internal compiler // error message. This error should be reported. ~constraintlist( ) { } void evaluate(const String&, Integer&, Integer&) const; bool known(const constraint&) const; void merge(const constraintlist& l) { forPixDef( i, l ) if ( !known( l(i) ) ) append( l(i) ); } void merge(const constraint& c) { if ( !known(c) ) append(c); } bool global( ) const { forPixDef( p, *this ) if ( !(*this)(p).global( ) ) return false; return true; } bool local( ) const { forPixDef( p, *this ) if ( !(*this)(p).local( ) ) return false; return true; } bool joint( ) const { forPixDef( p, *this ) if ( !(*this)(p).joint( ) ) return false; return true; } friend bool operator<=(const constraintlist& c1, const constraintlist& c2) { forPixDef( i, c1 ) if ( !c2.known( c1(i) ) ) return false; return true; } friend bool operator>=(const constraintlist& c1, const constraintlist& c2) { return c2 <= c1; } friend bool operator==(const constraintlist& c1, const constraintlist& c2) { return c1 <= c2 && c2 <= c1; } friend bool operator!=(const constraintlist& c1, const constraintlist& c2) { return !(c1 == c2); } operator String( ) const { String s; forPixDef( i, *this ) { if ( i != first( ) ) s += ", "; s += (*this)(i); } return s; } friend ostream& operator<<(ostream& s, const constraintlist& l) { forPixDef( i, l ) { if ( i != l.first( ) ) s << ", "; s << l(i); } return s; } friend constraintlist intersection(const constraintlist& l1, const constraintlist& l2) { constraintlist ans; forPixDef( p, l1 ) { if ( l2.known( l1(p) ) ) ans.merge( l1(p) ); else if ( l1(p).sense == '=' ) { constraint c = l1(p); c.sense = '>'; if ( l2.known(c) ) ans.merge(c); c.sense = '<'; if ( l2.known(c) ) ans.merge(c); } } forPix( p, l2 ) { if ( l1.known( l2(p) ) ) ans.merge( l2(p) ); else if ( l2(p).sense == '=' ) { constraint c = l2(p); c.sense = '>'; if ( l1.known(c) ) ans.merge(c); c.sense = '<'; if ( l1.known(c) ) ans.merge(c); } } return ans; } }; set_compile_file(constraint.cc) TEX(![ {\tt evaluate(v, low, high):}\ Let {\tt v} be a variable. Search for constraints whose \LHS\ is {\tt v}, to get integer lower and upper bounds. If no upper bound is found, {\tt high} is set to $-1$. The preexisting values for {\tt low} and {\tt high} are assumed to be known bounds, with the same convention regarding {\tt high} $= -1$. ]!) index_method(evaluate) void constraintlist::evaluate(const String& s, Integer& low, Integer& high) const { forPixDef( i, *this ) { const constraint& c = (*this)(i); if ( c.LHS != term_sum(s) ) continue; if ( c.sense == '=' || c.sense == '<' ) { // If the RHS of the constraint is negative, it is inherently // contradictory. This isn't likely to happen, so we just // give up in that case. if ( c.RHS < 0 ) return; if ( high == -1 ) high = floor(c.RHS); else high = min( high, floor(c.RHS) ); } if ( c.sense == '=' || c.sense == '>' ) low = max( low, ceil(c.RHS) ); } } TEX(![ The following constructor for a {\tt constraintlist} has as its argument a comma-separated list of constraints, allowing for compound forms, as discussed in the description of the {\tt show} command. ]!) constraintlist::constraintlist(const String& s) { static Regex snort = "[^<]*"; static Regex wheeze = "[-0-9]+"; prevector v = unpack(s); for ( int i = 0; i < v.length; i++ ) if ( v(i).freq("<") <= 1 ) append( constraint(v(i)) ); else // compound form { Integer low = atoI(take(v(i), wheeze)); require_char( v(i), '<' ); if ( v(i)[0] == '=' ) v(i).del("="); else ++low; append(constraint( v(i).at(snort) + ">=" + dec(low) )); append(constraint(v(i))); } } TEX(![ Determine if a constraint is in a constraintlist. This is at present checked in a more or less literal way, as follows. A constraint with ``{\tt=}'' in it must appear verbatim in the constraintlist in order for {\tt true} to be returned. A constraint with ``{\tt<=}'' or ``{\tt>=}'' will be ``found'' if a stronger constraint with the same \LHS\ appears. Thus for example {\tt y10 <= 15} will be found if {\tt y10 = 12} is in the constraintlist. ]!) index_method(known) bool constraintlist::known(const constraint& c) const { if ( c.LHS.length == 0 ) return test ( Integer(0), c.RHS, c.sense ); forPixDef( i, *this ) { const constraint& c_known = (*this)(i); if ( c.LHS != c_known.LHS ) continue; if ( (c.sense == c_known.sense || c_known.sense == '=') && test ( c_known.RHS, c.RHS, c.sense ) ) return true; } return false; } set_compile_file(code.c) HIDE(![#include "vconstraint.h"]!) TEX( \block{Word and code classes} \indexz{word} ) HIDE(![typedef vector word;]!) TEX( ![ Note that a code may exist in a built state (with {\tt x} defined), or in an unbuilt state (with {\tt x} undefined). The default is undefined. ]! ) set_include_file(code.h) index_class(code) class code { public: matrix basis; // rows are basis for the code matrix x; // rows are the elements themselves code(int, const String&); code( ) { } void build( ) const; // build x ("const", but modifies x) void unbuild( ) const; code& operator=(const code& c) { basis = c.basis; } }; set_compile_file(code.c) HIDE(![#include "code.h"]!) code::code(int nc, const String& s) : basis(nc, s) { basis.reduce( ); if ( basis.nrows != 0 && basis(basis.nrows-1).if_zero( ) ) ERROR("The alleged basis elements are dependent."); } index_method(build) void code::build( ) const { matrix& x_mutable = const_cast&>(x); if ( x.x == 0 ) { int i = 0, d = basis.nrows; if (d > 30) ERROR("I was about to compute all the elements of a code " << "of length > 30, which is probably a bad idea."); x_mutable.set_size( as_int( Ipow(2,d) ), basis.ncols ); if ( d == 0 ) return; word indx(d); do mul( indx, basis, x_mutable(i++) ); while ( indx.advance( ) != 0 ); } } index_method(unbuild) void code::unbuild( ) const { matrix& x_mutable = const_cast&>(x); if ( x_mutable.x != 0 ) { delete [ ] x_mutable.x; x_mutable.x = 0; } } TEX( ![ \block{Partition, wordtype, mawhome, and mawhometable classes}% \label{partition-wordtype-mawhome-section} \indexz{partition} ]! ) set_include_file(partition.h) index_method(operator*(vector$<$gf2$>$, partition)) index_method(set_all_ones) class partition : public vector { public: int n; // sum of the elements partition(const String&); partition( ) { } partition(int l) : vector(l) { } void set_all_ones(int r) { set_size(r); n = r; for ( int i = 0; i < r; i++ ) (*this)(i) = 1; } }; set_compile_file(code.c) HIDE(![#include "partition.h"]!) TEX(![ Constructor of partition from a string, which should be a white-space-free comma-separated list of $\geq 1$ positive integers. ]!) partition::partition(const String& s) : vector(s) { n = 0; for ( int i = 0; i < length; i++ ) { if ( (*this)(i) == 0 ) ERROR( "0 element in partition " << s ); n += (*this)(i); } } TEX(![ A ``{\tt wordtype}'' is the data structure which represents basic local variables, as well as the dual analog. We define here what it means for a wordtype $w$ to be {\it minimal}, as was promised on page \pageref{minimal-promise}. For the configuration $c$ to which $w$ is associated, let $M$ be the unique matrix in \RREF\ whose rows form a basis for the small code. Then $w$ is {\it minimal\/} if the following two conditions are satisfied: \begin{enumerate} \item for each $i$ such that $M$ has a leading $1$ in column $i$ (where the columns are numbered starting at $0$), we have $w(i) \leq p(i)/2$, where $p$ is the partition of $c$; \item amongst all wordtypes which are equivalent to $w$ and satisfy (1), $w$ is lexicographically minimal. \end{enumerate} \indexz{wordtype} ]!) set_include_file(wordtype.h) index_method(wcmp) class wordtype : public vector { public: const config* c; // pointer to associated config wordtype(const config*); // constructor of zero wordtype wordtype(const config*, String); // e.g. (1,2,3) from "x_1_2_3" wordtype(const vector& v) : vector(v) { } wordtype( ) { }; String variable( ) const; // make a variable name (string) advance(config_active*); // get next minimal admissible wordtype dual_advance(bool); void act(const word&, const wordtype&); void act(const word&); // Lexicographically compare two wordtypes. friend bool operator<(const wordtype& w1, const wordtype& w2) { for ( int i = 0; i < w1.length; i++ ) { if ( w1(i) < w2(i) ) return true; if ( w1(i) > w2(i) ) return false; } return false; } friend bool operator>(const wordtype& w1, const wordtype& w2) { return w2 < w1; } HIDE( ![ friend int sum(const wordtype&); friend bool is_pullback(const wordtype&, const wordtype&, const wordtype&); ]! ) friend int wcmp(const wordtype& a, const wordtype& b) { register int i, n = a.length; for ( i = 0; i < n; i++ ) { if ( a(i) > b(i) ) return 1; if ( a(i) < b(i) ) return -1; } return 0; } }; set_compile_file(wordtype.cc) HIDE(![#include "homedefs.h" matrix subdivide_matrix(const matrix&, const partition&, const wordtype&, bool); int String_cmp(const String&, const String&); ]!) wordtype::wordtype(const config* c, String v) : c(c) { static Regex alt_wordtype_pattern( "x[0-9]+" ); prevector args; String v_save = v; if ( v[0] == 'y' ) v.at("y") = "x_"; if_match( v, "x" + left + "_" + number_pat + right + "+" ) args = unpack(v.after("x_"), "_"); else if ( v.matches(alt_wordtype_pattern) ) args = unpack(v.after("x"), ""); else goto error_exit; if ( args.length != c->part.length ) goto error_exit; set_size(args.length); for ( int i = 0; i < args.length; i++ ) { (*this)(i) = as_int(args(i)); if ( (*this)(i) > c->part(i) ) goto error_exit; } return; error_exit: ERROR( "\"" << v_save << "\" is not a valid basic local variable." ); } // Construct zero wordtype. wordtype::wordtype(const config* c) : vector(c->part.length), c(c) { } index_method(variable) String wordtype::variable( ) const { String s = "x"; int i; for ( i = 0; i < length; i++ ) if ( x[i].x > 9 ) break; if ( i == length ) { for ( i = 0; i < length; i++ ) s += dec(x[i].x); } else { for ( i = 0; i < length; i++ ) s += String("_") + dec(x[i].x); } return s; } // Compute the sum of the elements of a wordtype. index_method(sum) int sum(const wordtype& w) { int sum = 0; for ( int i = 0; i < w.c->part.length; i++ ) sum += w(i); return sum; } TEX( Change wordtype to the next minimal admissible wordtype. Return $0$ if we're at the last one; otherwise return $1$. ) index_method(advance) int wordtype::advance(config_active* a) { int i, j, s, n = c->part.length; static vector border_rows; border_rows.set_size(c->small.basis.nrows); weightlist& rww = a->rww; if ( rww.empty( ) ) return 0; int rwwm = a->rww.Min( ), ss = sum(*this); wordtype alttype = *this; try_again: TEX( ![ \begin{quote} Advance to the next wordtype, and at the same time check that the wordtype cannot be ruled inadmissible simply because of its weight. This code has been somewhat optimized. \end{quote} ]! ) for ( i = n-1; i >= 0; i-- ) if ( x[i] != a->bound(i) ) break; if ( i == -1 ) return 0; for ( j = n-1; j > i; j-- ) { ss -= x[j]; x[j] = 0; } ++x[i]; ss++; if ( ss < rwwm || !rww.contains(ss) ) goto try_again; TEX( ![ \begin{quote} Check for admissibility, looking only at small code. This code has been somewhat optimized. \end{quote} ]! ) for ( i = 1; i < c->small.x.nrows; i++ ) { register int l, sum = 0; register gf2 *si = c->small.x.x[i].x; for ( l = 0; l < c->part.length; l++ ) sum += (si[l].x ? c->part.x[l] - x[l] : x[l]); if ( !rww.contains(sum) ) goto try_again; } TEX( ![ \begin{quote} Check for admissibility, looking only at dual small code. \end{quote} ]! ) if ( !a->dualsmall_working.basis.orthogonal_to( (*this) ) ) goto try_again; TEX( ![ \begin{quote} Do complete check for minimality. Compare with \verb|config::make_minimal|. \end{quote} ]! ) int border_count = 0, col; for ( i = 0; i < c->leading1s.length; i++ ) { col = c->leading1s(i); if ( 2 * (*this)(col) == c->part(col)) border_rows(border_count++) = i; } if ( border_count != 0 ) { vector indx(border_count); do { alttype = *this; for ( j = 0; j < border_count; j++ ) if ( indx(j) ) alttype.act(c->small.basis(border_rows(j))); if ( alttype < *this ) goto try_again; } while( indx.advance( ) != 0 ); } TEX( ![ \begin{quote} Check to see if a constraint sets a basic local variable to zero, thereby forcing the wordtype to be inadmissible. \end{quote} ]! ) forPixDef( p, c->con ) { constraint& cn = c->con(p); if ( cn.simple_local_zero( ) ) { wordtype wt2( c, cn.LHS.front( ).var ); if ( equiv( c->part, c->small.basis, *this, wt2 ) ) goto try_again; } } TEX( ![ \begin{quote} Check to see if a constraint sets an upper bound on a basic global variable, thereby forcing the wordtype to be inadmissible. For this, first determine the weight enumerator of the basic code associated to the small code that would result if the configuration were subdivided along the given wordtype. \end{quote} ]! ) config_core d; d.part = subdivide_partition(c->part, *this); d.smallbasis = subdivide_matrix( c->small.basis, c->part, *this, true ); vector wt = d.smallcode_we( ); for ( i = 0; i <= c->home->n; i++ ) if ( wt(i) != 0 && a->global_bound(i).second != -1 && wt(i) > a->global_bound(i).second ) goto try_again; TEX( ![ \begin{quote} Check to see if the basic local variable would violate the zeroness of a joint variable which is known to be zero. \end{quote} ]! ) if ( c->home->joint_vars.length != 0 ) { int i1x = sum(*this); // weight of one word for ( i = 1; i < c->small.x.nrows; i++ ) { word wd = c->small.x(i); int i1 = i1x; int i2 = wd * c->part; // weight of another word int i3 = i1 + i2 - 2 * (wd * (*this)); // weight of their sum if ( i2 > i3 ) swap( i2, i3 ); if ( i1 > i2 ) swap( i1, i2 ); if ( i2 > i3 ) swap( i2, i3 ); String var = String("jy") + dec(i1) + "y" + dec(i2) + "y" + dec(i3); if ( c->home->joint_vars.pos( var, &String_cmp ) == -1 ) goto try_again; } } return 1; } index_method(dual_advance) int wordtype::dual_advance(bool reset) { static vector border_rows; static int border_count; static vector indx; int i, j, col; config_active* a = c->home->active; if (reset) { border_rows.set_size(a->dualsmall_working.basis.nrows); border_count = 0; for ( i = 0; i < a->dual_leading1s.length; i++ ) { col = a->dual_leading1s(i); if ( 2 * (*this)(col) == c->part(col)) border_rows(border_count++) = i; } indx = vector(border_count); return 1; } int n = c->part.length; wordtype alttype = *this; try_again: for ( i = n-1; i >= 0; i-- ) if ( x[i] != a->dual_bound(i) ) break; if ( i == -1 ) return 0; for ( j = n-1; j > i; j-- ) x[j] = 0; ++x[i]; // Check for admissibility: if ( !c->small.basis.orthogonal_to( *this ) ) goto try_again; // Do complete check for minimality. if ( border_count == 0 ) return 1; indx.set_zero( ); do { alttype = *this; for ( j = 0; j < border_count; j++ ) if ( indx(j) ) alttype.act(a->dualsmall_working.basis(border_rows(j))); if ( alttype < *this ) goto try_again; } while( indx.advance( ) != 0 ); return 1; } index_method(act) void wordtype::act(const word& w, const wordtype& t) { for ( int i = 0; i < t.c->part.length; i++ ) x[i] = (w(i) == 0) ? t(i) : t.c->part(i) - t(i); } index_method(act) void wordtype::act(const word& w) { for ( int i = 0; i < c->part.length; i++ ) if ( w(i) ) x[i] = c->part(i) - x[i]; } TEX( Determine if the pullback of {\tt v} along {\tt edge} is {\tt w}. Used only by the ``{\tt infer}'' command. ) index_method(is_pullback) bool is_pullback( const wordtype& v, const wordtype& w, const wordtype& edge ) { int j = 0; // index for v for ( int i = 0; i < w.length; i++ ) { if ( (edge(i) == 0 || edge(i) == w.c->part(i)) && v(j) == w(i) ) j++; else if ( 0 < edge(i) && edge(i) < w.c->part(i) && v(j) + v(j+1) == w(i) ) j += 2; else return false; } HIDE( ![ if ( j != v.length ) INTERNAL_ERROR( "is_pullback" ); ]! ) return true; } set_include_file(wordtype.h) TEX(![ A {\tt mawhome} is the data structure associated to the equivalence class of an admissible basic local variable. The {\tt maw} member gives the minimal element $y$ of the equivalence class. The elements $x$ of the list {\tt w} are chosen so that $x + y$ ranges over the variables equivalent to $y$, without repetition. \indexz{mawhome} ]!) class mawhome { public: wordtype maw; SLList w; HIDE( ![ friend bool operator==(const mawhome& m1, const mawhome& m2) { INTERNAL_ERROR("mawhome== is not implemented"); } friend bool operator!=(const mawhome& m1, const mawhome& m2) { INTERNAL_ERROR("mawhome!= is not implemented"); } ]! ) }; index_class(mawhometable) class mawhometable : public prevector { public: static Pix w_ptr; // Used for iteration. static int maw_ptr; // Used for iteration. mawhometable( ) { } mawhometable(SLList l) : prevector(l) { } int find(const wordtype&) const; int mfind(wordtype) const; bool admissible(wordtype) const; void first(wordtype&); bool advance(wordtype&); SLList has_member_of_weight(int) const; }; set_compile_file(config.cc) HIDE( ![ // #define DEBUG #include "homedefs.h" int rcmp(const number&, const number&); #include "bitvec.h" #include "graph.h" #include "codetable.h" #include extern long time_used_by_subdivide; extern long time_used_by_igs; extern long time_used_by_smallcode_we; extern int show_variables, secondary_plus, silent, no_create; extern int warnings_are_fatal, debug; int String_cmp(const String&, const String&); String list_of(const String&, const String& = ","); vector dual_of_we(vector); int take_int(String&, const Regex&); matrix subdivide_matrix(const matrix&, const partition&, const wordtype&, bool); void parse_j_var(String, int&, int&, int&); ]! ) index_method(mfind) int mawhometable::mfind(wordtype w) const { w.c->home->active->c->make_minimal(w); return find(w); } index_method(admissible) bool mawhometable::admissible(wordtype w) const { w.c->home->active->c->make_minimal(w); return (find(w) != -1); } TEX( Return a list of all minimal admissible basic local variables which are equivalent to a basic local variable of given weight. ) index_method(has_member_of_weight) SLList mawhometable::has_member_of_weight(int d) const { SLList list; const mawhometable& me = *this; for ( int i = 0; i < length; i++ ) { forPixDef( p, me(i).w ) { wordtype alttype = me(i).maw; alttype.act( me(i).w(p) ); if ( sum(alttype) == d ) { list.append( me(i).maw ); break; } } } return list; } set_compile_file(code.c) HIDE( ![ #include "wordtype.h" template void sort_by_second( prevector< pair >& ); template void sort_by_second( prevector< pair< pair< matrix, int>, int> >& ); template inline bool operator==(const prevector&, const prevector&); ]! ) Pix mawhometable::w_ptr; int mawhometable::maw_ptr; TEX( The following two routines allow one to iterate through all admissible wordtypes. Do not in any way nest such iterations: it won't work. ) set_compile_file(mawhome.cc) HIDE(![#include "homedefs.h" matrix subdivide_matrix(const matrix&, const partition&, const wordtype&, bool); int take_int(String&, const Regex&); String list_of(const String&, const String& = ","); ]!) void mawhometable::first(wordtype& wt) { maw_ptr = 0; mawhome& m = (*this)(0); w_ptr = m.w.first( ); wt = m.maw; wt.act( m.w(w_ptr) ); } bool mawhometable::advance(wordtype& wt) { mawhometable& t = *this; t(maw_ptr).w.next(w_ptr); if ( w_ptr == 0 ) { if ( ++maw_ptr == length ) return false; w_ptr = t(maw_ptr).w.first( ); } wt = t(maw_ptr).maw; wt.act( t(maw_ptr).w(w_ptr) ); return true; } TEX(![ {\tt table.find(w)}: Search the mawhometable {\tt table} for the wordtype {\tt w}, returning $-1$ if it is not found, else its index. Probably instead we should sort the mawhometable (when it is created) and do a binary search here. ]!) index_method(find) int mawhometable::find(const wordtype& w) const { for ( int i = 0; i < length; i++ ) if ( w == (*this)(i).maw ) return i; return -1; } TEX( \block{Weightlist class} ) set_include_file(weightlist.h) TEX( A weightlist is an ordered list of integers $0 = n_1 < n_2 < \cdots < n_r$ which represent the weights in a code. We also use this class for other lists of weights. \indexz{weightlist}\mindex{divisible} ) class weightlist : public OSLList { public: weightlist(String, int); weightlist(const OSLList& w) : OSLList(w) { } bool divisible(int d) const { forPixDef( i, *this ) if ( (*this)(i) % d != 0 ) return false; return true; } void make_divisible(int); // replace list by its subset consisting // of elements divisible by the argument min( ) const // return smallest nonzero element { Pix a = first( ); next(a); return (*this)(a); } weightlist( ) { } HIDE( ![ friend ostream& operator<<(ostream&, const weightlist&); ]! ) }; set_compile_file(mawhome.cc) ostream& operator<<(ostream& s, const weightlist& w) { s << "{"; forPixDef( p, w ) { if ( p != w.first( ) ) s << ","; s << w(p); } return s << "}"; } index_method(make_divisible) void weightlist::make_divisible(int d) { weightlist w; for ( Pix i = first( ); i != 0; next(i) ) if ( (*this)(i) % d == 0 ) w.add( (*this)(i) ); *this = w; } index_method(int_set) weightlist int_set(String s) { weightlist ans; static Regex pos_pattern( pos_number ); s = s.after("{"); while( s[0] != '}' ) { int p1 = take_int(s, pos_pattern); if ( s[0] != '.' ) ans.add(p1); else { s = s.after( ".." ); int p2 = take_int(s, pos_pattern); if ( p2 < p1 ) ERROR("Weightlist data doesn't make sense."); for ( int i = p1; i <= p2; i++ ) ans.add(i); } if ( s[0] == ',' ) s.del(','); } return ans; } weightlist::weightlist(String s, int n) { String set_pat( "{" + list_of( pos_number + orsign + pos_number + "\\.\\." + pos_number ) + "}" ); static Regex set_pattern( set_pat ); static Regex weightlist_pat( pos_number + orsign + pos_number + "_" + pos_number + orsign + set_pat + orsign + pos_number + "-" + set_pat + orsign + pos_number + "_" + pos_number + "-" + set_pat ); static Regex number_pattern( number_pat ); if ( !s.matches( weightlist_pat ) ) ERROR("Weightlist syntax wrong."); if ( s[0] == '{' ) *this = int_set(take(s, set_pattern)); else { int divider = 1; // number by which all weights are divisible by int d = as_int(take(s, number_pattern)); if ( d <= 0 || d > n ) ERROR("Weight data doesn't make sense."); if ( s.contains("_", 0) ) { s.del("_"); divider = take_int(s, number_pattern); } if ( d % divider != 0 ) d += divider - (d % divider); for ( int i = d; i <= n; i += divider ) add(i); } if ( s.contains("-", 0) ) { weightlist dels = int_set(s.after("-")); forPixDef( p, dels ) del( dels(p) ); } add(0); } TEX(![ \block{Config and related classes}\label{main-config-section} Configurations are stored in a {\tt ShareGraph}. Whenever there is an edge in this graph, the source is realizable \IFF\ the target is realizable. There is therefore certain information which is shared amongst the members of a connected component of the graph. This information is carried by the class \verb|config_share|. An object of this class is used to record inferred constraints which involve only global variables. How they get recorded depends on what the constraint is. If it has the form {\tt y}\kern1pt$i$\kern5pt{\tt = 0}, then it is recorded by modifying the {\tt ww} (working weightlist) member of the \verb|config_share| object. Similarly, a constraint of the form {\tt mu}\kern1pt$i$\kern5pt{\tt = 0} may get recorded by modifying the \verb|dual_min_low| member of the \verb|config_share| object. Otherwise, the constraint is appended to the \verb|ycon| member. By the {\it computational state\/} of a configuration, we mean, generally, whether or not certain auxiliary data items (used to facilitate computation) exist at a given time. Because these data items are expensive (i.e.\ require lots of time to produce, or lots of memory/disk space to store), choices have to made as to which data items will exist at any given time. The computational state is managed at three levels: the {\tt config} class itself, the {\tt codehome} class, and the \verb|config_active| class. There is always a {\it current\/} configuration, pointed to by the {\tt current} member of the {\tt codehome} object. This configuration may or may not be {\it active}: if it is, the {\tt active} member of the {\tt codehome} object points to a \verb|config_active| object; otherwise, the {\tt active} member is set to zero. In the {\tt config} class is found a pointer to the associated {\tt codehome}, the four items which comprise the configuration definition, and a pointer to a \verb|config_share| object. These items exist for the lifetime of the {\tt codehome}. Certain items (labelled temporary) exist so long as the code type is current. The other items in the {\tt config} class are maintained indefinitely, unless at some point the configuration is proved unrealizable. Then the configuration is cleaned, to save space. This cleaning process also applies to the associated \verb|config_share| object. Only one configuration can be current at any given time. When a configuration is made current, this fact is registered by setting the {\tt current} member of the {\tt codehome} object. This means that the previous current configuration is no longer current, and as a consequence the old \verb|config_active| object is deleted and the {\tt active} member is reset to $0$. Various actions trigger the activation of the current configuration. The most expensive component of the \verb|config_active| object is a table of local variables (the mawhometable). If there are a lot of components in the partition, it will take a long time to build the mawhometable. The \verb|config_active| object also contains various and sundry working data items which facilitate computation. A configuration can moreover be {\it very active}: this means that a constraint file has been built. Again, this can be time consuming. Being in the very active state is indicated by the \verb|file_status| flag in the \verb|config_active| object. The following routines manage the status of configurations: \begin{itemize} \item \verb|codehome::set_current|: Set the current configuration. This invokes {\tt deactivate}. \item \verb|codehome::activate|: If the \verb|config_active| object already exists, do nothing. Otherwise, build it. \item \verb|codehome::deactivate|: Delete the constraint file (\verb|cplex_in|), if it exists, and then delete the \verb|config_active| object, if it exists. The routine {\tt deactivate} gets invoked whenever {\tt[current]} is changed and whenever a constraint is added that would necessitate the recomputation of the list of minimal admissible basic local variables (mawhometable). \item \verb|codehome::set_unrealizable(p)|: Set the configuration with Pix {\tt p} (and thus its logical equivalence class) to unrealizable. Do some cleaning. \item \verb|config_active::split|: This routine is the split linear programming routine. It is the creator and the only direct user of \verb|cplex_in|. Invoking it will make the current configuration very active. \item \verb|config_active::config_active|: invoked by activate. \item \verb|config_active::~config_active|: invoked by deactivate. \end{itemize} \indexz{config} ]!) set_include_file(config.h) index_method(basal) index_method(mostly_equal) class config { public: // who this belongs to codehome* home; TEX( \classbreak ) // the data items which comprise the configuration definition partition part; code small; code dualsmall; constraintlist assumed_cons; TEX( \classbreak ) // the data items which are proved after the configuration has been defined // (see also config_share) constraintlist con; Permutationlist aut; // automorphisms known for this configuration TEX( \classbreak ) // pointer to other things which are proved, shared with other configs config_share* share; TEX( \classbreak ) // The following item keeps track of automorphism labels. The first // part of the pair is the label, including the brackets. The second // part is the index of an automorphism in auto. SLList< pair > auto_labels; TEX( \classbreak ) // temporary data items vector leading1s; // column indices of leading ones in small.basis TEX( \classbreak ) // methods config(codehome*, const String&); config( ) { } config(const config&); config(codehome*, matrix); HIDE( ![ friend bool operator==(const config&, const config&); ]! ) // Return weight enumerator of the basic code associated to the small code // of a configuration. vector smallcode_we( ) const; matrix basic_small( ) const; bool is_automorphism(const Permutation&); bool known(const constraint&) const; void evaluate(const String&, Integer&, Integer&) const; bool basal( ) const { return small.basis.nrows == 0 && dualsmall.basis.nrows == 0 && part.length == 1; } bool terminal( ) const; void add_constraint(constraint&, bool&, bool = false); void add_constraint(String, bool&); void check_secondary_residuals(codetable&); void check_variable(String) const; HIDE( ![ friend partition subdivide_partition(const partition&, const wordtype&); friend bool configuration_search(const config&, const config&); ]! ) bool no_bad_weights( ) const; constraintlist known_cons( ) const; term_sum simplify_global_vars(const term_sum&, bool = false) const; friend bool mostly_equal( const config& c1, const config& c2 ) { return (c1.part == c2.part && c1.small.basis == c2.small.basis && c1.dualsmall.basis == c2.dualsmall.basis); } HIDE( ![ friend ostream& operator<<(ostream&, const config&); ]! ) HIDE( ![ friend bool equiv(const partition&, const matrix&, const wordtype&, const wordtype&); ]! ) pair< Permutationlist, Integer > find_automorphism_group( ) const; void make_minimal(wordtype&) const; friend Pix subdivide(const config&, const wordtype&); }; index_class(config_core) class config_core { public: partition part; matrix smallbasis; matrix dualsmallbasis; config_core( ) { } config_core(const config& c) : part(c.part), smallbasis(c.small.basis), dualsmallbasis(c.dualsmall.basis) { } vector smallcode_we( ) const; matrix basic_small( ) const; matrix basic_dualsmall( ) const; HIDE( ![ friend bool operator==(const config_core& a, const config_core& b) { INTERNAL_ERROR("== not implemented for class config_core"); } friend word subdivide_word(const partition&, const wordtype&, const word&); ]! ) }; index_class(config_share) class config_share { public: int realizable; // 1 if realizable, -1 if unrealizable, 0 if unknown weightlist ww; // working weightlist, possibly smaller // than the weightlist for the codehome short int dual_min_low; // lower bound for minimum weight of dual code short int dual_min_high; // upper bound for minimum weight of dual code constraintlist ycon; // constraintlist involving only global variables HIDE( ![ friend config_share* operator+(const config_share&, const config_share&); ]! ) }; index_class(config_active) class config_active { public: // data config* c; mawhometable vtable; TEX( ![ \classtext{ {\tt bound}:\ This is a vector whose \th{i} entry is\\ {\tt c->part(}$i${\tt)}, or $\floor{\hbox{{\tt c->part(}$i${\tt)}/2}}$, if {\tt c->small.basis} has a leading $1$ in column $i$. It is used in constructing the mawhometable. The vector {\tt dual\string_bound} is like {\tt bound}, but is based on {\tt dualsmall} instead of {\tt small}. It is used in constructing the main constraint file.} ]!) vector bound, dual_bound; TEX( ![ \classtext{ {\tt global\string_bound}:\ Gives the best known low and high values for $y_i$, $0 \leq i \leq n$. A high value of $-1$ means that no upper bound is known.} ]!) prevector< pair > global_bound; TEX( ![ \classtext{ {\tt small\string_we}:\ The weight enumerator of the basic code associated to the small code.} ]! ) vector small_we; TEX( ![ \classtext{ restricted working weightlist({\tt rww}): this is {\tt c->share->ww}, with the weight $i$ deleted if the constraint $y_i \leq r$ is known, where $r$ is the number of words of weight $i$ in the basic code associated to the small code. Consider a basic local variable $x_I$ which is not equivalent to the trivial basic local variable. If $x_I$ is admissible, then $\abs{I} \in$ {\tt rww}.} ]!) weightlist rww; code dualsmall_working; // working dualsmall code, possibly larger than // dualsmall vector dual_leading1s; // column indices of leading ones in // dualsmall_working.basis prevector y_as_vsum; // express y's in terms of v's; indexed by // share.working weightlist int file_status; // 1 if constraint file built, else 0 // constructor and destructor config_active(config*, bool, bool = false); ~config_active( ) { if ( file_status ) remove("calculations/cplex_in"); } // other methods void expand_term_sum(const term_sum&, vector&) const; bool split(bool, codetable&, constraintlist = constraintlist( ), bool = false); void convert_dual_variable(const word&, const wordtype&, Integer**, vector&) const; EquivRelIntList auto_equiv( ) const; int x_to_v(const String&) const; HIDE( ![ friend term_sum subdivide_basic_local_variable(const partition&, const matrix&, const config_active&, const wordtype&, const wordtype&, bool); friend constraint subdivide_constraint(const config&, const config&, const wordtype&, constraint); ]! ) }; set_compile_file(code.c) HIDE(![#include "weightlist.h"]!) HIDE(![#include "config.h"]!) TEX(![ \block{Codebase, codehome, and codetable classes} There are two classes for codes: a {\tt codebase}, and the derived class {\tt codehome}. When a code type is first defined, an object of the larger class {\tt codehome} is created. This will exist until the program terminates unless the code type is proven nonexistent. In that case only the {\tt codebase} object is kept, and it is appended to \verb|results.dead|. \indexz{codebase} ]!) set_include_file(codehome.h) class codebase_options { public: bool dual_may_be_code_of_design; int k, lambda; bool partition_of_word_by_dual_words; int w, d; bool doubly_even_part_is_subcode; codebase_options( ) { dual_may_be_code_of_design = false; k = 0; lambda = 0; partition_of_word_by_dual_words = false; w = 0; d = 0; doubly_even_part_is_subcode = false; } none_chosen( ) const { return !dual_may_be_code_of_design && !partition_of_word_by_dual_words && !doubly_even_part_is_subcode; } friend bool operator==(codebase_options a, codebase_options b) { return a.dual_may_be_code_of_design == b.dual_may_be_code_of_design && a.k == b.k && a.lambda == b.lambda && a.partition_of_word_by_dual_words == b.partition_of_word_by_dual_words && a.w == b.w && a.d == b.d && a.doubly_even_part_is_subcode == b.doubly_even_part_is_subcode; } }; class codebase { public: int n; // dimension of the ambient space int dim; // dimension of the code weightlist w; // assumed weight list constraintlist assumed_cons; // assumed constraints codebase_options opt; // options codebase( int n, int dim, const weightlist& w ) : n(n), dim(dim), w(w) { } codebase( int n, int dim, const weightlist& w, const constraintlist& ac ) : n(n), dim(dim), w(w), assumed_cons(ac) { } codebase( int n, int dim, int d ) : n(n), dim(dim), w( dec(d), n ) { } codebase( ) { } TEX(![ \begin{quote} Compute the ``Griesmer sum'' $\sum_{i=0}^{\hbox{\small\tt dim}-1} \ceiling{d / 2^i}$, where $d =$ {\tt w.min( )}. \end{quote} ]!) int griesmer( ) { int sum = 0; for ( int i = 0; i < dim; i++ ) sum += as_int( ceil( Rational( w.min( ), Ipow(2, i) ) ) ); return sum; } friend ostream& operator<<(ostream& s, const codebase& c) { return s << "[" << c.n << "," << c.dim << "," << c.w << "]{" << c.assumed_cons << "}"; } friend bool operator==(codebase a, codebase b) { return a.n == b.n && a.dim == b.dim && a.w == b.w && a.assumed_cons == b.assumed_cons && a.opt == b.opt; } }; TEX(![ The configurations in a given code type exist in a {\tt codehome} as vertices of a {\tt ShareGraph}. Recall that edges come in two flavors: constructive and logical. Logical edges are not actually represented by {\tt ShareGraph} edges. The member {\tt implications} is a list of pairs. The first member of each pair is a {\tt Pix} referring (via {\tt configs}) to a configuration (call it $c$). The second member of the pair is a list of {\tt Pix}'es referring to a list of configurations (call them $\VEC c1r$), with the property that ${\cal R}(c) \IN {\cal R}(c_1) \manycup {\cal R}(c_r)$. \indexz{codehome} ]!) index_method(deactivate) class codehome : public codebase { public: TEX( ![ \classtextt{Data items which contain information of lasting importance} ]! ) ShareGraph configs; SLList< pair< Pix, SLList > > implications; OSLList incorporate_labels; // used only to insure no repeats SLList< pair< Pix, Pix > > disjoint; SLList< pair > labels; // the Pix refers to a config in // configs Pix base; // index of base configuration bool classified; // set to true if code type gets classified // up to isomorphism bool unique; // set to true if the code type is found to // contain a unique code bool we_known; // set to true if the weight enumerator of the // codes (if any) in the realization of the code // type is uniquely determined and known prevector joint_vars; // Empty or else all joint variables // are known to lie in this sorted list. TEX( ![ \classtext{Data items which are used during computations, and should get deleted when attention shifts to another code type} ]! ) Pix current; // index of current configuration config_active* active; TEX( ![ \classtextt{Constructors and destructors} ]! ) codehome(int, int, const weightlist&, codetable& results, const constraintlist = constraintlist( ) ); codehome(int, int, const weightlist&, const constraintlist = constraintlist( ) ); codehome( ) { } HIDE( ![ codehome(const codehome&) { INTERNAL_ERROR("You can't copy a codehome."); } ]! ) ~codehome( ) { deactivate( ); } TEX( ![ \classtextt{Methods} ]! ) weightlist& ww( Pix p ) { return configs(p).share->ww; } void set_current(Pix); // Set discussion preceeding class config. void activate(bool, bool = false); // Ditto above comment. void deactivate( ) // Ditto above comment. { delete active; active = 0; } SLList< multiedge > convert_implications( ) const; bool show(constraintlist, codetable& results, bool = false, constraintlist = constraintlist( ), bool = false, bool = false ); SLList< matrix > list_extensions(bool, bool, codetable&); Pix merge_config(config&); void set_config(config&, const String& = ""); void set_config(const String&); bool contradiction(bool, codetable&); Pix label_to_Pix(String, const codetable&); bool check(const constraint&, const vector&, const config&) const; bool check_globals(const constraintlist&, const vector&, const config&) const; void set_unrealizable(Pix); bool isomorphic(const config&, const config&, bool = false) const; bool isomorphic(const config_core&, const config_core&, bool = false) const; bool options_satisfied(const config&); prevector basic_joint_vars(codetable&); void generate_joint_constraints(codetable&, constraintlist = constraintlist( )); void expand_jdi(String , vector&, const prevector&, Integer***); HIDE( ![ friend bool infeasible(codehome&, codetable&, bool); friend bool known_global(codehome*, config_share*, constraint); ]! ) }; set_compile_file(codehome.cc) extern char* PATH_PREFIX; HIDE( ![ #include "homedefs.h" #include #include "bitvec.h" #include "codetable.h" // #define DEBUG bool operator !=(const weightlist&, const weightlist&); extern int warnings_are_fatal; void eat_constraint(istream&); extern String homebrew_status; extern int homebrew, auto_round, use_quad, use_dual_dual_for_joint; int String_cmp(const String&, const String&); void execute_round_local(codehome*, codetable&); pair lp_crunch(const prevector&, int, int, const vconstraint&, bool = false); void add_to_rational_constraint(qvconstraint&, const vconstraint&, Rational&); bool joint_infeasible(codehome&, codetable&, constraintlist = constraintlist( )); ]! ) codehome::codehome(int n, int dim, const weightlist& w, codetable& results, const constraintlist assumed_cons ) : codebase( n, dim, w, assumed_cons ), base(0), active(0) { current = base = configs.add( config( this, String(dec(n)) + ":{}" ) ); config_share* s = new config_share; weightlist wp = w; HIDE( ![ if ( dim == 0 ) INTERNAL_ERROR("codehome constructor called with dim = 0"); ]! ) s->realizable = 0; labels.append( make_pair( String("[base]"), base ) ); classified = we_known = unique = false; forPixDef( p, results.open ) { codehome* h = results.open(p); if ( h->n == n && h->dim == dim && w <= h->w && h->assumed_cons == assumed_cons && h->opt.none_chosen( ) ) { // Merge weightlist and constraint information. But why are we // creating a new codehome at all?? wp = intersection( w, h->ww(h->base) ); s->ycon.merge( h->configs(h->base).share->ycon ); } } int d = wp.min( ); bool even = wp.divisible(2); s->ww = intersection( wp, results.possible_weights( n, dim, d, even ) ); if ( s->ww.length( ) == 1 ) { s->realizable = -1; s->dual_min_low = 1; s->dual_min_high = n; configs(base).share = s; return; } s->dual_min_low = 1; for ( int j = 1; j <= n-1; j++ ) { Integer low = 0, high = -1; assumed_cons.evaluate( String("mu") + dec(j), low , high ); if ( high == 0 ) s->dual_min_low = j+1; else break; } for ( short int dp = dim + 1; dp >= 2; dp-- ) if (results.not_exist(n - dp + 1, dim - dp + 2, s->ww)) { s->dual_min_low = dp; break; } s->dual_min_high = n; for ( int j = s->dual_min_low; j <= min(2 * s->dual_min_low - 1, n); j++ ) if ( results.not_exist( n - j, n - dim - 1, s->dual_min_low - j/2 ) ) s->ycon.merge( constraint( String("mu") + dec(j) + "=0" ) ); TEX( ![ \begin{quote} Get upper bound for dimension of a doubly even subcode. Then use Brouwer's result to bound number of words whose weight is divisible by $4$. \end{quote} ]! ) if ( s->ww.divisible(2) && d+2 <= n ) { int i, max_DE_dim = dim; String sss( dec(d+2) ); sss += "_4"; weightlist wt( sss, n ); if ( d % 4 != 0 && (results.not_exist(n, dim, wt) || results.not_exist(n-1, dim, d+1)) ) { for ( i = dim-1; i >= 1; i-- ) if ( !( results.not_exist(n, i, wt) || results.not_exist(n-1, i, d+1) ) ) break; max_DE_dim = i; } Integer DE_low = Ipow(2,dim-1) - Ipow(2, min(max_DE_dim, dim-2)); Integer DE_high = Ipow(2,dim-1) + Ipow(2, max_DE_dim - 1); s->ycon.merge( constraint( "div4>=" + String(dec(DE_low)) ) ); s->ycon.merge( constraint( "div4<=" + String(dec(DE_high)) ) ); } joint_vars.set_size(0); configs(base).share = s; } codehome::codehome(int n, int dim, const weightlist& w, const constraintlist assumed_cons ) : codebase( n, dim, w, assumed_cons ), base(0), active(0) { current = base = configs.add( config( this, String(dec(n)) + ":{}" ) ); config_share* s = new config_share; s->ww = w; s->realizable = (s->ww.length( ) == 1 ? -1 : 0); labels.append( make_pair( String("[base]"), base ) ); classified = we_known = unique = false; s->dual_min_low = 1; s->dual_min_high = n; joint_vars.set_size(0); configs(base).share = s; } index_method(set_current) void codehome::set_current(Pix p) { if ( p != 0 ) ww(p) = intersection( ww(p), ww(base) ); if ( current != 0 ) deactivate( ); current = p; } index_method(convert_implications) SLList< multiedge > codehome::convert_implications( ) const { SLList< multiedge > ml; forPixDef( q, implications ) { multiedge m; const pair< Pix, SLList >& imp = implications(q); m.first = configs( imp.first ).share; forPixDef( r, imp.second ) m.second.add( configs(imp.second(r)).share ); forPixDef( p, ml ) if ( ml(p).first == m.first && ml(p).second <= m.second ) break; if ( p == 0 ) ml.append(m); } return ml; } index_method(activate) void codehome::activate(bool quiet, bool weak) { if ( active == 0 ) active = new config_active(&configs(current), quiet, weak); } index_method(set_unrealizable) void codehome::set_unrealizable(Pix p) { config& c = configs(p); c.share->realizable = -1; TEX( ![ \begin{quote} Clear out stuff to save memory. But we don't want to clear out so much that another command might crash if accidentally invoked on an unrealizable configuration. In particular, we don't clear out the working weight list. \end{quote} ]! ) c.share->ycon.clear( ); forPixDef( q, configs ) { if ( configs(p).share == configs(q).share ) { config& d = configs(q); d.con.clear( ); d.aut.clear( ); d.auto_labels.clear( ); } } } TEX( ![ Determine if the current configuration leads to a contradiction. ]! ) index_method(contradiction) bool codehome::contradiction(bool quiet, codetable& results) { if ( configs(current).share->realizable == -1 ) return true; if ( infeasible(*this, results, quiet) ) { set_unrealizable(current); return true; } if (auto_round && choose(n, dim) <= atoI("3000000000000000000") ) { execute_round_local( this, results ); if ( infeasible(*this, results, quiet) ) { set_unrealizable(current); return true; } } return false; } TEX( ![ \verb|merge_config|:\ Merge a configuration {\tt c} into the {\tt configs} member of a {\tt codehome}. We proceed by comparing {\tt c} with each configuration {\tt d} in {\tt configs} which has the same partition, small basis, and dual small basis as {\tt c}, and for which every assumed constraint is known to {\tt c}. If the assumed constraints of {\tt d} are not the same as those of {\tt c}, we merge the known facts for {\tt d} into {\tt c}. Otherwise we merge the known facts for {\tt c} into {\tt d}. We not not merge in automorphisms. This code appears to supersede the redundancy checking of {\tt ShareGraph::add}. ]! ) index_method(merge_config) Pix codehome::merge_config(config& c) { Pix cref = 0; forPixDef( p, configs.vertices ) { config& d = configs(p); if ( mostly_equal(c, d) ) { forPixDef( q, d.assumed_cons ) if ( !c.known( d.assumed_cons(q) ) ) break; if ( q == 0 ) { if ( c.assumed_cons == d.assumed_cons ) { if ( cref == 0 ) { config_share* merge = *(c.share) + *(d.share); *(d.share) = *merge; delete merge; delete c.share; c.share = d.share; d.con.merge( c.con ); cref = p; } } else { if ( cref == 0 ) { config_share* merge = *(c.share) + *(d.share); *(c.share) = *merge; delete merge; c.con.merge( d.con ); } else { config_share* merge = *(configs(cref).share) + *(d.share); *(configs(cref).share) = *merge; delete merge; configs(cref).con.merge( d.con ); } } } } } if ( cref == 0 ) { p = configs.add(c); implications.append( make_pair( p, make_list(base) ) ); return p; } else return cref; } index_method(basic_joint_vars) TEX( ![ \verb|basic_joint_vars|:\ Generate a list of the minimal basic joint variables, in lexicographical order, using only the weights which occur in the working weightlist for {\tt[current]}. We should (but don't) use known restrictions on the joint variables of even codes to get restrictions on the joint variables of an arbitrary code. ]! ) prevector codehome::basic_joint_vars(codetable& results) { SLList vars; if ( configs(base).share->realizable == -1 ) return prevector(0); joint_vars.sort(&String_cmp); weightlist& w = configs(current).share->ww; int i, d = w.min( ); prevector poss(2*d); for ( i = d; i < min(2*d, n); i++ ) if ( dim-1 <= n-i ) poss(i) = results.possible_weights(n-i, dim-1, d-i/2, false); forPixDef( p, w ) { forPixDef( q, w ) { forPixDef( r, w ) { if ( w(p) <= w(q) && w(q) <= w(r) && w(p) + w(q) + w(r) <= 2*n && w(p) + w(r) >= w(q) && w(p) + w(q) >= w(r) && w(q) + w(r) >= w(p) && even( w(p) + w(q) + w(r) ) ) { if ( joint_vars.length == 0 ) { if ( d <= w(p) && w(p) < 2*d ) { if ( !poss(w(p)).contains( (w(q)+w(r)-w(p))/2 ) ) continue; } if ( d <= w(q) && w(q) < 2*d ) { if ( !poss(w(q)).contains( (w(p)+w(r)-w(q))/2 ) ) continue; } if ( d <= w(r) && w(r) < 2*d ) { if ( !poss(w(r)).contains( (w(p)+w(q)-w(r))/2 ) ) continue; } } String var = String("jy") + dec(w(p)) + "y" + dec(w(q)) + "y" + dec(w(r)); if ( configs(current).known( var + "=0" ) ) continue; if ( joint_vars.length != 0 && joint_vars.pos( var, &String_cmp ) == -1 ) continue; vars.append( var ); } } } } ofstream vardef("calculations/joint_variable_definitions"); prevector varsv(vars); for ( i = 0; i < varsv.length; i++ ) vardef << "v" << dec(i+1) << " = " << varsv(i) << "\n"; vardef.close( ); return varsv; } HIDE( ![ Integer*** make_krawtchouk(int); void delete_krawtchouk(Integer ***, int); int take_int(String&, const Regex&); ]! ) index_method(COMBO) #define COMBO(A,I,J) ((J <= I) ? combo[A][I][J] : \ (even(A) ? combo[A][J][I] : -combo[A][J][I])) index_method(parse_j_var) void parse_j_var( String v, int& r, int& s, int& t ) { static Regex number_pattern( number_pat ); v.del("j"); v = v.after( v[0] ); r = take_int( v, number_pattern ); v = v.after( v[0] ); s = take_int( v, number_pattern ); if ( v.empty( ) ) t = 0; else { v = v.after( v[0] ); t = take_int( v, number_pattern ); } } index_method(MULT) #define MULT(J,K,L) \ ((J != K && J != L && K != L) ? 6 : ((J == K && K == L) ? 1 : 3)) TEX( ![ \verb|joint_to_qv|:\ Convert a constraint {\tt c} involving only joint and global variables to a {\tt qvconstraint}. Upon entry {\tt vars} should be the list of joint variables defined by \verb|basic_joint_vars|, and {\tt combo} should be the Krawtchouk coefficient table made by \verb|make_krawtchouk|. ]! ) index_method(joint_to_qv) void joint_to_qv( constraint c0, qvconstraint& ex, const prevector& vars, codehome& home, Integer ***combo ) { ex.LHS.set_size(vars.length); weightlist& ww = home.configs(home.current).share->ww; static Regex number_pattern( number_pat ); static Regex j_pattern( "jy" + number_pat + "y" + number_pat + "y" + number_pat ); static Regex jd_pattern( "jd" + number_pat + "d" + number_pat + "d" + number_pat ); static Regex jdi_pattern( "jy" + number_pat + "d" + number_pat + "i" + number_pat ); static Regex jyd_pattern( "jy" + number_pat + "d" + number_pat ); int i, j, k, l, r, s, t; TEX( ![ \begin{quote} First expand {\tt co} variables. \end{quote} ]! ) constraint c( c0.sense, c0.RHS ); forPixDef( p, c0.LHS ) { if ( c0.LHS(p).var[0] != 'c' ) c.LHS.append( c0.LHS(p) ); else { String v = c0.LHS(p).var; if ( v == "co" ) { forPixDef( q, ww ) { String var2 = String("jy") + dec(ww(q)) + "d" + dec(ww(q)) + "i" + dec(ww(q)); c.addterm( c0.LHS(p).coeff, var2 ); } } else { v = v.after( "co" ); c.addterm( c0.LHS(p).coeff, "jy" + v + "d" + v + "i" + v); } } } Integer total = Ipow( 2, home.dim ), total_squared = total * total; c.LHS = home.configs(home.current).simplify_global_vars( c.LHS ); ex.LHS.set_zero( ); ex.set( c.sense, c.RHS ); forPixDef( qq, c.LHS ) { term te = c.LHS(qq); if ( te.var[0] == 'y' ) { r = yno( te.var ); i = vars.find(String("jy0y") + dec(r) + "y" + dec(r)); if ( i >= 0 ) ex.LHS(i) += te.coeff; } else if ( te.var.matches( j_pattern ) ) { parse_j_var( te.var, r, s, t ); if ( s > t ) swap( s, t ); if ( r > s ) swap( r, s ); if ( s > t ) swap( s, t ); i = vars.find( String("jy") + dec(r) + "y" + dec(s) + "y" + dec(t) ); if ( i >= 0 ) ex.LHS(i) += te.coeff; } else if ( te.var.matches(jdi_pattern) || te.var.matches(jyd_pattern) ) { parse_j_var( te.var, r, s, t ); int ii = home.n - (r + s - t); int jj = s - t, kk = r - t, ll = t; for ( int m = 0; m < vars.length; m++ ) { parse_j_var( vars(m), r, s, t ); i = home.n - (r+s+t)/2; j = (s+t-r)/2; k = (r+t-s)/2; l = (r+s-t)/2; // If 2 of j,k,l are equal, insure that the first two are. if ( j == l ) swap(k, l); if ( k == l ) swap(j, l); for ( int h = 0; h < MULT(j,k,l); h++ ) { if ( jj <= i + j && ll <= k + l && kk == k+l-ll ) ex.LHS(m) += te.coeff * Rational( COMBO(jj,i,j) * COMBO(ll,k,l), total ); if ( even(h) ) swap( k, l ); else swap( j, k ); } } } else if ( te.var.matches( jd_pattern ) ) { TEX( ![ \begin{quoteb} Use the formula\\ $\displaystyle{\cal J}_{C^\perp,C^\perp}(a,b,c,d) = {1\over\abs{C}^2}{\cal J}_{C,C}( (a+c)+(b+d), (a+c)-(b+d), (a-c)+(b-d), (a-c)-(b-d) ).$ \end{quoteb} ]! ) parse_j_var( te.var, r, s, t ); int ii = home.n - (r+s+t)/2; int jj = (s+t-r)/2, kk = (r+t-s)/2, ll = (r+s-t)/2; for ( int m = 0; m < vars.length; m++ ) { parse_j_var( vars(m), r, s, t ); i = home.n - (r+s+t)/2; j = (s+t-r)/2; k = (r+t-s)/2; l = (r+s-t)/2; // If 2 of j,k,l are equal, insure that the first two are. if ( j == l ) swap(k, l); if ( k == l ) swap(j, l); for ( int h = 0; h < MULT(j,k,l); h++ ) { for ( int a = max(0, home.n - ii - kk - k - l); a <= min(i+j, home.n - ii - kk); a++ ) { int b = home.n - a - ii - kk; ex.LHS(m) += te.coeff * Rational( COMBO(a, i, j) * COMBO(b, k, l) * COMBO(kk, i+j-a, k+l-b) * COMBO(ll, a, b), total_squared ); } if ( even(h) ) swap( k, l ); else swap( j, k ); } } } else INTERNAL_ERROR("Unrecognized variable \"" << te.var << "\" in joint_to_qv."); } } TEX( ![ \verb|output_joint_constraint|:\ Convert a constraint {\tt c} involving joint and global variables to a constraint involving {\tt v} variables, and output it to the given stream. Upon entry {\tt vars} should be the list of joint variables defined by \verb|basic_joint_vars|, and {\tt combo} should be the Krawtchouk coefficient table made by \verb|make_krawtchouk|. ]! ) index_method(output_joint_constraint) int output_joint_constraint( constraint c, const prevector& vars, ostream& out, codehome& home, Integer ***combo ) { qvconstraint qv; vconstraint vc(vars.length); joint_to_qv( c, qv, vars, home, combo ); if ( clear_denom( qv, vc ) != 0 ) { if ( vc.LHS.if_zero( ) && test( Integer(0), vc.RHS, vc.sense ) ) return 0; out << vc; return 1; } return 0; } index_method(generate_joint_constraints) TEX( ![ \verb|generate_joint_constraints|:\ The joint weight enumerator identity $${\cal J}_{C,C^\perp}(a,b,c,d) = {1\over\abs{C}}{\cal J}_{C,C} (a+b,a-b,c+d,c-d)$$% (see [.macwilliams sloane book.]\ p.\ 148) implies certain linear inequalities involving the minimal basic joint variables. Generate the corresponding constraints (in terms of {\tt v} variables), and write them to the file \verb|joint_in|. In this preliminary version, we generate one constraint for each monomial $a^i b^j c^k d^l$, thus in total $(n+1)^4$ of them! ]! ) void codehome::generate_joint_constraints(codetable& results, constraintlist forced) { prevector vars = basic_joint_vars(results); cerr << "[setting up linear program with " << vars.length << " variables and "; int constraint_count = 0; static Regex number_pattern(number_pat); int i, j, k, l, m, r, s, t; Integer ***combo = make_krawtchouk(n); prevector vc[n+1]; int multiplicity[ vars.length ]; weightlist& ww = configs(current).share->ww; int dl = configs(current).share->dual_min_low; if (!homebrew) { system( "echo maximize 0 > calculations/joint_in" ); system( "echo subject to >> calculations/joint_in" ); } else remove( "calculations/joint_in" ); String pipe_command = "sort -u | fold -s >> calculations/joint_in"; procbuf joint_inp = procbuf( pipe_command, ios::out ); ostream joint_in = ostream( &joint_inp ); for ( int J = 0; J <= n; J++ ) { for ( k = 0; k <= n-J; k++ ) { vc[k].set_size(n-J-k+1); for ( l = 0; l <= n-J-k; l++ ) { vc[k](l).LHS.set_size(vars.length); for ( m = 0; m < vars.length; m++ ) vc[k](l).LHS(m) = 0; vc[k](l).sense = (ww.contains(k+l) && even(l) && (J+l == 0 || J+l >= dl)) ? '>' : '='; vc[k](l).RHS = 0; } } for ( m = 0; m < vars.length; m++ ) { TEX( ![ \begin{quoteb} Put $v$ in the form $a^i b^j c^k d^l$, as in the joint weight enumerator. \end{quoteb} ]! ) parse_j_var( vars(m), r, s, t ); i = n - (r+s+t)/2; j = (s+t-r)/2; k = (r+t-s)/2; l = (r+s-t)/2; // If 2 of j,k,l are equal, insure that the first two are. if ( j == l ) swap(k, l); if ( k == l ) swap(j, l); multiplicity[m] = MULT(j,k,l); for ( int h = 0; h < multiplicity[m]; h++ ) { if ( J <= i + j ) for ( int k1 = 0; k1 <= k+l; k1++ ) vc[k+l-k1](k1).LHS(m) += ((j <= i) ? combo[J][i][j] : (even(J) ? combo[J][j][i] : -combo[J][j][i])) * ((l <= k) ? combo[k1][k][l] : (even(k1) ? combo[k1][l][k] : -combo[k1][l][k])); if ( even(h) ) swap( k, l ); else swap( j, k ); } } for ( k = 0; k <= n-J; k++ ) for ( l = 0; l <= n-J-k; l++ ) { vconstraint& vcx = vc[k](l); if ( !vcx.LHS.if_zero( ) ) { vcx.reduce( ); joint_in << vcx; constraint_count++; } } } vconstraint ex(m); for ( i = 0; i < vars.length; i++ ) ex.LHS(i) = (i == 0) ? 1 : 0; ex.set( '=', 1 ); joint_in << ex; constraint_count++; TEX( ![ \begin{quote} Create a constraint corresponding to the fact that $\displaystyle{\sum_{r,s,t} \verb|jy|r\verb|y|s\verb|y|t = \abs{C}^2}$. \end{quote} ]! ) for ( i = 0; i < vars.length; i++ ) ex.LHS(i) = multiplicity[i]; ex.set( '=', Ipow(2, 2*dim) ); joint_in << ex; constraint_count++; TEX( ![ \begin{quote} Generate constraints coming from weight restrictions on the subcode disjoint from a dual word of weight \verb|dl|. \end{quote} ]! ) weightlist dw = results.possible_weights(n-dl, dim-dl+1, ww.min( ), ww.divisible(2)); weightlist dwc = diff(ww, dw); forPixDef(q, dwc) { if ( dwc(q) <= n-dl ) constraint_count += output_joint_constraint( constraint( String("jy") + dec(dwc(q)) + "d" + dec(dl) + "=0" ), vars, joint_in, *this, combo ); } TEX( ![ \begin{quote} Create a constraint corresponding to the fact that $\displaystyle{\sum_r \verb|jy|0\verb|y|r\verb|y|r = \abs{C}}$. \end{quote} ]! ) ex.LHS.set_zero( ); forPix( q, ww ) { r = ww(q); i = vars.find( String("jy0y") + dec(r) + "y" + dec(r) ); ex.LHS(i) = 1; } ex.set( '=', Ipow(2, dim) ); joint_in << ex; constraint_count++; TEX( ![ \begin{quote} Create constraints corresponding to the fact that for each $r$, $$\sum_{s,t} \verb|jy|r\verb|y|s\verb|y|t = \abs{C} \cdot \verb|jy|r\verb|y|r\verb|y|0.$$ \end{quote} ]! ) ex.set( '=', 0 ); forPix( q, ww ) { r = ww(q); ex.LHS.set_zero( ); i = vars.find( String("jy0y") + dec(r) + "y" + dec(r) ); ex.LHS(i) -= Ipow(2, dim); for ( i = 0; i < vars.length; i++ ) { String v = vars(i).after("jy"); int rp = take_int( v, number_pattern ); v = v.after("y"); int sp = take_int( v, number_pattern ); v = v.after("y"); int tp = take_int( v, number_pattern ); if ( r != rp && r != sp && r != tp ); else if ( r == rp && r == sp && r == tp ) ex.LHS(i) += 1; else if ( (r == rp && r == sp) || (r == sp && r == tp) ) ex.LHS(i) += 2; else if ( multiplicity[i] == 6 ) ex.LHS(i) += 2; else if ( multiplicity[i] == 3 ) ex.LHS(i) += 1; } joint_in << ex; constraint_count++; } TEX( ![ \begin{quote} Adjoin constraints arising from the fact that the coefficients of the joint weight enumerator of $C^\perp$ with itself are nonnegative. \end{quote} ]! ) if (use_dual_dual_for_joint > 0) { for ( i = dl; i <= min(n, use_dual_dual_for_joint+dl); i++ ) for ( j = i; j <= min(n, use_dual_dual_for_joint+dl); j++ ) for ( k = j; k <= min(n, use_dual_dual_for_joint+dl); k++ ) { if ( i <= j+k && j <= i+k && k <= i+j && i+j+k <= 2*n ) { constraint_count += output_joint_constraint( constraint( String("jd") + dec(i) + "d" + dec(j) + "d" + dec(k) + ">=0" ), vars, joint_in, *this, combo ); } } } TEX( ![ \begin{quote} Adjoin ``linearized quadratic'' constraints coming from the quadratic constraints $$\sum_t \verb|jy|r\verb|y|s\verb|y|t = \verb|y|r \cdot \verb|y|s$$% by replacing $\verb|y|r$ by known bounds on it and converting to an inequality. \end{quote} ]! ) forPixDef( p1, ww ) { forPixDef( p2, ww ) { Integer low = 0, high = -1; configs(current).evaluate(String("y") + dec(ww(p1)), low, high); constraint cc1, cc2; forPixDef( p3, ww ) cc1.addterm( 1, String("jy") + dec(ww(p1)) + "y" + dec(ww(p2)) + "y" + dec(ww(p3)) ); cc1.RHS = 0; cc2 = cc1; if ( low != 0 ) { cc1.addterm( -low, String("y") + dec(ww(p2)) ); cc1.sense = '>'; constraint_count += output_joint_constraint( cc1, vars, joint_in, *this, combo ); } if ( high != -1 ) { cc2.addterm( -high, String("y") + dec(ww(p2)) ); cc2.sense = '<'; constraint_count += output_joint_constraint( cc2, vars, joint_in, *this, combo ); } } } TEX( ![ \begin{quote} Adjoin all known joint constraints. \end{quote} ]! ) constraintlist aux = configs(current).known_cons( ); aux.merge(forced); forPix( q, aux ) { if ( configs(current).part.length == 1 ) { forPixDef( qq, aux(q).LHS ) { String& av = aux(q).LHS(qq).var; if ( av[0] == 'x' ) av = String("y") + dec(yno(av)); } } if ( aux(q).joint( ) ) constraint_count += output_joint_constraint( aux(q), vars, joint_in, *this, combo ); } joint_inp.close( ); delete_krawtchouk( combo, n ); cerr << constraint_count << " constraints]\n"; } TEX( Before calling \verb|set_config|, the {\tt share} member of {\tt c} should be initialized. This routine may delete the {\tt share} member of {\tt c}. ) index_method(set_config) void codehome::set_config(config& c, const String& label) { Pix i = merge_config(c); set_current(i); if ( label != "" ) { forPixDef( j, labels ) if ( labels(j).first == label ) ERROR("Same label for configuration used twice."); labels.append( make_pair(label, i) ); } } void codehome::set_config(const String& s) { config c = config(this, s); set_config(c); } index_method(label_to_Pix) Pix codehome::label_to_Pix(String label, const codetable& results) { if ( label == "[current]" ) { if ( current == 0 ) ERROR("The current configuration is undefined."); return current; } // Check for known configuration. forPixDef( i, labels ) if ( labels(i).first == label ) return labels(i).second; // Check for colon syntax. static Regex alpha_pat = "[a-zA-Z_0-9]+"; if_match( label, "\\[[a-zA-Z_0-9]+:.*\\]" ) { String new_config_name = label; String labelx = label.after("["); String codehome_name = '[' + take(labelx, alpha_pat) + ']'; String config_name = labelx.after(":"); if ( config_name[ config_name.length( ) - 1 ] = ']' ) { config_name = '[' + config_name; forPixDef( p, results.olabels ) { if ( codehome_name == results.olabels(p).first ) { codehome* h = results.open(results.olabels(p).second); if ( h->n != n ) ERROR("Code length descrepancy."); forPix( i, h->labels ) if ( h->labels(i).first == config_name ) break; if ( i != 0 ) { config c; config& d = h->configs(h->labels(i).second); c.home = this; c.part = d.part; c.small = d.small; c.dualsmall = d.dualsmall; c.assumed_cons = d.assumed_cons; c.leading1s = d.leading1s; c.share = new config_share; *(c.share) = *(configs(base).share); Pix q = configs.add(c); labels.append( make_pair(new_config_name, q) ); return q; } } } } } ERROR("Configuration label " << label << " is unknown."); } TEX(![ {\tt check(c, y)}: Given a constraint {\tt c} involving only global variables, determine if it holds when {\tt y[i]} is substituted in for the variable {\tt yi}, for each {\tt i}. It is assumed that after this substitution, the \LHS\ of the constraint will be an integer. There is some funny stuff in the code. The case where {\tt c} involves only basic global variables is treated differently to avoid the need for a \verb|config_share| object in that case. ]!) HIDE( ![ inline bool test(const Rational& a, const Rational& b, char sense) { if ( sense == '=' ) return a == b; if ( sense == '<' ) return a <= b; return a >= b; } ]! ) index_method(check) bool codehome::check(const constraint& c, const vector& y, const config& cc) const { Rational LHS = 0; forPixDef( q, c.LHS ) if ( c.LHS(q).var[0] != 'y' ) break; term_sum ts = (q == 0) ? c.LHS : cc.simplify_global_vars(c.LHS); forPix( q, ts ) { String& v = c.LHS(q).var; LHS += ts(q).coeff * Rational( y( yno(v) ) ); } return test( LHS, c.RHS, c.sense ); } index_method(check_globals) bool codehome::check_globals(const constraintlist& l, const vector& y, const config& cc) const { forPixDef( p, l ) if ( l(p).global( ) && !check( l(p), y, cc ) ) return false; return true; } HIDE(![ SLList process_cplex_report(String, int&); ]! ) TEX(![ {\tt show}:\ Assuming that each of the constraints in the list {\tt forced} holds, attempt to show by split linear programming that each of the constraints in {\tt con} holds. Note that it is generally faster to simultaneously show that a bunch of constraints hold. This is because a lot of time gets spent just finding a feasible point, and if you show that the constraints hold simultaneously, you only have to find the feasible point once. However, if one uses the {\tt homebrew} option, as currently implemented, this advantage will not be exploited. To make more sense out of what's done here, it may be helpful to look at the comments attached to the code for {\tt infeasible}. ]!) index_method(show) bool codehome::show(constraintlist con0, codetable& results, bool quiet, constraintlist forced, bool joint, bool allow_stupid_show) { if (joint) { if (!con0.joint( ) ) ERROR( "Attempt to use joint linear " << "programming to prove a constraint involving local variables." ); constraint c, cneg; forPixDef( i, con0 ) { c = con0(i); c.clear_denominators( ); if ( c.sense == '>' || c.sense == '=' ) { cneg = c; cneg.sense = '<'; --cneg.RHS; forPixDef( p, cneg.LHS ) if ( cneg.LHS(p).coeff < 0 ) break; if ( !(p == 0 && cneg.RHS < 0) ) { constraintlist forcedplus = forced; forcedplus.append(cneg); if ( !joint_infeasible( *this, results, forcedplus ) ) return false; } } if ( c.sense == '<' || c.sense == '=' ) { cneg = c; cneg.sense = '>'; ++cneg.RHS; forPixDef( p, cneg.LHS ) if ( cneg.LHS(p).coeff > 0 ) break; if ( p == 0 && cneg.RHS > 0 ) continue; constraintlist forcedplus = forced; forcedplus.append(cneg); if ( !joint_infeasible( *this, results, forcedplus ) ) return false; } } return true; } if ( !con0.local( ) ) ERROR( "Attempt to use split linear " << "programming to prove a constraint involving joint variables." ); activate(quiet); constraintlist con, con1; forPixDef( i, con0 ) { constraint& c = con0(i); if ( c.simple_local( ) && c.sense == '>' && c.RHS == 1 && active->vtable.length == 2 ) { wordtype w( &configs(current), c.LHS.front( ).var ); active->c->make_minimal(w); if ( w == active->vtable(1).maw ) continue; } if ( c.simple_local( ) && c.sense == '>' && c.RHS == 1 ) { wordtype w( &configs(current), c.LHS.front( ).var ); active->c->make_minimal(w); for ( int j = 0; j <= n; j++ ) if ( configs(current).known( String("y") + dec(j) + ">" + dec(active->small_we(j)) ) ) { int ii; for ( ii = 1; ii < active->vtable.length; ii++ ) { forPixDef( p, active->vtable(ii).w ) { wordtype alttype = active->vtable(ii).maw; if ( alttype == w ) continue; alttype.act( active->vtable(ii).w(p) ); if ( sum(alttype) == j ) break; } if ( p != 0 ) break; } if ( ii == active->vtable.length ) return true; } } con1.append( con0(i) ); } TEX( ![ Test for constraints whose \LHS\ evaluates to a zero linear combination of basic local variables. In general, a warning is issued. An exception is where a constraint of the form $y_i = 0$ is to be proved and $i$ is in the working weight list. ]! ) forPix( i, con1 ) { activate(quiet); qvconstraint qvc = qvconstraint( con1(i), this ); if ( qvc.LHS.if_zero( ) ) { if ( !test( 0, qvc.RHS, qvc.sense ) ) return false; if ( con1(i).simple_global( ) && qvc.sense == '=' ) { int yn = yno( con1(i).LHS.front( ).var ); if ( ww(current).contains(yn) ) { ww(current).del(yn); deactivate( ); continue; } if ( !allow_stupid_show ) WARNING( "I already know that " << con1(i) << "." ); continue; } if ( !allow_stupid_show ) WARNING( "When I convert " << con1(i) << " to a constraint " << "involving only basic local variables, I get zero." << " This suggests that what you are doing is silly." << " If not, I apologize!" ); continue; } con.append( con1(i) ); } if ( con.length( ) == 0 ) return true; activate(quiet); if ( homebrew || choose(n, dim) > atoI("3000000000000000000") ) { constraint c, cneg; forPix( i, con ) { c = con(i); if ( c.simple_global( ) && (c.sense == '>' || (c.sense == '=' && c.RHS == 0)) ) { int yn = yno(c.LHS.front( ).var); if ( active->small_we(yn) == c.RHS ) { int ii; for ( ii = 1; ii < active->vtable.length; ii++ ) { forPixDef( p, active->vtable(ii).w ) { wordtype alttype = active->vtable(ii).maw; alttype.act( active->vtable(ii).w(p) ); if ( sum(alttype) == yn ) break; } if ( p != 0 ) break; } if ( ii == active->vtable.length ) return true; } } c.clear_denominators( ); if ( c.sense == '>' || c.sense == '=' ) { cneg = c; cneg.sense = '<'; --cneg.RHS; forPixDef( p, cneg.LHS ) if ( cneg.LHS(p).coeff < 0 ) break; if ( !(p == 0 && cneg.RHS < 0) ) { constraintlist forcedplus = forced; forcedplus.append(cneg); bool use_homebrew = active->split(quiet, results, forcedplus); prevector files(2); files(0) = "cplex_in"; files(1) = "cplex_in2"; vconstraint tot(active->vtable.length); tot.sense = '='; tot.RHS = Ipow( 2, dim ); for ( int ii = 0; ii < tot.LHS.length; ii++ ) tot.LHS(ii) = active->vtable(ii).w.length( ); bool use_quadx = use_quad || choose( n, dim ) > atoI("3000000000000000000"); lp_crunch(files, use_homebrew, use_quadx, tot); if ( homebrew_status == "confused" ) { WARNING( "Verification of linear program " << "calculation failed." ); return false; } if ( homebrew_status == "feasible" ) return false; } } if ( c.sense == '<' || c.sense == '=' ) { cneg = c; cneg.sense = '>'; ++cneg.RHS; forPixDef( p, cneg.LHS ) if ( cneg.LHS(p).coeff > 0 ) break; if ( p == 0 && cneg.RHS > 0 ) continue; constraintlist forcedplus = forced; forcedplus.append(cneg); bool use_homebrew = active->split(quiet, results, forcedplus); prevector files(2); files(0) = "cplex_in"; files(1) = "cplex_in2"; vconstraint tot(active->vtable.length); tot.sense = '='; tot.RHS = Ipow( 2, dim ); for ( int ii = 0; ii < tot.LHS.length; ii++ ) tot.LHS(ii) = active->vtable(ii).w.length( ); bool use_quadx = use_quad || choose( n, dim ) > atoI("3000000000000000000"); lp_crunch( files, use_homebrew, use_quadx, tot ); if ( homebrew_status == "confused" ) { WARNING( "Verification of linear program calculation " << "failed." ); return false; } if ( homebrew_status == "feasible" ) return false; } } return true; } remove( "calculations/cplex_commands0" ); ofstream command_file( "calculations/cplex_commands0" ); command_file << "set logfile *\n"; if ( CPLEX_VERSION[0] <= '2' ) { command_file << "set presolve n\n"; command_file << "set aggregate n\n"; } else { command_file << "set preprocessing presolve n\n"; command_file << "set preprocessing aggregator n\n"; } int opt_count = 0; int nvars = active->vtable.length; SLList vcons; int j, k; SLList ops; SLList multipliers; forPix( i, con ) { // For a constraint which is an equality, we normally have to // break it up into two constraints (>=, <=). However, if the // constraint had the form "variable = 0", we only need one. if ( con(i).simple( ) && con(i).sense == '=' && con(i).RHS == 0 ) con(i).sense = '<'; vconstraint vc(nvars); qvconstraint qvc = qvconstraint( con(i), this ); Rational multiplier = clear_denom( qvc, vc ); HIDE( ![ if ( multiplier == 0 ) INTERNAL_ERROR( "zero multiplier in show" );]!) for ( j = 0; j < nvars; j++ ) command_file << "change coeff obj v" << j + 1 << " " << vc.LHS(j) << "\n"; if ( vc.sense == '<' || vc.sense == '=' ) { char sense_save = vc.sense; vc.sense = '<'; vcons.append(vc); vc.sense = sense_save; command_file << "change sense obj max\n" << "opt\n"; ops.append("max"); remove( "calculations/cplex" + String(dec(opt_count)) + ".bin" ); command_file << "w " << PATH_PREFIX << "calculations/cplex" << opt_count++ << ".bin\n"; multipliers.append(multiplier); } if ( vc.sense == '>' || vc.sense == '=' ) { vc.sense = '>'; vcons.append(vc); command_file << "change sense obj min\n" << "opt\n"; ops.append("min"); remove( "calculations/cplex" + String(dec(opt_count)) + ".bin" ); command_file << "w " << PATH_PREFIX << "calculations/cplex" << opt_count++ << ".bin\n"; multipliers.append(multiplier); } } command_file.close( ); bool use_homebrew = active->split(quiet, results, forced); prevector files(2); files(0) = "cplex_in"; files(1) = "cplex_in2"; vconstraint tot(active->vtable.length); tot.sense = '='; tot.RHS = Ipow( 2, dim ); for ( int ii = 0; ii < tot.LHS.length; ii++ ) tot.LHS(ii) = active->vtable(ii).w.length( ); bool use_quadx = use_quad || choose(n, dim) > atoI("3000000000000000000"); lp_crunch( files, use_homebrew, use_quadx, tot, true ); SLList dual_activity[opt_count]; prevector opsv(ops); vector mult(multipliers); for ( k = 0; k < opt_count; k++ ) { int status; dual_activity[k] = process_cplex_report( String("calculations/cplex") + dec(k) + ".bin", status ); forPixDef( ppp, dual_activity[k] ) dual_activity[k](ppp) /= mult(k); // If we maximized, negate the dual activity numbers. if ( opsv(k) == "max" ) { forPix( ppp, dual_activity[k] ) dual_activity[k](ppp) = -dual_activity[k](ppp); } if ( status == 0 ) { if ( k == 0 ) ERROR( "show: system is infeasible; " << "perhaps you should be using via lp instead. Or perhaps " << "you're using \"kill by\" when you only need \"kill\"." ) else ERROR( "show: system is infeasible now, but it wasn't " << "a moment ago -- cplex has failed" ); } } ifstream conf("calculations/cplex_in"); char c; for ( j = 1; j <= 2; j++ ) // skip over "maximize 0 subject to" { do conf.get(c); while ( c != '\n' ); } qvconstraint qv[opt_count]; for ( k = 0; k < opt_count; k++ ) qv[k].LHS.set_size(nvars); vconstraint vcx(nvars); Pix d[opt_count]; for ( k = 0; k < opt_count; k++ ) d[k] = dual_activity[k].first( ); bool first_file = true; while(1) { if ( conf.peek( ) == EOF ) { if (first_file) { first_file = false; conf.close( ); conf.open("calculations/cplex_in2"); if ( conf.peek( ) == EOF ) break; } else break; } HIDE( ![ for ( k = 0; k < opt_count; k++ ) if ( d[k] == 0 ) INTERNAL_ERROR("show: not enough dual activity numbers"); ]! ) for ( k = 0; k < opt_count; k++ ) if ( sign(dual_activity[k](d[k])) != 0 ) break; if ( k != opt_count ) // at least one is nonzero { conf >> vcx; for ( k = 0; k < opt_count; k++ ) if ( sign(dual_activity[k](d[k])) != 0 ) add_to_rational_constraint( qv[k], vcx, dual_activity[k](d[k]) ); } else eat_constraint(conf); for ( k = 0; k < opt_count; k++ ) dual_activity[k].next(d[k]); } HIDE( ![ for ( k = 0; k < opt_count; k++ ) if ( d[k] != 0 ) INTERNAL_ERROR("show: too many dual activity numbers"); ]! ) conf.close( ); k = 0; forPix( i, con ) { vector vc; active->expand_term_sum( con(i).LHS, vc ); if ( con(i).sense == '<' || con(i).sense == '=' ) { Rational RHSx = qv[k].RHS - Rational(con(i).RHS); if ( RHSx >= 1 ) return false; for ( j = 0; j < nvars; j++ ) { Rational vx = qv[k].LHS(j) - vc(j); if ( sign(vx) < 0 ) { if ( -vx * Rational(Ipow(2, dim)) >= Rational(active->vtable(j).w.length( )) * (1 - RHSx) ) return false; } } k++; } if ( con(i).sense == '>' || con(i).sense == '=' ) { Rational RHSx = qv[k].RHS + Rational(con(i).RHS); if ( RHSx >= 1 ) return false; for ( j = 0; j < nvars; j++ ) { Rational vx = qv[k].LHS(j) + vc(j); if ( sign(vx) < 0 ) { if ( -vx * Rational(Ipow(2, dim)) >= Rational(active->vtable(j).w.length( )) * (1 - RHSx) ) return false; } } k++; } } return true; } TEX(![ The class {\tt codetable} is a placeholder for cumulated information about codes kept by the program. \indexz{codetable} ]!) set_include_file(codetable.h) index_method(classified) index_method(weakly_classified) class codetable { public: DLList open; // codes which may exist DLList< pair > olabels; // the Pix refers to a codehome in // open SLList dead; // codes which don't exist SLList< pair > dlabels; // the Pix refers to a codehome in // dead TEX( ![ \classtext{ For a given triple $(n,k,d)$, give (as a {\tt bitvec}) a weightlist which (for {\tt div1w}) all $[n,k,d]$ codes must have weights in and which (for {\tt div2w}) all even $[n,k,d]$ codes must have weights in.} ]! ) SLList< pair< triple, bitvec > > div1w, div2w; TEX( ![ \classtext{ For $1 \leq k \leq n$, {\tt lower\string_bound(}$n$\verb|,|$k$\verb|)| {\tt upper\string_bound(}$n$\verb|,|$k$\verb|)| gives the best known lower and upper bounds for the minimum distance of an $[n,k]$ code.} ]! ) matrix lower_bound, upper_bound; bool update_lower_bound(int, int, int); codetable( ); SLList< triple< int, int, int > > live_nkd; // some codes which exist void kill(const codebase&, String = ""); void kill(int, int, int); bool not_exist(int, int, int); bool not_exist(int, int, const weightlist&); bool not_exist(const codebase&); bool exist(int, int, int, bool = false); void recompute_lower_bound(int, int); bool is_unique(int n, int k, int d) { forPixDef( p, open ) if ( open(p)->unique && codebase(*(open(p))) == codebase(n,k,d) ) return true; return false; } void save(codehome&, String); bool new_not_exist(int, int, int, int, codehome*, String&, int = 2); int max_dim_of_code(int, const weightlist&); weightlist possible_weights(int, int, int, bool); bool classified(const codebase& cb) const { forPixDef( p, dead ) if ( dead(p) == cb ) return true; forPix( p, open ) { if ( open(p)->classified && codebase(*(open(p))) == cb ) return true; } return false; } bool weakly_classified(const codebase& cb) const { forPixDef( p, dead ) if ( dead(p) == cb ) return true; forPix( p, open ) { if ( (open(p)->classified || open(p)->we_known) && codebase(*(open(p))) == cb ) return true; } return false; } bool known(matrix); }; set_compile_file(codetable.cc) HIDE( ![ #include "homedefs.h" #include "bitvec.h" #include "codetable.h" #include "opt.h" extern int homebrew, limited_secondary_kill, full_secondary_kill; extern int secondary_kill_maxvars, auto_joint_search, auto_joint_test; extern int residual_check_for_kill, save_bounds, generate_noneven_bounds; int String_cmp(const String&, const String&); void execute_round_local(codehome*, codetable&); bool joint_infeasible(codehome&, codetable&, constraintlist = constraintlist( )); bool isomorphic(const matrix&, const matrix&); ]! ) index_method(known) TEX(![ \verb|known(M)|: Let $M$ be a matrix in \RREF. Determine if its rowspace is isomorphic to a known code. ]!) bool codetable::known(matrix M) { forPixDef( p, open ) { codehome* h = open(p); if ( h->n != M.ncols || h->dim != M.nrows ) continue; forPixDef( q, h->configs ) { config& c = h->configs(q); if ( c.small.basis.nrows != h->dim ) continue; if ( isomorphic( M, c.basic_small( ) ) ) return true; } } return false; } index_method(griesmer) TEX( ![ \verb|griesmer(|$n$\verb|,|$k$\verb|)|:\ Return the largest $d$ for which (according to the Griesmer bound) an $[n,k,d]$ code might exist. ]! ) int griesmer(int n, int k) { int i, d = 0, s, q; do { d++; s = 0; q = d; for ( i = 0; i < k; i++ ) { s += q; q++; q >>= 1; } } while ( s <= n ); return d - 1; } codetable::codetable( ) { lower_bound.set_size(100,100); upper_bound.set_size(100,100); for ( int n = 1; n < 100; n++ ) for ( int k = 1; k <= n; k++ ) { lower_bound(n,k) = 1; upper_bound(n,k) = griesmer(n,k); } } index_method(possible_weights) TEX( ![ \verb|possible_weights|:\ Return a list which all weights in an $[n,k,d]$ code must lie in. Do this by using the method of residual codes, by checking for known restrictions on the weights of $[n,k,d]$ codes, and by checking for known restrictions on the weights of $[n+1,k,d+1]$ codes in the case where $d$ is odd. ]! ) weightlist codetable::possible_weights(int n, int k, int d, bool if_even) { bitvec w(n+1), w_even; if ( even(d) && !if_even ) { int sum = 0; for ( int i = 0; i < k; i++ ) sum += as_int( ceil( Rational( d, Ipow(2, i) ) ) ); if ( sum == n ) if_even = true; } if ( !if_even && even(d) ) w_even = bitvec( possible_weights(n, k, d, true) ); w.set(0); for ( int i = d; i <= n; i += (if_even ? 2 : 1) ) if (k == 1 || i >= 2*d || !not_exist(n - i, k - 1, d - i/2)) w.set(i); if ( odd(d) ) { bitvec w_parity_check = bitvec( possible_weights(n+1, k, d+1, true) ); bitvec we3 = w_parity_check; we3.left_shift1( ); bitvec w_plus = Union(w_parity_check, we3); w = intersection( w, w_plus ); } Pix p, q, r; forPix( p, div1w ) { int n2 = div1w(p).first.first; int k2 = div1w(p).first.second; int d2 = div1w(p).first.third; bitvec ww = div1w(p).second; if ( n == n2 && k == k2 && d >= d2 ) w = intersection(w, ww); else if ( odd(d) && n2 == n+1 && k2 == k && d2 == d+1 ) { bitvec wo = ww.even_part( ); wo.left_shift1( ); w = intersection( w, Union( ww, wo ) ); } else if ( n2 == n-1 && k2 == k-1 && d2 == d ) { bool topbit = w.value(n); w = intersection(w, ww); if (topbit) w.set(n); } else if ( n2 == n-2 && k2 == k-2 && d2 == d ) { bool topbit = w.value(n); bool nextbit = w.value(n-1); w = intersection(w, ww); if (topbit) w.set(n); if (nextbit) w.set(n-1); } } forPix( p, div2w ) { int n2 = div2w(p).first.first; int k2 = div2w(p).first.second; int d2 = div2w(p).first.third; bitvec ww = div2w(p).second; if (n == n2 && k == k2 && d >= d2 && if_even) w = intersection(w, ww); else if ( odd(d) && n2 == n+1 && k2 == k && d2 == d+1 ) { bitvec wo = ww; wo.left_shift1( ); w = intersection( w, Union( ww, wo ) ); } else if ( n2 == n-1 && k2 == k-1 && d2 == d && if_even ) { bool topbit = w.value(n); w = intersection(w, ww); if (topbit) w.set(n); } else if ( n2 == n-2 && k2 == k-2 && d2 == d && if_even ) { bool topbit = w.value(n); bool nextbit = w.value(n-1); w = intersection(w, ww); if (topbit) w.set(n); if (nextbit) w.set(n-1); } } if ( !if_even && even(d) ) { bitvec we2 = w_even, we3 = w_even; we2.left_shift1( ); we3.right_shift1( ); bitvec w_even_plus = Union( Union(w_even, we2), we3 ); w = intersection( w, w_even_plus ); } weightlist ans; for ( int j = 0; j < w.length; j++ ) if ( w.value(j) ) ans.add(j); return ans; } TEX( Return the best known upper bound for the dimension of a code with given length and weightlist. ) index_method(max_dim_of_code) int codetable::max_dim_of_code(int n, const weightlist& w) { for ( int r = 1; r <= n; r++ ) if ( not_exist(n, r, w) ) return r-1; return n; } index_method(kill) void codetable::kill(const codebase& cb, String code_label) { int i, d = cb.w.min( ); for ( i = d; i <= cb.n; i++ ) if ( !cb.w.contains(i) ) break; if ( i == cb.n + 1 && cb.assumed_cons.empty( ) && cb.opt.none_chosen( ) ) { kill( cb.n, cb.dim, d ); if ( code_label == "" ) return; } Pix p = dead.append(cb); if ( code_label != "" ) dlabels.append( make_pair( code_label, p ) ); } TEX(![ \verb|not_exist(|$n,k,d$\verb|)|: Let $n,k,d$ be integers. Return {\tt true} if we know there is no $[n,k,d]$ code, else {\tt false}. ]! ) index_method(not_exist) bool codetable::not_exist(int n, int k, int d) { if ( k > n || (k == n && d > 1) || d > n ) return true; if ( n >= upper_bound.nrows ) kill(n,n,n); // force table enlargement return d > upper_bound(n,k); } TEX(![ \verb|not_exist(|$n${\tt,}\kern5pt$k${\tt,}\kern5pt$S${\tt)}: Let $n$ and $k$ be integers, and let $S$ be a weightlist. Return {\tt true} if we know there is no $[n,k,S]$ code, else {\tt false}. Weights in $S$ larger than $n$ are ignored. ]!) index_method(not_exist) bool codetable::not_exist(int n, int k, const weightlist& S) { weightlist T; if ( n >= upper_bound.nrows ) kill(n,n,n); // force table enlargement if ( S.min( ) > upper_bound(n,k) ) return true; forPixDef( i, S ) if ( S(i) <= n ) T.add( S(i) ); forPix( i, dead ) { const codebase& code = dead(i); if ( !code.assumed_cons.empty( ) ) continue; if ( !code.opt.none_chosen( ) ) continue; forPixDef( t, T ) { if ( T(t) > code.n ) continue; if ( !code.w.contains( T(t) ) ) break; } if ( t != 0 ) continue; if ( n <= code.n && k >= code.dim ) return true; if ( n > code.n && k >= code.dim + (n-code.n) ) return true; } if ( 2*k > n && T.divisible(4) ) return true; return false; } index_method(not_exist) bool codetable::not_exist(const codebase& cb) { int d = cb.w.min( ); if ( cb.n >= upper_bound.nrows ) kill(cb.n,cb.n,cb.n); // force table enlargement if ( d > upper_bound( cb.n, cb.dim ) ) return true; forPixDef( i, dead ) { const codebase& code = dead(i); if ( cb.n == code.n && cb.dim == code.dim && cb.w <= code.w && cb.assumed_cons >= code.assumed_cons ) return true; } return false; } TEX( ![ \verb|update_lower_bound|:\ Record the existence of an $[n,k,d]$ code. Return {\tt true} if this modifies the $[n,k]$ entry of the \verb|lower_bound| table. ]! ) index_method(update_lower_bound) bool codetable::update_lower_bound(int N, int K, int D) { int n, k; // Resize lower_bound table if needed. if ( N + 3 > lower_bound.nrows ) { int old_size = lower_bound.nrows, new_size = 2*N + 3; lower_bound.resize( new_size, new_size ); for ( n = old_size; n < new_size; n++ ) for ( k = 1; k <= n; k++ ) lower_bound(n, k) = 1; } if ( lower_bound(N, K) < D ) { lower_bound(N, K) = D; return true; } return false; } index_method(kill) void codetable::kill(int N, int K, int D) { int n, k; static SLList< triple > history; // Resize upper_bound table if needed. if ( N >= upper_bound.nrows ) { int old_size = upper_bound.nrows, new_size = N + 20; upper_bound.resize( new_size, new_size ); for ( n = old_size; n < new_size; n++ ) for ( k = 1; k <= n; k++ ) upper_bound(n, k) = griesmer(n, k); forPixDef( p, history ) { int N0 = history(p).first; int K0 = history(p).second; int D0m = history(p).third - 1; int g = griesmer(N0, K0) - D0m; for ( n = old_size; n < upper_bound.nrows; n++ ) for ( k = K0 + (n-N0); k <= K0 + (n-N0) + g; k++ ) if ( D0m < upper_bound(n,k) ) upper_bound(n,k) = D0m; } } int Dm = D - 1; int g = griesmer(N, K) - Dm; if ( g <= 0 ) return; history.append( make_triple( N, K, D ) ); for ( n = N - g; n <= N; n++ ) for ( k = K; k <= K + g - (N - n); k++ ) if ( Dm < upper_bound(n,k) ) upper_bound(n,k) = Dm; for ( n = N + 1; n < upper_bound.nrows; n++ ) for ( k = K + (n-N); k <= K + (n-N) + g; k++ ) if ( Dm < upper_bound(n,k) ) upper_bound(n,k) = Dm; } TEX( ![ {\tt exist}:\ Execute the procedure of the {\tt yes} command. The code is correct but probably trash. ]! ) index_method(exist) bool codetable::exist(int N, int K, int D, bool weak) { int n, k, n1, n2, k1, k2, a, b; // Resize lower_bound table if needed. if ( 2*N + 3 > lower_bound.nrows ) { int old_size = lower_bound.nrows, new_size = 3*N; lower_bound.resize( new_size, new_size ); for ( n = 1; n < new_size; n++ ) { for ( k = 1; k <= n; k++ ) { if ( k >= old_size || n >= old_size ) lower_bound(n, k) = 1; } } } // Propagate rules. bool something_changed; do { if ( D <= lower_bound(N,K) ) return true; something_changed = false; for ( n1 = 1; n1 <= N; n1++ ) for ( n2 = n1; n2 <= N; n2++ ) { int topk = min(n1, n2); if (weak) topk = min(topk, K); for ( k = 1; k <= topk; k++ ) something_changed = something_changed || update_lower_bound( n1 + n2, k, lower_bound(n1, k) + lower_bound(n2, k) ); } for ( n = 1; n <= N; n++ ) { int topk1 = n; if (weak) topk1 = min(topk1, K); for ( k1 = 1; k1 <= topk1; k1++ ) { int topk2 = k1; if (weak) topk2 = min(topk2, K - k1); for ( k2 = 1; k2 <= topk2; k2++ ) something_changed = something_changed || update_lower_bound( 2*n, k1 + k2, min( 2*lower_bound(n, k1), int( lower_bound(n, k2) ) ) ); } } for ( n = 1; n <= 2*N; n++ ) { int topk = n; if (weak) topk = min(topk, K); for ( k = 1; k <= topk; k++ ) for ( a = -1; a <= min(n-1,1); a++ ) for ( b = 0; b <= min(k-1,1); b++ ) { if ( n-a < k-b ) continue; int d = lower_bound(n,k) - max(a-b, 0); if ( d <= 0 ) continue; something_changed = something_changed || update_lower_bound( n-a, k-b, d ); } } for ( n = 1; n <= 2*N; n++ ) { int topk = n; if (weak) topk = min(topk, K); for ( k = 1; k <= topk; k++ ) if ( odd( int( lower_bound(n,k) ) ) ) something_changed = something_changed || update_lower_bound( n + 1, k, lower_bound(n,k) + 1 ); } } while(something_changed); return D <= lower_bound(N,K); } void codetable::recompute_lower_bound(int N, int K) { int n, k, n1, n2, k1, k2, a, b; // The increment to K (3, at present) has been chosen so that facts about // lower-dimensional codes are correctly deduced from higher-dimensional // codes, in the range of codes actually encountered so far. Zero is not // good enough; no other values have been tried. K += 3; // Resize lower_bound table if needed. if ( 2*N + 3 > lower_bound.nrows ) { int old_size = lower_bound.nrows, new_size = 3*N; lower_bound.resize( new_size, new_size ); for ( n = 1; n < new_size; n++ ) { for ( k = 1; k <= n; k++ ) { if ( k >= old_size || n >= old_size ) lower_bound(n, k) = 1; } } } // Propagate rules. bool something_changed; do { something_changed = false; for ( k = 1; k < K; k++ ) { if ( Ipow( 2, k - 1 ) > N ) break; int tk = as_int( Ipow( 2, k-1 ) ); for ( n = 1; n + 2*tk <= N; n++ ) something_changed = update_lower_bound( n + 2*tk, k + 1, min( lower_bound(n,k) + tk, 2*tk ) ) || something_changed; } for ( n1 = 1; n1 <= N; n1++ ) { int topk = min(n1, K); for ( k = 1; k <= topk; k++ ) { if ( lower_bound(n1-1,k) >= lower_bound(n1,k) ) continue; for ( n2 = n1; n2 <= N; n2++ ) something_changed = update_lower_bound( n1 + n2, k, lower_bound(n1, k) + lower_bound(n2, k) ) || something_changed; } } for ( n = 1; n <= N; n++ ) { int topk1 = min(n, K); for ( k1 = 1; k1 <= topk1; k1++ ) { int topk2 = min(k1, K - k1); for ( k2 = 1; k2 <= topk2; k2++ ) something_changed = update_lower_bound( 2*n, k1 + k2, min( 2*lower_bound(n, k1), int( lower_bound(n, k2) ) ) ) || something_changed; } } int np, kp; for ( n = 1; n <= 2*N; n++ ) { int topk = min(n, K); for ( k = 1; k <= topk; k++ ) { if ( n-1 >= k && lower_bound(n-1,k) >= lower_bound(n,k) ) continue; if ( n+1 <= 2*N && k+1 <= topk && lower_bound(n+1,k+1) >= lower_bound(n,k) ) continue; if ( n+1 <= 2*N && lower_bound(n+1,k) > lower_bound(n,k) ) continue; for ( np = 1; np <= 2*N; np++ ) { int topkp = min(np, k); for ( kp = 1; kp <= topkp; kp++ ) { int d = lower_bound(n, k); int dp = np - n - (kp - k) + d; if ( dp > np ) dp = np; if ( dp > d + 1) dp = d + 1; if ( dp == d + 1 && even(d) ) dp = d; something_changed = update_lower_bound(np, kp, dp) || something_changed; } } } } } while(something_changed); } TEX( \verb|new_not_exist|:\ Execute the procedure of the ``{\tt no}'' command. The only allowed values for {\tt div} are $1$ and $4$. Be sure to set {\tt home = 0} after calling. ) index_method(new_not_exist) bool codetable::new_not_exist(int n, int k, int d, int div, codehome* home, String& code_label, int allowed_failures) { // First save the previous codehome, if there was one. if (home != 0) save( *home, code_label ); HIDE( ![ if (n == 0 || k == 0 || k > n || d == 0 || d > n || (div != 1 && div != 4)) INTERNAL_ERROR( "new_not_exist: bad arguments." ); ]! ) // Now deal with some silly cases. if ( k == n ) return d != 1; if ( k == 1 ) return false; if ( not_exist( n, k, d ) || not_exist( n-1, k, d-1 ) ) return true; if ( n >= 2 && k == n - 1 && d == 2 ) return false; if ( div == 4 && d % 4 != 0 ) return false; if ( div == 1 ) div = 2; int i, dual_min, wx; // Reduce to even case. if ( odd(d) ) { n++; d++; } // If you remove "= weightlist" from the following line, a parse // error results. This must be a compiler bug. weightlist w = weightlist(String(dec(d)) + String("_") + dec(div), n), wd; if ( not_exist( n, k, w ) || not_exist( n-1, k-1, w ) ) return true; w = intersection( w, possible_weights( n, k, d, true ) ); if ( w.length( ) == 1 ) return true; // 0 is only weight // Is Griesmer bound violated? if ( codebase( n, k, w ).griesmer( ) > n ) return true; // Get lower bound for minimum weight of dual code. dual_min = 1; for ( i = k-1; i >= 0; i-- ) if ( not_exist( n-i-1, k-i, d ) ) { dual_min = i + 2; break; } if ( not_exist( n, n - k, dual_min ) ) return true; TEX(![ \begin{quote} Now we have to do linear programming. If $k \geq n/2$, we will work with the dual code instead. The reason for this is that the numerical instability of the linear programming problem grows with $k$, so for $k > n/2$ the dual problem is more stable. A better way to handle this would be to have the {\tt split} routine do this automatically. \end{quote} ]!) int fail_count = 0; if ( 2*k <= n ) { home = new codehome(n, k, w, *this); home->joint_vars = home->basic_joint_vars(*this); home->joint_vars.sort(&String_cmp); OSLList joint_maybe_nonzero; // The list "joint_maybe_nonzero" list causes some variables not // to be tested for zeroness. It is conceivable that such a variable // could actually be zero, and so the list could result in a // harmless "mistake". weightlist wz = home->configs(home->base).share->ww; if ( home->contradiction(true, *this) ) { delete home; return true; } bool no_successes_yet = true; while(1) { wx = wz.Max( ); if ( wx == 0 ) break; bool pretest = false; home->set_current(home->base); if ( home->configs(home->base). known( String("y") + dec(wx) + "!=0" ) ) { wz.del(wx); if (!no_successes_yet) cerr << ".\n"; no_successes_yet = true; if ( ++fail_count == allowed_failures ) break; cerr << "Weight " << wx << " may exist.\n"; continue; } if ( home->show( String("y") + dec(wx) + "=0", *this, true ) ) pretest = true; if (!pretest) { if ( n == wx ) home->set_config(String(dec(wx)) + ":{1}"); else home->set_config( String(dec(wx)) + "," + dec(n - wx) + ":{10}" ); home->configs(home->current). check_secondary_residuals(*this); } wz.del(wx); bool win_flag = pretest || home->contradiction(true, *this); if (!win_flag && (limited_secondary_kill || full_secondary_kill)) { Pix yy, p = home->current; config& c = home->configs(p); SLList to_kill; if (full_secondary_kill) { for ( i = 1; i < home->active->vtable.length; i++ ) to_kill.append( home->active->vtable(i).maw ); } else if ( n != wx ) { for ( i = 0; i < 2; i++ ) { forPix( yy, home->ww(p) ) { weightlist& www = home->ww(p); if ( www(yy) == 0 ) continue; int first_part = www(yy), second_part = 0; if ( i == 1 ) swap(first_part, second_part); if ( first_part > c.part(0) || second_part > c.part(1) ) continue; wordtype wt(&c, String("x_")+dec(first_part) + "_" + dec(second_part) ); if ( home->active->vtable.mfind(wt) > 0 ) to_kill.append(wt); } } } else { forPix( yy, home->ww(p) ) { weightlist& www = home->ww(p); if ( www(yy) == 0 ) continue; wordtype wt(&c, String("x_") + dec(www(yy)) ); if ( home->active->vtable.mfind(wt) > 0 ) to_kill.append(wt); } } prevector to_kill_v(to_kill); for ( i = 0; i < to_kill_v.length; i++ ) c.make_minimal(to_kill_v(i)); to_kill_v.unique_sort(&wcmp); int success_count = 0; String var; for ( i = 0; i < to_kill_v.length; i++ ) { wordtype& wtt = to_kill_v(i); if ( wtt.length == 2 ) { int i1 = wx; int i2 = wtt(0) + wtt(1); int i3 = wx - wtt(0) + wtt(1); if ( i2 > i3 ) swap( i2, i3 ); if ( i1 > i2 ) swap( i1, i2 ); if ( i2 > i3 ) swap( i2, i3 ); var = String("jy") + dec(i1) + "y" + dec(i2) + "y" + dec(i3); if ( joint_maybe_nonzero.contains(var) ) continue; } Pix pi = subdivide(home->configs(home->current), wtt); home->set_current(pi); if (residual_check_for_kill) home->configs(home->current). check_secondary_residuals(*this); home->activate(true); if ( secondary_kill_maxvars == 0 || secondary_kill_maxvars >= home->active->vtable.length ) { if ( home->contradiction(true, *this) ) { success_count++; cerr << "[" << wtt.variable( ) << " killed]"; home->configs(home->base).share->ycon.append( var + "=0" ); if ( wtt.length == 2 ) { int po = home->joint_vars.pos( var, &String_cmp ); HIDE( ![ if ( po == -1 ) INTERNAL_ERROR("joint variable " << "already known to be " << "zero"); ]! ) home->joint_vars(po) = ""; } home->configs(p).con.append( wtt.variable( ) + "=0" ); home->set_current(p); if ( home->contradiction(true, *this) ) { win_flag = true; break; } } else if ( wtt.length == 2 ) joint_maybe_nonzero.add(var); } if ( home->current != p ) home->set_current(p); home->activate(true); } if ( !win_flag && success_count > 0 && home->contradiction(true, *this) ) win_flag = true; } if (win_flag) { if (no_successes_yet) cerr << "There are no words of weight: " << wx; else cerr << "," << wx; joint_maybe_nonzero.clear( ); no_successes_yet = false; fail_count = 0; home->set_current(home->base); bool nan; home->configs(home->base).add_constraint( String("y") + dec(wx) + "=0", nan ); if ( home->contradiction(true, *this) ) { cerr << ".\n"; delete home; return true; } for ( i = 2; i <= 3; i++ ) { int divx = as_int( Ipow(2, i) ); if ( !wz.divisible(divx) && home->show( String("div") + dec(divx) + ">" + dec( (divx - 1) * Ipow(2, home->dim - i) ), *this, true ) ) { wz.make_divisible(divx); home->ww(home->base).make_divisible(divx); cerr << ",all weights not divisible by " << divx; home->deactivate( ); if ( home->contradiction(true, *this) ) { cerr << ".\n"; delete home; return true; } } else break; } } else { if (!no_successes_yet) cerr << ".\n"; no_successes_yet = true; cerr << "Weight " << wx << " may exist.\n"; if ( ++fail_count == allowed_failures ) break; } } if (!no_successes_yet) cerr << ".\n"; if ( 2*k != n ) goto joint_phase; // Perhaps we can show that the all 1's word is in the code. // (Not discussed in documentation for "no" command.) bool all_ones = false; if ( even(n) && home->ww(home->base).contains(n) ) { home->set_current(home->base); if ( home->show( String("y") + dec(n) + "!=0", *this, true ) ) { cerr << "The word of weight " << n << " is in the code.\n"; all_ones = true; } } fail_count = 0; bool a_fail_occurred = false; int dp = home->configs(home->base).share->dual_min_low; while(1) { if ( all_ones && odd(dp) && n != dp ) { dp++; continue; } if ( n == dp ) { config dd = config( home, String(dec(dp)) + "::{1}" ); home->set_config(dd); } else { if ( !all_ones ) { config dd = config( home, String(dec(n - dp)) + "," + dec(dp) + "::{01}" ); home->set_config(dd); } else { config dd = config( home, String(dec(n - dp)) + "," + dec(dp) + ":{11}:{01}" ); home->set_config(dd); } } if ( home->contradiction(true, *this) ) { fail_count = 0; home->configs(home->base).share->ycon. append( String("mu") + dec(dp) + "=0" ); cerr << "There is no dual word of weight " << dp++ << ".\n"; if ( !a_fail_occurred && not_exist(n,n-k,dp) ) { delete home; return true; } home->set_current(home->base); if ( home->contradiction(true, *this) ) { delete home; return true; } } else { cerr << "There may be a dual word of weight " << dp << ".\n"; a_fail_occurred = true; if ( ++fail_count == allowed_failures || n == dp++ ) goto joint_phase; } } } else { wd.add(0); for ( i = dual_min; i <= n; i++ ) wd.add(i); home = new codehome(n, n-k, wd, *this); if ( home->configs(home->base).share->realizable == -1 ) { delete home; return true; } home->configs(home->base).share->dual_min_low = d; for ( i = d; i <= n; i += 2 ) if ( !w.contains(i) ) home->configs(home->base).share->ycon. append( String("mu") + dec(i) + "=0" ); home->set_config( String(dec(n)) + ":{1}" ); if ( home->contradiction(true, *this) ) { delete home; return true; } while(1) { wx = w.Max( ); if ( wx == 0 ) break; if ( home->n == wx ) home->set_config( String(dec(wx)) + ":{1}:{1}" ); else home->set_config( String(dec(wx)) + "," + dec(n - wx) + ":{11}:{10}" ); w.del(wx); if ( home->contradiction(true, *this) ) { cerr << "Weight " << wx << " does not exist.\n"; fail_count = 0; home->configs(home->base).share->ycon. append( String("mu") + dec(wx) + "=0" ); home->set_config( String(dec(n)) + ":{1}" ); if ( home->contradiction(true, *this) ) { delete home; return true; } } else { cerr << "Weight " << wx << " may exist.\n"; if ( ++fail_count == allowed_failures ) break; } } // Perhaps we can show that the all 1's word is in the code. // (Not discussed in documentation for "no" command.) if ( even(n) && w.contains(n) ) { home->set_current(home->base); if ( home->show( String("mu") + dec(n) + "!=0", *this, true ) ) { cerr << "The word of weight " << n << " is in the code.\n"; home->configs(home->base).share->ww.make_divisible(2); } } fail_count = 0; weightlist www = home->configs(home->base).share->ww; while(1) { wx = www.min( ); if ( wx == n ) { delete home; return false; } home->set_config( String(dec(wx)) + "," + dec(n - wx) + ":{10,01}" ); www.del(wx); if ( home->contradiction(true, *this) ) { cerr << "There is no dual word of weight " << wx << ".\n"; fail_count = 0; home->configs(home->base).share->ww.del(wx); if ( not_exist(n,n-k,home->ww(home->base)) ) { delete home; return true; } home->set_config( String(dec(n)) + ":{1}" ); if ( home->contradiction(true, *this) ) { delete home; return true; } } else { cerr << "There may be a dual word of weight " << wx << ".\n"; if ( ++fail_count == allowed_failures ) { delete home; return false; } } } } joint_phase: if (auto_joint_search > 0 || auto_joint_test > 0 ) { home->joint_vars.unique_sort( &String_cmp ); int njvars = home->joint_vars.length; if ( home->joint_vars(0) == "" ) njvars--; if ( auto_joint_test == 1 || njvars <= auto_joint_test ) { home->set_current(home->base); if ( joint_infeasible(*home, *this) ) { delete home; return true; } } if ( njvars <= auto_joint_search ) { home->set_current(home->base); opt_table search(home); weightlist www = home->ww(home->base); www.del(0); forPixDef( ppp, www ) search.add( String("y") + dec( www(ppp) ) ); search.compute(*this, true); if ( search.feasible == false ) cerr << "It would " << "appear that this code type is unrealizable.\n"; else { forPix( ppp, search.data ) cerr << search.data(ppp); if (save_bounds) { cerr << "saving the following bounds for even codes:\n"; Rational eps(1,1000), low, high; constraint cc; config& cur = home->configs(home->base); forPix( ppp, search.data ) { low = search.data(ppp).min; high = search.data(ppp).max; Integer Ilow = ceil(low - eps); Integer Ihigh = floor(high + eps); cc.LHS = search.data(ppp).var; if ( Ilow > 0 ) { cc.sense = '>'; cc.RHS = Ilow; cerr << " " << cc << "\n"; cur.share->ycon.append(cc); } cc.sense = '<'; cc.RHS = Ihigh; cerr << " " << cc << "\n"; cur.share->ycon.append(cc); } save(*home, ""); home = 0; } } } } delete home; home = 0; if (generate_noneven_bounds > 0) { w = weightlist( dec(d), n ); home = new codehome(n, k, w, *this); home->joint_vars = home->basic_joint_vars(*this); home->joint_vars.sort(&String_cmp); if (home->joint_vars.length <= generate_noneven_bounds) { opt_table search(home); weightlist www = home->ww(home->base); www.del(0); forPixDef( ppp, www ) search.add( String("y") + dec( www(ppp) ) ); search.compute(*this, true); if ( search.feasible == false ) cerr << "It would " << "appear that this code type is unrealizable.\n"; else { cerr << "saving the following bounds for all codes:\n"; Rational eps(1,1000), low, high; constraint cc; config& cur = home->configs(home->base); forPix( ppp, search.data ) { low = search.data(ppp).min; high = search.data(ppp).max; Integer Ilow = ceil(low - eps); Integer Ihigh = floor(high + eps); cc.LHS = search.data(ppp).var; if ( Ilow > 0 ) { cc.sense = '>'; cc.RHS = Ilow; cerr << " " << cc << "\n"; cur.share->ycon.append(cc); } cc.sense = '<'; cc.RHS = Ihigh; cerr << " " << cc << "\n"; cur.share->ycon.append(cc); } } save(*home, ""); home = 0; } } delete home; return false; } index_method(save) void codetable::save(codehome& home, String code_label) { if ( home.configs(home.base).share->realizable == -1 ) { kill(home, code_label); delete &home; } else { forPixDef( q, home.configs ) { if ( home.configs(q).share->realizable == 1 ) { update_lower_bound( home.n, home.dim, home.w.min( ) ); break; } } Pix p = open.append(&home); if ( code_label != "" ) olabels.append( make_pair( code_label, p ) ); if ( !home.assumed_cons.empty( ) || !home.opt.none_chosen( ) ) return; int d = home.w.min( ); if ( home.w.length( ) == home.n - d + 2 ) // all weights present div1w.append( make_pair( make_triple(home.n, home.dim, d), bitvec(home.ww(home.base)) ) ); else if ( even(d) && home.w.length( ) == (home.n - d)/2 + 2 ) { forPix( q, home.w ) // all even weights present? if ( !even( home.w(q) ) ) break; if ( q == 0 ) div2w.append( make_pair( make_triple(home.n, home.dim, d), bitvec(home.ww(home.base)) ) ); } } } set_compile_file(code.c) HIDE( ![ #include "codehome.h" #include "codetable.h" ]! ) TEX( \block{Miscellaneous methods} ) set_compile_file(config.cc) HIDE(![vector we_from_String( String, int, int ); extern int matrix_isomorphism_silent;]!) TEX(![ When the {\tt config} constructor is called, it automatically sets the share pointer to equal the share pointer for the base configuration. If the base pointer has not yet been defined (signified by {\tt base == 0}), this step is omitted. ]!) index_method(config constructor) config::config(codehome* h, const String& s) : home(h) { prevector args = unpack(s, ":"); if ( args.length < 2 || args.length > 4 ) ERROR( "The configuration |" << s << "| is mangled."); part.partition::partition(args(0)); if ( part.n != h->n ) ERROR( "The sum of the partition elements does not equal the " << "length of the code type." ); small.code::code(part.length, args(1)); if ( args.length >= 3 ) dualsmall.code::code(part.length, args(2)); else dualsmall.code::code(part.length, "{}"); leading1s = small.basis.leading_ones( ); if ( args.length == 4 ) { if ( args(3).length( ) == 0 || args(3)[0] != '{' || args(3)[args(3).length( )-1] != '}' ) ERROR("The constraintlist does not have the correct form."); args(3).gsub( "{", 0 ); args(3).gsub( "}", 0 ); if ( args(3).contains( '^' ) ) { prevector cons = unpack( args(3) ); int i; for ( i = 0; i < cons.length; i++ ) if ( cons(i).contains( '^' ) ) break; vector we = we_from_String( cons(i), h->n, h->dim ); String c; bool first = true; for ( int j = 0; j < cons.length; j++ ) { if ( j != i ) { if ( !first ) c += ","; c += cons(i); first = false; } } for ( i = 1; i <= h->n; i++ ) if ( h->w.contains(i) ) { if ( !first ) c += ","; c += String("y") + dec(i) + "=" + dec(we(i)); first = false; } args(3) = c; } assumed_cons.constraintlist::constraintlist( args(3) ); } if ( h->base != 0 ) { share = new config_share; *share = *(h->configs(h->base).share); } aut.n = part.length; } config::config(codehome* h, matrix m) : home(h) { part.set_all_ones(home->n); small.basis = m; leading1s = small.basis.leading_ones( ); dualsmall.basis.set_size(0, home->n); share = new config_share; *share = *(h->configs(h->base).share); aut.n = part.length; } TEX(![ I don't know why the following copy constructor is needed. Without it, one gets a segmentation fault. ]!) config::config(const config& c) { home = c.home; part = c.part; small = c.small; dualsmall = c.dualsmall; assumed_cons = c.assumed_cons; con = c.con; aut = c.aut; share = c.share; auto_labels = c.auto_labels; leading1s = c.leading1s; } ostream& operator<<(ostream& s, const config& c) BHIDE1( ![ if ( c.part.x == 0 ) INTERNAL_ERROR( "I'm trying to print out a configuration whose " << "partition was not defined." ); ]!, ![ s << " config "; ]! ) for ( int i = 0; i < c.part.length; i++ ) { s << c.part(i); if ( i < c.part.length - 1 ) s << ","; } s << " : " << c.small.basis << " : " << c.dualsmall.basis << " : {" << c.assumed_cons << "}\n"; HIDE( ![ if ( c.share == 0 ) INTERNAL_ERROR("Pointer to share is zero."); ]! ) if ( c.share->realizable == -1 ) return s << " unrealizable\n"; HIDE( ![ if ( c.share->ww.length( ) == 0 ) INTERNAL_ERROR("Weight list is empty."); ]! ) s << " working weight list is " << c.share->ww << "\n"; if ( c.con.length( ) != 0 ) s << " known constraints (local): " << c.con << "\n"; if ( c.share->ycon.length( ) != 0 ) s << " known constraints (global): " << c.share->ycon << "\n"; s << " minimum weight of dual code is between " << c.share->dual_min_low << " and " << c.share->dual_min_high << "\n"; if ( c.aut.length != 0 ) { s << " known automorphisms:\n"; for ( int i = 0; i < c.aut.length; i++ ) s << " " << c.aut(i) << "\n"; } if ( c.share->realizable == 1 ) s << " realizable\n"; return s; } TEX( Replace a \verb|term_sum| by one in which the only global variables which appear are {\tt y} variables (or {\tt x} variables, in the case where the partition has only one part.) ) index_method(simplify_global_vars) term_sum config::simplify_global_vars(const term_sum& in, bool verbatim) const { term_sum out; int i, j, k, n = home->n; Rational ycoeff[n + 1]; weightlist& w = share->ww; Pix p, q; for ( i = 0; i <= n; i++ ) ycoeff[i] = 0; forPix( p, in ) { // Evade const to avoid problems with "after". String& v = const_cast(in(p).var); const Rational& cf = in(p).coeff; if ( v[0] == 'y' || (v[0] == 'x' && part.length == 1) ) ycoeff[ yno(v) ] += cf; else if ( v[0] == 'd' ) { int divider = as_int( v.after("div") ); for ( j = 0; j <= n; j += divider ) ycoeff[j] += cf; } else if ( v[0] == 'm' ) { k = as_int( v.after("mu") ); Integer sum, total = Ipow(2, home->dim); forPix( q, w ) { sum = 0; for ( j = 0; j <= k; j++ ) if ( j <= w(q) && k - j <= n - w(q) ) sum += minus1_to_the(j) * choose( w(q), j ) * choose( n - w(q), k - j ); ycoeff[ w(q) ] += Rational(sum) * cf / total; } } else out.append( in(p) ); } if (!verbatim) { forPix( q, w ) { if ( ycoeff[ w(q) ] != 0 ) out.append( term( ycoeff[ w(q) ], String("y") + dec(w(q)) ) ); } } else for ( i = 0; i <= n; i++ ) if ( ycoeff[ i ] != 0 ) out.append( term( ycoeff[ i ], String("y") + dec(i) ) ); return out; } TEX( \verb|no_bad_weights|: Make sure that every word in the smallcode of the given configuration has weight in the working weightlist of the base configuration. ) index_method(no_bad_weights) bool config::no_bad_weights( ) const { vector y = smallcode_we( ); for ( int i = 0; i <= home->n; i++ ) if ( y(i) > 0 && !home->ww(home->base).contains(i) ) return false; return true; } TEX(![ {\tt evaluate(v, low, high):}\ Let {\tt v} be a variable. Search for known constraints whose \LHS\ is {\tt v}, to get integer lower and upper bounds for it. If no upper bound is found, {\tt high} is set to $-1$. The preexisting values for {\tt low} and {\tt high} are assumed to be known bounds, with the same convention regarding {\tt high} $= -1$. ]!) index_method(evaluate) void config::evaluate(const String& s, Integer& low, Integer& high) const { assumed_cons.evaluate( s, low, high ); share->ycon.evaluate( s, low, high ); con.evaluate( s, low, high ); home->assumed_cons.evaluate( s, low, high ); if ( share != home->configs(home->base).share ) home->configs(home->base).share->ycon.evaluate( s, low, high ); } TEX(![ {\tt known}, \verb|known_global|:\ Determine if a constraint is ``known'' for a configuration. In the current version, the constraint must either appear essentially verbatim (see {\tt constraintlist::known}) in one of the lists of known constraints, or must be of the form $\hbox{\tt y}_i$\ {\tt = 0}, where $i$ does not appear in the working weightlist for the configuration. ]!) index_method(known_global) bool known_global( codehome* home, config_share* cs, constraint f ) { if ( home->assumed_cons.known(f) || cs->ycon.known(f) ) return true; if ( cs != home->configs(home->base).share ) if ( home->configs(home->base).share->ycon.known(f) ) return true; if ( f.simple_global( ) && f.sense == '=' && f.RHS == 0 ) if ( !cs->ww.contains( yno(f.LHS.front( ).var) ) ) return true; return false; } index_method(known) bool config::known(const constraint& f) const { return assumed_cons.known(f) || con.known(f) || known_global(home, share, f); } index_method(known_cons) constraintlist config::known_cons( ) const { constraintlist u = home->assumed_cons; u.merge( assumed_cons ); u.merge( share->ycon ); u.merge( con ); if ( share != home->configs(home->base).share ) u.merge( home->configs(home->base).share->ycon ); if ( share->ww.divisible(4) ) u.merge( constraint(String("div8>=") + dec(Ipow(2, home->dim - 3))) ); return u; } TEX(![ The following routine ``adjoins'' a constraint which has been proved by one of the constraint generation commands, such as {\tt show} or {\tt infer}. It is not always the case that a constraint is added to a constraintlist. Moreover, depending on what the constraint is, some additional action may be taken. The flag ``\verb|new_active_needed|'' is set if the \verb|config_active| object will need to be recomputed; this will be the case if either a basic global variable or a basic local variable is set to $0$. Otherwise, the flag is not modified. The given configuration must be {\tt current}, or else bad things will happen. This is a poor design feature which should be corrected. ]!) index_method(add_constraint) void config::add_constraint(constraint& conx, bool& new_active_needed, bool no_create) { static Regex ynumber_pat( "y" + number_pat + orsign + "x_" + number_pat + orsign + "x[0-9]" ); static Regex basic_joint_pattern( "jy" + number_pat + "y" + number_pat + "y" + number_pat ); if ( conx.LHS.empty( ) ) { share->ycon.merge(conx); return; } term term1 = conx.LHS.front( ); TEX( ![ \begin{quote} Does the constraint have the form ``variable = 0''? \end{quote} ]! ) if ( conx.simple( ) && conx.sense == '=' && conx.RHS == 0 ) { // Does the constraint set a basic global variable to 0? if ( term1.var.matches(ynumber_pat) ) { int weight = yno(term1.var); if ( !home->ww(home->current).contains(weight) ) return; // the constraint is already known share->ww.del(weight); if ( home->current == home->base ) { for ( int i = 0; i < home->joint_vars.length; i++ ) { String& jv = home->joint_vars(i); if ( jv.contains( String("y") + dec(weight) + String("y") ) || jv.contains( String("y") + dec(weight), -1 ) ) jv = ""; } } new_active_needed = true; return; } // Does the constraint set a basic joint variable to 0? if ( home->current == home->base && term1.var.matches(basic_joint_pattern) ) { int i1, i2, i3; parse_j_var( term1.var, i1, i2, i3 ); if ( i2 > i3 ) swap( i2, i3 ); if ( i1 > i2 ) swap( i1, i2 ); if ( i2 > i3 ) swap( i2, i3 ); String var = String("jy") + dec(i1) + "y" + dec(i2) + "y" + dec(i3); int pos = home->joint_vars.pos( var, &String_cmp ); if ( pos != -1 ) home->joint_vars(pos) = ""; new_active_needed = true; } // Does it set a mu variable to 0? if_match( term1.var, "mu" + number_pat ) { int weight = as_int(term1.var.after("mu")); if ( share->dual_min_low == weight ) { share->dual_min_low += 1; new_active_needed = true; return; } } // Does it set a basic local variable to 0? Probably we should // use the "orbit" routine instead. if ( term1.var.contains("x", 0) ) { OSLList orb; Pix yy, zz; orb.add( wordtype( this, term1.var ) ); int old_length; wordtype wt; do { old_length = orb.length( ); for( int ii = 0; ii < aut.length; ii++ ) { check_orb: forPix( yy, orb ) { wt = orb(yy); aut(ii).act(wt); forPix( zz, orb ) if ( equiv(part, small.basis, wt, orb(zz)) ) break; if ( zz == 0 ) { orb.add(wt); goto check_orb; } } } } while( old_length != orb.length( ) ); forPix( yy, orb ) con.merge( constraint( orb(yy).variable( ) + "=0" ) ); new_active_needed = true; } } TEX( ![ \begin{quote} Does the constraint have the form ``$\verb|div|i = 2^k$'' (for some $i$) or ``{\tt div4 = }$2^{k-2}$'', where $k$ is the dimension of the code type? \end{quote} ]! ) if ( conx.simple( ) && conx.LHS.front( ).var.contains("div") && conx.sense == '=' && conx.RHS == Ipow(2, home->dim) ) { int div = as_int( conx.LHS.front( ).var.after("div") ); share->ww.make_divisible(div); new_active_needed = true; } if (conx.simple( ) && conx.LHS.front( ).var == "div4" && conx.sense == '=') { if ( conx.RHS == Ipow(2, home->dim - 2) ) new_active_needed = true; } TEX( ![ \begin{quote} Append the constraint. \end{quote} ]! ) if ( conx.global( ) ) share->ycon.merge(conx); else con.merge(conx); TEX( ![ \begin{quote} If the constraint sets a basic global variable to a nonzero value, and this results in the weight enumerator being completely determined, we delete some weights from the working weightlist. Also, the nonzeroness of a basic global variable may force some other basic global variables to be zero. \end{quote} ]! ) if ( conx.simple_global( ) && conx.sense != '<' && conx.RHS >= 0 ) { weightlist& w = home->ww(home->current); if ( w.length( ) != 1 ) { int d = w.min( ); int yn = yno( conx.LHS.front( ).var ); Pix p; int i, n = home->n; begin_del: forPix( p, w ) { if ( w(p) != yn && 2 * n - w(p) - yn < d ) { w.del( w(p) ); goto begin_del; } } Integer low, high; vector lowv(n+1); lowv.set_zero( ); lowv(0) = 1; forPix( p, w ) { if ( w(p) == 0 ) continue; low = 0; high = -1; evaluate( String("y") + dec(w(p)), low, high ); lowv( w(p) ) = low; } Integer sum = 0; for ( i = 0; i <= n; i++ ) sum += lowv(i); if ( sum == Ipow(2, home->dim) ) for ( i = 0; i <= n; i++ ) if ( lowv(i) == 0 ) w.del(i); new_active_needed = true; } } TEX(![ \begin{quote} If the constraint tells us that a {\tt mu} variable is nonzero, and {\tt[current]} $\sim$ {\tt[base]}, we subdivide {\tt[base]} accordingly. \end{quote} ]!) if ( conx.simple( ) ) { String vb = term1.var; if ( vb[0] == 'm' && conx.sense != '<' && conx.RHS >= 1 && share == home->configs(home->base).share ) { int mu_no = as_int( vb.after("mu") ); config c( home, String( dec(home->n - mu_no) ) + "," + dec(mu_no) + "::{01}" ); Pix p = home->merge_config(c); home->configs.join( home->base, p ); } } TEX(![ \begin{quote} If the constraint tells us that the sum of one or more nontrivial basic local variables is nonzero, we subdivide and adjoin the corresponding logical data. (This feature is not adequately documented.) If one or more of the basic local variables are inadmissible, this will cause pointless but harmless things to happen. In the case where the partition has one part, we have to treat the variable {\tt y}$i$ like \verb|x_|$i$. Because we subdivide, this part of \verb|add_constraint| is a potential time sink. \end{quote} ]!) if ( conx.sense == '<' || conx.RHS <= 0 || no_create ) return; SLList ws; forPixDef( ee, conx.LHS ) { if ( conx.LHS(ee).coeff != 1 ) return; String vb = conx.LHS(ee).var; if ( vb[0] != 'x' && (vb[0] != 'y' || part.length != 1) ) return; wordtype w = wordtype(this, vb); word mm(part.length); int i; for ( i = 0; i < mm.length; i++ ) { if ( w(i) == 0 ) mm(i) = 0; else if ( w(i) == part(i) ) mm(i) = 1; else break; } if ( !( i == mm.length && small.basis.rowspace_member(mm) ) ) ws.append(w); } if ( ws.empty( ) ) return; home->activate(true); if ( ws.length( ) == 1 ) { Pix pi = subdivide( home->configs(home->current), ws.front( ) ); home->configs.join( home->current, pi, ws.front( ) ); } else { SLList pxs; forPix( ee, ws ) pxs.append( subdivide( home->configs(home->current), ws(ee) ) ); home->implications.append(make_pair( home->current, pxs )); } } void config::add_constraint(String conx_s, bool& new_active_needed) { constraint conx(conx_s); add_constraint( conx, new_active_needed ); } index_method(check_secondary_residuals) void config::check_secondary_residuals(codetable& results) { if ( home->dim <= 2 ) return; bool nan = false; home->activate(true); SLList answer; small.build( ); int i, j, k, l, m, r, fl, dw, d = share->ww.min( ), n = home->n; mawhometable& vt = home->active->vtable; wordtype v(this); Pix p, q; for ( i = 1; i < vt.length; i++ ) { SLList& words = vt(i).w; forPix( q, words ) { v.act( words(q), vt(i).maw ); for ( j = 1; j < small.x.nrows; j++ ) { word w = small.x(j); dw = w * part; if ( dw < d ) ERROR( "The basic code associated to the small code " << "has a word whose weight is less than the " << "minimum weight of the code." ); if ( dw >= 2*d ) continue; r = w.complement( ) * v; fl = d - dw/2; if ( results.not_exist( n - dw, home->dim - 1, fl ) || !results.possible_weights( n - dw, home->dim - 1, fl, false ).contains(r) ) { add_constraint( vt(i).maw.variable( ) + "=0", nan ); answer.append( vt(i).maw ); break; } if ( r < fl ) ERROR("The wordtype " << vt(i).maw.variable( ) << " is inadmissible."); if ( r < 2 * fl && results.not_exist( n - dw - r, home->dim - 2, fl - r/2 ) ) { add_constraint( vt(i).maw.variable( ) + "=0", nan ); answer.append( vt(i).maw ); break; } } if ( j < small.x.nrows ) break; } } if (!secondary_plus) { if (nan) home->deactivate( ); return; } config_core cc(*this); iterate: for ( i = 1; i < vt.length; i++ ) { forPix( q, answer ) if ( answer(q) == vt(i).maw ) break; if ( q != 0 ) continue; partition dpart = subdivide_partition( part, vt(i).maw ); code dsmall; dsmall.basis = subdivide_matrix( small.basis, part, vt(i).maw, true ); dsmall.build( ); TEX( ![ \begin{quotea} Make a list of all the admissible wordtypes for the subdivision of {\tt[current]} along its \th{i}\ wordtype. \end{quotea} ]! ) SLList vars; for ( k = 0; k < vt.length; k++ ) { forPix( q, answer ) if ( answer(q) == vt(k).maw ) break; if ( q != 0 ) continue; term_sum t = subdivide_basic_local_variable( dpart, dsmall.basis, *(home->active), vt(i).maw, vt(k).maw, false ); forPix( p, t ) { // Build the wordtype corresponding to t(p).var, // except that we don't actually have a // configuration, so we have to do some stupid // stuff. prevector args; if ( t(p).var[1] == '_' ) args = unpack(t(p).var.after("x_"), "_"); else args = unpack(t(p).var.after("x"), ""); wordtype wt(args.length); for ( l = 0; l < args.length; l++ ) wt(l) = as_int(args(l)); for ( l = 0; l < dsmall.x.nrows; l++ ) { wordtype wt2(args.length); for ( m = 0; m < dpart.length; m++ ) { if ( dsmall.x(l)(m) == 0 ) wt2(m) = wt(m); else wt2(m) = dpart(m) - wt(m); } vars.append(wt2); } } } prevector varsv(vars); // We sort now, which is bad. Instead, we should not have generated // duplicate wordtypes in the first place. varsv.unique_sort(&wcmp); vector indx(dpart.length); while( indx.advance( ) ) { int iw = indx * dpart, Pn = dpart.n - iw, Pk, Pd = Pn; if ( Pn == 0 ) continue; int Sn = iw, Sk, Sd = Sn + 1; for ( l = 0; l < varsv.length; l++ ) { for ( m = 0; m < dpart.length; m++ ) if ( !indx(m) && varsv(l)(m) != 0 ) break; if ( m == dpart.length ) { int Sd_new = indx * varsv(l); if ( Sd_new != 0 ) Sd = min( Sd, Sd_new ); } int Pd_new = 0; for ( m = 0; m < dpart.length; m++ ) if ( !indx(m) ) Pd_new += varsv(l)(m); if ( Pd_new != 0 ) Pd = min( Pd, Pd_new ); } for ( Sk = 0; Sk <= min(Sn, home->dim) - 1; Sk++ ) if ( results.not_exist( Sn, Sk + 1, Sd ) ) break; if ( Sk != home->dim ) { if ( results.not_exist( Pn, home->dim - Sk, Pd ) ) { answer.append( vt(i).maw ); add_constraint( vt(i).maw.variable( ) + "=0", nan ); cerr << "appending " << vt(i).maw.variable( ) << " to answer\n"; goto iterate; } } } } if (nan) home->deactivate( ); } index_method(terminal) bool config::terminal( ) const { return small.basis.nrows == home->dim && dualsmall.basis.nrows == 0 && assumed_cons.global( ); } TEX(![ Test to see if a variable is valid, i.e.\ known to the language. Exit with error if not. Note that {\tt v} variables are not included, because they are not supposed to be entered by the user. ]!) index_method(check_variable) void config::check_variable(String v) const { static Regex div_number_pattern("div" + number_pat); static Regex word_pattern = "[01]*"; static Regex sub_pattern( "sub.*" ); static Regex dual_pattern( "q" + list_of( "_" + left + "z" + orsign + number_pat + right, "") + orsign + "q[0-9z]+" ); static Regex basic_joint_pattern( "jy" + number_pat + "y" + number_pat + "y" + number_pat ); static Regex jdi_pattern( "jy" + number_pat + "d" + number_pat + "i" + number_pat ); static Regex jyd_pattern( "jy" + number_pat + "d" + number_pat ); static Regex jd_pattern( "jd" + number_pat + "d" + number_pat + "d" + number_pat ); static Regex number_pattern(number_pat); String rest; if ( v[0] == 'y' ) { rest = v.after("y"); if_no_match( rest, number_pat ) goto invalid_variable; if ( atoI(rest) > part.n ) goto invalid_variable; return; } if ( v[0] == 'm' && v.length( ) >= 2 && v[1] == 'u' ) { if ( atoI( String(v.after("mu")) ) > part.n ) goto invalid_variable; return; } if ( v[0] == 'x' || v[0] == 'z' ) { v[0] = 'x'; wordtype(this, v); return; } if ( v.matches(div_number_pattern) ) { rest = v.after("div"); if ( atoI(rest) > part.n || atoI(rest) == 0 ) goto invalid_variable; int divi = as_int(rest); while( even(divi) ) divi /= 2; if ( divi != 1 ) goto invalid_variable; return; } if ( v.matches( sub_pattern ) ) { rest = v.after("sub"); String wd = take( rest, word_pattern ); if ( wd.length( ) != part.length ) goto invalid_variable; if ( rest.length( ) == 0 ) return; if_no_match( rest, "_" + number_pat ) goto invalid_variable; rest = rest.after("_"); if ( atoI(rest) > part.n ) goto invalid_variable; return; } if ( v.matches( dual_pattern ) ) { prevector qs; if ( v[1] == '_' ) qs = unpack( v.after("q_"), "_"); else qs = unpack( v.after("q"), "" ); if ( qs.length != part.length ) goto invalid_variable; for ( int i = 0; i < qs.length; i++ ) if ( qs(i) != "z" && atoI( qs(i) ) > Integer(part(i)) ) goto invalid_variable; return; } if ( v.matches( basic_joint_pattern ) || v.matches( jdi_pattern ) || v.matches( jd_pattern ) || v.matches( jyd_pattern) ) { int r, s, t; parse_j_var( v, r, s, t ); if ( (v.matches(basic_joint_pattern) || v.matches(jd_pattern)) && r <= part.n && s <= part.n && t <= part.n && r + s >= t && r + t >= s && s + t >= r && r + s + t <= 2*part.n ) return; if ( v.matches(jdi_pattern) && t <= r && t <= s && r + s - t <= part.n ) return; if ( v.matches(jyd_pattern) && r + s <= part.n ) return; } if ( v.contains( "co", 0 ) ) { String v2 = v.after( "co" ); if ( v2.empty( ) ) return; if ( v2.matches(number_pattern) && as_int(v2) <= part.n ) return; } invalid_variable: ERROR("The variable \"" << v << "\" is not defined in the language."); } TEX(![ \verb|configuration_search(c1, c2)|: Let {\tt c1} be a terminal configuration, and let {\tt c2} be any configuration. Determine if the words defined by {\tt c2.small.basis} could be in the code $C$ defined by {\tt c1}. The implementation is horrendously inefficient, as it literally cycles through the r-tuples of elements of $C$, where $r$ is the dimension of {\tt c2}. ]!) index_method(configuration_search) bool configuration_search(const config& c1, const config& c2) { c1.small.build( ); int r = c2.small.basis.nrows; int k, l; vector indx(r); indx.set_zero( ); vector candidate(r); int intersection_weight; // The outer loop cycles through r-tuples of elements of c1's smallcode. while(1) { for ( k = 0; k < r; k++ ) candidate(k) = c1.small.x(indx(k)); vector subset(r); TEX( \begin{quotea} The next loop cycles through subsets of the $r$ elements. The intersection of the words in the subset should have the same weight as the intersection of the corresponding words in {\tt c2}'s small code. \end{quotea} ) while( subset.advance( ) ) { intersection_weight = 0; for ( k = 0; k < c1.part.length; k++ ) { for ( l = 0; l < r; l++ ) if ( subset(l) && !candidate(l)(k) ) break; if ( l == r ) intersection_weight += c1.part(k); } for ( k = 0; k < c2.part.length; k++ ) { for ( l = 0; l < r; l++ ) { if ( !subset(l) ) continue; if ( !c2.small.basis(l,k) ) break; } if ( l == r ) intersection_weight -= c2.part(k); } if ( intersection_weight != 0 ) break; } if ( intersection_weight == 0 ) return true; for ( k = r - 1; k >= 0; k-- ) if ( indx(k) != c1.small.x.nrows - 1 ) break; if ( k < 0 ) return false; for ( l = r - 1; l > k; l-- ) indx(l) = 0; ++indx(k); } } TEX( \verb|expand_term_sum(t)|: Expand the sum of terms {\tt t} as a linear combination of {\tt v} variables. Return a vector {\tt v} whose \th{i}\ entry is the coefficient of $\hbox{\tt v}(i+1)$ in the expanded expression. ) index_method(expand_term_sum) void config_active::expand_term_sum(const term_sum& t, vector& v) const { static Regex zero_one_string( "[01]*" ); term_sum tg = c->simplify_global_vars(t); v.set_size(vtable.length); v.set_zero( ); HIDE( ![ if ( y_as_vsum.length != c->share->ww.length( ) ) INTERNAL_ERROR("expand_term_sum: ww modified without deactivation." << " The working weight list is " << c->share->ww << " but y_as_vsum has length " << y_as_vsum.length << "."); ]! ) forPixDef( i, tg ) { // There are many cases, corresponding to the many possible types // of variables. HIDE( ![ if ( joint_var( tg(i).var ) ) INTERNAL_ERROR( "Joint variable passed to expand_term_sum." ); ]! ) if ( tg(i).var[0] == 'v' ) { int var_no = as_int( tg(i).var.after("v") ); v(var_no - 1) += tg(i).coeff; } else if ( tg(i).var[0] == 'y' ) { int r = 0, weight = yno( tg(i).var ); forPixDef( j, c->share->ww ) { if ( weight == c->share->ww(j) ) break; r++; } if ( j == 0 ) continue; forPix( j, y_as_vsum(r) ) { term& tt = y_as_vsum(r)(j); int var_no = as_int( tt.var.after("v") ); v(var_no - 1) += tt.coeff * tg(i).coeff; } } else if ( tg(i).var[0] == 'x' ) { int var_no = x_to_v(tg(i).var); if ( var_no != 0 ) v(var_no - 1) += tg(i).coeff; } else if ( tg(i).var[0] == 's' ) { String rest = tg(i).var.after("sub"); word w( take( rest, zero_one_string ), 0 ); int mm = -1; if ( !rest.empty( ) ) mm = as_int( rest.after("_") ); wordtype z(c); for ( int l = 0; l < vtable.length; l++ ) { forPixDef( j, vtable(l).w ) { z.act( vtable(l).w(j), vtable(l).maw ); if ( w.complement( ) * z == 0 ) if ( mm == -1 || sum(z) == mm ) v(l) += tg(i).coeff; } } } else if ( tg(i).var[0] == 'z' || tg(i).var[0] == 'q' ) { prevector ss; char z_or_q = tg(i).var[0]; tg(i).var.del(z_or_q); if ( tg(i).var[0] == '_' ) ss = unpack( tg(i).var.after("_"), "_" ); else ss = unpack( tg(i).var, "" ); wordtype wt(c); word w(c->part.length); w = w.complement( ); int j, l; for ( l = 0; l < c->part.length; l++ ) { if ( ss(l) == 'z' ) w(l) = 0; else wt(l) = as_int( ss(l) ); } Integer** binom = new Integer*[c->home->n + 1]; for ( l = 0; l <= c->home->n; l++ ) { binom[l] = new Integer[l+1]; binom[l][0] = 1; for ( j = 1; j < l; j++ ) binom[l][j] = binom[l-1][j] + binom[l-1][j-1]; binom[l][l] = 1; } vector vi(vtable.length); convert_dual_variable(w, wt, binom, vi); Integer code_size = Ipow(2, c->home->dim); for ( j = 0; j < vtable.length; j++ ) { if ( z_or_q == 'z' ) v(j) += tg(i).coeff * Rational( vi(j), code_size ); else v(j) += tg(i).coeff * Rational(vi(j)); } for ( l = 0; l <= c->home->n; l++ ) delete [ ] binom[l]; delete [ ] binom; } } } index_method(add_to_rational_constraint) void add_to_rational_constraint ( qvconstraint& qv, const vconstraint& vcon, Rational& multiplier ) { // We're building a <= constraint. If the contribution will // amount to a >= constraint, it can't be used. Ignore it. if ( vcon.sense == '<' && sign(multiplier) < 0 ) return; if ( vcon.sense == '>' && sign(multiplier) > 0 ) return; qv.RHS += Rational(vcon.RHS) * multiplier; for ( int i = 0; i < vcon.LHS.length; i++ ) qv.LHS(i) += vcon.LHS(i) * multiplier; } TEX( Two configurations are declared to be ``equal'' if their {\it defining\/} members are equal. ) bool operator==(const config& c1, const config& c2) { return (mostly_equal(c1,c2) && c1.assumed_cons == c2.assumed_cons); } TEX(![ The routine ``\verb|is_automorphism|'' does not do a good job with local variables in assumed constraints. Indeed, if $\cal T$ is the set of assumed constraints for the configuration, what is tested is not whether $\sigma(\cal T) \sim \cal T$, but rather whether $\sigma(f) \sim f$, for all $f \in \cal T$. Thus \verb|is_automorphism| will sometimes return {\tt false} when it should return {\tt true}. ]!) index_method(is_automorphism) bool config::is_automorphism(const Permutation& p) { // Check to see if the alleged permutation preserves the sizes // of the partition elements. int i; for ( i = 0; i < part.length; i++ ) if ( part(i) != part(p(i)-1) ) return false; // Does it preserve the basis and dual basis? matrix* b[ ] = { &small.basis, &dualsmall.basis }; for ( int k = 0; k < 2; k++ ) { Permutation* colfix = b[k]->column_fix( ); matrix permuted_basis = *(b[k]); Permutation colfix_i = colfix->inverse( ); permuted_basis.permute_columns( (*colfix) * p * colfix_i ); int rank = rank_of_rowspace_sum(*(b[k]), permuted_basis); b[k]->permute_columns(colfix_i); delete colfix; if ( rank != b[k]->nrows ) return false; } // Are assumed constraints preserved? forPixDef( q, assumed_cons ) { term_sum& ts = assumed_cons(q).LHS; term_sum local_part; // to be the local part of the given constraint forPixDef( r, ts ) { // Test for local variable. if ( local_var( ts(r).var ) ) local_part.append( ts(r) ); } if ( local_part.length( ) != 0 ) { home->activate(false); int nvars = home->active->vtable.length; vector vs(nvars), vs_new(nvars); home->active->expand_term_sum(local_part, vs); for ( i = 0; i < nvars; i++ ) { wordtype w = home->active->vtable(i).maw; p.act(w); int j = home->active->vtable.mfind(w); if ( vs(i) != vs(j) ) return false; } } } return true; } TEX( Return weight enumerator of the basic code associated to the small code of a configuration. ) index_method(smallcode_we) vector config_core::smallcode_we( ) const { time_used_by_smallcode_we -= time(0); vector y(part.n + 1); HIDE( ![ if (debug) { matrix m = smallbasis; m.reduce_nz( ); if ( m != smallbasis ) INTERNAL_ERROR( "smallcode_we: matrix not reduced" ); } ]! ) if ( 2 * smallbasis.nrows <= part.n || part.length != part.n ) { vector indx(smallbasis.nrows), sum(smallbasis.ncols); y.set_zero( ); do { mul( indx, smallbasis, sum ); ++y( sum * part ); } while( indx.advance( ) ); } else { matrix D; basic_small( ).nullspace_equals(D); y = dual_of_we( D.enumerate_weights( ) ); } time_used_by_smallcode_we += time(0); return y; } vector config::smallcode_we( ) const { return config_core(*this).smallcode_we( ); } TEX( Return a generator matrix for the basic code associated to the small code of a configuration. ) index_method(basic_small) matrix config_core::basic_small( ) const { matrix M(smallbasis.nrows, part.n); int k = 0; // column index for M for ( int j = 0; j < smallbasis.ncols; j++ ) { for ( int l = 0; l < part(j); l++ ) for ( int i = 0; i < smallbasis.nrows; i++ ) M(i, k + l) = smallbasis(i,j); k += part(j); } return M; } matrix config::basic_small( ) const { return config_core(*this).basic_small( ); } index_method(basic_dualsmall) matrix config_core::basic_dualsmall( ) const { matrix M(dualsmallbasis.nrows, part.n); int k = 0; // column index for M for ( int j = 0; j < dualsmallbasis.ncols; j++ ) { for ( int l = 0; l < part(j); l++ ) for ( int i = 0; i < dualsmallbasis.nrows; i++ ) M(i, k + l) = dualsmallbasis(i,j); k += part(j); } return M; } HIDE( ![ template void sort_by_second( prevector< pair >& ); ]! ) TEX( ![ \verb|invariant_generating_set|:\ Given a matrix $M$ over $\F_2$ with linearly independent rows, and a partition $p$, with the length $\ell$ of $p$ equalling the number of columns of $M$, find a subset $S$ of the rowspace $V$ of $M$ with the following properties. First, $S$ generates $V$. Second, $S$ is invariant, meaning that if $\sigma \in S_{\ell}$ and $\sigma(p) = p$ and $\sigma(V) = V$, then $\sigma(S) = S$. Third, $S$ is relatively small. Fourth, the routine should be {\it canonical\/} in the sense that if the columns of $M$ are permuted by a permutation $\sigma$, the resulting $S$ will be the same, except that its columns will also be permuted by $\sigma$. The method is to divide $V$ into a collection $\cal C$ of invariant subsets, and then try to find a collection of those subsets whose union is small and yet generates $V$. There is quite a bit of room for improvement in the algorithm. ]! ) index_method(invariant_generating_set) prevector invariant_generating_set( const matrix& M, const partition& p ) BHIDE1( ![ if ( M.ncols != p.length ) INTERNAL_ERROR("invariant_generating_set: garbage input"); ]!, ![ if ( M.nrows == 0 ) return prevector(0); ]! ) time_used_by_igs -= time(0); int i, j, n = p.n, nparts = p.length; prevector< pair< SLList, matrix > > bag(n+1); TEX( ![ \begin{quote} Let $\verb|bag(|i\verb|).first|$ be the set of all words of weight $i$ in $V$, where the weights are computed relative to $p$. \end{quote} ]! ) word ind(M.nrows), x(M.ncols); do { mul( ind, M, x ); bag(x * p).first.append(x); } while ( ind.advance( ) != 0 ); TEX( ![ \begin{quote} Let $\verb|bag(|i\verb|).second|$ be a basis for $\verb|bag(|i\verb|).first|$. \end{quote} ]! ) for ( i = 0; i <= n; i++ ) { if ( bag(i).first.length( ) != 0 ) { bag(i).second = matrix(nparts, bag(i).first); bag(i).second.reduce_nz( ); } } TEX( ![ \begin{quote} Now we have ${\cal C} = \{\verb|bag(|i\verb|).first|\}_{0 \leq i \leq n}$. We would like to apply an algorithm which cycles through the subsets $D$ of $\cal C$ in increasing order according to the size of the union of the sets in $D$, and which does so in an efficient manner. In lieu of such an algorithm, we sort the elements of $\cal C$ by size, and then (using this order on $\cal C$) cycle through its full power set. When we encounter a $D$ which generates, we stop. There is no guarantee that the size of the union of the sets in $D$ is minimized. \end{quote} ]! ) SLList< pair< pair< matrix, int>, int> > cag; for ( i = 0; i <= n; i++ ) if ( bag(i).first.length( ) != 0 ) cag.append( make_pair( make_pair( bag(i).second, i ), bag(i).first.length( ) ) ); prevector< pair< pair< matrix, int>, int> > vag(cag); sort_by_second(vag); int k = vag.length; word indx(k), indxr(k); // indxr is indx with the bit order reversed do { int nrows = 0, row_ptr = 0; for ( i = 0; i < k; i++ ) indxr(i) = indx(k - i - 1); for ( i = 0; i < k; i++ ) if ( indxr(i) ) nrows += vag(i).first.first.nrows; matrix B( nrows, nparts ); for ( i = 0; i < k; i++ ) if ( indxr(i) ) for ( j = 0; j < vag(i).first.first.nrows; j++ ) B(row_ptr++) = vag(i).first.first(j); if ( B.reduce( ) == M.nrows ) break; } while( indx.advance( ) != 0 ); int sz = 0, ans_ptr = 0; for ( i = 0; i < k; i++ ) if ( indxr(i) ) sz += bag(vag(i).first.second).first.length( ); prevector answer(sz); for ( i = 0; i < k; i++ ) if ( indxr(i) ) { j = vag(i).first.second; forPixDef( q, bag(j).first ) answer(ans_ptr++) = bag(j).first(q); } time_used_by_igs += time(0); return answer; } TEX( ![ Find generators for the automorphism group of a configuration and compute its size. The problem is rephrased in terms of finding the automorphism group of a vertex-colored graph. ]! ) index_method(find_automorphism_group) pair< Permutationlist, Integer > config::find_automorphism_group( ) const { int i, j, n = home->n, nparts = part.length; if ( !assumed_cons.global( ) ) ERROR("The routine find_automorphism_group can only" << " work with configurations having global assumed constraints."); prevector cd = invariant_generating_set( small.basis, part ); prevector dcd = invariant_generating_set( dualsmall.basis, part ); vertex_colored_graph g(nparts + cd.length + dcd.length); for ( i = 0; i < nparts; i++ ) g.c(i) = part(i); for ( i = nparts; i < nparts + cd.length; i++ ) g.c(i) = n + 1; // a color different from the others for ( i = nparts + cd.length; i < g.n; i++ ) g.c(i) = n + 2; // another color for ( i = 0; i < cd.length; i++ ) for ( j = 0; j < nparts; j++ ) if ( cd(i)(j) ) { g.a(j).set(nparts + i); g.a(nparts + i).set(j); } for ( i = 0; i < dcd.length; i++ ) for ( j = 0; j < nparts; j++ ) if ( dcd(i)(j) ) { g.a(j).set(nparts + cd.length + i); g.a(nparts + cd.length + i).set(j); } pair< Permutationlist, Integer > ans0 = g.find_automorphism_group( ); Permutationlist pl(part.length); for ( i = 0; i < ans0.first.length; i++ ) { Permutation q(part.length); for ( j = 0; j < part.length; j++ ) q(j) = ans0.first(i)(j); pl.append(q); } return make_pair( pl, ans0.second ); } index_method(find_automorphism_group) pair< Permutationlist, Integer > find_automorphism_group(const matrix& M) { int i, j, n = M.ncols; if (!matrix_isomorphism_silent) { cerr << "computing the automorphism group of an " << M.nrows << " x " << M.ncols << " matrix; weight enumerator = " << as_poly(M.enumerate_weights( )) << "... "; } partition part(n); part.set_all_ones(n); prevector cd = invariant_generating_set( M, part ); vertex_colored_graph g(n + cd.length); for ( i = 0; i < n; i++ ) g.c(i) = part(i); for ( i = n; i < n + cd.length; i++ ) g.c(i) = n + 1; // a color different from the others for ( i = 0; i < cd.length; i++ ) for ( j = 0; j < n; j++ ) if ( cd(i)(j) ) { g.a(j).set(n + i); g.a(n + i).set(j); } pair< Permutationlist, Integer > ans0 = g.find_automorphism_group( ); Permutationlist pl(part.length); for ( i = 0; i < ans0.first.length; i++ ) { Permutation q(part.length); for ( j = 0; j < part.length; j++ ) q(j) = ans0.first(i)(j); pl.append(q); } if (!matrix_isomorphism_silent) cerr << "done\n"; return make_pair( pl, ans0.second ); } SLList< vector > dual_words_of_given_weight(matrix, int); // For the following method, both M1 and M2 should be in reduced row-echelon // form. index_method(isomorphic) bool isomorphic(const matrix& M1, const matrix& M2) { if ( M1.nrows != M2.nrows || M1.ncols != M2.ncols ) return false; vector y = M1.enumerate_weights( ); if ( y != M2.enumerate_weights( ) ) return false; if (!matrix_isomorphism_silent) { cerr << "testing to see if two " << M1.nrows << " x " << M1.ncols << " matrices are isomorphic; weight enumerator = " << as_poly(M1.enumerate_weights( )) << "... "; } int i, j, k, n = M1.ncols; TEX( ![ \begin{quote} Test for codes with exactly one odd weight. These are extremely difficult for the automorphism tester, but can often be dealt with faster. \end{quote} ]! ) int odd_count = 0; for ( i = 0; i <= n; i++ ) if ( odd(i) && y(i) != 0 ) odd_count++; if (odd_count == 1) { matrix M[2], Me[2], Mh[2]; // code, even subcode, half of it M[0] = M1; M[1] = M2; int l; k = M1.nrows; for ( l = 0; l < 2; l++ ) { for ( i = 0; i < k; i++ ) if ( odd( M[l](i).weight( ) ) ) break; if ( !odd( M[l]( k-1 ).weight( ) ) ) M[l]( k-1 ) += M[l](i); for ( j = 0; j < k-1; j++ ) if ( odd( M[l](j).weight( ) ) ) M[l](j) += M[l]( k-1 ); Me[l] = M[l]; Me[l].resize( k-1, n ); SLList< vector > d2 = dual_words_of_given_weight( Me[l], 2 ); if ( d2.length( ) * 2 != n ) goto special_fails; forPixDef( p, d2 ) { forPixDef( q, d2 ) if ( intersection_size( d2(p), d2(q) ) == 1 ) goto special_fails; } forPix( p, d2 ) if ( int(M[l](k-1, d2(p)(0))) + int(M[l](k-1, d2(p)(1))) != 1 ) goto special_fails; Mh[l].set_size(k-1, n/2); i = 0; forPix( p, d2 ) { for ( j = 0; j < k-1; j++ ) Mh[l](j,i) = Me[l](j, d2(p)(0)); i++; } } if (!matrix_isomorphism_silent) cerr << "reformulating\n"; return isomorphic( Mh[0], Mh[1] ); } special_fails: partition part; part.set_all_ones(n); prevector cd[2]; cd[0] = invariant_generating_set( M1, part ); cd[1] = invariant_generating_set( M2, part ); if ( cd[0].length != cd[1].length ) { if (!matrix_isomorphism_silent) cerr << "done\n"; return false; } vertex_colored_graph g[2]; for ( j = 0; j < 2; j++ ) { g[j] = vertex_colored_graph(n + cd[j].length); for ( i = 0; i < n; i++ ) g[j].c(i) = 1; for ( i = n; i < n + cd[j].length; i++ ) g[j].c(i) = n + 1; // a color different from the others for ( i = 0; i < cd[j].length; i++ ) for ( k = 0; k < n; k++ ) if ( cd[j](i)(k) ) { g[j].a(k).set(n + i); g[j].a(n + i).set(k); } } bool answer = Isomorphic( g[0], g[1] ); if (!matrix_isomorphism_silent) cerr << "done\n"; return answer; } index_method(isomorphic) bool codehome::isomorphic(const config_core& c1, const config_core& c2, bool fully_refined) const { int i, j, k; const config_core* c[ ] = { &c1, &c2 }; // Are the configurations blatantly non-isomorphic? if ( c1.smallbasis.nrows != c2.smallbasis.nrows || c1.dualsmallbasis.nrows != c2.dualsmallbasis.nrows || (!fully_refined && c1.part.length != c2.part.length) ) return false; if ( c1.smallcode_we( ) != c2.smallcode_we( ) ) return false; TEX( ![ \begin{quote} Find permutations $\sigma_i$ of {\tt part.length} ($i = 1,2$) which put the elements of {\tt ci.part} in increasing order. \end{quote} ]! ) partition part[2]; code small[2], dualsmall[2]; int nparts; Permutation p[2]; if ( !fully_refined ) { for ( i = 0; i < 2; i++ ) { part[i] = c[i]->part; small[i].basis = c[i]->smallbasis; dualsmall[i].basis = c[i]->dualsmallbasis; part[i].sort( rcmp, p[i] ); } nparts = c1.part.length; if ( part[0] != part[1] ) return false; for ( i = 0; i < 2; i++ ) { for ( j = 0; j < small[i].basis.nrows; j++ ) p[i].act( small[i].basis(j) ); for ( j = 0; j < dualsmall[i].basis.nrows; j++ ) p[i].act( dualsmall[i].basis(j) ); } } else { for ( j = 0; j < 2; j++ ) { part[j].set_all_ones(n); p[j] = Permutation(n); small[j].basis = c[j]->basic_small( ); dualsmall[j].basis = c[j]->basic_dualsmall( ); } nparts = n; } prevector cd[2], dcd[2]; for ( j = 0; j < 2; j++ ) cd[j] = invariant_generating_set( small[j].basis, part[j] ); if ( cd[0].length != cd[1].length ) return false; for ( j = 0; j < 2; j++ ) dcd[j] = invariant_generating_set( dualsmall[j].basis, part[j] ); if ( dcd[0].length != dcd[1].length ) return false; vertex_colored_graph g[2]; for ( j = 0; j < 2; j++ ) { g[j] = vertex_colored_graph(nparts + cd[j].length + dcd[j].length); for ( i = 0; i < nparts; i++ ) g[j].c(i) = part[0](i); for ( i = nparts; i < nparts + cd[j].length; i++ ) g[j].c(i) = n + 1; // a color different from the others for ( i = nparts + cd[j].length; i < g[j].n; i++ ) g[j].c(i) = n + 2; // another color for ( i = 0; i < cd[j].length; i++ ) for ( k = 0; k < nparts; k++ ) if ( cd[j](i)(k) ) { g[j].a(k).set(nparts + i); g[j].a(nparts + i).set(k); } for ( i = 0; i < dcd[j].length; i++ ) for ( k = 0; k < nparts; k++ ) if ( dcd[j](i)(k) ) { g[j].a(k).set(nparts + cd[j].length + i); g[j].a(nparts + cd[j].length + i).set(k); } } return Isomorphic( g[0], g[1] ); } TEX( ![ \verb|isomorphic|:\ Determine if two configurations are isomorphic. If the ``\verb|fully_refine|'' parameter is set, the configurations will be fully refined before testing. Beware about the way that assumed constraints are tested. ]! ) bool codehome::isomorphic(const config& c1, const config& c2, bool fully_refined) const BHIDE1( ![ if ( !c1.assumed_cons.global( ) || !c2.assumed_cons.global( ) ) INTERNAL_ERROR("The routine isomorphic can only" << " work with configurations having global assumed constraints."); ]!, ![ if ( c1.assumed_cons != c2.assumed_cons ) return false; ]! ) return isomorphic( config_core(c1), config_core(c2), fully_refined ); } TEX( ![ \verb|dual_words_of_given_weight|:\ Find all words of the given weight $w$ in $\F_2^n$ dual to the rowspace of the given matrix $D$. The method is to traverse lexicographically through all words of weight $w$ in $\F_2^n$. ]! ) index_method(dual_word) SLList< vector > dual_words_of_given_weight(matrix D, int w) { SLList< vector > answer; int i, j, k; vector bit_on(w); for ( i = 0; i < w; i++ ) bit_on(i) = i; gf2 dot; while(1) { for ( i = 0; i < D.nrows; i++ ) { dot = 0; for ( j = 0; j < w; j++ ) dot += D(i)(bit_on(j)); if (dot) break; } if ( i == D.nrows ) answer.append( bit_on ); if ( bit_on( w-1 ) < D.ncols - 1 ) ++bit_on( w-1 ); else { for ( i = w-1; i >= 0; i-- ) if ( bit_on(i) != D.ncols - w + i ) break; if ( i == -1 ) break; j = bit_on(i) - i + 1; for ( k = i; k < w; k++ ) bit_on(k) = j + k; } } return answer; } TEX( ![ \verb|core_design_test|:\ Implement the condition described on page \pageref{elaborate-design-condition}, using ($n,m,\kappa,A,B,C$) as inputs to the routine. Here $m$ is the dimension of the code and $\kappa$ is the block size. The implementation could no doubt be substantially speeded up. ]! ) index_method(core_design_test) bool core_design_test( int n, int m, int k, SLList< vector >& twos, SLList< vector >& dual_words, OSLList< vector >& contained_by_every_design ) { int i, j; Pix p, q; while(1) { SLList< vector > uniquely_covered_twos; forPix( p, twos ) { number count; forPix( q, dual_words ) if ( subset( twos(p), dual_words(q) ) ) ++count; if ( count == 0 ) return false; if ( count == 1 ) uniquely_covered_twos.append( twos(p) ); } if ( uniquely_covered_twos.empty( ) ) { int block_count = contained_by_every_design.length( ); if ( Integer(block_count) * choose(k,2) != choose(n,2) ) return true; matrix blocks(block_count, n); int block_ptr = 0; forPix( p, contained_by_every_design ) { vector block = contained_by_every_design(p); for ( i = 0; i < block.length; i++ ) blocks(block_ptr, block(i)) = 1; block_ptr++; } return (blocks.reduce( ) == n - m); } SLList< vector > special_dual_words; forPix( p, dual_words ) forPix( q, uniquely_covered_twos ) { if ( subset( uniquely_covered_twos(q), dual_words(p) ) ) { special_dual_words.append( dual_words(p) ); break; } } prevector< vector > sdw(special_dual_words); for ( i = 0; i < sdw.length; i++ ) { contained_by_every_design.add( sdw(i) ); for ( j = i+1; j < sdw.length; j++ ) if ( intersection_size( sdw(i), sdw(j) ) >= 2 ) return false; } SLList< vector > saved_twos, deleted_twos, saved_dual_words; forPix( p, twos ) { forPix( q, special_dual_words ) if ( subset( twos(p), special_dual_words(q) ) ) break; if ( q == 0 ) saved_twos.append( twos(p) ); else deleted_twos.append( twos(p) ); } forPix( p, dual_words ) { vector& ww = dual_words(p); forPix( q, deleted_twos ) if ( subset( deleted_twos(q), ww ) ) break; if ( q == 0 ) saved_dual_words.append( ww ); } twos = saved_twos; dual_words = saved_dual_words; } } index_method(options_satisfied) bool codehome::options_satisfied(const config& d) BHIDE1( ![ if ( !d.terminal( ) ) INTERNAL_ERROR( "options_satisfied called with non-terminal configuration" ); ]!, ![ matrix D = d.basic_small( ); ]! ) SLList< vector > dual_words, dual_words_save, uniquely_contained; SLList< vector > all_twos; prevector< SLList< prevector< vector > > > covers; int i, j, k; Pix p, q; if ( opt.partition_of_word_by_dual_words ) { dual_words = dual_words_of_given_weight(D, opt.d); dual_words_save = dual_words; SLList containers; code dc; dc.basis = D; dc.build( ); for ( i = 0; i < dc.x.nrows; i++ ) if ( dc.x(i).weight( ) == opt.w ) containers.append( dc.x(i) ); prevector tw(containers); covers.set_size( tw.length ); vector ii(opt.w/opt.d), ii_save(opt.w/opt.d); for ( i = 0; i < tw.length; i++ ) { TEX( ![ \begin{quotebneg} Find all dual words of weight {\tt opt.d} contained in the given word of weight {\tt opt.w}. \end{quotebneg} ]! ) SLList< vector > in_it; forPix( p, dual_words) { vector& dw = dual_words(p); for ( j = 0; j < dw.length; j++ ) if ( !(tw(i)(dw(j))) ) break; if ( j == dw.length ) in_it.append(dw); } prevector< vector > in_itv(in_it); TEX( ![ \begin{quoteb} At any given point, the first $\verb|ii_ptr| + 1$ elements of {\tt ii} are to be an increasing sequence of elements between $0$ and $\verb|in_itv.length| - 1$. \end{quoteb} ]! ) int ii_ptr = 0; ii(0) = 0; if ( in_itv.length < ii.length ) return false; int twicount = 0; while(1) { for ( j = 0; j < ii_ptr; j++ ) if ( intersection_size( in_itv( ii(ii_ptr) ), in_itv( ii(j) ) ) > 0 ) break; if ( j == ii_ptr && ii_ptr == opt.w/opt.d - 1 ) { twicount++; prevector< vector > a_cover(opt.w/opt.d); for ( k = 0; k < a_cover.length; k++ ) a_cover(k) = in_itv( ii(k) ); covers(i).append( a_cover ); ii_save = ii; } if ( j == ii_ptr && ii_ptr != opt.w/opt.d - 1 ) { ii_ptr++; ii(ii_ptr) = ii(ii_ptr-1) + 1; } else { // Work backwards to find element of ii that can // be incremented. for ( j = ii_ptr; j >= 0; j-- ) if ( ii(j) < in_itv.length - 1 - (opt.w/opt.d - 1 - j) ) break; if ( j < 0 ) break; ii_ptr = j; ++ii(j); } } if ( twicount == 1 ) { for ( j = 0; j < ii_save.length; j++ ) uniquely_contained.append( in_itv(ii_save(j)) ); } if ( twicount == 0 ) return false; } d.small.unbuild( ); } if ( opt.dual_may_be_code_of_design ) { matrix cover(D.ncols, D.ncols); cover.set_zero( ); if ( !opt.partition_of_word_by_dual_words || opt.d != opt.k ) dual_words = dual_words_of_given_weight(D, opt.k); forPix( p, dual_words ) for ( i = 0; i < opt.k; i++ ) for ( j = i+1; j < opt.k; j++ ) ++cover( dual_words(p)(i), dual_words(p)(j) ); for ( i = 0; i < D.ncols; i++ ) for ( j = i+1; j < D.ncols; j++ ) if ( cover(i,j) < opt.lambda ) return false; if ( opt.lambda == 1 ) { for ( i = 0; i < D.ncols; i++ ) for ( j = i+1; j < D.ncols; j++ ) { vector x(2); x(0) = i; x(1) = j; all_twos.append(x); } } } if ( opt.dual_may_be_code_of_design && opt.lambda == 1 && opt.partition_of_word_by_dual_words && opt.d == opt.k ) { SLList< vector > twos; OSLList< vector > duals_in_cover; prevector< prevector< prevector< vector > > > coversv; coversv.set_size(covers.length); for ( i = 0; i < coversv.length; i++ ) coversv(i) = covers(i); prevector which(coversv.length); int level = 0; while(1) { prevector< vector > a = coversv(level)(which(level)); for ( i = 0; i < level; i++ ) { prevector< vector > b = coversv(i)(which(i)); for ( j = 0; j < a.length; j++ ) for ( k = 0; k < b.length; k++ ) { int isize = intersection_size( a(j), b(k) ); if ( isize > 1 && isize < opt.d ) goto bad_cover; } } if ( level == coversv.length - 1 ) { duals_in_cover.clear( ); for ( i = 0; i < which.length; i++ ) { prevector< vector > cw; // cover of a word cw = coversv(i)(which(i)); for ( j = 0; j < cw.length; j++ ) duals_in_cover.add( cw(j) ); } dual_words.clear( ); forPix( q, dual_words_save ) { forPixDef( qq, duals_in_cover ) { int is = intersection_size( dual_words_save(q), duals_in_cover(qq) ); if ( is > 1 ) break; } if ( qq == 0 ) dual_words.append( dual_words_save(q) ); } twos.clear( ); forPix( q, all_twos ) { forPixDef( qq, duals_in_cover ) { if ( subset( all_twos(q), duals_in_cover(qq) ) ) break; } if ( qq == 0 ) twos.append( all_twos(q) ); } if ( core_design_test( n, dim, opt.k, twos, dual_words, duals_in_cover ) ) goto next_test; goto bad_cover; } which(++level) = 0; continue; bad_cover: for ( i = level; i >= 0; i-- ) if ( which(i) < coversv(i).length - 1 ) break; if ( i == -1 ) return false; level = i; ++which(level); } } next_test: if ( opt.dual_may_be_code_of_design && opt.lambda == 1 ) { OSLList< vector< number> > cb; if ( core_design_test(n, dim, opt.k, all_twos, dual_words, cb) ) return true; } if ( opt.doubly_even_part_is_subcode ) { SLList de; code dc; dc.basis = D; dc.build( ); for ( i = 0; i < dc.x.nrows; i++ ) if ( dc.x(i).weight( ) % 4 == 0 ) de.append( dc.x(i) ); matrix dem(n, de); if ( Ipow( 2, dem.reduce( ) ) != dem.nrows ) return false; } return true; } TEX( ![ A lot of time gets spent in the following routine. This time shows up as time spent in the routine ``{\tt subdivide}''. ]! ) index_method(equiv) bool equiv(const partition& part, const matrix& smallbasis, const wordtype& wt1, const wordtype& wt2) { word wd(part.length); SLList ambiguous_positions; for ( int j = 0; j < part.length; j++ ) { if ( wt1(j) == wt2(j) ) { if ( 2 * wt1(j) == part(j) ) ambiguous_positions.append(j); else wd(j) = 0; } else if ( wt2(j) == part(j) - wt1(j) ) wd(j) = 1; else return false; } if ( ambiguous_positions.empty( ) ) return smallbasis.rowspace_member(wd); vector amb(ambiguous_positions); vector indx( amb.length ), wdx( wd.length ); do { wdx = wd; for ( int k = 0; k < indx.length; k++ ) wdx( amb(k) ) += indx(k); if ( smallbasis.rowspace_member(wdx) ) return true; } while( indx.advance( ) != 0 ); return false; } index_method(subdivide_partition) partition subdivide_partition( const partition& cp, const wordtype& w ) { int i, r = cp.length, k = 0; for ( i = 0; i < cp.length; i++ ) if ( 1 <= w(i) && w(i) < cp(i) ) r++; partition p(r); p.n = cp.n; for ( i = 0; i < cp.length; i++ ) { if ( 1 <= w(i) && w(i) < cp(i) ) { p(k++) = w(i); p(k++) = cp(i) - w(i); } else p(k++) = cp(i); } return p; } TEX(![ This routine and the way it gets invoked is inefficient, but it probably doesn't matter. ]!) index_method(subdivide_word) word subdivide_word( const partition& cp, const wordtype& w, const word& wo ) { partition p = subdivide_partition(cp, w); word w_new = word(p.length); int k = 0; for ( int i = 0; i < cp.length; i++ ) { if ( 1 <= w(i) && w(i) < cp(i) ) w_new(k++) = w_new(k++) = wo(i); else w_new(k++) = wo(i); } return w_new; } index_method(subdivide_matrix) matrix subdivide_matrix( const matrix& m0, const partition& p0, const wordtype& w, bool extra ) { partition p = subdivide_partition( p0, w ); matrix m( m0.nrows + extra, p.length ); for ( int j = 0; j < m0.nrows; j++ ) m(j) = subdivide_word( p0, w, m0(j) ); if (extra) { int k = 0; for ( int i = 0; i < p0.length; i++ ) { m( m.nrows - 1, k++ ) = (w(i) > 0); if ( 1 <= w(i) && w(i) < p0(i) ) m( m.nrows - 1, k++ ) = 0; } m.reduce( ); } return m; } index_method(reduce_wordtype_list) SLList reduce_wordtype_list(const SLList& l1, const config& d) { prevector l2(l1); SLList ans; l2.unique_sort(&String_cmp); int i, j; for ( i = 0; i < l2.length; i++ ) { for ( j = i + 1; j < l2.length; j++ ) if ( equiv( d.part, d.small.basis, wordtype( &d, l2(i) ), wordtype( &d, l2(j) ) ) ) break; if ( i == l2.length - 1 || j == l2.length ) ans.append( l2(i) ); } return ans; } index_method(subdivide) Pix subdivide( const config& c, const wordtype& w ) { time_used_by_subdivide -= time(0); int i, j, k = 0; // Check for bogus subdivision. word mm(c.part.length); for ( i = 0; i < mm.length; i++ ) { if ( w(i) == c.part(i) ) mm(i) = 1; else if ( w(i) != 0 ) break; } if ( i == mm.length && c.small.basis.rowspace_member(mm) ) ERROR( "An attempt has been made to subdivide a configuration " << "along the wordtype corresponding to a small code member." ); config d; d.home = c.home; d.part = subdivide_partition(c.part, w); int r = d.part.length; d.small.basis = subdivide_matrix( c.small.basis, c.part, w, true ); d.dualsmall.basis = subdivide_matrix(c.dualsmall.basis, c.part, w, false); d.leading1s = d.small.basis.leading_ones( ); // Create the new constraints. forPixDef( p, c.assumed_cons ) { constraint q = subdivide_constraint( d, c, w, c.assumed_cons(p) ); d.assumed_cons.append(q); } forPix( p, c.con ) { if ( c.con(p).simple_local_zero( ) ) continue; if ( c.con(p).simple_local( ) && c.con(p).sense == '>' && c.con(p).RHS == 1 && c.con(p).LHS.front( ).var == w.variable( ) ) continue; constraint q = subdivide_constraint( d, c, w, c.con(p) ); d.con.append(q); } TEX( ![ \begin{quote} If the parent configuration has any constraints of the form $v = 0$, where $v$ is a basic local variable, this is communicated to the child configuration. \end{quote} ]! ) SLList must_be_zero; forPix( p, c.con ) { if ( c.con(p).simple_local_zero( ) ) { wordtype wt( &c, c.con(p).LHS.front( ).var ); c.home->activate(true); config_active& a = *(c.home->active); term_sum dead_stuff = subdivide_basic_local_variable( d.part, d.small.basis, a, w, wt, true ); forPixDef( pp, dead_stuff ) must_be_zero.append( dead_stuff(pp).var ); } } SLList mbz = reduce_wordtype_list(must_be_zero, d); forPix( p, mbz ) d.con.append( constraint( mbz(p) + "=0" ) ); d.aut.n = r; d.share = new config_share( *(c.share) ); Pix tttt = c.home->merge_config(d); time_used_by_subdivide += time(0); return tttt; } HIDE( ![ prevector< triple< int, int, prevector< pair > > > sblv_triple_maker(const partition&, const partition&, const wordtype&, wordtype&); ]! ) index_method(subdivide_constraint) constraint subdivide_constraint( const config& d, const config& c, const wordtype& w, constraint con ) { constraint ans( con.sense, con.RHS ); if ( con.global( ) ) return con; c.home->activate(true); config_active& a = *(c.home->active); forPixDef( p, con.LHS ) { String va = con.LHS(p).var; if ( global_var(va) || joint_var(va) ) ans.LHS.append( con.LHS(p) ); else if ( va[0] == 'x' ) { wordtype v( &c, va ); if ( !a.vtable.admissible(v) ) continue; // inadmissible variable term_sum ts = subdivide_basic_local_variable( d.part, d.small.basis, a, w, v, false ); forPixDef( q, ts ) { ts(q).coeff = con.LHS(p).coeff; ans.LHS.append( ts(q) ); } } else if ( va[0] == 's' ) { String subw = va.after("sub"), tail = ""; if ( subw.contains("_") ) { tail = "_" + subw.after("_"); subw = subw.before("_"); } word wd = subdivide_word( c.part, w, word( subw, 0 ) ); subw = "sub" + String(wd) + tail; ans.LHS.append( term( con.LHS(p).coeff, subw ) ); } else if ( va[0] == 'z' || va[0] == 'q' ) { String vax = va; char z_or_q = va[0]; vax[0] = 'x'; vax.gsub( "z", "0" ); wordtype v( &c, vax ); prevector sv; va.del(z_or_q); if ( va[0] == '_' ) sv = unpack( va.after("_"), "_" ); else sv = unpack( va, "" ); wordtype vnew = vector(d.part.length); prevector< triple< int, int, prevector< pair > > > t = sblv_triple_maker( d.part, c.part, v, vnew ); int i, j; vector indx(t.length); while(1) { for ( i = 0; i < t.length; i++ ) { vnew( t(i).first ) = t(i).third(indx(i)).first; vnew( t(i).first + 1 ) = t(i).third(indx(i)).second; } if ( d.small.basis.orthogonal_to(vnew) ) { String newv = z_or_q; j = 0; for ( i = 0; i < c.part.length; i++ ) { if ( 1 <= w(i) && w(i) < c.part(i) ) { if ( sv(i) == "z" ) newv += "_z_z"; else newv += String("_") + dec(int(vnew(j))) + "_" + dec(int(vnew(j + 1))); j += 2; } else { if ( sv(i) == "z" ) newv += "_z"; else newv += String("_") + dec(int(vnew(j))); j++; } } ans.LHS.append( term( con.LHS(p).coeff, newv ) ); } for ( i = t.length - 1; i >= 0; i-- ) if ( indx(i) < t(i).third.length - 1 ) break; if ( i < 0 ) break; for ( j = t.length - 1; j > i; j-- ) indx(j) = 0; ++indx(i); } } } if ( ans.LHS.length( ) > 1000 ) WARNING( "The process of subdivision has lead to a very large " << "constraint -- it has " << ans.LHS.length( ) << " terms." << " It is possible that a string-related abortion will result." ); return ans; } index_method(sblv_triple_maker) prevector< triple< int, int, prevector< pair > > > sblv_triple_maker( const partition& p, const partition& cp, const wordtype& v, wordtype& vnew ) { prevector< triple< int, int, prevector< pair > > > t(p.length - cp.length); int i, j, k = 0, t_ptr = 0; for ( i = 0; i < p.length; i++ ) { if ( p(i) == cp(k) ) vnew(i) = v(k++); // Set the fixed entries. else // Determine range of values for variable entries. { SLList< pair > t_entry; // Note: cp(k) = p(i) + p(i+1). Split v(k). for ( j = 0; j <= v(k); j++ ) { if ( j > p(i) || v(k) - j > p(i+1) ) continue; t_entry.append( make_pair( j, v(k) - j ) ); } t(t_ptr++) = make_triple( i++, k++, prevector< pair >(t_entry) ); } } return t; } TEX(![ \verb|subdivide_basic_local_variable(|% \verb|d.part, d.small.basis, c, w, v, weak)|: Let $c$ be a configuration, and let $w$ be a wordtype for it. Let $d$ be the subdivision of $c$ along $w$, which has dimension $\dim(c) + 1$. Let $v$ be another wordtype for $c$, thought of as a basic local variable. Let {\tt weak} be {\tt true} or {\tt false}. If {\tt weak} = {\tt false}, assume that $v$ is admissible. Then $v$ induces a sum of (generally) admissible basic local variables of $d$. Return this sum. If {\tt weak} = {\tt true}, it is not assumed that $v$ is admissible, and the variables returned in the sum are admissible only in the weak sense that adding an element of the small code yields a basic local variable whose weight is in {\tt rww}, and the dot product with each word in the dual small code is even. Also, only one representative from each equivalence class is returned. Presumably a variant of this routine (with {\tt weak} = {\tt false}) could be used as a tool for computing the {\tt mawhometable} of $d$, and presumably it would be much faster. ]!) index_method(subdivide_basic_local_variable) term_sum subdivide_basic_local_variable( const partition& dpart, const matrix& dsmallbasis, const config_active& a, const wordtype& w, const wordtype& v, bool weak ) { const partition& p = dpart; // silly? TEX( ![ \begin{quote} Each new wordtype will be called {\tt vnew}. Some of its entries are fixed, whereas others will vary in adjacent pairs. The object {\tt t} keeps track of these pairs. \end{quote} ]! ) wordtype vnew2(p.length), vnew(p.length); prevector< triple< int, int, prevector< pair > > > t = sblv_triple_maker( p, a.c->part, v, vnew ); int i, j; vector indx(t.length); wordtype vup = v; for ( i = 0; i < v.length; i++ ) if ( w(i) == a.c->part(i) ) vup(i) = w(i) - v(i); SLList vnew_list; while(1) { // Make vnew. for ( i = 0; i < t.length; i++ ) { vnew( t(i).first ) = t(i).third(indx(i)).first; vnew( t(i).first + 1 ) = t(i).third(indx(i)).second; } TEX(![ \begin{quotea} Is {\tt vnew} admissible? To answer this, add to {\tt vnew} the smallword in $d$ induced by w, and lift back to a wordtype vup of $c$. If vup is admissible (in $c$), then {\tt vnew} is admissible in $d$. For efficiency, it would make sense to only cycle through ``minimal'' {\tt vnew}'s. Perhaps the definition of {\tt minimal} would have to be changed to make this work well. \end{quotea} ]!) for ( i = 0; i < t.length; i++ ) vup( t(i).second ) = p(t(i).first) - vnew(t(i).first) + vnew(t(i).first + 1); if (!weak) { if ( a.vtable.admissible(vup) ) vnew_list.append(vnew); } else { wordtype alttype = vup; for ( i = 0; i < a.c->small.x.nrows; i++ ) { alttype.act( a.c->small.x(i), vup ); if ( !a.rww.contains( sum(alttype) ) ) break; } if ( i == a.c->small.x.nrows ) { if ( a.c->dualsmall.basis.orthogonal_to(vup) ) { forPixDef( aaa, vnew_list ) if ( equiv( dpart, dsmallbasis, vnew_list(aaa), vnew ) ) break; if ( aaa == 0 ) vnew_list.append(vnew); } } } // Advance "indx" so that we will be ready to build the next vnew. for ( i = t.length - 1; i >= 0; i-- ) if ( indx(i) < t(i).third.length - 1 ) break; if ( i < 0 ) break; for ( j = t.length - 1; j > i; j-- ) indx(j) = 0; ++indx(i); } // Build the answer. term_sum ts; forPixDef( pp, vnew_list ) ts.append( term( 1, vnew_list(pp).variable( ) ) ); return ts; } index_method(operator+(config_share, config_share)) config_share* operator+(const config_share& c1, const config_share& c2) { config_share* c = new config_share; HIDE( ![ if ( c1.realizable * c2.realizable == -1 ) INTERNAL_ERROR( "Two configurations are logically equivalent," << " but one is realizable and one is unrealizable." ); ]! ) if ( c1.realizable == 1 || c2.realizable == 1 ) c->realizable = 1; else if ( c1.realizable == -1 || c2.realizable == -1 ) c->realizable = -1; else c->realizable = 0; c->ww = intersection( c1.ww, c2.ww); c->dual_min_low = max( c1.dual_min_low, c2.dual_min_low ); c->dual_min_high = min( c1.dual_min_high, c2.dual_min_high ); c->ycon.merge(c1.ycon); c->ycon.merge(c2.ycon); return c; } TEX( ![ \verb|x_to_v|: convert an {\tt x} variable to a {\tt v} variable, returning the number of the {\tt v} variable, or $0$ if it is not admissible. The code overlaps with {\tt mawhometable::find}. ]! ) index_method(x_to_v) int config_active::x_to_v(const String& xvar) const { wordtype w(c, xvar); c->make_minimal(w); for ( int i = 0; i < vtable.length; i++ ) if ( w == vtable(i).maw ) return i + 1; return 0; } TEX( ![ If the {\tt weak} option is chosen, the {\tt w} member of the mawhome entries will not be computed. Also \verb|y_as_vsum| will not be computed. Use with caution! ]! ) index_method(config_active constructor) config_active::config_active(config* c, bool quiet, bool weak) : c(c), bound(c->part.length), dual_bound(c->part.length), file_status(0) { int i, j; c->small.build( ); c->dualsmall.build( ); c->home->joint_vars.unique_sort( &String_cmp ); weightlist& w = c->share->ww; TEX(![ \begin{quote} Build \verb|global_bound|. \end{quote} ]!) int n = c->home->n; Integer low, high; global_bound.set_size(n + 1); global_bound(0) = make_pair(Integer(1), Integer(1)); for ( i = 1; i <= n; i++ ) global_bound(i) = make_pair(Integer(0), Integer(0)); forPixDef( p, w ) { if ( w(p) == 0 ) continue; low = 0; high = -1; c->evaluate( String("y") + dec(w(p)), low, high ); global_bound( w(p) ) = make_pair( low, high ); } TEX(![ \begin{quote} Build {\tt rww}, the restricted working weightlist. \end{quote} ]!) small_we = c->smallcode_we( ); forPix( p, w ) { if ( w(p) == 0 ) continue; low = global_bound( w(p) ).first; high = global_bound( w(p) ).second; if ( high == -1 || high > small_we( w(p) ) ) rww.add( w(p) ); else if ( high < small_we( w(p) ) ) ERROR( "For the current configuration, the constraint y" << w(p) << " <= " << high << " is known," << " but the number of words of weight " << w(p) << " in the basic code associated to the small code is " << small_we( w(p) ) << ". Therefore the configuration is " << "unrealizable. You should probably use " << "\"via lp [current] = ;\"." ); } // Set up dualsmall_working. SLList< vector > dsmw_temp; for ( i = 0; i < c->dualsmall.basis.nrows; i++ ) dsmw_temp.append( c->dualsmall.basis(i) ); if ( w.divisible(2) ) { vector v(c->part.length); for ( i = 0; i < c->part.length; i++ ) v(i) = 1; dsmw_temp.append(v); if ( w.divisible(4) ) for ( i = 0; i < c->small.basis.nrows; i++ ) dsmw_temp.append( c->small.basis(i) ); } if ( c->home->opt.doubly_even_part_is_subcode || ( w.divisible(2) && c->known( "div4=" + String(dec(Ipow(2, c->home->dim - 2))) ) ) ) { for ( i = 0; i < c->small.basis.nrows; i++ ) { if ( (c->small.basis(i) * c->part) % 4 == 0 ) dsmw_temp.append( c->small.basis(i) ); } } // Now convert dsmw_temp to dualsmall_working. matrix dsmw2(c->part.length, dsmw_temp); dsmw2.reduce_nz( ); dualsmall_working.basis = dsmw2; dualsmall_working.build( ); // Set up dual_leading1s. dual_leading1s = dualsmall_working.basis.leading_ones( ); for ( i = 0; i < c->part.length; i++ ) bound(i) = dual_bound(i) = c->part(i); for ( i = 0; i < c->small.basis.nrows; i++ ) bound(c->leading1s(i)) /= 2; for ( i = 0; i < dualsmall_working.basis.nrows; i++ ) dual_bound(dual_leading1s(i)) /= 2; TEX(![ \begin{quote} We build the table of mawhomes, by cycling through all wordtypes, testing each for admissibility and minimality. \end{quote} ]!) ofstream var_def( "calculations/variable_definitions" ); SLList vtable0; wordtype wu(c), alt(c); int vcount = 1; if (!weak) { wordtype types[c->small.x.nrows]; do { mawhome m; m.maw = wu; int wordcount = 0; for ( i = 0; i < c->small.x.nrows; i++ ) { alt.act( c->small.x(i), wu ); for ( j = 0; j < wordcount; j++ ) if ( types[j] == alt ) break; if ( j == wordcount ) { types[wordcount++] = alt; m.w.append( c->small.x(i) ); } } if (show_variables) cerr << "v" << vcount++ << " = " << wu.variable( ) << "\n"; vtable0.append(m); } while( wu.advance(this) != 0 ); } else { do { mawhome m; m.maw = wu; if (show_variables) cerr << "v" << vcount++ << " = " << wu.variable( ) << "\n"; vtable0.append(m); } while( wu.advance(this) != 0 ); } vtable = mawhometable(vtable0); for ( i = 0; i < vtable.length; i++ ) var_def << "v" << i + 1 << " = " << vtable(i).maw.variable( ) << "\n"; var_def.close( ); TEX( ![ \begin{quote} Compute \verb|y_as_vsum|, which expresses each \verb|y_i| as a sum of \verb|v|'s. Note that this must be recomputed if \verb|c->share->ww| is changed. \end{quote} ]! ) if (!weak) { int count, wt_no = 0; y_as_vsum.set_size( w.length( ) ); forPix( p, w ) { for ( i = 0; i < vtable.length; i++ ) { count = 0; SLList& words = vtable(i).w; forPixDef( q, words ) { alt.act( words(q), vtable(i).maw ); if ( sum(alt) == w(p) ) count++; } y_as_vsum(wt_no).append( term(count, String("v") + (i+1) )); } wt_no++; } } } TEX( \verb|make_minimal(w)|: make a given wordtype {\tt w} minimal. ) index_method(make_minimal) void config::make_minimal(wordtype& w) const { static vector border_rows; border_rows.set_size(small.basis.nrows); int border_count = 0, diff, i, col; for ( i = 0; i < leading1s.length; i++ ) { col = leading1s(i); diff = 2 * w(col) - part(col); if ( diff > 0 ) w.act(small.basis(i)); else if ( diff == 0 ) border_rows(border_count++) = i; } if ( border_count == 0 ) return; TEX(![ \begin{quote} Now we have to deal with the borderline cases, where $2 * $\verb|w(i)| = \verb|part(i)| for some \verb|i|. Form the subcode of the small code generated by the ``borderline rows'' of the associated matrix. One by one let these act on \verb|w|, to see if it can be made smaller. This method can no doubt be much improved. \end{quote} ]!) vector indx(border_count); wordtype v(w), best(w); do { v = w; for ( int j = 0; j < border_count; j++ ) if ( indx(j) ) v.act( small.basis(border_rows(j))); if ( v < best ) best = v; } while ( indx.advance( ) != 0 ); w = best; } TEX( The following routine determines the equivalence relation on the admissible basic local variables induced by the known automorphisms of the configuration. ) index_method(auto_equiv) EquivRelIntList config_active::auto_equiv( ) const { EquivRelIntList e(vtable.length); wordtype w(c); for ( int i = 0; i < c->aut.length; i++ ) for ( int j = 0; j < vtable.length; j++ ) { w = vtable(j).maw; c->aut(i).act(w); int k = vtable.mfind(w); if ( k == -1 ) ERROR("The admissible basic local variable " << vtable(j).maw.variable( ) << " is carried by the automorphism\n" << c->aut(i) << "\nto the inadmissible basic local" << " variable " << w.variable( ) << ". The current " << "version of the language is not smart enough to " << "handle this. You can work around the problem " << "by using the \"reduce variable set\" command."); e.join(j, k); } return e; } qvconstraint::qvconstraint(const constraint& con, codehome* home) : sense( con.sense ), RHS( con.RHS ) { home->active->expand_term_sum( con.LHS, LHS ); } set_include_file(homedefs.h) HIDE( ![ #include "basedefs.h" class config; class config_active; class config_share; class codebase; class codehome; class codetable; #include "share.h" #include "multiedge.h" #include "vconstraint.h" #include "code.h" #include "partition.h" #include "wordtype.h" #include "weightlist.h" #include "config.h" #include "codehome.h" ]! ) set_compile_file(code.c) TEX(![ \block{Linear programming methods} We describe the structure of the {\it constraint file}. This is modelled roughly on the ``LP format'' of CPLEX. In particular, we impose various quirky conditions because they are imposed by CPLEX; other conditions are imposed for our convenience. We have already described the syntax of constraints, but their use here is slightly more restrictive. A variable name ({\it var}) starts with a letter, may include letters, numbers, and underscores, and has at most $16$ characters in it. Let {\it int\/} denote any integer, {\it pos\/} any positive integer. A {\it constraint\/} has the form {\it [{\tt-}]pos var $\pm \cdots \pm$ pos var op int\/}, where {\it [{\tt-}]\/} denotes an optional minus sign and {\it op\/} is one of {\tt =}, {\tt >=}, or {\tt <=}. White space may appear anywhere, except within a {\tt var}, within a sequence of digits, within {\tt >=}, or within {\tt <=}. A newline may not occur between {\it op\/} and {\it int}. At most $255$ characters may occur between newlines. A {\it constraint file\/} is a file which starts with the single line ``maximize 0 subject to'' and which is followed by zero or more constraints, each beginning on a new line. CPLEX prefers that the last line of the file is ``{\tt end}'', but we do not follow this convention. ]! ) set_compile_file(process.cc) HIDE( ![ extern char* PATH_PREFIX; #include "homedefs.h" #include void eat_constraint(istream&); extern int homebrew, use_quad, warnings_are_fatal; extern String homebrew_status; pair lp_crunch(const prevector&, int, int, const vconstraint&, bool = false); void add_to_rational_constraint(qvconstraint&, const vconstraint&, Rational&); int take_int(String&, const Regex&); void parse_j_var(String, int&, int&, int&); ]! ) index_class(int_item) class int_item { public: union { char c[sizeof(int)]; int x; }; friend istream& operator>>(istream& s, int_item& l) { for ( int i = 0; i < sizeof(int); i++ ) s.get( l.c[i] ); return s; } }; index_class(double_item) class double_item { public: union { char c[sizeof(double)]; double x; }; friend istream& operator>>(istream& s, double_item& l) { for ( int i = 0; i < sizeof(double); i++ ) s.get( l.c[i] ); return s; } }; index_method(skip_record) void skip_record( istream& s ) { int_item l_start, l_stop; s >> l_start; for ( int i = 0; i < l_start.x; i++ ) s.get( ); s >> l_stop; if ( !s || l_start.x != l_stop.x ) INTERNAL_ERROR( "error reading CPLEX record" ); } TEX(![ \par\noindent\verb|process_cplex_report( |{\it report file}\verb|, |% {\it status indicator}\verb| )|:\ The report file is supposed to have been generated with the CPLEX write command, e.g.\ \verb|w solution.bin|. First determine the status, $1$ for feasible, $0$ for infeasible. Then determine the dual activity for each constraint, which is a double precision number. This dual activity is rounded to a rational, and put into a list, which is returned to the caller. Remove the report file when done. This routine is perilously dependent on the exact structure of the CPLEX report file. Any deviance will cause this routine to produce an error and exit. It is conceivable that a different version of CPLEX or an implementation of the same version on another machine could produce slightly different report files. In that case, this routine would have to be appropriately modified. ]!) index_method(process_cplex_report) SLList process_cplex_report( String report_file, int& status ) { ifstream report( report_file ); if (!report) ERROR( "The CPLEX report file \"" << report_file << "\" was not written. It is " << "possible that CPLEX ran out of memory. (If so, try increasing " << "swap space.) If you look at the file cplex_output, you will " << "probably be able to figure out what happened." ); int i; int_item l; for ( i = 0; i < 4; i++ ) // skip 4 records skip_record(report); // extract status from solution record for ( i = 0; i < 112 + sizeof(int); i++ ) report.get( ); char status_string[4]; for ( i = 0; i < 4; i++ ) report.get( status_string[i] ); for ( i = 0; i < 84 + sizeof(int); i++ ) report.get( ); for ( i = 0; i < 5; i++ ) // skip 5 records skip_record(report); double_item d[8]; SLList dual_activity_rational; while(1) BHIDE2( ![ if (!report) INTERNAL_ERROR( "error reading CPLEX row records" ); ]!, ![ report >> l; // read length ]! ) for ( i = 0; i < 8; i++ ) report >> d[i]; if ( String(d[0].c).contains("$ENDSEC$", 0) ) break; dual_activity_rational.append(d[4].x); report >> l; } if ( status_string[0] == 'N' && status_string[1] == 'F' ) status = 0; else status = 1; report.close( ); remove( report_file ); return dual_activity_rational; } bool infeasible_core(const prevector&, bool, const vconstraint&); TEX(![ \verb|infeasible(codehome)|:\ Use CPLEX to determine if the system given by the constraint files \verb|cplex_in| and \verb|cplex_in2| (built if need be) is infeasible. Return true if we know (with certainty) that the system is infeasible. Otherwise, return false. However, if CPLEX reports infeasible, but it can't be verified, issue an error. ]!) index_method(infeasible) bool infeasible( codehome& home, codetable& results, bool quiet ) { home.activate(quiet); bool use_homebrew = home.active->split(quiet, results, constraintlist( )); prevector files(2); files(0) = "cplex_in"; files(1) = "cplex_in2"; vconstraint tot(home.active->vtable.length); tot.sense = '='; tot.RHS = Ipow( 2, home.dim ); for ( int i = 0; i < tot.LHS.length; i++ ) tot.LHS(i) = home.active->vtable(i).w.length( ); bool use_quadx = use_quad || choose(home.n, home.dim) > atoI("3000000000000000000"); lp_crunch( files, use_homebrew, use_quadx, tot ); return infeasible_core( files, use_homebrew, tot ); } index_method(joint_infeasible) bool joint_infeasible( codehome& home, codetable& results, constraintlist forced ) { home.generate_joint_constraints(results, forced); prevector vars = home.basic_joint_vars(results); int nvars = vars.length; prevector files(1); files(0) = "joint_in"; vconstraint tot(nvars); tot.sense = '='; tot.RHS = Ipow( 2, 2 * home.dim ); for ( int i = 0; i < nvars; i++ ) { int r, s, t; parse_j_var( vars(i), r, s, t ); if ( r != s && r != t && s != t ) tot.LHS(i) = 6; else if ( r == s && s == t ) tot.LHS(i) = 1; else tot.LHS(i) = 3; } lp_crunch( files, homebrew, use_quad, tot ); return infeasible_core( files, homebrew, tot ); } index_method(infeasible_core) bool infeasible_core( const prevector& files, bool use_homebrew, const vconstraint& tot ) { int nvars = tot.LHS.length; if ( use_homebrew ) { if ( homebrew_status == "infeasible" ) return true; if ( homebrew_status == "confused" ) WARNING("Homebrew calculation failed."); return false; } int status; SLList dual_activity = process_cplex_report( "calculations/cplex.bin", status ); if ( status != 0 ) return false; // system appears to be feasible TEX(![ \begin{quote} Multiply each constraint (from \verb|cplex_in| and \verb|cplex_in2|) by the corresponding dual activity. Add it up, to get a ![$<=$]! inequality. \end{quote} ]!) ifstream conf("calculations/" + files(0)); char c; for ( int j = 1; j <= 2; j++ ) // skip over "maximize 0 subject to" { do { conf.get(c); } while ( c != '\n' ); } qvconstraint qv(nvars); vconstraint vcx(nvars); qv.RHS = 0; Pix d = dual_activity.first( ); bool first_file = true; while(1) { if ( conf.peek( ) == EOF ) { if (first_file) { first_file = false; conf.close( ); if ( files.length == 1 ) break; conf.open("calculations/" + files(1)); if ( conf.peek( ) == EOF ) break; } else break; } HIDE( ![ if ( d == 0 ) INTERNAL_ERROR("infeasible: not enough dual activity numbers"); ]! ) // If dual activity is nonzero, read a constraint, multiply by // dual activity, and add to sum. Otherwise, skip over constraint. if ( sign(dual_activity(d)) != 0 ) { conf >> vcx; add_to_rational_constraint( qv, vcx, dual_activity(d) ); } else eat_constraint(conf); dual_activity.next(d); } HIDE( ![ if (d != 0) INTERNAL_ERROR("infeasible: too many dual activity numbers"); ]! ) conf.close( ); TEX(![ \begin{quote} Now decide if there's a contradiction. The idea is that if $k$ is the dimension of the code, and we write $(*):$ $2^k = \sum_i a_i v_i$ $(a_i > 0$), then if the summed constraint is feasible, there will be a point where the constraint holds, with all but one of the $v$'s zero, and the remaining $v$ equal to whatever makes $(*)$ work. \end{quote} ]!) if ( sign(qv.RHS) >= 0 ) ERROR("CPLEX's infeasibility claim was not verified"); for ( int i = 0; i < nvars; i++ ) if ( qv.LHS(i) < 0 ) { if ( qv.LHS(i) * Rational(tot.RHS) <= Rational(tot.LHS(i)) * qv.RHS ) { WARNING("CPLEX claim of infeasibility was not verified"); return false; } } return true; } set_include_file(opt.h) index_class(opt_card) class opt_card { public: term_sum var; // what is to be minimized or maximized String request; // can be "min", "max", "minmax" double min; // computed minimum double max; // computed maximum opt_card( const term_sum& var, const String& request ) : var(var), request(request) { } opt_card( ) { } HIDE( ![ friend ostream& operator<<(ostream&, const opt_card&); ]! ) }; index_method(add) index_class(opt_table) class opt_table { public: codehome* home; bool feasible; SLList data; opt_table( codehome* home ) : home(home) { } void compute( codetable&, bool joint = false ); void add( const term_sum& var, const String& request = String("minmax") ) { data.append( opt_card( var, request ) ); } }; set_compile_file(opt.cc) HIDE(![ #include "homedefs.h" #include "simplex.h" extern int homebrew, use_quad; extern int vars, create_con_file_only; extern char* PATH_PREFIX; extern "C" int srandom(unsigned); #ifndef NeXT extern "C" double floor(double); #endif #include "opt.h" pair lp_crunch(const prevector&, int, int, const vconstraint&, bool = false); void joint_to_qv(constraint, qvconstraint&, const prevector&, codehome&, Integer ***); Integer*** make_krawtchouk(int); ]!) index_method(intish_double_to_String) String intish_double_to_String( double x ) { String sign; if ( x < 0 ) { sign = "-"; x = -x; } Integer int_part = floor(Rational(x)); String ans = dec(int_part); double tail = x - int_part.as_double( ); int itail = (int) floor(10000 * tail); if ( itail == 0 && ans == "0" ) return ans; if ( itail == 0 ) return sign + ans; if ( itail == 9999 ) return sign + dec( int_part + 1 ); if ( itail > 999 ) return sign + ans + "." + dec(itail); if ( itail > 99 ) return sign + ans + ".0" + dec(itail); if ( itail > 9 ) return sign + ans + ".00" + dec(itail); return sign + ans + ".000" + dec(itail); } ostream& operator<<(ostream& s, const opt_card& o) { if ( o.request == "minmax" ) { String low = intish_double_to_String(o.min); String high = intish_double_to_String(o.max); if ( low == high ) return s << o.var << " = " << low << "\n"; if ( low == "0" ) return s << o.var << " <= " << high << "\n"; return s << low << " <= " << o.var << " <= " << high << "\n"; } if ( o.request == "min" ) cerr << intish_double_to_String(o.min) << " <= "; s << o.var; if ( o.request == "max" ) s << " <= " << intish_double_to_String(o.max); if ( o.max >= 0 && o.min >= 0 && o.max < 0.99999 * o.min ) s << " (doesn't look reliable)"; return s << "\n"; } index_method(compute) void opt_table::compute( codetable& results, bool joint ) { if ( home->ww(home->current).length( ) == 1 && home->dim < home->n ) { feasible = false; return; } remove( "calculations/homebrew.log" ); int homebrew_saved = homebrew; if (choose(home->n, home->dim) > atoI("3000000000000000000")) homebrew = 1; prevector jvars; Integer*** combo; if (joint) { homebrew = 0; jvars = home->basic_joint_vars(results); home->generate_joint_constraints(results); combo = make_krawtchouk(home->n); } if (homebrew) { home->deactivate( ); home->activate(true); create_con_file_only = 1; bool use_homebrew = home->active->split(false, results, constraintlist( ), false); prevector files(2); files(0) = "cplex_in"; files(1) = "cplex_in2"; vconstraint tot(home->active->vtable.length); tot.sense = '='; tot.RHS = Ipow( 2, home->dim ); for ( int ii = 0; ii < tot.LHS.length; ii++ ) tot.LHS(ii) = home->active->vtable(ii).w.length( ); bool use_quadx = use_quad || choose(home->n, home->dim) > atoI("3000000000000000000"); pair rep = lp_crunch( files, use_homebrew, use_quadx, tot ); int total_constraints = rep.first; int eq_constraints = rep.second; create_con_file_only = 0; ifstream homebrew_in( "calculations/homebrew_in" ); int precision; if ( use_quad || choose( home->n, home->dim ) > atoI("3000000000000000000") ) precision = 16; else precision = 8; int n = vars, m = total_constraints, m_eq = eq_constraints; srandom(1); bool confused; int ii; constraint cc( '=', 0 ); // sense and RHS are dummies if ( precision == 8 ) { canonical_lp_problem prob(m, n + m - m_eq); prob.slacks = m - m_eq; homebrew_in >> prob; homebrew_in.seekg(0, ios::beg); vector cost(n), improve; extend obj; forPixDef( i, data ) { cc.LHS = data(i).var; qvconstraint qv( cc, home ); for ( ii = 0; ii < qv.LHS.length; ii++ ) assign( prob.c(ii), qv.LHS(ii) ); if ( data(i).request != "max" ) { obj = prob.simple_simplex( cost, improve, confused, false ); if (confused) ERROR( "Simplex calculation failed. " << "Retry using quad precision." ); if ( obj.PlusInfinity( ) ) { feasible = false; homebrew = homebrew_saved; home->deactivate( ); return; } assign( data(i).min, double(obj) ); if ( data(i).request != "min" ) { for ( ii = 0; ii < prob.c.length; ii++ ) prob.c(ii) = -prob.c(ii); obj = prob.simple_simplex( cost, improve, confused, false ); if (confused) ERROR( "Simplex calculation failed. " << "Retry using quad precision." ); if ( obj.PlusInfinity( ) ) { feasible = false; homebrew = homebrew_saved; home->deactivate( ); return; } assign( data(i).max, -double(obj) ); } } } } if ( precision == 16 ) { canonical_lp_problem prob(m, n + m - m_eq); prob.slacks = m - m_eq; homebrew_in >> prob; homebrew_in.seekg(0, ios::beg); vector cost(n), improve; extend obj; forPixDef( i, data ) { cc.LHS = data(i).var; qvconstraint qv( cc, home ); for ( ii = 0; ii < qv.LHS.length; ii++ ) assign( prob.c(ii), qv.LHS(ii) ); if ( data(i).request != "max" ) { obj = prob.simple_simplex( cost, improve, confused, false ); if (confused) ERROR( "Simplex calculation failed. " << "Higher precision floating point arithmetic " << "would help, but it isn't installed in Split " << "yet. Sorry." ); if ( obj.PlusInfinity( ) ) { feasible = false; homebrew = homebrew_saved; home->deactivate( ); return; } assign( data(i).min, Quad(obj) ); if ( data(i).request != "min" ) { for ( ii = 0; ii < prob.c.length; ii++ ) prob.c(ii) = -prob.c(ii); obj = prob.simple_simplex( cost, improve, confused, false ); if (confused) ERROR( "Simplex calculation failed. " << "Higher precision floating point arithmetic " << "would help, but it isn't installed in Split " << "yet. Sorry." ); if ( obj.PlusInfinity( ) ) { feasible = false; homebrew = homebrew_saved; home->deactivate( ); return; } assign( data(i).max, -Quad(obj) ); } } } } homebrew = homebrew_saved; feasible = true; home->deactivate( ); return; } ofstream command_file("calculations/cplex_commands0"); command_file << "set logfile *\n"; if ( CPLEX_VERSION[0] <= '2' ) { command_file << "set presolve n\n"; command_file << "set aggregate n\n"; } else { command_file << "set preprocessing presolve n\n"; command_file << "set preprocessing aggregator n\n"; } SLList multipliers; int j; forPixDef( i, data ) { // Convert the term_sum to be optimized to a linear combination of v // variables, with rational coefficients. Clear the denominators by // multiplying through by a number "multiplier". We'll have to // divide by this later. constraint cc( '=', 0 ); // sense and RHS are dummies cc.LHS = data(i).var; vconstraint vc(joint ? jvars.length : home->active->vtable.length); Rational multiplier; qvconstraint qv; if (!joint) qv = qvconstraint( cc, home ); else joint_to_qv( cc, qv, jvars, *home, combo ); multiplier = clear_denom( qv, vc ); multipliers.append(multiplier); if ( multiplier == 0 ) // we're trying to optimize 0 { // Issue a warning of sorts. We could bypass optimization but // it would complicate the flow of the routine. cerr << "The expression " << data(i).var << " is identically " << "zero, but I'll optimize it anyway.\n"; } // Turn off CPLEX's echoing of "change coeff..." commands. The // double newline is needed to prevent the next command from being // gobbled up. command_file << "set output results n\n\n"; for ( j = 0; j < vc.LHS.length; j++ ) command_file << "change coeff obj v" << j + 1 << " " << vc.LHS(j) << "\n"; command_file << "set output results y\n\n"; // Load optimization instructions. if ( data(i).request != "max" ) command_file << "change sense obj min\n" << "opt\n"; if ( data(i).request == "max" || data(i).request == "minmax" ) command_file << "change sense obj max\n" << "opt\n"; } command_file.close( ); bool use_homebrew; prevector files; if (!joint) { use_homebrew = home->active->split(false, results, constraintlist( ), true); if (use_homebrew) INTERNAL_ERROR("compute - homebrew"); files.set_size(2); files(0) = "cplex_in"; files(1) = "cplex_in2"; vconstraint tot(home->active->vtable.length); tot.sense = '='; tot.RHS = Ipow( 2, home->dim ); for ( int ii = 0; ii < tot.LHS.length; ii++ ) tot.LHS(ii) = home->active->vtable(ii).w.length( ); bool use_quadx = use_quad || choose(home->n, home->dim) > atoI("3000000000000000000"); lp_crunch( files, use_homebrew, use_quadx, tot, true ); remove("calculations/cplex_in2"); } else { files.set_size(1); files(0) = "joint_in"; if ( CPLEX_VERSION[0] <= '2' ) system(String("echo set sizes nonzeros 2000000 5000 > ") + "calculations/cplex_commands"); else { system(String("echo set read nonzeros 2000000 100000 > ") + "calculations/cplex_commands"); system(String("echo set read constraints 20000 1000 >> ") + "calculations/cplex_commands"); } system( String("echo r ") + PATH_PREFIX + "calculations/joint_in lp >> calculations/cplex_commands" ); system(String("cat calculations/cplex_commands0 >> ") + "calculations/cplex_commands"); remove("calculations/cplex_commands0"); remove("cplex.log"); system( String(CPLEX) + " < calculations/cplex_commands > calculations/cplex_output" ); } ifstream infile ("calculations/cplex_output"); double optimum; String infile_piece; Pix mpix = multipliers.first( ); forPix( i, data ) { for ( j = 1; j <= 2; j++ ) { while(1) { infile >> infile_piece; if (!infile) goto error_exit; if ( infile_piece == "infeasible," || infile_piece == "Infeasible:" ) goto infeasible_exit; if ( infile_piece == "Optimal:" ) { infile >> infile_piece; if ( infile_piece != "Objective" ) goto error_exit; infile >> infile_piece; if ( infile_piece != "=" ) goto error_exit; infile >> optimum; break; } } if ( j == 2 ) { if ( multipliers(mpix) != 0 ) data(i).max = optimum/multipliers(mpix); else data(i).max = 0; break; } if ( data(i).request == "min" || data(i).request == "minmax" ) { if ( multipliers(mpix) != 0 ) data(i).min = optimum/multipliers(mpix); else data(i).min = 0; if ( data(i).request == "min" ) break; } if ( data(i).request == "max" ) { if ( multipliers(mpix) != 0 ) data(i).max = optimum/multipliers(mpix); else data(i).max = 0; break; } } multipliers.next(mpix); } infile.close( ); feasible = true; return; infeasible_exit: if ( i == data.first( ) ) { feasible = false; return; } ERROR("The optimization status has changed from feasible to" << " infeasible. The explanation for this is presumably" << " that the problem is numerically unstable. Under the" << " current version, there is nothing that can be done" << " about this. Try looking at codes which have smaller" << " length and/or dimension."); error_exit: ERROR( "opt_table::compute got confused while" << " scanning output of CPLEX. This could conceivably be an " << "\"internal error\", but other causes are more likely. For " << "example, CPLEX could have run out of memory. (Check the file " << "\"calculations/cplex_output\" for confirmation. Consider using " << "the homebrew option.) Interrupting " << "a process can also result in this error message." ); } TEX(![ \block{The split linear programming routine} The procedure {\tt split} temporarily has two modes, depending on whether {\tt homebrew} is set. If {\tt homebrew} is not set, we proceed as follows. If \verb|file_status| $= 0$, the procedure \verb|split| first builds the file \verb|cplex_in|, which contains the main constraints coming from the split linear programming method. If \verb|file_status| $ = 1$, it will be assumed that the file \verb|cplex_in| is already built and current. The construction of \verb|cplex_in| can be very time-consuming. Next the procedure prepares a file \verb|cplex_commands|. This file tells CPLEX to read the file \verb|cplex_in|, and it also tells it to add all auxiliary constraints, which are placed in the file \verb|cplex_in2|. The file \verb|cplex_commands0| (which should exist prior to calling \verb|split|) is then appended to \verb|cplex_commands|. Then CPLEX is invoked from the file \verb|cplex_commands|. Output is written to the file \verb|cplex_output|. If {\tt homebrew} is set, the behavior is different, primarily because the built-in simplex solver is used in place of CPLEX. But there is another fundamental difference, namely that we will always try to show that the system is infeasible. The outcome of this attempt is reported via the global variable \verb|homebrew_status|, which is set to {\tt infeasible} if the system has been proved infeasible, {\tt feasible} if the system {\it appears\/} to be feasible, and {\tt confused} if the simplex calculation terminated abnormally. There is no provision yet for multiple objective functions as would be appropriate e.g.\ if one were simultaneously trying to prove several inequalities. ]! ) set_compile_file(split.cc) HIDE( ![ extern char* PATH_PREFIX; #include "homedefs.h" #include #include #include extern int sort_flag; extern long time_used_by_CPLEX; extern long time_used_generating_Krawtchouk_table; extern long time_used_generating_constraints; extern int homebrew, use_quad, dual_constraint_bound; extern int smart_dual, silent, dcb_depth_limit, auto_projection; extern int vars, total_constraints, eq_constraints, create_con_file_only; extern String homebrew_status; Integer choose(int, int); extern "C" int srandom(unsigned); #include "simplex.h" #include "bitvec.h" #include "codetable.h" ]! ) TEX( ![ \verb|convert_dual_variable|:\ Given $w \in \F_2^r$ and a multi-index $J = \verb|dualw|$, let $D$ be the subcode of $C$ supported on $w$. Compute $\abs{D} \cdot \abs{\setofh{$J$-words in $D^\perp$}}$, by expressing it as a $\Z$-linear combination of basic local variables, with coefficients given in the vector {\tt vi}. Upon entry {\tt binom} should be an array of binomial coefficients. Compare with the implementation of {\tt split}. ]! ) index_method(convert_dual_variable) void config_active::convert_dual_variable( const word& w, const wordtype& dualw, Integer** binom, vector& vi ) const { int i, j, k, a, r, jj, sumx, n = c->home->n; word w_comp = w.complement( ); bool all_ones = w_comp.if_zero( ); Pix p; vi.set_size(vtable.length); Integer coeff, S; for ( j = 0; j < vtable.length; j++ ) { wordtype& v = vtable(j).maw; sumx = 0; forPix( p, vtable(j).w ) { if (!all_ones) { wordtype alt = v; alt.act( vtable(j).w(p) ); if ( w_comp * alt != 0 ) continue; } if ( even( vtable(j).w(p) * dualw ) ) sumx++; else sumx--; } if ( sumx != 0 ) { coeff = 1; for ( k = 0; k < c->part.length; k++ ) { S = 0; r = dualw(k); i = c->part(k) - v(k); jj = v(k); TEX(![ \begin{quotec} We compute the coefficient of $x^r$ in $(1+x)^i (1-x)^j$, according to the formula $\displaystyle{\sum_{a = \max(0,r-j)}^{\min(r,i)} {i \choose a} {j \choose r-a} (-1)^{r-a}}$. \end{quotec} ]!) for ( a = max(0,r-jj); a <= min(r,i); a++ ) { if ( even(r-a) ) S += binom[i][a] * binom[jj][r-a]; else S -= binom[i][a] * binom[jj][r-a]; } coeff *= S; } coeff *= sumx; vi(j) = coeff; } else vi(j) = 0; } } index_method(make_krawtchouk) Integer*** make_krawtchouk( int mp ) { Integer ***combo = new Integer**[mp+1]; int i, j, k; for ( k = 0; k <= mp; k++ ) { combo[k] = new Integer*[mp+1]; for ( i = (k+1)/2; i <= mp; i++ ) combo[k][i] = new Integer[ min(i, mp-i) + 1 ]; } for( i = 0; i <= mp; i++ ) { combo[0][i][0] = combo[i][i][0] = 1; for( k = 1; k <= i-1; k++ ) combo[k][i][0] = combo[k-1][i-1][0] + combo[k][i-1][0]; for( j = 1; j <= min(i, mp - i); j++ ) { combo[0][i][j] = 1; for( k = 1; k <= i+j-1; k++ ) combo[k][i][j] = combo[k][i][j-1] - combo[k-1][i][j-1]; combo[i+j][i][j] = -combo[i+j-1][i][j-1]; } } return combo; } index_method(delete_krawtchouk) void delete_krawtchouk( Integer ***combo, int mp ) { int i, k; for ( k = 0; k <= mp; k++ ) for ( i = (k+1)/2; i <= mp; i++ ) delete [ ] combo[k][i]; for ( k = 0; k <= mp; k++ ) delete [ ] combo[k]; delete [ ] combo; } // Return true if using homebrew. index_method(split) bool config_active::split(bool quiet, codetable& results, constraintlist forced, bool use_cplex) { int homebrew_saved = homebrew; if ( !use_cplex && choose( c->home->n, c->home->dim ) > atoI("3000000000000000000") ) homebrew = 1; // Test to see if the first line of cplex_in is "maximize 0". if ( file_status == 1 ) { ifstream cpin( "calculations/cplex_in" ); if ( cpin.peek( ) == 'm' ) file_status = !homebrew; cpin.close( ); } if ( file_status == 1 ) { time_used_generating_constraints -= time(0); goto build_cplex_in2; } remove( "calculations/cplex_in" ); { int i, j, k, l, n = c->home->n; Pix p, q; TEX(![ \begin{quote} We will need to know the coefficient of $x^k$ in $(1+x)^i (1-x)^j$, for many triples $(k,i,j)$. Sometimes it is better to build a complete table in advance, and sometimes it is better to compute the coefficients one by one as needed, building only a table of binomial coefficients in advance. We have not yet thought carefully about how this choice should be made. In general, how to proceed should depend on the partition of $n$ belonging to the current partition. Let $mp$ be the maximum size of a part in the partition of the current configuration. For the time being, we build the complete table whenever $mp < 60$, building an array {\tt combo} whose $\hbox{\tt [k][i][j]}^{\operatoratfont th}$ entry is the coefficient of $x^k$ in $(1+x)^i (1-x)^j$, for $0 \leq j \leq i$ and $0 \leq k \leq i+j \leq mp$. \end{quote} ]!) Integer ***combo, **binom; number mp = c->part(0); for ( i = 1; i < c->part.length; i++ ) mp = max( mp, c->part(i) ); bool complete_table = (mp < 60); if (complete_table) { time_used_generating_Krawtchouk_table -= time(0); combo = make_krawtchouk(mp); time_used_generating_Krawtchouk_table += time(0); } else { binom = new Integer*[n+1]; for ( i = 0; i <= n; i++ ) { binom[i] = new Integer[i+1]; binom[i][0] = 1; for ( j = 1; j < i; j++ ) binom[i][j] = binom[i-1][j] + binom[i-1][j-1]; binom[i][i] = 1; } } TEX( \begin{quote} Now generate the main constraints. \end{quote} ) time_used_generating_constraints -= time(0); ofstream cplexin1( "calculations/cplex_in" ); if (!homebrew) cplexin1 << "maximize 0\nsubject to\n"; cplexin1.close( ); String pipe_command; if (sort_flag) { if (!homebrew) pipe_command = "sort -u | fold -s >> calculations/cplex_in"; else pipe_command = "sort -u >> calculations/cplex_in"; } else { if (!homebrew) pipe_command = "fold -s - >> calculations/cplex_in"; else ERROR("Bad idea... sort before using homebrew lp."); } procbuf cplexin2p = procbuf( pipe_command, ios::out ); ostream cplexin2 = ostream( &cplexin2p ); if (!quiet && !silent) cerr << "[setting up linear program with " << vtable.length << " variables and "; int constraint_count = 0, sumx, sign_error; wordtype dualw(c); dualw.dual_advance(true); // initialize vconstraint vc(vtable.length); bool non_zero; vc.RHS = 0; Integer coeff; word all_ones(c->part.length); for ( i = 0; i < all_ones.length; i++ ) all_ones(i) = 1; do { if ( dual_constraint_bound > 0 && dualw(0) > dual_constraint_bound && (dcb_depth_limit == 0 || c->part.length <= dcb_depth_limit) ) continue; non_zero = false; if (!complete_table) { convert_dual_variable(all_ones, dualw, binom, vc.LHS); if ( !vc.LHS.if_zero( ) ) non_zero = true; goto constraint_computed; } for ( j = 0; j < vtable.length; j++ ) { wordtype& v = vtable(j).maw; TEX(![ \begin{quoteb} Let $w_p$ range over a collection of words in the smallcode such that $w_p + {\tt v}$ gives all basic local variables equivalent to {\tt v}, without repetition. Set\\ \ \ \ \ \ \ $\displaystyle{\hbox{\tt sum} \ =\ \sum_p (-1)^{w_p \hbox{$\cdot$}\kern2pt \hbox{\tt\small dualw}}}$. \end{quoteb} ]!) sumx = 0; forPix( p, vtable(j).w ) { if ( even( vtable(j).w(p) * dualw ) ) sumx++; else sumx--; } if ( sumx != 0 ) { TEX( ![ \begin{quotec} We set {\tt coeff} $=$\\[0.05in] $\prod_{i = 0}^{\hbox{\small c-$>$part.length} - 1} \hbox{\tt combo[dualw(}i\hbox{\tt)][c->part(}i\hbox{\tt) - v(}i \hbox{\tt)][v(}i\hbox{\tt)]}$, except that things are complicated by the fact that we've only defined $\hbox{\tt combo[}k\hbox{\tt][}i\hbox{\tt][}j\hbox{\tt]}$ when $i \geq j$. \end{quotec} ]! ) sign_error = 0; if ( c->part(0) - v(0) >= v(0) ) coeff = combo[ dualw(0) ] [ c->part(0) - v(0) ] [ v(0) ]; else { coeff = combo[ dualw(0) ] [ v(0) ] [ c->part(0) - v(0) ]; sign_error += dualw(0); } for ( i = 1; i < c->part.length; i++ ) { if ( c->part(i) - v(i) >= v(i) ) coeff *= combo[ dualw(i) ] [ c->part(i) - v(i) ] [ v(i) ]; else { coeff *= combo[ dualw(i) ] [ v(i)] [ c->part(i) - v(i) ]; sign_error += dualw(i); } } if ( odd(sign_error) ) coeff = -coeff; coeff *= sumx; vc.LHS(j) = coeff; if ( coeff != 0 ) non_zero = true; } else vc.LHS(j) = 0; } constraint_computed: if ( !non_zero ) continue; // constraint is identically zero constraint_count++; if ( constraint_count * vtable.length > 20000000 ) ERROR( "The number of basic local variables times the number of " << "constraints generated thusfar exceeds 20,000,000. " << "Under the current version this is regarded as an " << "error." ); TEX( ![ \begin{quotea} Determine if {\tt dualw} is dual-equivalent to a word of an admissible weight. \end{quotea} ]! ) bool must_be_zero = false; wordtype altz(c); for( i = 0; i < dualsmall_working.x.nrows; i++ ) { altz.act( dualsmall_working.x(i), dualw ); int dualweight = sum(altz); if ( 1 <= dualweight && dualweight < c->share->dual_min_low ) { must_be_zero = true; break; } } if (smart_dual && !must_be_zero) { int su = 0; for ( i = 0; i < c->part.length; i++ ) su += min( int(dualw(i)), c->part(i) - dualw(i) ); if ( 2 * su < c->share->dual_min_low ) { vc.sense = '<'; vc.RHS = Ipow( 2, c->home->dim ); cplexin2 << vc; vc.RHS = 0; } } vc.reduce( ); vc.sense = ( must_be_zero ? '=' : '>' ); cplexin2 << vc; } while( dualw.dual_advance(false) != 0 ); if (!quiet && !silent) cerr << constraint_count << " main constraints]\n"; cplexin2 << "v1 = 1\n"; if (!homebrew) { vconstraint tot(vtable.length); tot.sense = '='; tot.RHS = Ipow( 2, c->home->dim ); for ( i = 0; i < tot.LHS.length; i++ ) tot.LHS(i) = vtable(i).w.length( ); cplexin2 << tot; } cplexin2p.close( ); TEX( \begin{quote} Release space occupied by {\tt combo}. This is to avoid hogging memory. \end{quote} ) if (complete_table) delete_krawtchouk( combo, mp ); else { for ( i = 0; i <= n; i++ ) delete [ ] binom[i]; delete [ ] binom; } file_status = 1; } build_cplex_in2: TEX(![ \begin{quote} Build the auxiliary constraintlist. Adjoin constraints as in ``{\tt projection onto}''. Then print it out in terms of {\tt v} variables, to the file \verb|cplex_in2|. \end{quote} ]!) constraintlist aux = c->known_cons( ); aux.merge(forced); if (auto_projection) { c->small.build( ); int j, d = c->home->ww(c->home->current).min( ); for ( j = 0; j < c->small.x.nrows; j++ ) { word& wd = c->small.x(j); int dw = wd * c->part; if ( dw < d || dw >= 2*d ) continue; if ( results.not_exist(c->home->n - dw, c->home->dim - 1, d - dw/2) ) continue; weightlist residues; wordtype v(c); for ( int i = 0; i < vtable.length; i++ ) { SLList& words = vtable(i).w; forPixDef( q, words ) { v.act( words(q), vtable(i).maw ); int r = wd.complement( ) * v; residues.add(r); } } term_sum tr[c->home->n - dw + 1]; wordtype wt(c), wtm(c); vtable.first(wt); do { int s = wd.complement( ) * wt; wtm = wt; c->make_minimal(wtm); tr[s].merge( term( 1, wtm.variable( ) ) ); } while( vtable.advance(wt) ); forPixDef( p, results.open ) { codehome* h = results.open(p); if ( h->n != c->home->n - dw || h->dim != c->home->dim - 1 || !h->opt.none_chosen( ) || !h->assumed_cons.empty( ) || !(residues <= h->w) ) continue; constraintlist& cl = h->configs(h->base).share->ycon; forPixDef( q, cl ) { if ( !cl(q).global( ) ) continue; constraint cnew( cl(q).sense, cl(q).RHS * 2 ); term_sum ts = h->configs(h->base).simplify_global_vars( cl(q).LHS ); forPixDef( t, ts ) { term_sum tr2 = tr[ yno( ts(t).var ) ]; forPixDef( xxx, tr2 ) tr2(xxx).coeff *= ts(t).coeff; cnew.adjoin(tr2); } forPix( t, cnew.LHS ) if ( cnew.LHS(t).coeff < 0 ) break; if ( t == 0 && cnew.sense == '>' && cnew.RHS == 0 ) continue; if ( !aux.known(cnew) ) { cerr << "merging constraint " << cnew << " (from " << cl(q) << ")\n"; aux.append(cnew); } } } } } String to_do; if (!homebrew) to_do = "fold -s > calculations/cplex_in2"; else to_do = "cat > calculations/cplex_in2"; procbuf cplex_in2p = procbuf( to_do, ios::out ); ostream cplex_in2 = ostream( &cplex_in2p ); vconstraint vc(vtable.length); forPixDef( ii, aux ) { if ( !aux(ii).local( ) ) continue; Rational mult = clear_denom( qvconstraint( aux(ii), c->home ), vc ); if ( mult != 0 ) cplex_in2 << vc; } cplex_in2p.close( ); time_used_generating_constraints += time(0); int use_homebrew = homebrew; homebrew = homebrew_saved; return use_homebrew; } // Return (total constraints, number of equality constraints). index_method(lp_crunch) pair lp_crunch( const prevector& files, int use_homebrew, int use_quadx, const vconstraint& tot, bool skip_setup = false ) { int i, j; remove( "calculations/homebrew.log" ); TEX(![ \begin{quote} Make the CPLEX command file. We turn off the CPLEX presolver and aggregator, because sometimes these processors find that the system is infeasible, and then CPLEX won't allow us to write a file (via ``\verb|w|'') so that we may verify CPLEX's conclusion. \end{quote} ]!) if ( !skip_setup ) { remove( "calculations/cplex_commands0" ); ofstream command_file( "calculations/cplex_commands0" ); command_file << "set logfile *\n"; if ( CPLEX_VERSION[0] <= '2' ) { command_file << "set presolve n\n"; command_file << "set aggregate n\n"; } else { command_file << "set preprocessing presolve n\n"; command_file << "set preprocessing aggregator n\n"; } command_file << "opt\n"; remove("calculations/cplex.bin"); command_file << "w " << PATH_PREFIX << "calculations/cplex.bin\n"; command_file.close( ); } TEX(![ \begin{quote} On most machines one has to give an upper bound on the number of nonzero coefficients, using the ``\verb|set sizes nonzeros|'' command. It was set to 100,000,000, but I lowered it. At one time I also added a line\\ ``\verb|set read constraints 2000000 100000|'' to the CPLEX commands file, for some reason, but I noticed subsequently that this slowed down most calculations. It may need to be added back under certain conditions. \end{quote} ]!) if (!use_homebrew) { if ( CPLEX_VERSION[0] <= '2' ) system(String("echo set sizes nonzeros 2000000 5000 > ") + "calculations/cplex_commands"); else { system(String("echo set read nonzeros 2000000 100000 > ") + "calculations/cplex_commands"); system(String("echo set read constraints 20000 1000 >> ") + "calculations/cplex_commands"); } system( String("echo r ") + PATH_PREFIX + "calculations/" + files(0) + " lp >> calculations/cplex_commands" ); for ( i = 1; i < files.length; i++ ) system(String("echo add ") + PATH_PREFIX + "calculations/" + files(i) + " >> calculations/cplex_commands"); system(String("cat calculations/cplex_commands0 >> ") + "calculations/cplex_commands"); remove("calculations/cplex_commands0"); remove("cplex.log"); time_used_by_CPLEX -= time(0); system( String(CPLEX) + " < calculations/cplex_commands > calculations/cplex_output" ); time_used_by_CPLEX += time(0); } else { // Compute number of constraints and their types. Merge constraint // files to form homebrew_in. int nvars = tot.LHS.length; vars = nvars; ofstream homebrew_in( "calculations/homebrew_in" ); vconstraint vvv(vars); homebrew_in << tot; int total_constraints = 1, eq_constraints = 1; for ( i = 0; i < files.length; i++ ) { ifstream cpin1( "calculations/" + files(i) ); while( cpin1.peek( ) != EOF ) { cpin1 >> vvv; if ( vvv.sense == '=' ) eq_constraints++; total_constraints++; homebrew_in << vvv; } cpin1.close( ); } homebrew_in.close( ); ofstream homebrew_log( "calculations/homebrew.log", ios::app ); homebrew_log << total_constraints << " constraints, of which " << eq_constraints << " are equalities\n"; homebrew_log << vars << " variables\n"; homebrew_log.close( ); int precision = use_quadx ? 16 : 8; exact_lp_problem ex; ex.n = vars; ex.m = total_constraints; ex.m_eq = eq_constraints; ex.known_to_be_infeasible = false; ex.con_file = "calculations/homebrew_in"; ex.presolve( ); if ( create_con_file_only ) return make_pair(ex.m, ex.m_eq); if ( ex.known_to_be_infeasible ) { homebrew_status = "infeasible"; return make_pair(ex.m, ex.m_eq); } TEX( ![ \begin{quotea} Reset random number generator. This makes it easier to replicate problems. \end{quotea} ]! ) srandom(1); homebrew_status = ex.show_infeasible_by_primal_simplex_on_dual( precision, tot); return make_pair(ex.m, ex.m_eq); } } set_compile_file(code.c) HIDE(![#include "opt.h"]!) TEX(![ \block{Analyze code extensions} This section contains the \verb|list_extensions| routine, which is invoked only by the\\ \verb|via extension| command. The code in this section is written to the file {\tt extensions.cc}. \vspace{0.1in} \par\noindent {\tt minimal}: Let a group $G = \langle\VEC g1n\rangle$ act on an ordered set $S$. Let $x \in S$. Return {\tt true} if $x \leq gx$ for all $g \in G$, else {\tt false}. The method is to construct the orbit $Gx$, or part of it, in the {\tt false} case. Space may run out in the process, in which case execution will terminate abnormally. \vspace{0.1in} \par\noindent{\bf Outline of method} \vspace{0.1in} If an element of $Gx$ is expressible in the form $g_{\alpha_1} \cdots g_{\alpha_r} x$ $(1 \leq \VEC\alpha1r \leq n)$, we say that it has {\it length\/} $r$. If moreover it does not have length $s$ for any $0 \leq s < r$, we say it has {\it pure length\/} $r$. \vspace{0.1in} \par\noindent $Q := \setof{\VEC g1n}$\\ $X_{-1} := \emptyset$\\ $X_0 := \setof{x}$\\ $i := 1$\\ \begin{tabular}{lll} \kern-6pt repeat \{\ \ \ \ & $X_i := Q X_{i-1}$\ &(list of $\abs{Q} \cdot \abs{X_{i-1}}$ elements)\\ & \multicolumn{2}{l}{(As we go through the above, test for minimality, and if violated, return {\tt false}.)}\\ & $X_i := $ unique sort of $X_i$\\ & \multicolumn{2}{l}{(At this point $X_i = Q \cdot \setofh{elements of pure length $i-1$}$.)}\\ & $X_{i-1} := X_{i-2} \cup X_{i-1}$\ &(merge of nonoverlapping unique-sorted\\ && sets, to form a new unique-sorted set)\\ & \multicolumn{2}{l}{(At this point $X_{i-1}$ consists of all elements of length $\leq i-1$.)}\\ & delete $X_{i-2}$\\ & $X_i := X_i - X_{i-1}$ & (still a unique-sorted set)\\ & \multicolumn{2}{l}{(At this point $X_i$ consists of all elements having pure length $i$.)}\\ & if ( $X_i = \emptyset$ ) return {\tt true}\\ & $i${\tt++}\ \ \ \ \ \ \ \} \end{tabular} \mindex{minimal} ]!) set_compile_file(extensions.cc) HIDE( ![ #include "homedefs.h" #ifdef NeXT #include #else #include #endif #include extern long time_used_by_list_extensions; template void sort_by_second( prevector< pair >& ); ]! ) TEX(\label{bool-minimal}) template bool minimal( const prevector& Q, const S& x, int (*cmp)(const S&, const S&), void (*act)(const G&, const S&, S&) ) { prevector Xa(0), Xb(1), Xc, Xt; Xb(0) = x; int i, j, k, c, n = Q.length; while(1) { Xc.set_size( n * Xb.length ); for ( i = 0; i < Q.length; i++ ) for ( j = 0; j < Xb.length; j++ ) { act( Q(i), Xb(j), Xc( i + n * j ) ); if ( (*cmp)(Xc( i + n * j ), x) < 0 ) return false; } Xc.unique_sort(cmp); merge( Xa, Xb, Xt, cmp ); // Merge Xa and Xb to get Xa = Xt; // new Xa, then set Xb = Xc - Xa. diff( Xc, Xa, Xb, cmp ); if ( Xb.length == 0 ) return true; } } HIDE(![int rcmp(const number&, const number&);]!) index_method(yact) void yact(const Permutation& p, const vector& v, vector& v_new) { v_new.set_size(v.length); for ( int i = 0; i < v.length; i++ ) v_new(i) = p( v(i) - 1 ); v_new.sort(rcmp); } index_method(ycmp) int ycmp(const vector& a, const vector& b) { register int i, n = a.length; for ( i = 0; i < n; i++ ) { if ( a(i).x > b(i).x ) return 1; if ( a(i).x < b(i).x ) return -1; } return 0; } index_method(list_extensions) SLList< matrix > codehome::list_extensions(bool alternate_extension_method, bool enumerators_only, codetable& results) { time_used_by_list_extensions -= time(0); config& c = configs(current); Pix q, l; constraintlist cons = c.known_cons( ); int i, j, k, wt; int s = c.small.basis.nrows; // dimension of code we start with int r = dim - s; // number of extension steps if ( r == 0 ) ERROR( "This is silly." ); int rg = c.part(c.part.length-1); // room to grow // Check the current configuration to see if it meets the // requirements of the "via extension" command. for ( i = 0; i < c.part.length - 1; i++ ) if ( c.part(i) != 1 ) ERROR("The partition of the configuration must have the " << "form 1,1,...,r for some r."); for ( i = 0; i < s; i++ ) if ( c.small.basis(i,c.part.length-1) != 0 ) ERROR("Configuration not of correct type: " << "last entry of each small code element must be 0."); if ( rg < r ) ERROR("Configuration not of correct type."); // Find the generator matrix of the code D to be extended. matrix B(s, n - r); for ( i = 0; i < B.nrows; i++ ) { for ( j = 0; j < n - rg; j++ ) B(i,j) = c.small.basis(i,j); } if ( !c.no_bad_weights( ) ) ERROR("There is a word of illegal weight."); // Form the list of permutations which are known to act on D. Permutationlist genset(n-r); Permutation p(n-r); for ( int ii = 0; ii < c.aut.length; ii++ ) { Permutation p0 = c.aut(ii); if ( p0(p0.length-1) == c.part.length ) { for ( i = 0; i < p0.length - 1; i++ ) p(i) = p0(i); for ( i = p0.length; i < p.length; i++ ) p(i) = i + 1; genset.append(p); } } TEX( ![ \begin{quote} Determine the minimum weight and if we are working with even codes. Also determine if there are other weights to be excluded. \end{quote} ]! ) weightlist& wl = c.share->ww; int min_weight = wl.min( ); bool w_is_even = wl.divisible(2); OSLList bad_weights; int incre = ( w_is_even ? 2 : 1 ); for ( i = min_weight; i <= n; i += ( w_is_even ? 2 : 1 ) ) bad_weights.append(i); forPix( q, wl ) bad_weights.del( wl(q) ); OSLList bw_curr = bad_weights; forPix( q, bad_weights ) if ( bad_weights(q) > n - r + 1 ) bw_curr.del( bad_weights(q) ); vector bw_curr_v(bw_curr); vector bwv(n+1); for ( i = 0; i <= n; i++ ) bwv(i) = true; forPix( q, wl ) if ( wl(q) ) bwv( wl(q) ) = false; TEX( ![ \begin{quote} Determine if the dual small code has a dual word corresponding to the last bit of the partition. \end{quote} ]! ) vector lastbit(c.part.length); lastbit( lastbit.length - 1 ) = 1; bool last_dual = c.dualsmall.basis.rowspace_member( lastbit ); TEX( ![ \begin{quote} Form a matrix {\tt M} in \RREF\ whose rows form a basis for the nullspace of {\tt B}. Let {\tt M1} be obtained by adding a ``blank'' column to {\tt M}. The rows of the matrix {\tt D} will form a basis for the nullspace of {\tt M1}. \end{quote} ]! ) matrix M; B.nullspace_equals(M); M.reduce( ); matrix M1, a_col( M.nrows, 1 ), D(s + 1, n - r + 1); hcat( M, a_col, M1 ); // Find the admissible elements of V := F_2^{n-r-s}. SLList< vector > adm; vector v(n-r-s), test(n-r+1); do { TEX( ![ \begin{quoteaneg} If the code is even, and you add together all the rows of the generator matrix for the dual code, you will get the all $1$'s word. Hence the columns of the dual code generator matrix should have odd weight. \end{quoteaneg} ]! ) if ( w_is_even && even( v.weight( ) ) ) continue; M1.set_col( n-r, v ); M1.nullspace_equals(D); vector indx(s); do { for ( j = 0; j < test.length; j++ ) test(j) = D(s,j); for ( i = 0; i < indx.length; i++ ) if ( indx(i).x ) for ( j = 0; j < test.length; j++ ) test(j).x ^= D(i,j).x; wt = test.weight( ); if ( wt < min_weight || bw_curr_v.member(wt) ) goto inadmissible; } while( indx.advance( ) != 0 ); if ( v.length == MAXSHORT ) ERROR("There are > " << MAXSHORT << " admissible elements," << " which is too many for the language to handle."); adm.append(v); inadmissible: continue; } while( v.advance( ) != 0 ); cerr << "There are " << adm.length( ) << " admissible elements.\n"; vector< vector > admv(adm); admv.sort(&cmp); int count = admv.length; // genset2 will act on the admissible elements. We compute its action. Permutationlist genset2(count); genset2.set_size( genset.length ); matrix Mc, Q; vector rx; Permutation pp(count); for ( k = 0; k < genset.length; k++ ) { Mc = M; Mc.permute_columns( genset(k) ); Mc.reduce_i(Q); for ( i = 0; i < count; i++ ) { mul( Q, admv(i), rx ); int xp = admv.pos( rx, cmp ); HIDE( ![ if ( xp == -1 ) INTERNAL_ERROR("computation of genset2"); ]! ) pp(i) = xp + 1; } genset2(k) = pp; } // Make a list of 200 group elements. Permutationlist genset2v(count); genset2v.generate( genset2, 200 ); // Delete identity if present in list. for ( i = 0; i < genset2v.length; i++ ) { if ( genset2v(i) == Permutation(count) ) { Permutationlist genset2vx(count); genset2vx.set_size( genset2v.length - 1 ); for ( j = 0; j < genset2v.length; j++ ) { if ( j < i ) genset2vx(j) = genset2v(j); if ( j > i ) genset2vx(j-1) = genset2v(j); } genset2v = genset2vx; break; } } SLList< vector > level[r+1]; SLList< matrix > answer; // Compute level 1. vector one(1); for ( i = 1; i <= count; i++ ) { one(0) = i; if ( minimal( prevector(genset2), one, ycmp, yact ) ) { if ( r != 1 ) level[1].append(one); else { M1.set_col( n-r, admv(i-1) ); M1.nullspace_equals(D); vector weights = D.enumerate_weights( ); if ( check_globals( cons, weights, configs(base) ) ) { config_core c2[2]; for ( k = 0; k < 2; k++ ) { c2[k].part.set_all_ones(D.ncols); c2[k].dualsmallbasis.set_size(0, D.ncols); } c2[1].smallbasis = D; codehome lrhome( D.ncols, D.nrows, weightlist("1", D.ncols), results ); Pix qr; if (enumerators_only) { forPix( qr, answer ) if (weights == answer(qr).enumerate_weights( ) ) break; } else { forPix( qr, answer ) { c2[0].smallbasis = answer(qr); if ( lrhome.isomorphic( c2[0], c2[1] ) ) break; } } if ( qr == 0 ) { level[1].append(one); answer.append(D); cerr << "Extension " << answer.length( ) << ": " << D << "\n" << "weight enumerator: " << as_poly(weights) << "\n"; } } } } } cerr << "level 1 has " << level[1].length( ) << " elements\n"; // Compute levels 2,...,r. int lev; for ( lev = 2; lev <= r; lev++ ) { bw_curr = bad_weights; forPix( q, bad_weights ) if ( bad_weights(q) > n-r + lev ) bw_curr.del( bad_weights(q) ); bw_curr_v = vector( bw_curr ); vector curr(lev); matrix M2, lev_cols( M.nrows, lev ), D2(s + lev, n - r + lev); hcat( M, lev_cols, M2 ); codehome lrhome( D2.ncols, D2.nrows, weightlist("1", D2.ncols), results ); vector test(n-r+lev), indx(s+lev-1); forPix( q, level[lev-1] ) { for ( i = 0; i < lev-1; i++ ) curr(i) = level[lev-1](q)(i); for ( j = 0; j < lev - 1; j++ ) M2.set_col( M.ncols+j, admv(curr(j) - 1) ); TEX( ![ \begin{quoteb} We have a matrix {\tt M2}. For each iteration of the main loop (below), its last column changes (or at least it would, if we did not use the faster methods to be described here). We would then determine if there could exist an ``illegal weight'' vector having one in its last position and orthogonal to the rows of {\tt M2}. However, it is faster to first make some computations which apply to each {\tt M2}. For this, we actually set the last column of {\tt M2} to zero. First perform elementary row operations and then column permutations on {\tt M2} to yield a matrix {\tt M2f} of the form $[I|*]$. \end{quoteb} ]! ) matrix M2f = M2, D2f, QQ; for ( i = 0; i < M2f.nrows; i++ ) // Make sure last col is zero. M2f( i, M2f.ncols - 1 ) = 0; M2f.reduce_i(QQ); bool QQ_is_identity = false; for ( i = 0; i < QQ.nrows; i++ ) for ( j = 0; j < QQ.ncols; j++ ) if ( QQ(i,j) != (i == j) ) goto not_identity; QQ_is_identity = true; not_identity: for ( i = 0; i < M2f.ncols; i++ ) if ( M2f( M2f.nrows - 1, i ) ) break; if ( i == M2f.ncols ) INTERNAL_ERROR( "Matrix should have full row rank." ); Permutation* colfix = M2f.column_fix( ); delete colfix; // Create a matrix kerM2f whose rows are the vectors which // (1) are orthogonal to the rows of M2f and // (2) have one in their last position. M2f.nullspace_equals(D2f); matrix kerM2f( as_int(Ipow(2, D2f.nrows-1)), M2f.ncols ); word indxf( D2f.nrows ), kv( D2f.ncols ); i = 0; do { mul( indxf, D2f, kv ); if ( kv( kv.length - 1 ) ) kerM2f( i++ ) = kv; } while ( indxf.advance( ) ); // Set kerM2f1 to the first M2f.nrows columns of kerM2f. // Then set wkerM2f2 to the vector whose i'th entry is the weight // of the part of the i'th row of kerM2f to the right of the // first M2f.nrows columns. matrix kerM2f1 = kerM2f; kerM2f1.resize( kerM2f.nrows, M2f.nrows ); vector wkerM2f2( kerM2f.nrows ); for ( i = 0; i < wkerM2f2.length; i++ ) { int sum = 0; for ( j = M2f.nrows+1; j < kerM2f.ncols; j++ ) if ( kerM2f(i,j) ) sum++; wkerM2f2(i) = sum; } for ( i = curr(lev-2) + 1; i <= count; i++ ) { curr(lev-1) = i; TEX( ![ \begin{quotec} Test for $G$-minimality, where $G$ is the $200$ (or less) element subset of the automorphism group constructed above. If the parameter \verb|alternate_extension_method| is set, we use the entire known automorphism group. \end{quotec} ]! ) if ( alternate_extension_method ) { if ( !minimal( prevector(genset2), curr, ycmp, yact ) ) continue; } else if ( genset2v.length > 0 && !genset2v.minimal(curr) ) continue; // Test for admissibility. if ( w_is_even ) { word ka ( QQ.nrows ); if ( QQ_is_identity ) ka = admv(i-1); else mul( QQ, admv(i-1), ka ); static int targ(0); register gf2* r2 = ka.x; for ( j = 0; j < kerM2f.nrows; j++ ) { register gf2* r1 = kerM2f1.x[j].x; register int sum = wkerM2f2(j); for ( register int jj = 0; jj < ka.length; jj++ ) sum += r1[jj] ^ r2[jj]; if ( odd(sum) ) sum++; if ( bwv.x[sum] ) #define TOP_QUEUE 6 { if ( j >= TOP_QUEUE ) { swap( kerM2f1(j), kerM2f1(targ) ); swap( wkerM2f2(j), wkerM2f2(targ) ); targ++; targ %= TOP_QUEUE; } goto inadmissible2; } } } else { M2.set_col( M.ncols+lev-1, admv(i-1) ); M2.nullspace_equals(D2); register gf2* D2k; register int tl; indx.set_zero( ); do { // Set test = (indx(0), ..., indx(last),1) * D2. register int j, k; for ( j = 0; j < test.length; j++ ) test(j) = D2(s+lev-1,j); for ( k = 0; k < indx.length; k++ ) if ( indx(k).x ) { D2k = D2.x[k].x; tl = test.length; for ( j = 0; j < tl; j++ ) test(j).x ^= D2k[j].x; } wt = test.weight( ); if ( wt < min_weight || bw_curr_v.member(wt) ) goto inadmissible2; } while( indx.advance( ) != 0 ); } if (last_dual) { M2.set_col( M.ncols+lev-1, admv(i-1) ); M2.nullspace_equals(D2); for ( j = 0; j < D2.nrows; j++ ) { char sum = 0; for ( k = n-rg; k < D2.ncols; k++ ) sum ^= D2(j,k); if ( sum != 0 ) break; } if ( j != D2.nrows ) continue; } if ( lev != r ) level[lev].append(curr); if ( lev == r ) { M2.set_col( M.ncols+lev-1, admv(i-1) ); M2.nullspace_equals(D2); D2.reduce( ); vector weights = D2.enumerate_weights( ); if ( check_globals( cons, weights, configs(base) ) ) { config_core c2[2]; for ( k = 0; k < 2; k++ ) { c2[k].part.set_all_ones(D2.ncols); c2[k].dualsmallbasis.set_size(0, D2.ncols); } c2[1].smallbasis = D2; Pix qr; if (enumerators_only) { forPix( qr, answer ) if (weights == answer(qr).enumerate_weights( ) ) break; } else { forPix( qr, answer ) { c2[0].smallbasis = answer(qr); if ( lrhome.isomorphic(c2[0], c2[1]) ) break; } } if ( qr == 0 ) { level[lev].append(curr); answer.append(D2); cerr << "Extension " << answer.length( ) << ": " << D2 << "\n" << "weight enumerator: " << as_poly(weights) << "\n"; } } } inadmissible2: continue; } } cerr << "level " << lev << " has " << level[lev].length( ) << " elements\n"; } time_used_by_list_extensions += time(0); return answer; } set_compile_file(code.c) TEX(![ \block{Command parser} The parser is invoked by: \vspace{0.05in} \par\noindent\kern0.5in\verb|parse( s, &( |$\hbox{\it item}_1$\verb|, |% $\ldots$\verb|, |$\hbox{\it item}_r$\verb| ) )| \vspace{0.05in} \par\noindent where \verb|s| is a pre-existing string and the given items each have one of the following forms: \begin{itemize} \item \verb|parse_text(|{\it required text}\verb|)|, where {\it required text\/} must occur; \item \verb|parse_pat(|{\it pattern}\verb|, |{\it string-name}\verb| )|\\ where {\it pattern\/} points to a regular expression, and {\it string-name\/} is the name of a \verb|String| object to be filled with whatever matches {\it pattern}; \item \verb|parse_pos(|{\it Integer-name}\verb|,|\kern5pt% {\it lowest allowed value (default $1$)}\verb|,|\kern5pt% {\it highest allowed value (default $\infty$)}\verb|)|, where {\it Integer-name} is the name of a \verb|Integer| object to be filled. \item \verb|parse_pos_list(|{\tt number} {\it vector}\verb|,|\kern5pt% {\it low}\verb|,|\kern5pt{\it high}\verb|)|, where {\it low}, {\it high} are as in the \verb|parse_pos| form; \item \verb|parse_short(|{\it short int-name}\verb|,|\kern5pt% {\it lowest allowed value (default $1$)}\verb|,|\kern5pt% {\it highest allowed value (default $\infty$)}\verb|)|, where {\it short int-name} is the name of a \verb|short int| object to be filled. \item \verb|parse_word(|{\it word}\verb|)| \item \verb|parse_open_code_type(|{\it codetable}\verb|, | {\it string-name}\verb|, |{\it pix-name}\verb| )| \item \verb|parse_constraint(|{\it constraint-name}\verb|)| \item \verb|parse_constraint_list(|{\it constraintlist-name}\verb|)| \item \verb|parse_known_config(results, |{\it pointer to\/} {\tt codehome}% \verb|, |{\it string-name}\verb|, |{\it pix-name}\verb| )| \end{itemize} The routine {\tt parse} returns {\tt true} if there is a successful match (with all the items, in order), and otherwise {\tt false}. ]!) index_class(parse_base) index_method(create) class parse_base { public: static String in; static parse_base* first; static parse_base* last; parse_base* next; parse_base( ); virtual bool create( ) = 0; }; parse_base::parse_base( ) { if ( first == 0 ) first = this; else last->next = this; last = this; next = 0; } String parse_base::in; parse_base* parse_base::first = 0; parse_base* parse_base::last; index_class(parse_pos) class parse_pos : public parse_base { public: Integer* n; Integer low, high; bool create( ); parse_pos(Integer& r, const Integer& low = 1, const Integer& high = -1) : low(low), high(high) { n = &r; } }; Regex pos_number_pattern = Regex(pos_number); bool parse_pos::create( ) { if ( !in.contains( pos_number_pattern, 0 ) ) return false; *n = atoI( take( in, pos_number_pattern ) ); if ( *n < low ) ERROR("The number " << *n << " is too small. It should be at " << "least " << low << "."); if ( high != -1 && *n > high ) ERROR("The number " << *n << " is too large. It should be no " << "greater than " << high << "."); return true; } index_class(parse_small) class parse_short : public parse_base { public: short int* n; int low, high; bool create( ); parse_short(short int& r, const int& low = 1, const int& high = MAXSHORT) : low(low), high(high) { n = &r; } }; bool parse_short::create( ) { if ( !in.contains( pos_number_pattern, 0 ) ) return false; Integer N = atoI( take( in, pos_number_pattern ) ); if ( N < low ) ERROR("The number " << N << " is too small. It should be at " << "least " << low << "."); if ( high != -1 && N > high ) ERROR("The number " << N << " is too large. It should be no " << "greater than " << high << "."); *n = as_int(N); return true; } index_class(parse_pos_list) class parse_pos_list : public parse_base { public: vector* v; Integer low; Integer high; bool create( ); parse_pos_list( vector& vv, const Integer& low = 1, const Integer& high = MAXSHORT ) : low(low), high(high) { v = &vv; } }; bool parse_pos_list::create( ) { static Regex pos_list_pattern(pos_list); if ( in.empty( ) || !isdigit(in[0]) ) return false; String matching_piece = take( in, pos_list_pattern ); prevector args = unpack( matching_piece ); v->set_size( args.length ); for ( int i = 0; i < args.length; i++ ) { Integer n = atoI(args(i)); if ( n < low ) ERROR("The number " << n << " is too small. It should be " << "at least " << low << "."); if ( high != -1 && n > high ) ERROR("The number " << n << " is too large. It should be " << "no greater than " << high << "."); (*v)(i) = as_int(n); } return true; } index_class(parse_word) class parse_word : public parse_base { public: word* w; bool create( ); parse_word( word& wd ) { w = &wd; } }; bool parse_word::create( ) { static Regex zero_one_pat( "[01]+" ); if ( !in.contains( zero_one_pat, 0 ) ) return false; *w = word( take( in, zero_one_pat ), 0 ); return true; } index_class(parse_pat) class parse_pat : public parse_base { public: Regex* pat; String* s; bool create( ) { if ( !in.contains( *pat, 0 ) ) return false; *s = take( in, *pat ); return true; } parse_pat( Regex* r, String& st ) : pat(r) { s = &st; } }; index_class(parse_test) class parse_test : public parse_base { public: String s; bool* test; bool create( ); parse_test( const String& st, bool& t ) : s(st) { test = &t; } }; bool parse_test::create( ) { if ( !in.contains( s, 0 ) ) *test = false; else { *test = true; in.del(s); } return true; } index_class(parse_known_config) class parse_known_config : public parse_base { public: codetable* results; codehome* home; String* label; Pix* p; bool create( ); parse_known_config( codetable& c, codehome& h, String& l, Pix& pr ) { results = &c, home = &h, label = &l, p = ≺ } }; bool parse_known_config::create( ) { static Regex gen_label_pattern( gen_label_pat ); if ( !in.contains( gen_label_pattern, 0 ) ) return false; *label = take( in, gen_label_pattern ); // The following line is dangerous because there could be a command which // starts with a label pattern, but the label is not supposed to // be a preexisting configuration. *p = home->label_to_Pix(*label, *results); return true; } index_class(parse_open_code_type) class parse_open_code_type : public parse_base { public: const codetable* results; String* label; Pix* px; bool create( ); parse_open_code_type( const codetable& c, String& l, Pix& p ) { results = &c, label = &l, px = &p; } }; bool parse_open_code_type::create( ) { static Regex label_pattern(label_pat); if ( !in.contains( label_pattern, 0 ) ) return false; *label = take( in, label_pattern ); forPixDef( p, results->olabels ) { if ( results->olabels(p).first == *label ) { *px = results->olabels(p).second; break; } } if ( p == 0 ) ERROR("Code type " << *label << " is not a known open type."); return true; } index_class(parse_code_type) class parse_code_type : public parse_base { public: const codetable* results; String* label; Pix* px; int* status; // -1 if dead, else 0 bool create( ); parse_code_type( const codetable& c, String& l, Pix& p, int& st ) { results = &c, label = &l, px = &p, status = &st; } }; bool parse_code_type::create( ) { static Regex label_pattern(label_pat); if ( !in.contains( label_pattern, 0 ) ) return false; *label = take( in, label_pattern ); forPixDef( p, results->olabels ) { if ( results->olabels(p).first == *label ) { *px = results->olabels(p).second; *status = 0; return true; } } forPix( p, results->dlabels ) { if ( results->dlabels(p).first == *label ) { *px = results->dlabels(p).second; *status = -1; return true; } } ERROR("Code type " << *label << " is not a known code type."); } index_class(parse_constraint) class parse_constraint : public parse_base { public: constraint* con; bool create( ); parse_constraint( constraint& c ) { con = &c; } }; bool parse_constraint::create( ) { static Regex gen_constraint_pattern(constraint_pat + orsign + var + "!=0"); // Check for fake constraints (kludge). if ( in.contains("dual",0) || in.contains("by",0) || in.contains("from",0) || in.contains("kill",0) ) return false; if ( !in.contains( gen_constraint_pattern, 0 ) ) return false; *con = take( in, gen_constraint_pattern ); return true; } index_class(parse_constraint_list) class parse_constraint_list : public parse_base { public: constraintlist* con; bool create( ); parse_constraint_list( constraintlist& c ) { con = &c; } }; bool parse_constraint_list::create( ) { static String less_op = left + "<" + orsign + "<=" + right; static String compound_constraint_pat = "[-]?" + number_pat + less_op + LHS_pat + less_op + "[-]?" + number_pat; static Regex constraint_list_pat( list_of( constraint_pat + orsign + var + "!=0" + orsign + compound_constraint_pat) ); if ( !in.contains( constraint_list_pat, 0 ) ) return false; *con = take( in, constraint_list_pat ); return true; } index_class(parse_text) class parse_text : public parse_base { public: String require; bool create( ); parse_text(const String& s) : require(s) { } }; bool parse_text::create( ) { if ( !in.contains( require, 0 ) ) return false; in.del(require); return true; } bool parse( const String& parse_me ... ) { parse_base::in = parse_me; parse_base* current = parse_base::first; parse_base::first = 0; while ( current != 0 ) { if ( !(*current).create( ) ) return false; current = current->next; } return parse_base::in.empty( ); } set_compile_file(op.cc) HIDE( ![ #include "homedefs.h" #include "bitvec.h" #include "codetable.h" int take_int(String&, const Regex&); extern String pos_number, left, right, orsign, gen_label_pat, pos_list; pair< Permutationlist, Integer > find_automorphism_group(const matrix&); ]! ) TEX( \block{Process matrix descriptors} ) matrix process_matrix_descriptor( String s, const codetable& results, codehome* home, String& code_label ) { prevector< matrix > at_codes(10); HIDE( ![ static Regex alphanumericu( "[a-zA-Z0-9_]*" ); static Regex number_pattern( number_pat ); static Regex pos_number_pattern( pos_number ); static Regex gen_label_pattern( gen_label_pat ); static Regex pos_list_pattern( pos_list ); static Regex zero_one_pat = "[01]+"; ]! ) int at_count = 0; int i, j, k; if ( s.contains('@') ) ERROR( "Syntax error in matrix descriptor." ); TEX( ![ \begin{quote} First deal with the case where {\tt s} contains a {\tt cyclic} atom. \end{quote} ]! ) static Regex cyclic_pat( "cyclic{.*" + orsign + number_pat + "-" + "cyclic{.*" + orsign + "(" + pos_list + ")-cyclic{.*" ); if ( home != 0 && s.matches( cyclic_pat ) ) { int n = home->n; if ( s.contains( "+check", -1 ) ) n--; String prefix; if ( s[0] == 'c' ) prefix = dec(n); else if ( isdigit( s[0] ) ) { int q = take_int(s, number_pattern); s.del( '-' ); if ( n % q != 0 ) ERROR(q << " does not divide " << n << "."); for ( i = 0; i < q; i++ ) { prefix += dec(n/q); if ( i != q-1 ) prefix += ","; } } else { s = s.after("("); prefix = take( s, pos_list_pattern ); s.del( ")-" ); } vector p(prefix); Permutation sigma(n); int pos = 0; for ( i = 0; i < p.length; i++ ) { if ( pos + p(i) > n ) ERROR("Illegal permutation."); for ( j = 0; j < p(i)-1; j++ ) sigma(pos + j) = pos + j + 2; sigma(pos + p(i) - 1) = pos + 1; pos += p(i); } s = s.after( "cyclic{" ); bool extra_given = false; word extra(0), gen = word( take(s, zero_one_pat), 0); if ( s[0] != '}' ) { extra_given = true; extra = word( take(s, zero_one_pat), 0 ); s.del( "," ); } s.del( "}" ); if ( gen.length > n || extra.length > n ) ERROR( "A zero-one vector is too long." ); if (gen.length == 0) ERROR( "A zero-one vector is too short." ); matrix M(home->dim, n); for ( i = 0; i < gen.length; i++ ) M(0, i) = gen(i); for ( i = 1; i < home->dim - extra_given; i++ ) { M(i) = M(i-1); sigma.act( M(i) ); } if (extra_given) { for ( j = 0; j < extra.length; j++ ) M( home->dim - 1, j ) = extra(j); } if ( s != "" && s != "+check" ) ERROR("Illegal use of cyclic atom."); M.reduce_nz( ); at_codes[at_count] = M; s = String("@") + dec(at_count++) + s; } TEX( ![ \begin{quote} Now replace any atoms in {\tt s} with strings of the form @n, where n >= 0, and put the corresponding matrix in \verb|at_codes|. \end{quote} ]! ) String s_new; for ( i = 0; i < s.length( ); i++ ) { static Regex SimpProj_pat( left + "Simp" + orsign + "Proj" + right + "(" + pos_number + ")" ); static Regex Even_pat( "Even(" + pos_number + ")" ); static Regex RM_pat( "RM1(" + pos_number + ")" ); static Regex QR_pat( "QuadraticResidue(" + pos_number + ")" ); static Regex config_pat("\\[[a-zA-Z_0-9]+\\.[---a-z.:A-Z_0-9!]+\\]"); // Test for { zero-one matrix } at position i. if ( s[i] == '{' && ( i == 0 || (s[i-1] != 'g' && s[i-1] != '_') ) ) { for ( j = i + 1; j < s.length( ); j++ ) if ( s[j] == '}' ) break; if ( j == s.length( ) ) ERROR( "Syntax error in matrix descriptor." ); matrix B = String( s.at( i, j-i+1 ) ); B.reduce_nz( ); at_codes[at_count] = B; s_new += String("@") + dec(at_count++); i = j; } // The first part of the if in the following line is there because // of a bug in contains. else if ( (s.contains("S", i) || s.contains("P", i)) && s.contains( SimpProj_pat, i ) ) { String t = s.at( SimpProj_pat, i ); String t2 = t.after(4); int col = 0, r = as_int( t2.before(")") ); int ncols = as_int(Ipow(2,r)); if ( t[0] == 'S' ) ncols--; matrix M( r, ncols ); word indx(r); if ( t[0] == 'S' ) indx.advance( ); do M.set_col( col++, indx ); while( indx.advance( ) ); M.reduce_nz( ); at_codes[at_count] = M; s_new += String("@") + dec(at_count++); i += t.length( ) - 1; } else if ( s.contains("R", i) && s.contains(RM_pat, i) ) { String t = s.at( RM_pat, i ); String t2 = t.after( "RM1(" ); int col = 0, r = as_int( t2.before(")") ); int ncols = as_int(Ipow(2,r)); matrix M( r+1, ncols ); word indx(r+1); do { if ( indx(0) == 1 ) M.set_col( col++, indx ); } while( indx.advance( ) ); M.reduce_nz( ); at_codes[at_count] = M; s_new += String("@") + dec(at_count++); i += t.length( ) - 1; } else if ( s.contains("E", i) && s.contains(Even_pat, i) ) { String t = s.at( Even_pat, i ); String t2 = t.after( "Even(" ); int r = as_int( t2.before(")") ); matrix M( r-1, r ); for ( j = 0; j < M.nrows; j++ ) { M(j, j) = 1; M(j, j+1) = 1; } M.reduce_nz( ); at_codes[at_count] = M; s_new += String("@") + dec(at_count++); i += t.length( ) - 1; } else if ( s.contains("Q", i) && s.contains(QR_pat, i) ) { String t = s.at( QR_pat, i ); String t2 = t.after( "QuadraticResidue(" ); int col = 0, q = as_int( t2.before(")") ); if ( q % 8 != 1 && q % 8 != 7 ) ERROR( q << " is not 1 or -1 (mod 8)." ); for ( j = 2; j < q; j++ ) if ( q % j == 0 ) ERROR( q << " is not prime." ); if ( q < 2 ) ERROR( q << " is not prime." ); word p2( 1+(q-1)/2 ), p_desired(1+q); p_desired(0) = 1; p_desired(q) = 1; do { if ( !p2( p2.length - 1 ) ) continue; if ( divides_as_poly( p2, p_desired ) ) goto p_found; } while( p2.advance( ) ); INTERNAL_ERROR("QuadraticResidue"); p_found: matrix M( (q+1)/2, q ); for ( j = 0; j < p2.length; j++ ) for ( k = 0; k < M.nrows; k++ ) M(k,j+k) = p2(j); M.reduce_nz( ); at_codes[at_count] = M; s_new += String("@") + dec(at_count++); i += t.length( ) - 1; } // The first "contains" in the following line is there because // of a bug in contains. else if ( s.contains( "[", i ) && s.contains( config_pat, i ) ) { String t = s.at( config_pat, i ); String t2 = t.after("["); String clabel = "[" + take( t2, alphanumericu ) + "]"; codehome* xhome; if (clabel == code_label) xhome = home; else { forPixDef( p, results.olabels ) { if ( results.olabels(p).first == clabel ) { xhome = results.open(results.olabels(p).second); break; } } if (p == 0) ERROR("Code type " << clabel << " is not a known open type."); } t2.del("."); t2 = "[" + t2; int del_co = 0; String ll = t2.before("]"); if ( ll.contains("-") ) { String cx1 = t2.before("-"); String cx2 = t2.after("-"); del_co = take_int( cx2, pos_number_pattern ); t2 = cx1 + cx2; } Pix pix1 = xhome->label_to_Pix( take(t2, gen_label_pattern), results ); matrix A = xhome->configs(pix1).basic_small( ); if ( del_co > 0 ) A.delete_column( del_co - 1 ); A.reduce_nz( ); at_codes[at_count] = A; s_new += String("@") + dec(at_count++); i += t.length( ) - 1; } else s_new += s[i]; } s = "(" + s_new + ")"; bool something_changed = true; while(something_changed) { something_changed = false; // Test for a contractible sharp expression. static Regex sharp_pat( "(@" + number_pat + "#@" + number_pat + ")" ); if ( s.contains( sharp_pat ) ) { something_changed = true; String first = s.before( sharp_pat ); String middle = s.at( sharp_pat ); String last = s.after( sharp_pat ); middle.del( "(@" ); int i1 = take_int( middle, number_pattern ); middle.del( "#@" ); middle.del( "#@" ); int i2 = take_int( middle, number_pattern ); matrix A1 = at_codes(i1), A2 = at_codes(i2); matrix B( A1.nrows + A2.nrows, A1.ncols * A2.ncols ); for ( i = 0; i < A1.nrows; i++ ) for ( j = 0; j < A1.ncols; j++ ) for ( k = 0; k < A2.ncols; k++ ) B( i, A2.ncols * j + k ) = A1(i, j); for ( i = 0; i < A2.nrows; i++ ) for ( j = 0; j < A2.ncols; j++ ) for ( k = 0; k < A1.ncols; k++ ) B( i + A1.nrows, A2.ncols * k + j ) = A2(i, j); B.reduce_nz( ); at_codes[at_count] = B; s = first + "(@" + dec(at_count++) + ")" + last; continue; } // Test for P(@n). static Regex P_pat( "P(@" + number_pat + ")" ); if ( s.contains( P_pat ) ) { something_changed = true; String first = s.before( P_pat ); String middle = s.at( P_pat ); String last = s.after( P_pat ); middle.del( "P(@" ); matrix A = at_codes( as_int( middle.before( ")" ) ) ); int k2 = as_int( Ipow(2, A.nrows) ); matrix B( A.nrows + 1, k2 + A.ncols ); for ( i = 0; i < A.nrows; i++ ) for ( j = 0; j < A.ncols; j++ ) B( i+1, j + k2 ) = A(i, j); for ( j = 0; j < k2; j++ ) B(0, j) = 1; i = 0; word indx(A.nrows); do { for ( k = 0; k < A.nrows; k++ ) B( k + 1, i ) = indx(k); i++; } while( indx.advance( ) ); B.reduce_nz( ); at_codes[at_count] = B; s = first + "@" + dec(at_count++) + last; continue; } // Test for dual(@n). static Regex dual_pat( "dual(@" + number_pat + ")" ); if ( s.contains( dual_pat ) ) { something_changed = true; String first = s.before( dual_pat ); String middle = s.at( dual_pat ); String last = s.after( dual_pat ); middle.del( "dual(@" ); int jj = as_int( middle.before( ")" ) ); matrix B = at_codes(jj), A; B.nullspace_equals(A); A.reduce_nz( ); at_codes[at_count] = A; s = first + "@" + dec(at_count++) + last; continue; } // Test for deletable parentheses. static Regex paren_pat( "(@" + number_pat + ")" ); if ( s.contains( paren_pat ) ) { something_changed = true; String first = s.before( paren_pat ); String middle = s.at( paren_pat ); String last = s.after( paren_pat ); middle.del("("); s = first + middle.before( ")" ) + last; continue; } // Test for a "+ check" operator. static Regex check_pat( "@" + number_pat + "\\+check" ); if ( s.contains( check_pat ) ) { something_changed = true; String first = s.before( check_pat ); String middle = s.at( check_pat ); String last = s.after( check_pat ); middle.del( '@' ); int jj = take_int( middle, number_pattern ); matrix B = at_codes(jj); matrix Bp = B; Bp.resize( B.nrows, B.ncols+1 ); bool found_odd = false; for ( j = 0; j < B.nrows; j++ ) { if ( odd( B(j).weight( ) ) ) { Bp( j, B.ncols ) = 1; found_odd = true; } } if ( !found_odd ) ERROR( "You are adding a parity check " << "to an even code." ); Bp.reduce_nz( ); at_codes[at_count] = Bp; s = first + "@" + dec(at_count++) + last; continue; } // Test for a "- column" operator. static Regex micol_pat( "@" + number_pat + "-column" + pos_number ); if ( s.contains( micol_pat ) ) { something_changed = true; String first = s.before( micol_pat ); String middle = s.at( micol_pat ); String last = s.after( micol_pat ); middle.del('@'); int jj = take_int( middle, number_pattern ); matrix B = at_codes(jj); int r = as_int( middle.after("-column") ) - 1; if ( r >= B.ncols ) ERROR( "Illegal column number." ); B.delete_column(r); B.reduce_nz( ); at_codes[at_count] = B; s = first + "@" + dec(at_count++) + last; continue; } // Test for a "+ column" operator. static Regex plcol_pat( "@" + number_pat + "\\+column" + pos_number ); if ( s.contains( plcol_pat ) ) { something_changed = true; String first = s.before( plcol_pat ); String middle = s.at( plcol_pat ); String last = s.after( plcol_pat ); middle.del('@'); int jj = take_int( middle, number_pattern ); matrix B = at_codes(jj); int r = as_int( middle.after( "+column" ) ) - 1; if ( r >= B.ncols ) ERROR( "Illegal column number." ); matrix Bp( B.nrows, B.ncols+1 ); for ( j = 0; j <= r; j++ ) for ( int l = 0; l < B.nrows; l++ ) Bp(l,j) = B(l,j); for ( j = r; j < B.ncols; j++ ) for ( int l = 0; l < B.nrows; l++ ) Bp(l,j+1) = B(l,j); Bp.reduce_nz( ); at_codes[at_count] = Bp; s = first + "@" + dec(at_count++) + last; continue; } // Test for a "+ zero column" operator. static Regex zcol_pat( "@" + number_pat + "\\+zerocolumn" ); if ( s.contains( zcol_pat ) ) { something_changed = true; String first = s.before( zcol_pat ); String middle = s.at( zcol_pat ); String last = s.after( zcol_pat ); middle.del('@'); int jj = take_int( middle, number_pattern ); matrix B = at_codes(jj); B.resize( B.nrows, B.ncols + 1 ); at_codes[at_count] = B; s = first + "@" + dec(at_count++) + last; continue; } // Test for transforms. static Regex transform_pat( "@" + number_pat + "^Tusing{" + left + "[,0-9_:$a-zA-Z]" + orsign + "{[^{}]*}" + right + "*" + "}" ); if ( s.contains( transform_pat ) ) { something_changed = true; String first = s.before( transform_pat ); String middle = s.at( transform_pat ); String last = s.after( transform_pat ); middle.del("@"); int jj = take_int( middle, number_pattern ); matrix A = at_codes(jj); middle.del( "^Tusing{" ); middle.del( "}", -1 ); SLList cols; if ( !middle.contains( ":" ) ) // "dual transform" { SLList< pair< int, prevector > > w; SLList sw; String piece; int paren_count = 0; for ( j = 0; j < middle.length( ); j++ ) { char c = middle[j]; if ( c == ',' && paren_count == 0 ) { sw.append(piece); piece = ""; continue; } if ( c == '{' ) paren_count++; if ( c == '}' ) paren_count--; if ( paren_count == -1 ) ERROR( "Syntax error in matrix descriptor." ); piece += c; } sw.append(piece); forPixDef( p, sw ) { String s = sw(p); if ( s.empty( ) || !isdigit(s[0]) ) ERROR( "Syntax error in matrix descriptor." ); int r = take_int(s, number_pattern); if ( s.empty( ) ) w.append( make_pair( r, prevector(0) ) ); else { if ( !s.contains("_{") ) ERROR("Syntax error in matrix descriptor."); s.del("_"); s.del("{"); if ( s[ s.length( ) - 1 ] != '}' ) ERROR("Syntax error in matrix descriptor."); s.del("}"); w.append(make_pair(r, prevector(s))); } } word indx(A.nrows), wd(A.ncols); do { mul( indx, A, wd ); int wt = wd.weight( ); forPix( p, w ) { if (w(p).first > A.ncols) ERROR("Garbage weight for dual transform."); if ( wt == w(p).first ) { int jj; for ( jj = 0; jj < w(p).second.length; jj++ ) { Integer k = w(p).second(jj); if ( k == 0 || k < -A.ncols || k > A.ncols ) { ERROR( "Column numbers " << "don't make sense." ); } if ( k > 0 && !wd(as_int(k-1)) ) break; if ( k < 0 && wd(as_int(-k-1)) ) break; } if ( jj == w(p).second.length ) cols.append(indx); } } } while( indx.advance( ) != 0 ); } else // "dual orbit code" { prevector gs = unpack( middle.before(":") ); prevector gsi( gs.length ); Permutationlist aut = find_automorphism_group(A).first; for ( i = 0; i < gs.length; i++ ) { static Regex dollar_n( "\\$" + pos_number ); if ( !gs(i).matches( dollar_n ) ) ERROR("Illegal automorphism label."); int r = as_int( gs(i).after("$") ); if ( r > aut.length ) ERROR(gs(i) << " does not make sense because there are " << " only " << aut.length << " generators."); gsi(i) = aut(r-1); } matrix cs( A.nrows, middle.after(":") ); word w( A.ncols ); OSLList gwi; for ( i = 0; i < cs.nrows; i++ ) { mul( cs(i), A, w ); gwi.add(w); } int old_length; do { old_length = gwi.length( ); forPixDef( q, gwi ) { for ( j = 0; j < gsi.length; j++ ) { w = gwi(q); gsi(j).act(w); gwi.add(w); } } } while ( gwi.length( ) > old_length ); forPixDef( q, gwi ) cols.append( A.coord_vector( gwi(q) ) ); } prevector colsv = cols; colsv.sort( &cmp ); matrix B(A.nrows, colsv.length); for ( j = 0; j < colsv.length; j++ ) B.set_col( j, colsv(j) ); B.reduce_nz( ); at_codes[at_count] = B; s = first + "@" + dec(at_count++) + last; continue; } } static Regex final_pat( "@" + number_pat ); if ( !s.matches (final_pat) ) ERROR("Syntax error in matrix descriptor."); return at_codes( as_int( s.after( "@" ) ) ); } TEX( \block{Routines invoked by main program to execute particular commands} ) set_compile_file(execute1.cc) HIDE( ![ #include "homedefs.h" #include "state.h" #include "bitvec.h" #include "codetable.h" #include "opt.h" extern int warnings_are_fatal, auto_group_computation; Integer round_down_to_power_of_2(Integer); Integer round_up_to_power_of_2(Integer); void log2(const Integer&, Integer&, Integer&); int yno(String); inline bool test(const Rational& a, const Rational& b, char sense) { if ( sense == '=' ) return a == b; if ( sense == '<' ) return a <= b; return a >= b; } bool joint_infeasible(codehome&, codetable&, constraintlist = constraintlist( )); bool isomorphic(const matrix&, const matrix&); ]! ) index_command(infer) void execute_infer_command(codehome* home, config& cur, constraint c, codetable& results, bool gullible) { static Regex subword = "sub[01]*"; if (gullible) { forPixDef( q, c.LHS ) cur.check_variable( c.LHS(q).var ); } String variable; // The following line // if (gullible) goto infer_ok; // resulted in strange and somewhat unpredictable errors. I think the // problem resulted from a compiler error which had something to do with // jumping over variable definitions. (Perhaps I was being punished for // using the evil goto statement.) In any case I circumvented the problem // by eliminating the jump, as accomplished by the following line: if (!gullible) { if ( !c.simple( ) ) ERROR("Incorrect syntax."); variable = c.LHS.front( ).var; cur.check_variable(variable); Pix p, q; Integer l = 0; Integer h = -1; cur.evaluate(variable, l, h); forPix( p, home->configs.vertices ) { config& d = home->configs(p); if ( d.share->realizable == -1 && mostly_equal(home->configs(home->current), d) ) { SLList unknowns; forPix( q, d.assumed_cons ) if ( !cur.known( d.assumed_cons(q) ) ) unknowns.append( d.assumed_cons(q) ); if ( unknowns.length( ) != 1 ) continue; constraint& cp = unknowns.front( ); if ( !cp.simple( ) || cp.LHS.front( ).var != variable ) continue; if ( cp.sense == '>' || cp.sense == '=' ) { Integer h2; if ( h == -1 ) h2 = cp.RHS - 1; else h2 = min( h, cp.RHS - 1 ); if ( !test( l, c.RHS, c.sense ) ) continue; if ( !test( h2, c.RHS, c.sense ) ) continue; } else if ( cp.sense == '<' || cp.sense == '=' ) { Integer l2 = max( l, cp.RHS + 1 ); if ( !test( l2, c.RHS, c.sense ) ) continue; if ( h == -1 ) { if ( c.sense != '>' ) continue; } else if ( !test( h, c.RHS, c.sense ) ) continue; } goto infer_ok; } } if ( variable[0] == 'm' && c.sense == '=' && c.RHS == 0 ) { int dp = as_int( variable.after("mu") ); String cf = String(dec(home->n - dp)) + "," + dec(dp) + "::{01}"; Pix i = home->configs.find( config( home, cf ) ); if ( i == 0 || home->configs(i).share->realizable != -1 ) ERROR("The configuration " << cf << " must be unrealizable."); goto infer_ok; } if ( variable[0] == 'y' && c.sense == '=' && c.RHS == 0 ) { int i = yno(variable); forPixDef( p, home->configs ) { config& cf = home->configs(p); int n = home->n; if (i == n && !(cf.part.length == 1)) continue; if (i < n && !(cf.part.length == 2 && cf.part(0) == i)) continue; if ( cf.small.basis.nrows != 1 ) continue; if ( i < n && !(cf.small.basis(0,1) == 0) ) continue; if ( cf.dualsmall.basis.nrows != 0 ) continue; forPixDef( q, cf.assumed_cons ) { if ( !cf.assumed_cons(q).joint( ) ) break; if ( !cur.known( cf.assumed_cons(q) ) ) break; } if ( q != 0 ) continue; goto infer_ok; } } if (variable == "div2" && c.sense == '>' && c.RHS == Ipow(2, home->dim-1)) goto infer_ok; if ( variable == "div2" && c.sense == '=' && c.RHS == Ipow(2, home->dim) ) { if ( cur.known( String("div2>") + dec(Ipow(2, home->dim-1)) ) ) goto infer_ok; } if ( variable == "div8" && c.sense == '=' && c.RHS == Ipow(2, home->dim) ) { if ( cur.known( String("div8>") + dec(Ipow(2, home->dim) - Ipow(2, home->dim - 3)) ) ) goto infer_ok; } if ( variable == "div4" && home->dim >= 2 ) { weightlist w = cur.share->ww; if ( !w.divisible(2) ) ERROR("To make an inference about div4 you must" << " know that the codes are even."); TEX( \begin{quotea} We figure out what the strongest statement we can make about {\tt div4} is. Then we check to see if the claimed assertion about {\tt div4} is consistent with the statement. First figure out what is already known about {\tt div4}. \end{quotea} ) Integer low = Ipow(2, home->dim - 2), high = Ipow(2, home->dim); cur.evaluate("div4", low, high); w.make_divisible(4); // Find the smallest r for which we know that there is no // doubly even subcode of dimension r. int k = home->dim; int r = min( k, results.max_dim_of_code(home->n, w) ) + 1; // Make a list of the possible values for div4, not taking // into account low and high yet. OSLList possible, possible2; int i; for ( i = r - 1; i >= 0; i-- ) { Integer candidate = Ipow(2, k-1) - Ipow(2, i); if ( candidate > 0 ) possible.add(candidate); } possible.add( Ipow(2, k-1) ); for ( i = 0; i <= r - 2; i++ ) possible.add( Ipow(2, k-1) + Ipow(2, i) ); // Use the list to improve low and high. forPix( p, possible ) if ( possible(p) >= low && possible(p) <= high ) possible2.add( possible(p) ); // The following line corresponds to the situation where the known // value of div4 is impossible, so in fact [current] is unrealizable. // Therefore any statement about div4 can be inferred. // This is a sloppy approach. if ( possible2.empty( ) ) goto infer_ok; low = possible2.Min( ); high = possible2.Max( ); if ( test( low, c.RHS, c.sense ) && test( high, c.RHS, c.sense ) ) goto infer_ok; } if ( variable[0] == 'y' && c.sense == '>' && c.RHS == 1 ) { if ( cur.share->ww.length( ) >= 3 ) { if ( cur.share->ww.min( ) == yno(variable) && codebase( home->n, home->dim, cur.share->ww.element(2) ).griesmer( ) > home->n ) goto infer_ok; } } if ( variable[0] == 'y' && c.sense == '>' ) { constraintlist cl = cur.known_cons( ); forPixDef( p, cl ) { constraint& cn = cl(p); if ( cn.simple( ) && cn.LHS.front( ).var[0] == 's' && cn.sense != '<' && cn.RHS >= c.RHS ) { String var = cn.LHS.front( ).var.after( subword ); if ( var == "" ) continue; int i_in_sub_var = as_int( var.after("_") ); if ( yno(variable) == i_in_sub_var ) goto infer_ok; } } } if ( variable[0] == 'x' && cur.small.basis.nrows < home->dim ) { wordtype w( &cur, variable ); home->activate(false); if ( c.sense == '=' && c.RHS == 0 ) { p = subdivide( home->configs(home->current), w ); if ( home->configs(p).share->realizable == -1 ) goto infer_ok; } if ( c.sense == '>' ) { ShareGraph& cs = home->configs; forPix( q, cs ) { SLList ed = cs.edges[ make_pair( home->current, q) ]; forPixDef( r, ed ) { wordtype& edge = ed(r); forPixDef( s, cs(q).con ) { constraint& x = cs(q).con(s); if ( !(x.simple_local( ) && x.sense != '<' && x.RHS >= c.RHS) ) continue; wordtype v( &cs(q), x.LHS.front( ).var ); if ( is_pullback( v, w, edge ) ) goto infer_ok; } } } } } if ( variable[0] == 's' ) { vector wd = prevector(variable.after("sub"),0); int wt = wd * cur.part; // "length" of subcode if ( cur.small.basis.rowspace_member(wd) && !wd.if_zero( ) && wt < 2 * cur.share->ww.min( ) && c.sense == '=' && c.RHS == 2 ) goto infer_ok; int low_dim = home->dim - (home->n - wt); // Check to see if the variable represents the number of // words disjoint from a dual word. vector wdp = wd.complement( ); if ( cur.dualsmall.basis.rowspace_member(wdp) ) low_dim++; Integer low = Ipow(2, max(0, low_dim) ); // Use nonexistence of subcodes to get an upper bound on // the variable. Integer high = Ipow(2, results.max_dim_of_code(wt, cur.share->ww) ); // Take into account known constraints. cur.evaluate(variable, low, high); low = round_up_to_power_of_2( low ); high = round_down_to_power_of_2( high ); // Now decide if the constraint really can be inferred. if ( test( Rational(low), c.RHS, c.sense ) && test( Rational(high), c.RHS, c.sense ) ) goto infer_ok; } ERROR("Constraint " << c << " cannot be inferred."); } infer_ok: bool new_active_needed = false; cur.add_constraint(c, new_active_needed); if (new_active_needed) home->deactivate( ); } index_command(kill) void execute_kill_variable_by( codehome* home, prevector vars, bool gullible, codetable& results ) { Pix curp = home->current; if ( curp == 0 ) ERROR("The current configuration is undefined."); bool nan; // not really used for ( int j = 0; j < vars.length; j++ ) { for ( int ii = 2; ii <= 3; ii++ ) { int divx = as_int( Ipow( 2, ii ) ); if ( vars(j) == String("ndiv") + dec(divx) ) { if (!gullible) { if ( home->ww(curp).divisible(divx) ) { WARNING( "I already know that all words have " << "weight divisible by " << divx << "." ); goto next_var; } Integer low = Ipow(2, home->dim) - Ipow(2, home->dim - ii); if ( !home->show( String("div") + divx + ">" + dec(low), results ) ) { WARNING( String("I couldn't kill ndiv") + divx ); goto next_var; } } home->ww(curp).make_divisible(divx); goto next_var; } } { String v; prevector lvs(0); bool alt_list = vars(j).contains( "," ); if ( vars(j).contains( "by" ) ) { v = vars(j).before( "by" ); vars(j) = vars(j).after("by"); vars(j).gsub( "(", 0 ); vars(j).gsub( ")", 0 ); lvs = unpack( vars(j), (alt_list ? "," : "|") ); } else v = vars(j); if ( lvs.length == 1 ) alt_list = true; config& c = home->configs(curp); c.check_variable(v); if ( v[0] != 'x' && v[0] != 'y' ) ERROR( v << " is not a basic local or basic global variable." ); String v0 = v; if ( c.part.length == 1 && v[0] == 'y' ) v.at("y") = "x_"; if ( lvs.length != 0 && v[0] != 'x' ) ERROR( v << " is not a basic local variable." ); if (gullible) goto add_con; if ( c.known( v0 + "=0" ) ) { WARNING( "I already know that " << v0 << " = 0." ); continue; } home->activate(false); if ( lvs.length > 0 && alt_list ) { wordtype wt( &c, v ); home->set_current( subdivide(home->configs(home->current), wt) ); home->configs(home->current).check_secondary_residuals(results); for ( int i = 0; i < lvs.length; i++ ) { home->configs(home->current).check_variable(lvs(i)); if ( lvs(i)[0] != 'x' ) ERROR( lvs(i) << " is not a basic local variable." ); wordtype wx( &home->configs(home->current), lvs(i) ); Pix ppp = home->current; home->activate(false); if ( !home->active->vtable.admissible(wx) ) { WARNING( "The basic local variable " << lvs(i) << " is not admissible. So you may as well remove " << "it from your kill command." ); continue; } home->set_current( subdivide( home->configs(home->current), wx ) ); home->configs(home->current). check_secondary_residuals(results); if ( !home->contradiction(false, results) ) ERROR( "Subdivided configuration may be realizable." ); home->set_current(ppp); home->configs(ppp).add_constraint( lvs(i) + "=0", nan ); } if ( !home->contradiction(false, results) ) ERROR( "Subdivided configuration may be realizable." ); } else if ( lvs.length > 0 ) { wordtype wt( &c, v ); home->set_current( subdivide(home->configs(home->current), wt) ); for ( int i = 0; i < lvs.length; i++ ) { home->configs(home->current). check_secondary_residuals(results); home->configs(home->current).check_variable(lvs(i)); if ( lvs(i)[0] != 'x' ) ERROR( lvs(i) << " is not a basic local variable." ); wordtype wx( &home->configs(home->current), lvs(i) ); if ( !home->show( lvs(i) + "!=0", results ) ) ERROR("I couldn't show that " << lvs(i) << " is nonzero."); home->activate(false); home->set_current( subdivide( home->configs(home->current), wx ) ); } home->configs(home->current).check_secondary_residuals(results); if ( !home->contradiction(false, results) ) ERROR( "Subdivided configuration may be realizable." ); } else { if ( v[0] == 'x' ) { wordtype wt( &c, v ); if ( !home->active->vtable.admissible(wt) ) WARNING( "The basic local variable " << v << " is not admissible. So trying to kill it " << "is pointless." ); home->set_current( subdivide( c, wt ) ); home->configs(home->current). check_secondary_residuals(results); if ( !home->contradiction(false, results) ) ERROR("Subdivided configuration may be realizable."); } else { int w = yno( v ); SLList to_kill = home->active->vtable.has_member_of_weight(w); if ( to_kill.length( ) == 0 ) ERROR( "There are no admissible basic local " << "variables of weight " << dec(w) << "." ); forPixDef( qq, to_kill ) { home->activate(false); Pix pi = subdivide( home->configs(home->current), to_kill(qq) ); home->set_current(pi); if ( !home->contradiction(false, results) ) ERROR( "Subdivided configuration may be " << "realizable." ); home->set_current(curp); // We set individual local variables to zero. It // would be good at the end of the command to go // back and delete these equations, as they become // superfluous once you set the y variable to zero. c.add_constraint( to_kill(qq).variable( ) + "=0", nan); } } } home->set_current(curp); add_con: c.add_constraint( v + "=0", nan ); } next_var: continue; } home->deactivate( ); } HIDE( ![ constraint translate(const config&, const constraint&, const String&, int, int, bool = false); ]! ) TEX( Note that the following code for {\tt incorporate} does not activate any configuration. ) index_command(incorporate) execute_incorporate_command( codehome* home, String label1, String label2, String label3, String sub_var, Pix pix2, Pix pix3, codetable& results, bool gullible ) { if ( home->incorporate_labels.contains(label1) ) ERROR( "You can't use the same label for two incorporate " << "statements within a given code type." ); home->incorporate_labels.append( label1 ); codehome* sub_home = results.open(pix2); if ( sub_home->opt.dual_may_be_code_of_design || sub_home->opt.partition_of_word_by_dual_words || (sub_home->opt.doubly_even_part_is_subcode && !home->opt.doubly_even_part_is_subcode) ) ERROR("Illegal use of type options."); config& c = home->configs(pix3); vector sub_word(sub_var, 0); if ( sub_word.length != c.part.length ) ERROR("Variable sub" << sub_var << " is not compatible with configuration."); Pix p, q; int i, j; if ( sub_word * c.part != sub_home->n ) ERROR("The length of code type " << label2 << " is not compatible with the variable sub" << sub_var << "."); constraint sub_con("sub" + sub_var + ">=" + dec(Ipow(2, sub_home->dim))); if ( !c.known( sub_con ) ) execute_infer_command(home, c, sub_con, results, false); if ( sub_word.weight( ) != 1 ) ERROR("The word " << sub_var << " must have weight one."); if ( !gullible ) { forPix( p, home->ww(pix3) ) { int we = home->ww(pix3)(p); if ( we <= sub_home->n && !sub_home->w.contains(we) ) WARNING( "The weight " << we << " should be in the weight" << " list for " << label2 << "." ); } } forPix( p, sub_home->assumed_cons ) { constraint cn = sub_home->assumed_cons(p); if ( !cn.local( ) ) ERROR( "The assumed constraints of " << label2 << " cannot have joint variables in them." ); if ( c.small.basis.rowspace_member( sub_word ) && cn == constraint( String("y") + dec(sub_home->n) + "=1" ) ) continue; term_sum tx = sub_home->configs(sub_home->base). simplify_global_vars(cn.LHS); constraint cnew( cn.sense, cn.RHS ); forPix( q, tx ) { String va = "x" + sub_var; va.gsub("0", "_0"); va.gsub( "1", String("_") + dec( yno( tx(q).var ) ) ); cnew.addterm( tx(q).coeff, va ); } if ( !c.known( cnew ) ) WARNING( "Since " << cn << " is an assumed constraint for " << label2 << ", " << cnew << " must be known for " << label3 << "." ); } TEX(![ \begin{quote} Merge in the configurations from the subcode. We keep track of the \verb|config_share| objects by constructing a temporary table which contains pairs consisting of a pointer to the old share object and a pointer to a new share object. Similarly, we make such a table for the {\tt config} objects. \end{quote} ]!) int insertion_point = sub_word.find(1); SLList< pair > share_dictionary; Map< Pix, Pix > config_dictionary; forPix( p, sub_home->configs ) { config& cs = sub_home->configs(p); if ( !cs.assumed_cons.local( ) ) ERROR( "The assumed constraints " << " of the configurations of " << label2 << " may not have joint " << "variables in their assumed constraints." ); int new_length = c.part.length + cs.part.length - 1; config cnew; cnew.home = home; cnew.assumed_cons = c.assumed_cons; // Make the new sub variable. String sub_var2 = replicate( "0", insertion_point ) + replicate( "1", cs.part.length ) + replicate( "0", c.part.length - insertion_point - 1 ); TEX( ![ \begin{quotea} If the {\tt share} object associated to {\tt cs} is not already in the share dictionary, create a new {\tt share} object, and add a dictionary entry. \end{quotea} ]! ) forPix( q, share_dictionary ) if ( share_dictionary(q).first == cs.share ) break; if ( q != 0 ) cnew.share = share_dictionary(q).second; else { config_share* cshare = new config_share; cnew.share = cshare; share_dictionary.append( make_pair(cs.share, cshare) ); TEX( ![ \begin{quoteb} Build the new share object. Unrealizability can be copied, but not realizability. \end{quoteb} ]! ) cshare->realizable = (cs.share->realizable == -1) ? -1 : 0; cshare->ww = c.share->ww; cshare->dual_min_low = c.share->dual_min_low; cshare->dual_min_high = c.share->dual_min_high; } TEX(![ \begin{quotea} If the working weightlist for \verb|c.share| has entries which are not in \verb|cs.share|, these are translated into constraints. Then we copy the working weightlist for \verb|cs.share|. \end{quotea} ]!) forPix( q, c.share->ww ) { if ( c.share->ww(q) > sub_home->n ) break; if ( !cs.share->ww.contains( c.share->ww(q) ) ) cnew.con.append( "sub" + sub_var2 + "_" + dec(c.share->ww(q)) + "=0" ); } // Translate dual_min_low and dual_min_high into constraints. for ( i = 1; i < cs.share->dual_min_low; i++ ) cnew.con.append( translate ( cs, String("mu") + dec(i) + "=0", sub_var2, c.part.length, insertion_point ) ); if ( cs.share->dual_min_high != sub_home->n ) { constraint woof( '>', 1 ); for ( i = cs.share->dual_min_low; i <= cs.share->dual_min_high; i++ ) woof.addterm( 1, String("mu") + dec(i) ); cnew.con.append( translate ( cs, woof, sub_var2, c.part.length, insertion_point ) ); } // Translate known constraints in share. forPix( q, cs.share->ycon ) cnew.con.append( translate ( cs, cs.share->ycon(q), sub_var2, c.part.length, insertion_point ) ); // Make the new partition. cnew.part = partition(new_length); cnew.part.n = home->n; for ( i = 0; i < insertion_point; i++ ) cnew.part(i) = c.part(i); for ( i = 0; i < cs.part.length; i++ ) cnew.part( insertion_point + i ) = cs.part(i); for ( i = insertion_point + 1; i < c.part.length; i++ ) cnew.part( cs.part.length + i - 1 ) = c.part(i); // Make the new small basis. cnew.small.basis = matrix( c.small.basis.nrows + cs.small.basis.nrows, new_length ); for ( i = 0; i < c.small.basis.nrows; i++ ) { for ( j = 0; j < insertion_point; j++ ) cnew.small.basis(i, j) = c.small.basis(i, j); for ( j = 0; j < cs.part.length; j++ ) cnew.small.basis(i, insertion_point + j) = c.small.basis(i, insertion_point); for ( j = insertion_point + 1; j < c.part.length; j++ ) cnew.small.basis(i, cs.part.length + j - 1 ) = c.small.basis(i, j); } for ( i = 0; i < cs.small.basis.nrows; i++ ) { for ( j = 0; j < insertion_point; j++ ) cnew.small.basis(i + c.small.basis.nrows, j) = 0; for ( j = 0; j < cs.part.length; j++ ) cnew.small.basis(i + c.small.basis.nrows, insertion_point + j) = cs.small.basis(i, j); for ( j = insertion_point + 1; j < c.part.length; j++ ) cnew.small.basis(i + c.small.basis.nrows, cs.part.length + j - 1 ) = 0; } cnew.small.basis.reduce_nz( ); cnew.leading1s = cnew.small.basis.leading_ones( ); // Make the new dual small basis. // Erasing "= matrix" makes program bomb. cnew.dualsmall.basis = matrix(c.dualsmall.basis.nrows, new_length ); for ( i = 0; i < c.dualsmall.basis.nrows; i++ ) { for ( j = 0; j < insertion_point; j++ ) cnew.dualsmall.basis(i, j) = c.dualsmall.basis(i, j); for ( j = 0; j < cs.part.length; j++ ) cnew.dualsmall.basis(i, insertion_point + j) = c.dualsmall.basis(i, insertion_point); for ( j = insertion_point + 1; j < c.part.length; j++ ) cnew.dualsmall.basis(i, cs.part.length + j - 1 ) = c.dualsmall.basis(i, j); } // Convert dual small basis info into assumed constraints. for ( i = 0; i < cs.dualsmall.basis.nrows; i++ ) { String dual_con[new_length + 1]; dual_con[0] = "q"; for ( j = 1; j <= new_length; j++ ) dual_con[j] = "_z"; for ( j = 0; j < cs.part.length; j++ ) dual_con[insertion_point + j + 1] = String("_") + dec( cs.dualsmall.basis(i,j) ? cs.part(j) : 0 ); String dc; for ( j = 0; j <= new_length; j++ ) dc += dual_con[j]; cnew.assumed_cons.append( constraint( dc + "=" + dec(Ipow(2, sub_home->dim)) )); } // Translate constraints. forPixDef( ppp, cs.assumed_cons ) { cnew.assumed_cons.append( translate( cs, cs.assumed_cons(ppp), sub_var2, c.part.length, insertion_point, true ) ); } forPix( ppp, cs.con ) cnew.con.append( translate( cs, cs.con(ppp), sub_var2, c.part.length, insertion_point ) ); // Translate automorphisms. for ( i = 0; i < cs.aut.length; i++ ) { Permutation per(cnew.part.length); for ( j = 0; j < cs.part.length; j++ ) per( j + insertion_point ) = cs.aut(i)(j) + insertion_point; cnew.aut.append(per); } // Copy automorphism labels. cnew.auto_labels = cs.auto_labels; // Merge the new configuration into the ShareGraph. q = home->configs.vertices.append( cnew ); config_dictionary[p] = q; } TEX( \begin{quote} Translate the configuration labels. \end{quote} ) forPix( p, sub_home->labels ) { String new_label = label1 + "." + sub_home->labels(p).first; new_label.gsub("[", 0); new_label.gsub("]", 0); home->labels.append( make_pair( "[" + new_label + "]", config_dictionary[ sub_home->labels(p).second ] ) ); } TEX( \begin{quote} Translate the {\tt ShareGraph} edges. Add a logical edge from c to the base configuration of the subcode. \end{quote} ) forPix( p, sub_home->configs.edges ) { Pix p1 = sub_home->configs.edges(p).first; config& c1_old = sub_home->configs(p1); Pix p2 = sub_home->configs.edges(p).second; Pix q1 = config_dictionary[p1]; Pix q2 = config_dictionary[p2]; SLList new_edges; config& c1 = home->configs(q1); SLList& wl = sub_home->configs.edges.take(p); forPixDef( pp, wl ) { // Make constructive edge. wordtype w(&c1); for ( int jj = 0; jj < c1_old.part.length; jj++ ) w(insertion_point + jj) = wl(pp)(jj); new_edges.append(w); } home->configs.edges[ make_pair( q1, q2 ) ] = new_edges; } home->configs.join( pix3, config_dictionary[ sub_home->base ] ); TEX( \begin{quote} Translate the {\tt implications} and {\tt disjoint} members of the subcode. \end{quote} ) forPix( p, sub_home->implications ) { pair< Pix, SLList > imp = sub_home->implications(p); imp.first = config_dictionary[ imp.first ]; forPixDef( pp, imp.second ) imp.second(pp) = config_dictionary[ imp.second(pp) ]; home->implications.append( imp ); } forPix( p, sub_home->disjoint ) { pair< Pix, Pix > dis = sub_home->disjoint(p); dis.first = config_dictionary[ dis.first ]; dis.second = config_dictionary[ dis.second ]; home->disjoint.append(dis); } } index_command(deduce) void execute_deduce( codehome* home, String& mlabel, prevector& labels, bool gullible, const codetable& results, bool finish ) { Pix pixes[labels.length]; int i, j; for ( i = 0; i < labels.length; i++ ) pixes[i] = home->label_to_Pix(labels(i), results); Pix mpix = home->label_to_Pix(mlabel, results); if (!gullible) { Pix p, q, r; SLList cs = home->configs.sharelist( ); state_list st; TEX( \begin{quotea} Verify that ${\cal R}(m) \IN {\cal R}(\ell_1) \manycup {\cal R}(\ell_r)$. \end{quotea} ) forPix( q, cs ) st[ cs(q) ] = (cs(q)->realizable == -1); for ( i = 0; i < labels.length; i++ ) st[ home->configs(pixes[i]).share ] = true; SLList< multiedge > ml = home->convert_implications( ); st.propagate(ml); if ( !st[ home->configs(mpix).share ] ) { if ( labels.length != 0 ) ERROR( "I don't know that the realization of " << mlabel << " is contained in the union of the realizations of " << "the other given configurations." ) else ERROR( "I don't know that " << mlabel << " is unrealizable." ); } TEX( \begin{quotea} Verify that ${\cal R}(\ell_i) \IN {\cal R}(m)$ for each $i$. \end{quotea} ) state_list< config_share* > sti; for ( i = 0; i < labels.length; i++ ) { forPix( q, cs ) sti[ cs(q) ] = false; sti[home->configs(mpix).share] = true; sti.propagate(ml); if ( !sti[ home->configs(pixes[i]).share ] ) { config& cm = home->configs(mpix); config& cl = home->configs( pixes[i] ); if ( cm.basal( ) && cl.small.basis.nrows == home->dim ) { vector y = cl.small.basis.enumerate_weights( ); forPix( p, cm.assumed_cons ) if ( !home->check( cm.assumed_cons(p), y, cm ) ) break; if (p == 0) continue; } ERROR( "I don't know that " << labels(i) << " implies " << mlabel << "." ); } } } if (finish) { if ( labels.length == 0 ) home->set_unrealizable(mpix); if ( labels.length == 1 ) home->configs.join( mpix, pixes[0] ); home->set_current(0); } } HIDE( ![ int String_cmp(const String&, const String&); ]! ) index_command(via lp) void execute_via_lp_command( codehome* home, String label1, bool gullible, codetable& results, bool joint ) { Pix q = home->label_to_Pix(label1, results); if (!gullible) { home->set_current(q); TEX(![ \begin{quotea} Find all known simple constraints, i.e.\ those constraints whose \LHS\ is a variable. Try to get a contradiction from these, together with the constraints implied by the working weightlist. \end{quotea} ]!) constraintlist c = home->configs(home->current).known_cons( ); constraintlist c_simple; forPixDef( p, c ) if ( c(p).simple( ) ) c_simple.append( c(p) ); OSLList vars; forPix( p, c_simple ) vars.add( c_simple(p).LHS.front( ).var ); forPix( p, vars ) { Integer low = 0, high = -1; c_simple.evaluate( vars(p), low, high ); if ( high != -1 && high < low ) break; if ( low > 0 && vars(p)[0] == 'y' ) if ( !home->ww(q).contains( yno( vars(p) ) ) ) break; } if ( p == 0 ) { if ( (joint && !joint_infeasible(*home, results)) || (!joint && !home->contradiction(false, results)) ) { WARNING("Contradiction failed."); return; } } } home->set_unrealizable(q); home->set_current( 0 ); } TEX( ![ \verb|process_config_target_list|:\ Given a list of configuration labels, sort the corresponding configurations according to whether they are basal, terminal, or neither. For those that are terminal, compute the weight enumerator. Also compute the list of pixes corresponding to the configurations. ]! ) index_method(process_config_target_list) void process_config_target_list( codehome* home, prevector labels, SLList< pair< config, vector > >& terminals, SLList& basals, SLList& others, SLList& pixlist, bool gullible, const codetable& results ) { int i; Pix pixes[labels.length]; for ( i = 0; i < labels.length; i++ ) { pixes[i] = home->label_to_Pix(labels(i), results); pixlist.append( pixes[i] ); } if (!gullible) { for ( i = 0; i < labels.length; i++ ) { config& ci = home->configs( pixes[i] ); if ( ci.basal( ) ) basals.append(ci); else if ( ci.terminal( ) ) { vector y = ci.smallcode_we( ); if ( !home->check_globals( ci.assumed_cons, y, ci ) ) ERROR( "An assumed constraint of " << labels(i) << " fails for it." ); terminals.append( make_pair( ci, y ) ); } else others.append(ci); } } } index_method(check_config_list) bool check_config_list( codehome* home, const matrix& ext, const SLList< pair< config, vector > >& terminals, const SLList& basals, const SLList& others ) { int i; Pix p, q, r; vector we = ext.enumerate_weights( ); TEX( \begin{quote} First look for matches with basal configurations. \end{quote} ) forPix( q, basals ) { const constraintlist& ac = basals(q).assumed_cons; if ( home->check_globals( ac, we, home->configs(home->current) ) ) return true; } TEX( \begin{quote} Now look for matches with terminal configurations. \end{quote} ) config_core ci; ci.part.set_all_ones(home->n); ci.smallbasis = ext; ci.dualsmallbasis.set_size(0, home->n); forPix( q, terminals ) if ( we == terminals(q).second ) if ( home->isomorphic( config_core(terminals(q).first), ci, true ) ) return true; TEX( \begin{quote} Now look for matches with configurations which are neither basal nor terminal. \end{quote} ) forPix( r, others ) { if (!home->check_globals(others(r).known_cons( ), we, others(r))) continue; // Make a terminal configuration. (This is silly. We should modify // configuration_search to take a matrix for its first argument.) config c1; c1.home = home; c1.part.set_all_ones(home->n); c1.small.basis = ext; c1.dualsmall.basis.set_size(0, home->n); c1.share = 0; // Don't use! if ( configuration_search( c1, others(r) ) ) return true; } return false; } index_command(via extension) void execute_via_extension( codehome* home, String label1, prevector labels, bool alternate_extension_method, bool gullible, codetable& results, String pound_label_head, int& pound_label_ctr ) { bool fail_flag = false; SLList basals, others; SLList< pair< config, vector > > terminals; SLList pixlist; process_config_target_list( home, labels, terminals, basals, others, pixlist, gullible, results ); Pix pix1 = home->label_to_Pix( label1, results ); if (!gullible) { home->set_current( pix1 ); if ( !home->configs(home->current).no_bad_weights( ) ) { cerr << "Configuration " << label1 << " has a word of " << "a weight which we know can't occur.\n"; home->set_unrealizable(pix1); home->set_current(0); return; } bool enumerators_only = false; if ( terminals.length( ) == 0 && others.length( ) == 0 && pound_label_head == "" ) { if ( !(basals.length( ) == 1 && basals.front( ).assumed_cons.length( ) == 0) ) enumerators_only = true; } SLList< matrix > ext0= home->list_extensions(alternate_extension_method, enumerators_only, results); prevector< matrix > ext(ext0); int pound_label_ctr_first = pound_label_ctr; for ( int i = 0; i < ext.length; i++ ) if (check_config_list( home, ext(i), terminals, basals, others )) cerr << "Extension " << i + 1 << " of " << ext.length << " found.\n"; else if ( pound_label_head != "" ) { int k; for ( k = 1; k < pound_label_ctr_first; k++ ) { String pound_labelk = pound_label_head + dec(k) + "]"; Pix p = home->label_to_Pix(pound_labelk, results); if ( isomorphic(ext(i), home->configs(p).small.basis) ) { cerr << "Extension " << i + 1 << " of " << ext.length << " found.\n"; break; } } if ( k == pound_label_ctr_first ) { String pound_label = pound_label_head + dec(pound_label_ctr++) + "]"; cerr << "creating " << pound_label << " terminal " << ext(i) << ";\n"; config c( home, ext(i) ); if ( auto_group_computation ) { pair< Permutationlist, Integer > pp = c.find_automorphism_group( ); c.aut = pp.first; } Pix j = home->merge_config(c); pixlist.append(j); home->labels.append( make_pair(pound_label, j) ); } } else { fail_flag = true; WARNING( "Extension " << i + 1 << " of " << ext.length << " NOT found. It has weight enumerator " << as_poly(ext(i).enumerate_weights( )) ); } } if (!fail_flag) home->implications.append( make_pair(pix1, pixlist) ); home->set_current(0); } index_command(dump) void execute_dump( codehome* home ) { SLList shares = home->configs.sharelist( ); DLList& configs = home->configs.vertices; int share_count = 1, unlabelled_config_count = 1; Map< Pix, String > lab; cerr << "\nDump of all configurations associated to the " << "current code type. Unlabelled configurations are given" << " temporary labels of the form [$n], n = 1,2,... .\n\n"; forPixDef( p, shares ) { cerr << "Configuration equivalence class " << share_count++ << ":\n\n"; forPixDef( q, configs ) if ( configs(q).share == shares(p) ) { // Make a label for the configuration. forPixDef( r, home->labels ) if ( q == home->labels(r).second ) break; if ( r != 0 ) lab[q] = home->labels(r).first; else lab[q] = String("[$") + dec(unlabelled_config_count++) + "]"; cerr << " " << lab[q] << "\n" << configs(q) << "\n"; } } cerr << "Implications:\n"; forPix( p, home->implications ) { pair< Pix, SLList >& imp = home->implications(p); cerr << " " << lab[imp.first] << " |-> "; forPixDef( q, imp.second ) { if ( q != imp.second.first( ) ) cerr << " or "; cerr << lab[imp.second(q)]; } cerr << ";\n"; } cerr << "\n"; } HIDE( ![ template void sort_by_second( prevector< pair >& ); ]! ) index_command(try to kill) void execute_try_to_kill_current( codehome* home, codetable& results ) { if ( home->current == 0 ) ERROR("The current configuration is undefined."); config& c = home->configs(home->current); home->activate(true); if ( c.assumed_cons.global( ) ) { pair< Permutationlist, Integer > pp = c.find_automorphism_group( ); c.aut = pp.first; } EquivRelIntList e = home->active->auto_equiv( ); int i, class_count = 0; prevector< pair< wordtype, int > > blv( e.orbit_count( ) - 1 ); mawhometable& vt = home->active->vtable; for ( i = 1; i < e.length; i++ ) if ( e.minimal(i) ) blv(class_count++).first = vt(i).maw; Pix curp = home->current; cerr << "There are " << blv.length << " variables that I'll try to kill.\n"; for ( i = 0; i < blv.length; i++ ) { home->set_current( subdivide ( home->configs(home->current), blv(i).first ) ); home->activate(true); blv(i).second = home->active->vtable.length; home->set_current(curp); home->activate(true); } sort_by_second(blv); ofstream to_kill( "calculations/to_kill" ); for ( i = 0; i < blv.length; i++ ) to_kill << "will try to kill " << blv(i).first.variable( ) << " (" << blv(i).second << " variables)\n"; to_kill.close( ); cerr << "A list of the variables to be killed may be found in " << "\"calculations/to_kill\".\n"; for ( i = 0; i < blv.length; i++ ) { cerr << "trying to kill " << blv(i).first.variable( ); home->set_current( subdivide ( home->configs(home->current), blv(i).first ) ); home->configs(home->current).check_secondary_residuals(results); home->activate(true); cerr << " (" << home->active->vtable.length << " variables)... "; if ( home->contradiction(true, results) ) { cerr << "done\n"; bool nan; home->set_current(curp); home->configs(curp).add_constraint( blv(i).first.variable( ) + "=0", nan ); if ( home->contradiction(true, results) ) { cerr << "split linear programming kills [current]\n"; home->set_unrealizable(curp); home->set_current(0); return; } } else { cerr << "failed\n"; home->set_current(curp); home->activate(true); } } } index_command(disjoint) void execute_disjoint( codehome* home, prevector labels, bool gullible, const codetable& results ) { Pix pixes[labels.length]; int i, j, k, l; for ( i = 0; i < labels.length; i++ ) pixes[i] = home->label_to_Pix(labels(i), results); for ( i = 0; i < labels.length; i++ ) for ( j = i+1; j < labels.length; j++ ) { constraintlist l1, l2; Pix p, q; config *c1, *c2; if (gullible) goto disjoint_yes; l1 = home->configs(pixes[i]).assumed_cons; l1.merge(home->configs(pixes[i]).share->ycon); l2 = home->configs(pixes[j]).assumed_cons; l2.merge(home->configs(pixes[j]).share->ycon); forPix( p, l1 ) forPix( q, l2 ) if ( l1(p).simple( ) && l2(q).simple( ) && l1(p).LHS.front( ).var == l2(q).LHS.front( ).var ) { if ( l1(p).sense != '<' && l2(q).sense != '>' && l2(q).RHS < l1(p).RHS ) goto disjoint_yes; if ( l1(p).sense != '>' && l2(q).sense != '<' && l1(p).RHS < l2(q).RHS ) goto disjoint_yes; } c1 = &(home->configs(pixes[i])); c2 = &(home->configs(pixes[j])); if ( home->configs(pixes[i]).terminal( ) ); else if ( home->configs(pixes[j]).terminal( ) ) swap( c1, c2 ); else goto disjoint_no; if ( c1->terminal( ) && c2->terminal( ) ) { if ( !home->isomorphic(*c1,*c2,true) ) goto disjoint_yes; WARNING( "The terminal configurations " << labels(i) << " and " << labels(j) << " are isomorphic." ); continue; } if ( !configuration_search(*c1, *c2) ) goto disjoint_yes; disjoint_no: WARNING("The realizations of configurations " << labels(i) << " and " << labels(j) << " may not be disjoint."); continue; disjoint_yes: home->disjoint.append( make_pair( pixes[i], pixes[j] ) ); } home->set_current(0); } index_command(via weight enumerator) void execute_via_weight_enumerator( codehome* home, String label1, String label2, Pix pix1, Pix pix2, bool gullible ) { if (!gullible) { config& c1 = home->configs(pix1); config& c2 = home->configs(pix2); if ( !c1.terminal( ) ) ERROR(label1 << " is not terminal."); if ( !c2.basal( ) ) ERROR( label2 << " is not basal." ); if ( !home->check_globals( c2.assumed_cons, c1.smallcode_we( ), c2 ) ) ERROR( "An assumed constraint of " << label1 << " is not satisfied by " << label2 << "." ); } home->implications.append(make_pair(pix1, make_list(pix2) )); home->set_current(0); } index_command(via constraint drop) void execute_via_constraint_drop( codehome* home, String label1, String label2, Pix pix1, Pix pix2, bool gullible, codetable& results ) { config& c1 = home->configs(pix1); config& c2 = home->configs(pix2); if (!gullible) { if ( !mostly_equal(c1,c2) ) ERROR("The two configurations can differ only " << "in their assumed constraints."); forPixDef( i, c2.assumed_cons ) if ( !c1.known(c2.assumed_cons(i)) ) ERROR("Assumed constraint " << c2.assumed_cons(i) << " of " << label2 << " is not known for " << label1 << "." ); constraintlist& as = c1.assumed_cons; constraintlist to_prove; forPixDef( p, as ) if ( !c2.assumed_cons.known( as(p) ) ) to_prove.append( as(p) ); if ( c1.terminal( ) ) { if ( !home->check_globals( to_prove, c1.smallcode_we( ), c1 ) ) ERROR( "Nope, I can't drop those constraints." ); } else { home->set_current(pix2); if ( !to_prove.length != 0 && !home->show( to_prove, results ) ) ERROR("Show failed."); } } home->configs.join( pix1, pix2 ); home->set_current(0); } index_command(up to isomorphism show) void execute_up_to_isomorphism_show( codehome* home, String vr, bool gullible, codetable& results ) { if ( home->current == 0 ) ERROR("The current configuration is undefined."); config& cur = home->configs(home->current); cur.check_variable(vr); if ( vr[0] != 'x' ) ERROR(vr << " is not a basic local variable."); home->activate(false); wordtype w(&cur, vr); int vno = home->active->vtable.mfind(w); if ( vno == -1 ) ERROR("The basic local variable " << vr << " is not admissible."); if (!gullible) { pair< Permutationlist, Integer > pp = cur.find_automorphism_group( ); cur.aut = pp.first; EquivRelIntList e = home->active->auto_equiv( ); if ( cur.small.basis.nrows == home->dim || e.orbit_count( ) != 2 || e.equiv(vno, 0) ) { constraint con( '>', 1 ); con.addterm( 1, home->active->vtable(vno).maw.variable( ) ); int vnoe = vno; while( (vnoe = e(vnoe)) != vno ) con.addterm( 1, home->active->vtable(vnoe).maw.variable() ); constraintlist clist; clist.append(con); if ( !home->show( clist, results ) ) ERROR( "Show failed." ); } } home->configs.join( home->current, subdivide( home->configs(home->current), w ) ); } index_command(via variable split) void execute_via_variable_split( codehome* home, String label0, prevector labels, bool gullible, const codetable& results ) { prevector pixes(labels.length); int i, j; Pix p, q; for ( i = 0; i < labels.length; i++ ) pixes(i) = home->label_to_Pix( labels(i), results ); Pix pix0 = home->label_to_Pix( label0, results ); if (!gullible) { config& c0 = home->configs(pix0); for ( j = 0; j < labels.length; j++ ) if ( !mostly_equal( c0, home->configs( pixes(j) ) ) ) ERROR( "The configurations may differ only in" << " their assumed constraints." ); constraintlist as0 = c0.assumed_cons, as[ labels.length ]; for ( i = 0; i < labels.length; i++ ) { as[i] = home->configs( pixes(i) ).assumed_cons; forPix( p, as0 ) { forPix( q, as[i] ) { if ( as0(p) == as[i](q) ) { as[i].del(q); goto found_it; } } ERROR( "The constraint " << as0(p) << " is assumed for " << label0 << ", but not for " << labels(i) << "." ); found_it: continue; } } OSLList vars; for ( i = 0; i < labels.length; i++ ) forPix( q, as[i] ) { if ( !as[i](q).simple( ) ) ERROR( "The constraint " << as[i](q) << " is not simple." ); vars.add( as[i](q).LHS.front( ).var ); } prevector varsv(vars); TEX( \begin{quotea} Determine all values which occur as the \RHS\ of a constraint whose \LHS\ is a variable in {\tt varsv}. Then add a phantom value between each pair of values. \end{quotea} ) OSLList values0[varsv.length]; for ( i = 0; i < labels.length; i++ ) forPix( q, as[i] ) { String v = as[i](q).LHS.front( ).var; values0[ varsv.find(v) ].add( as[i](q).RHS ); } OSLList values[varsv.length]; for ( i = 0; i < varsv.length; i++ ) { values[i].add(0); Pix prev = 0; forPix( q, values0[i] ) { values[i].add( values0[i](q) ); if ( prev != 0 ) values[i].add((values0[i](prev) + values0[i](q)) / 2); prev = q; } values[i].add( values0[i](prev) + 1 ); } TEX(![ \begin{quotea} Cycle through each possible assignment of values to variables, using only values from the lists {\tt values}. \end{quotea} ]!) prevector vp(varsv.length); for ( i = 0; i < vp.length; i++ ) vp(i) = values[i].first( ); do { for ( i = 0; i < labels.length; i++ ) { forPix( q, as[i] ) { String v = as[i](q).LHS.front( ).var; j = varsv.find(v); TEX( ![ \begin{quoted} Break if the constraint {\tt as[i](q)} is not satisfied when {\tt values[j]( vp(j) )} is substituted in for {\tt v}. \end{quoted} ]! ) if ( !test( values[j](vp(j)), as[i](q).RHS, as[i](q).sense ) ) break; } if ( q == 0 ) break; } if ( i == labels.length ) ERROR( "Command fails." ); // Advance the pix vector. for ( i = vp.length - 1; i >= 0; i-- ) { values[i].next( vp(i) ); if ( vp(i) == 0 ) vp(i) = values[i].first( ); else break; } } while( i >= 0 ); } home->implications.append( make_pair( pix0, make_listv(pixes) ) ); for ( i = 0; i < labels.length; i++ ) home->implications.append( make_pair( pixes(i), make_list(pix0) ) ); } index_command(implies) void execute_implies( codehome* home, String label1, String label2, Pix pix1, Pix pix2, bool gullible ) { config& c1 = home->configs(pix1); config& c2 = home->configs(pix2); if (gullible) goto implies_ok; if ( !(c2.part.length == 1 && c2.small.basis.nrows == 0 && c2.dualsmall.basis.nrows == 0) && !mostly_equal(c1, c2) ) ERROR("The partitions, small bases, or dual small " << "bases do not satisfy the requirements of this command."); forPixDef( i, c2.assumed_cons ) if ( !c1.known(c2.assumed_cons(i)) ) ERROR( "Assumed constraint " << c2.assumed_cons(i) << " of " << label2 << " is not known for " << label1 << "." ); implies_ok: home->implications.append(make_pair(pix1, make_list(pix2) )); home->set_current(0); } index_command(kill current by) void execute_kill_current_by( codehome* home, prevector vars, bool gullible, codetable& results ) { if ( home->current == 0 ) ERROR("The current configuration is undefined."); Pix curp = home->current; if (!gullible) { for ( int i = 0; i < vars.length; i++ ) { home->configs(home->current).check_variable( vars(i) ); if ( vars(i)[0] != 'x' ) ERROR( vars(i) << " is not a basic local variable." ); wordtype wt(&(home->configs(home->current)), vars(i)); if ( !home->show( vars(i) + "!=0", results ) ) ERROR("I couldn't show that " << vars(i) << " is nonzero."); home->activate(false); home->set_current( subdivide( home->configs(home->current), wt ) ); } if ( !home->contradiction(false, results) ) ERROR( "Subdivided configuration may be realizable." ); } home->set_unrealizable(curp); home->set_current(0); } index_command(=) void execute_equals( codehome* home, Pix pix1, Pix pix2, bool gullible ) { if (!gullible) { config* c1 = &(home->configs(pix1)); config* c2 = &(home->configs(pix2)); constraintlist ac1(c1->assumed_cons), ac2(c2->assumed_cons); constraint ex; Pix p; // Test for refinement. int c2part_ptr_first, c2part_ptr_last = 0; matrix c2small = c2->small.basis; matrix c2dualsmall = c2->dualsmall.basis; if ( c1->small.basis.nrows != c2->small.basis.nrows || c1->dualsmall.basis.nrows != c2->dualsmall.basis.nrows ) goto phase2; int i, j, k; for ( i = 0; i < c1->part.length; i++ ) { int to_fill = c1->part(i); c2part_ptr_first = c2part_ptr_last; while ( to_fill > 0 ) { if ( c2part_ptr_last > c2->part.length - 1 ) goto phase2; to_fill -= c2->part(c2part_ptr_last++); } if ( to_fill < 0 ) goto phase2; for ( k = c2part_ptr_first; k < c2part_ptr_last; k++ ) for ( j = 0; j < c1->small.basis.nrows; j++ ) c2small(j,k) = c1->small.basis(j,i); for ( j = 0; j < c1->dualsmall.basis.nrows; j++ ) c2dualsmall(j,k) = c1->dualsmall.basis(j,i); } c2small.reduce( ); if ( c2small != c2->small.basis ) goto phase2; c2dualsmall.reduce( ); if ( c2dualsmall != c2->dualsmall.basis ) goto phase2; if ( c2->terminal( ) && c2->share->realizable == 1 ) { if ( !(ac1 <= ac2) ) goto phase2; } else if ( !(ac1 == ac2) ) goto phase2; goto finish; phase2: // Test for realizable full case. matrix M1 = c1->basic_small( ); matrix M2 = c2->basic_small( ); if ( c1->share->realizable != 1 || c2->share->realizable != 1 ) goto phase3; if ( c1->small.basis.nrows != home->dim ) goto phase3; if ( c2->small.basis.nrows != home->dim ) goto phase3; if ( isomorphic( M1, M2 ) ) goto finish; phase3: if ( c1->small.basis.nrows == 1 && c1->small.basis.ncols == 1 ) swap( c1, c2 ); if ( c1->small.basis.nrows == 0 && c1->dualsmall.basis.nrows == 0 && c2->small.basis.nrows == 1 && c2->small.basis.ncols == 1 && c2->dualsmall.basis.nrows == 0 ) ex = String("y") + dec( home-> n ) + "=1"; else { if ( c1->small.basis.nrows != 0 || c1->dualsmall.basis.nrows != 0 || c2->part.length != 2 ) swap( c1, c2 ); if ( c1->small.basis.nrows != 0 || c1->dualsmall.basis.nrows != 0 || c2->part.length != 2 ) goto oops; if ( c2->small.basis.nrows == 0 && c2->dualsmall.basis == matrix( 2, "{01}" ) ) ex = String("mu") + dec( c2->part(1).x ) + "!=0"; else if ( c2->dualsmall.basis.nrows == 0 && c2->small.basis == matrix( 2, "{10}" ) ) ex = String("y") + dec( c2->part(0).x ) + "!=0"; else goto oops; } if ( !ac1.joint( ) || !ac2.joint( ) ) goto oops; ac2.append( ex ); forPix( p, ac2 ) if ( !c1->known( ac2(p) ) ) goto oops; forPix( p, ac1 ) if ( !c2->known( ac1(p) ) && ac1(p) != ex ) goto oops; } finish: home->configs.join( pix1, pix2 ); home->set_current(0); return; oops: ERROR( "Configurations do not match the requirements for =." ); } index_command(via dual word) void execute_via_dual_word( codehome* home, String label2, Pix pix2, bool gullible ) { config& c = home->configs(pix2); if (!gullible) { if ( c.small.basis.nrows != 0 || c.dualsmall.basis.nrows != 0 || c.part.length != 2 || c.assumed_cons.length( ) != 1 ) ERROR( label2 << " is not of the right sort." ); int r = c.part(1); if ( c.share->dual_min_high > r ) ERROR( "I don't known that there is a dual word of " << "weight <= " << r << "." ); if ( r > home->dim + 1 || c.assumed_cons.front( ) != constraint( String("sub10=") + dec(Ipow(2, home->dim-r+1)) ) ) ERROR( label2 << " is not of the correct sort." ); } home->implications.append( make_pair( home->base, make_list(pix2) ) ); home->set_current(0); } index_command(via configuration search) void execute_via_configuration_search( codehome* home, String label1, String label2, Pix pix1, Pix pix2, bool gullible ) { config& c1 = home->configs(pix1); config& c2 = home->configs(pix2); if ( gullible ) goto via_configuration_search_ok; if (!c1.terminal( )) ERROR(label1 << " is not a terminal configuration."); if ( c2.dualsmall.basis.nrows != 0 ) ERROR( "Configuration " << label2 << " must have zero dual small code." ); forPixDef( p, c2.assumed_cons ) if ( !c1.known( c2.assumed_cons(p) ) ) ERROR( "The constraint " << c2.assumed_cons(p) << " is assumed for " << label2 << " but not known " << "for " << label2 << "." ); if ( !configuration_search( c1, c2 ) ) ERROR( "Search failed." ); via_configuration_search_ok: home->implications.append( make_pair( pix1, make_list(pix2) ) ); } index_command(load constraints by parity check from) void execute_load_constraints( codehome* home, codetable& results, String cd, Pix p ) { if ( home->current != home->base ) ERROR("Current configuration must be base."); if ( !home->assumed_cons.empty( ) ) ERROR("Current code type may have no assumed constraints."); codehome* r = results.open(p); if ( !r->assumed_cons.empty( ) ) ERROR("The code type " << cd << " may have no assumed constraints."); if ( home->dim != r->dim ) ERROR("Dimensions wrong."); if ( home->n != r->n - 1 ) ERROR("Code lengths wrong."); weightlist& w = home->ww(home->base); forPixDef( pp, w ) { int wp = w(pp) + odd( w(pp) ); if ( !r->w.contains(wp) ) ERROR("Weight " << wp << " is missing from the " << "assumed weight list for " << cd << "."); } bool new_active_needed = false; for ( int i = 2; i <= r->n; i += 2 ) if ( !r->ww(r->base).contains(i) ) { w.del(i); w.del(i-1); new_active_needed = true; } constraintlist& c = r->configs(r->base).share->ycon; forPix( p, c ) { constraint cp_new( c(p).sense, c(p).RHS ); term_sum ts = r->configs(r->base).simplify_global_vars( c(p).LHS ); forPixDef( q, ts ) { term t = ts(q); int var_no = yno( t.var ); if ( even(var_no) ) { if ( var_no != r->n ) cp_new.LHS.append(t); if ( var_no != 0 ) { t.var = String("y") + dec(var_no - 1); cp_new.LHS.append(t); } } } home->configs(home->base).add_constraint(cp_new, new_active_needed); } if (new_active_needed) home->deactivate( ); } index_command(projection onto) void execute_projection_onto( codehome* home, word wd, String cd, Pix p, codetable& results, bool gullible, int status ) { if ( home->current == 0 ) ERROR("The current configuration is undefined."); config& c = home->configs(home->current); if ( wd.length != c.part.length ) ERROR( "The word " << wd << " does not have the right length." ); word wdp = wd.complement( ); Integer low = 0, high = -1, log_low, log_high; c.evaluate( "sub" + String(wdp), low, high ); if ( low != high ) ERROR( "The value of the variable sub" << wdp << " must be known." ); log2( low, log_low, log_high ); if ( log_low != log_high ) ERROR( "The value of the variable sub" << wdp << " is not a power of 2, so [current] is unrealizable."); codebase* r0; codehome* r; // Why are we allowing projection onto a dead code type?? if ( status == 0 ) r0 = r = results.open(p); else r0 = &(results.dead(p)); if ( r0->n != wd * c.part ) ERROR( "The length of codetype " << cd << " is wrong." ); if ( r0->dim != home->dim - log_low ) ERROR( "The dimension of codetype " << cd << " is wrong." ); if ( !r0->assumed_cons.empty( ) ) ERROR( "The codetype " << cd << " can't have assumed constraints." ); home->activate(false); mawhometable& vt = home->active->vtable; wordtype wt(&c), wtm(&c); vt.first(wt); term_sum tr[r0->n + 1]; int s; bool new_active_needed = false; do { s = wd * wt; if ( !r0->w.contains(s) ) ERROR( "The codetype " << cd << " should have " << s << " in its assumed weightlist, but it doesn't." ); if ( status == 0 ) { if ( r->ww(r->base).contains(s) ) { wtm = wt; c.make_minimal(wtm); tr[s].merge( term( 1, wtm.variable( ) ) ); } else c.add_constraint( wt.variable( ) + "=0", new_active_needed ); } } while( vt.advance(wt) ); if ( status == -1 ) { home->set_unrealizable(home->current); return; } constraintlist& cl = r->configs(r->base).share->ycon; forPixDef( q, cl ) { if ( !cl(q).global( ) ) continue; constraint cnew( cl(q).sense, cl(q).RHS * low ); term_sum ts = r->configs(r->base).simplify_global_vars( cl(q).LHS ); forPixDef( t, ts ) { term_sum tr2 = tr[ yno( ts(t).var ) ]; forPixDef( xxx, tr2 ) tr2(xxx).coeff *= ts(t).coeff; cnew.adjoin(tr2); } c.add_constraint(cnew, new_active_needed); } if (new_active_needed) home->deactivate( ); } index_command(infer by residual code) void execute_infer_by_residual_code( codehome* home, String cd, Pix op, constraintlist l, codetable& results, bool gullible ) { if ( home->current == 0 ) ERROR("The current configuration is undefined."); forPixDef( p, l ) if ( !( l(p).simple_local_zero( ) ) ) ERROR( "The constraint " << l(p) << " is not of the correct type." ); config& cur = home->configs(home->current); if (!gullible) { home->activate(false); codehome* res = results.open(op); if ( res->dim != home->dim - 1 ) ERROR( "The dimension of code type " << cd << " should be " << home->dim - 1 << "." ); if ( !res->assumed_cons.empty( ) ) ERROR( cd << " may not have assumed constraints." ); int d = cur.share->ww.min( ), wt = home->n - res->n; for ( int i = d - wt/2; i <= res->n; i++ ) if ( !res->w.contains(i) ) ERROR( "The assumed weight list of " << cd << " must include all weights between " << d - wt/2 << " and " << res->n << "." ); forPix( p, l ) { String var = l(p).LHS.front( ).var; wordtype w(&cur, var); if ( w.length != cur.part.length ) ERROR( var << " is not a basic local variable " << "for the current configuration." ); if ( sum(w) != wt || sum(w) >= 2 * d ) ERROR( "The weight of " << var << " is wrong." ); weightlist& ww = res->ww(res->base); cur.small.build( ); int j; for ( j = 0; j < cur.small.x.nrows; j++ ) { word& wd = cur.small.x(j); int residue = 0; for ( int k = 0; k < wd.length; k++ ) if ( wd(k) ) residue += cur.part(k) - w(k); if ( !ww.contains(residue) ) break; } if ( j == cur.small.x.nrows ) ERROR( "I can't show that " << l(p) << "." ); } } bool new_active_needed; forPix( p, l ) cur.add_constraint( l(p), new_active_needed ); home->deactivate( ); } index_method(dual_of_we) vector dual_of_we( vector we ) { int i, j, n = we.length - 1; vector dwe(n+1); dwe.set_zero( ); Integer total = 0, sum; for ( i = 0; i <= n; i++ ) { total += we(i); for ( int l = 0; l <= n; l++ ) { sum = 0; for ( j = 0; j <= i; j++ ) if ( j <= l && l - j <= n - i ) sum += minus1_to_the(j) * choose( i, j ) * choose( n - i, l - j ); dwe(l) += sum * we(i); } } for ( i = 0; i <= n; i++ ) dwe(i) /= total; return dwe; } index_command(realizable) void execute_realizable( codehome* home, prevector labels, bool gullible, const codetable& results ) { Pix pixes[labels.length]; for ( int i = 0; i < labels.length; i++ ) { pixes[i] = home->label_to_Pix(labels(i), results); config& c = home->configs(pixes[i]); if ( !c.terminal( ) ) ERROR(labels(i) << " is not a terminal configuration."); if ( !gullible && c.share->realizable != -1 ) { vector y = c.smallcode_we( ); for ( int j = 0; j <= home->n; j++ ) if ( y(j) != 0 && !home->w.contains(j) ) WARNING( "A word of weight " << j << " occurs in configuration " << labels(i) << "." ); constraintlist as = home->assumed_cons; as.merge( c.assumed_cons ); if ( !home->check_globals( as, y, c ) ) ERROR( "An assumed constraint fails for " << labels(i) << "." ); if ( !home->options_satisfied(c) ) WARNING( "Options are not satisfied for configuration " << labels(i) << "." ); for ( int j = 0; j <= home->n; j++ ) if ( y(j) != 0 && !home->ww(home->base).contains(j) ) INTERNAL_ERROR( "The code just defined has a word " << "of weight " << j << ", which I know is " << "impossible. So either you have discovered " << "an error in Split, or else some command " << "preceding this command has been executed in " "gullible mode, and it would fail otherwise." ); } c.share->realizable = 1; home->configs(home->base).share->realizable = 1; if ( !c.assumed_cons.empty( ) ) { forPixDef( q, home->configs ) { config& d = home->configs(q); if (mostly_equal(c, d) && d.assumed_cons <= c.assumed_cons) home->configs.join( pixes[i], q ); } } } home->set_current(0); } index_command(classification of) void execute_classification_of( codehome* home, String& mlabel, prevector& labels, bool gullible, const codetable& results ) { execute_deduce( home, mlabel, labels, gullible, results, false ); Pix pixes[labels.length]; int i, j; Pix p, q, r; for ( i = 0; i < labels.length; i++ ) pixes[i] = home->label_to_Pix(labels(i), results); Pix mpix = home->label_to_Pix(mlabel, results); if (!gullible) { SLList cs = home->configs.sharelist( ); state_list st, st_old, st_unreal, st_real; SLList< multiedge > ml = home->convert_implications( ); TEX( \begin{quotea} Determine which configuration equivalence classes are known to be unrealizable. \end{quotea} ) forPix( q, cs ) st_unreal[ cs(q) ] = (cs(q)->realizable == -1); st_unreal.propagate(ml); SLList< multiedge > ml_clean; forPix( q, ml ) { if ( st_unreal[ ml(q).first ] ) continue; multiedge m; m.first = ml(q).first; forPixDef( r, ml(q).second ) if ( !st_unreal[ ml(q).second(r) ] ) m.second.add( ml(q).second(r) ); ml_clean.append(m); } TEX(![ \begin{quotea} Verify that ${\cal R}(\ell_1), \ldots, {\cal R}(\ell_r)$ are all realizable. \end{quotea} ]!) forPix( q, cs ) { if ( cs(q)->realizable == 1 ) st_real[ cs(q) ] = true; else st_real[ cs(q) ] = false; } st_real.reverse_propagate(ml_clean); for ( i = 0; i < labels.length; i++ ) if ( st_unreal[ home->configs(pixes[i]).share ] || !st_real[ home->configs(pixes[i]).share ] ) { prevector l(1); l(0) = labels(i); execute_realizable( home, l, gullible, results ); } TEX(![ \begin{quotea} Show that ${\cal R}(\ell_1),\ldots,{\cal R}(\ell_r)$ are pairwise disjoint. We proceed by making a list of all pairs of configuration equivalence classes. We associate to each pair the value {\tt true} if the corresponding realizations are known to be disjoint, else {\tt false}. \end{quotea} ]!) Map< pair, bool> dis; forPix( p, cs ) { forPix( q, cs ) dis[make_pair(cs(p), cs(q))] = false; } forPix( p, home->disjoint ) { dis[ make_pair( home->configs(home->disjoint(p).first).share, home->configs(home->disjoint(p).second).share ) ] = true; dis[ make_pair( home->configs(home->disjoint(p).second).share, home->configs(home->disjoint(p).first).share ) ] = true; } do { forPix( p, ml_clean ) { if ( ml_clean(p).second.length( ) == 1 ) { config_share *s1, *s2; s1 = ml_clean(p).first; s2 = ml_clean(p).second.front( ); TEX(![ \begin{quoted} ${\cal R}(s_1) \IN {\cal R}(s_2)$, $s_2 \cap x = \emptyset \Longrightarrow s_1 \cap x = \emptyset$ \end{quoted} ]!) bool succeeded = false; forPix( q, dis.data ) { if ( !dis.data(q).second && dis.data(q).first.first == s1 && dis[ make_pair( s2, dis.data(q).first.second ) ] ) { dis.data(q).second = true; succeeded = true; } } TEX(![ \begin{quoted} ${\cal R}(s_1) \IN {\cal R}(s_2)$, $x \cap s_2 = \emptyset \Longrightarrow x \cap s_1 = \emptyset$ \end{quoted} ]!) forPix( q, dis.data ) { if ( !dis.data(q).second && dis.data(q).first.second == s1 && dis[ make_pair( dis.data(q).first.first, s2 ) ] ) { dis.data(q).second = true; succeeded = true; } } if (succeeded) break; } } for ( i = 0; i < labels.length; i++ ) for ( j = i+1; j < labels.length; j++ ) if ( !dis[ make_pair( home->configs(pixes[i]).share, home->configs(pixes[j]).share) ] ) goto not_done_yet; goto all_done; not_done_yet: continue; } while ( p != 0 ); execute_disjoint( home, labels, false, results ); } all_done: if ( labels.length == 0 ) home->set_unrealizable(mpix); if ( labels.length == 1 ) home->configs.join( mpix, pixes[0] ); for ( i = 0; i < labels.length; i++ ) if ( !home->configs(pixes[i]).terminal( ) ) break; if ( i == labels.length && mpix == home->base ) { home->classified = true; if ( labels.length == 1 && home->configs(home->base).share->realizable == 1 ) home->unique = true; } if ( labels.length > 0 ) { weightlist& w = home->ww(mpix); next_weight: forPix( p, w ) { for ( i = 0; i < labels.length; i++ ) if ( home->ww(pixes[i]).contains( w(p) ) ) break; if ( i == labels.length ) { w.del( w(p) ); goto next_weight; } } constraintlist true_for_all = home->configs(pixes[0]).assumed_cons; weightlist wd = diff( home->ww(home->base), home->ww(pixes[0]) ); forPix( p, wd ) true_for_all.merge(constraint(String("y") + dec(wd(p)) + "=0")); for ( i = 1; i < labels.length; i++ ) { constraintlist tfa = home->configs(pixes[i]).assumed_cons; wd = diff( home->ww(home->base), home->ww(pixes[i]) ); forPix( p, wd ) tfa.merge( constraint( String("y") + dec(wd(p)) + "=0" ) ); true_for_all = intersection( true_for_all, tfa ); } home->configs(mpix).share->ycon.merge( true_for_all ); } if (gullible) { SLList pixesv; for ( i = 0; i < labels.length; i++ ) pixesv.append( pixes[i] ); home->implications.append( make_pair(mpix, pixesv) ); } home->set_current(0); } index_command(automorphism) void execute_automorphism( codehome* home, String label, Permutation p, bool gullible ) { if ( home->current == 0 ) ERROR("The current configuration is undefined."); config& c = home->configs(home->current); if ( label != "" ) { forPixDef( p, c.auto_labels ) if ( c.auto_labels(p).first == label ) ERROR("You are trying to redefine a label."); } if ( !gullible && (p.length != c.part.length || !c.is_automorphism(p)) ) WARNING("That is not an automorphism.") else { c.aut.append(p); if ( label != "" ) c.auto_labels.append(make_pair(label, c.aut.length - 1)); } } index_command(via dual nonexistence infer) void execute_via_dual_nonexistence( codehome* home, codetable& results, bool gullible ) { if (!gullible) { if ( home->assumed_cons.length( ) != 0 ) ERROR("Sorry, in this version, the code type " << " can't have assumed constraints."); int d = home->ww(home->base).min( ); constraintlist l; for ( int i = 1; i < d; i++ ) l.append( String("mu") + dec(i) + "=0" ); int dp = home->configs(home->base).share->dual_min_low; codebase cb( home->n, home->n - home->dim, weightlist( dec(dp), home->n ), l ); if ( home->ww(home->base).divisible(2) ) cb.assumed_cons.append( String("y") + dec(home->n) + "=1" ); if ( !results.not_exist(cb) ) { WARNING("The required nonexistence result is not known."); return; } } home->set_unrealizable( home->base ); } index_command(report group size) void execute_report_group_size( codehome* home, prevector labels ) { if ( home->current == 0 ) ERROR("The current configuration is undefined."); config& c = home->configs(home->current); Permutationlist gen(c.part.length), gp(c.part.length); for ( int i = 0; i < labels.length; i++ ) { forPixDef( p, c.auto_labels ) if ( c.auto_labels(p).first == labels(i) ) { gen.append(c.aut(c.auto_labels(p).second) ); break; } if ( p == 0 ) ERROR(" Unknown label -- " << labels(i) << "." ); gp.generate(gen); cout << "The group generated by the first " << i + 1 << " automorphisms has " << gp.length << " elements.\n"; } } index_command(propagate) void execute_propagate( codehome* home, constraintlist clist ) { if ( home->base != home->current ) ERROR("Current configuration must be base."); forPixDef( p, clist ) { if ( !clist(p).global( ) ) ERROR("The constraint " << clist(p) << " has local or joint variables in it."); SLList cs = home->configs.sharelist( ); state_list st, st_old; forPixDef( q, cs ) st[ cs(q) ] = known_global( home, cs(q), clist(p) ); st_old = st; SLList< multiedge > ml = home->convert_implications( ); st.propagate(ml); forPix( q, cs ) if ( st[ cs(q) ] && !st_old[ cs(q) ] ) { if ( clist(p).simple_global( ) && clist(p).sense == '=' && clist(p).RHS == 0 ) cs(q)->ww.del( yno( clist(p).LHS.front( ).var ) ); else cs(q)->ycon.append( clist(p) ); } } home->deactivate( ); } set_compile_file(execute2.cc) HIDE( ![ #include #include #include "homedefs.h" #include "state.h" #include "bitvec.h" #include "codetable.h" #include "opt.h" extern int warnings_are_fatal, auto_macaulay, fill_weight; extern int dual_transform_dim_low, dual_transform_dim_high, dual_transform_length_limit, auto_joint_list, auto_group_computation; extern "C" int isdigit(int); Integer round_down_to_power_of_2(Integer); Integer round_up_to_power_of_2(Integer); void log2(const Integer&, Integer&, Integer&); int yno(String); int rcmp(const number&, const number&); int take_int(String&, const Regex&); int String_cmp(const String&, const String&); String list_of(const String&, const String& = ","); sort_by_secondx( prevector< pair >& ); extern long time_used_by_build; extern int allowed_failures, doubly_even_test, no_test_if_classified; extern int auto_mu1; extern String LHS_pat, label_pat, gen_label_pat, config_list, config_list_piece; prevector< triple< int, int, prevector< pair > > > sblv_triple_maker(const partition&, const partition&, const wordtype&, wordtype&); void execute_macaulay(const matrix&); void execute_kill_variable_by(codehome*, prevector, bool, codetable&); bool isomorphic(const matrix&, const matrix&); inline bool test(const Rational& a, const Rational& b, char sense) { if ( sense == '=' ) return a == b; if ( sense == '<' ) return a <= b; return a >= b; } matrix subdivide_matrix(const matrix&, const partition&, const wordtype&, bool); pair< Permutationlist, Integer > find_automorphism_group(const matrix&); ]! ) index_command(config from) void execute_config_from( codehome* home, String vars, String label, bool gullible, codetable& results ) { if ( home->current == 0 ) ERROR("The current configuration is undefined."); prevector lvs = unpack( vars, "|" ); config& c = home->configs(home->current); for ( int i = 0; i < lvs.length; i++ ) { home->configs(home->current).check_variable(lvs(i)); if ( lvs(i)[0] != 'x' ) ERROR( lvs(i) << " is not a basic local variable." ); wordtype wx( &home->configs(home->current), lvs(i) ); if ( !gullible && !home->show( lvs(i) + "!=0", results ) ) ERROR("I couldn't show that " << lvs(i) << " is nonzero."); home->activate(false); Pix pi = subdivide( home->configs(home->current), wx ); home->configs.join( home->current, pi, wx ); home->set_current(pi); } if ( !label.empty( ) ) { forPixDef( j, home->labels ) if ( home->labels(j).first == label ) ERROR("Same label for configuration used twice."); home->labels.append( make_pair( label, home->current ) ); } } index_command(bound) void execute_bound( codehome* home, String s, codetable& results ) { if ( home->current == 0 ) ERROR("The current configuration is undefined."); bool joint = false; if ( s.contains( "(joint)", 0 ) ) { joint = true; s.del( "(joint)" ); } config& c = home->configs(home->current); prevector ss = unpack(s); home->activate(false); opt_table search(home), search_joint(home); SLList brack, brack_joint; weightlist w = home->ww(home->current); w.del(0); for ( int i = 0; i < ss.length; i++ ) { String v = ss(i); if ( v.length( ) == 0 ) continue; if ( v.length( ) == 1 ) WARNRET("Syntax incorrect."); bool bracket = false; if ( v[0] == '[' ) { v.del('['); if ( v[ v.length( ) - 1 ] != ']' ) WARNRET("Syntax incorrect."); v.del(']'); bracket = true; } if ( v == "y*" ) { forPixDef( p, w ) { if (!joint) { search.add( term_sum( "y" + String(dec(w(p))) ) ); brack.append( bracket ); } else { search_joint.add( term_sum("y" + String(dec(w(p)))) ); brack_joint.append( bracket ); } } } else if ( v == "x*" ) { if (joint) WARNRET( "You can't use the (joint) option with " << "local variables." ); if ( c.assumed_cons.global( ) ) { pair< Permutationlist, Integer > pp = c.find_automorphism_group( ); c.aut = pp.first; } EquivRelIntList e = home->active->auto_equiv( ); for ( int j = 1; j < e.length; j++ ) if ( e.minimal(j) ) { search.add( term_sum( home->active->vtable(j).maw.variable( ) ) ); brack.append( bracket ); } } else if ( v == "mu*" ) { for ( int j = c.share->dual_min_low; j <= c.share->dual_min_high; j++ ) { if (!joint) { search.add( String("mu") + dec(j) ); brack.append( bracket ); } else { search_joint.add( String("mu") + dec(j) ); brack_joint.append( bracket ); } } } else if ( v == "~x*" ) { if (joint) WARNRET( "You can't use the (joint) option with " << "local variables." ); if ( !c.assumed_cons.global( ) ) WARNRET( "Since there are local variables in the assumed " << "constraints for [current], you can't bound " << "~x*." ); pair< Permutationlist, Integer > pp = c.find_automorphism_group( ); c.aut = pp.first; EquivRelIntList e = home->active->auto_equiv( ); int class_count = 1; mawhometable& vt = home->active->vtable; for ( int ii = 1; ii < e.length; ii++ ) { if ( e.minimal(ii) ) { opt_card oc; oc.request = "minmax"; oc.var.append( term (1, vt(ii).maw.variable( ) )); int j = ii; while( (j = e(j)) != ii ) oc.var.append( term (1, vt(j).maw.variable( ) ) ); search.data.append(oc); brack.append( bracket ); } } } else if ( v == "j*" ) { prevector bjv = home->basic_joint_vars(results); for ( int j = 1; j < bjv.length; j++ ) { search_joint.add( bjv(j) ); brack_joint.append( bracket ); } } else if ( v == "jyd*" ) { forPixDef( p, w ) { for ( int j = c.share->dual_min_low; j <= min( int(c.share->dual_min_high), home->n - w(p) ); j++ ) { search_joint.add( String("jy") + dec(w(p)) + "d" + dec(j) ); brack_joint.append( bracket ); } } } else { bool local = false, jointc = false; if_no_match( v, LHS_pat ) WARNRET(v << " is not of the right form."); term_sum t( v ); forPixDef( p, t ) { c.check_variable( t(p).var ); if ( local_var( t(p).var ) ) local = true; if ( joint_var( t(p).var ) ) jointc = true; } if ( local && jointc ) WARNRET( "You have mixed local and joint variables." ); if ( local && joint ) WARNRET( "Don't use (joint) option with local variables." ); if (jointc || joint) { search_joint.add( v ); brack_joint.append( bracket ); } else { search.add( v ); brack.append( bracket ); } } } if ( !search.data.empty( ) ) { search.compute(results); if ( !search.feasible ) { WARNING( "It would appear that the current " << "configuration is infeasible." ) return; } Pix pb = brack.first( ); forPixDef( p, search.data ) { if ( !brack(pb) || search.data(p).min >= 1e-6 || search.data(p).max <= 1 - 1e-6 ) cerr << search.data(p); brack.next(pb); } } if ( !search_joint.data.empty( ) ) { search_joint.compute(results, true); if ( !search_joint.feasible ) { WARNING( "It would appear that the current " << "configuration is infeasible." ) return; } Pix pb = brack_joint.first( ); forPixDef( p, search_joint.data ) { if ( !brack(pb) || search_joint.data(p).min >= 1e-6 || search_joint.data(p).max <= 1 - 1e-6 ) cerr << search_joint.data(p); brack_joint.next(pb); } } } TEX( ![ The following class stores a list of wordtypes as a string of zeros and ones. For example, if the partition is $2,5,6$ and the wordtype is $1,3,4$, the wordtype would contribute {\tt 1011100111100} to the string. ]! ) index_class(compressed_wordtype_list) class compressed_wordtype_list { public: bitvec b; int length; // number of wordtypes compressed_wordtype_list( ) { } compressed_wordtype_list(const partition& p, SLList l) : length( l.length( ) ), b( p.n * l.length( ) ) { int i, j, k, b_ptr = 0; forPixDef( q, l ) { wordtype& w = l(q); for ( j = 0; j < p.length; j++ ) { int ones = w(j); int zeros = p(j) - w(j); for ( k = 0; k < ones; k++ ) b.set(b_ptr++); for ( k = 0; k < zeros; k++) b.set(b_ptr++, false); } } } index_method(uncompress) SLList uncompress(const config& c) const { SLList l; int i, j, k, ptr = 0; for ( i = 0; i < length; i++ ) { vector v(c.part.length); for ( j = 0; j < c.part.length; j++ ) { int r = c.part(j); for ( k = 0; k < r; k++ ) v(j) += b.value(ptr++); } wordtype w(v); w.c = &c; l.append(w); } return l; } HIDE( ![ friend bool operator==(const compressed_wordtype_list& w1, const compressed_wordtype_list& w2) { INTERNAL_ERROR( "== not implemented for class compressed_wordtype_list" ); } ]! ) }; HIDE( ![ void process_config_target_list(codehome*, prevector, SLList< pair< config, vector > >&, SLList&, SLList&, SLList&, bool, const codetable&); bool check_config_list(codehome*, const matrix&, const SLList< pair< config, vector > >&, const SLList&, const SLList&); ]! ) index_command(via building) void execute_via_building( codehome* home, int show_terminals_only, bool gullible, String label1, prevector labels, bool quiet_build, bool depth_first, const codetable& results, String pound_label_head, int& pound_label_ctr ) { time_used_by_build -= time(0); int pound_label_ctr_first = pound_label_ctr; Pix p, q, pix1 = home->label_to_Pix( label1, results ); home->set_current( pix1 ); config& b = home->configs(pix1); if ( b.terminal( ) ) ERROR( "It is silly to invoke this command on a " << "terminal configuration." ); Integer fill_low, fill_high; if ( fill_weight > 0 ) b.evaluate( String("y") + dec(fill_weight), fill_low, fill_high ); SLList basals, others, terminals_found; SLList< pair< config, vector > > terminals; SLList pixlist; process_config_target_list( home, labels, terminals, basals, others, pixlist, gullible, results ); if (gullible) { home->implications.append( make_pair(home->current, pixlist) ); time_used_by_build += time(0); home->set_current(0); return; } SLList< triple< config_core, compressed_wordtype_list, bool > > stack; TEX(![ \begin{quote} The \verb|compressed_wordtype_list| is a list of all minimal, admissible, nontrivial basic local variables for the configuration; the {\tt bool} is set to {\tt false} when the configuration has been subdivided along each of these basic local variables. \end{quote} ]!) int config_count = 0, terminal_config_count = 0; int yvar = 0; if ( basals.length( ) == 1 && pixlist.length( ) == 1 && basals.front( ).assumed_cons.length( ) == 1 && basals.front( ).assumed_cons.front( ).simple_global( ) && basals.front( ).assumed_cons.front( ).sense == '<' ) yvar = yno(basals.front().assumed_cons.front( ).LHS.front( ).var); TEX( ![ \begin{quote} First we initialize the stack by putting on the current configuration. \end{quote} ]! ) SLList list0; home->activate( true, yvar == 0 ); mawhometable& m = home->active->vtable; Integer ybound; if ( yvar > 0 ) { ybound = basals.front().assumed_cons.front( ).RHS; if ( yvar == 0 ) ERROR("That is silly."); for ( int l = 1; l < m.length; l++ ) { forPix( p, m(l).w ) { wordtype alttype = m(l).maw; alttype.act( m(l).w(p) ); if ( sum(alttype) == yvar ) { list0.append( m(l).maw ); break; } } } } else { for ( int l = 1; l < m.length; l++ ) list0.append( m(l).maw ); } home->deactivate( ); stack.append( make_triple( config_core(home->configs(home->current)), compressed_wordtype_list(b.part, list0), true ) ); if ( show_terminals_only == 0 ) cerr << "\nConfiguration " << ++config_count << "\n" << b << "will have <= " << list0.length( ) << " configurations directly below it.\n\n"; constraintlist kn = b.known_cons( ); forPix( p, kn ) if ( kn(p).global( ) ) kn(p).LHS = b.simplify_global_vars(kn(p).LHS); // Now for the main loop. while(1) { // Check to see if we're done and count nodes. int nodes = 0; forPix( p, stack ) if ( stack(p).third ) nodes += stack(p).second.length; if ( nodes == 0 ) break; if (!quiet_build) cerr << "There are at least " << nodes << " remaining " << "configurations" << ", not taking account of possible repetition.\n\n"; TEX( ![ \begin{quotea} Find a stack element with a wordtype list of minimal length, unless \verb|depth_first| is set. \end{quotea} ]! ) if ( !depth_first ) { int lenx = -1; forPix( p, stack ) if ( stack(p).third && (lenx < 0 || stack(p).second.length < lenx ) ) { q = p; lenx = stack(p).second.length; } } else { int dimx = -1; forPix( p, stack ) if ( stack(p).third && stack(p).first.smallbasis.nrows > dimx ) { q = p; dimx = stack(p).first.smallbasis.nrows; } } int i, j, k; config c; c.home = home; c.part = stack(q).first.part; c.small.basis = stack(q).first.smallbasis; c.dualsmall.basis = stack(q).first.dualsmallbasis; c.leading1s = c.small.basis.leading_ones( ); c.small.build( ); vector w0; if ( fill_weight > 0 ) w0 = c.smallcode_we( ); SLList list = stack(q).second.uncompress(c), list2; TEX( ![ \begin{quotea} We can reduce the set of variables which we will subdivide along by taking into account automorphisms of the configuration. \end{quotea} ]! ) prevector listv(list); for ( i = 0; i < listv.length; i++ ) c.make_minimal( listv(i) ); listv.sort(&wcmp); if ( listv.length == 1 ) list2.append( listv(0) ); else { wordtype alt(&c); int pp; pair< Permutationlist, Integer> au = c.find_automorphism_group(); EquivRelIntList e(listv.length + 1); // The last element of e is a "dummy" place for an inadmissible // variable. for ( i = 0; i < listv.length; i++ ) { for ( j = 0; j < au.first.length; j++ ) { alt = listv(i); au.first(j).act(alt); c.make_minimal(alt); pp = listv.pos(alt, &wcmp); // Test if an admissible basic local variable is // automorphism-equivalent to an inadmissible basic // local variable. if ( pp < 0 ) e.join( i, listv.length ); else e.join( i, pp ); } } for ( i = 0; i < listv.length; i++ ) if ( e.minimal(i) ) list2.append( listv(i) ); } forPix( p, list2 ) { TEX( ![ \begin{quotebneg} Subdivide to get a new configuration. If the new configuration is terminal, we force its dual small code to be zero. \end{quotebneg} ]! ) wordtype w = list2(p); config d; d.home = c.home; d.part = subdivide_partition( c.part, w ); partition P = d.part; int s = d.part.length; d.small.basis = subdivide_matrix(c.small.basis, c.part, w, true); if ( d.small.basis.nrows != home->dim ) d.dualsmall.basis = subdivide_matrix( c.dualsmall.basis, c.part, w, false ); else d.dualsmall.basis.set_size( 0, s ); d.leading1s = d.small.basis.leading_ones( ); // Have we already looked at d (non-terminal case)? Pix uu = 0; time_used_by_build += time(0); if ( d.small.basis.nrows != home->dim ) { forPix( uu, stack ) if ( home->isomorphic( config_core(d), stack(uu).first ) ) break; } time_used_by_build -= time(0); vector wts; if ( uu == 0 ) { wts = d.smallcode_we( ); if ( fill_weight > 0 && wts(fill_weight) < fill_low && wts(fill_weight) == w0(fill_weight) ) uu = q; } // Does d violate a known simple global constraint? if ( uu == 0 && d.small.basis.nrows != home->dim ) forPix( uu, kn ) if ( kn(uu).simple_global( ) && kn(uu).sense != '>' ) { int yn = yno( kn(uu).LHS.front( ).var ); if ( wts(yn) > kn(uu).RHS ) break; } TEX( ![ \begin{quoteb} Deal with the case where $d$ is terminal. First check to see if it satisfies all known global constraints. Next check to see if options are satisfied. Then check to see if the given terminal configuration has already been encountered. An experiment should be done to determine if reversing the order of the last two steps would be faster. \end{quoteb} ]! ) Pix pp; if ( uu == 0 && d.small.basis.nrows == home->dim ) { Pix qm, rr, ccc; if ( !home->check_globals( kn, wts, d ) ) goto get_out; if ( !home->options_satisfied(d) ) goto get_out; // Have we already looked at d? time_used_by_build += time(0); forPix( uu, terminals_found ) if ( home->isomorphic( terminals_found(uu), d, true ) ) { time_used_by_build -= time(0); goto get_out; } time_used_by_build -= time(0); terminals_found.append(d); cerr << "Terminal configuration [#" << ++terminal_config_count << "] "; for ( i = 0; i < d.part.length; i++ ) { cerr << d.part(i); if ( i < d.part.length - 1 ) cerr << ","; } cerr << " : " << d.small.basis << "\n" << "has weight enumerator " << as_poly(wts) << ".\n"; if (auto_macaulay) { cerr << "generators for ideal: "; execute_macaulay(d.basic_small( )); } if ( !check_config_list( home, d.basic_small( ), terminals, basals, others ) ) { if ( pound_label_head == "" ) { WARNING( "This code does not appear in your list." ); } else { for ( k = 1; k < pound_label_ctr_first; k++ ) { String pound_labelk = pound_label_head + dec(k) + "]"; Pix p = home->label_to_Pix(pound_labelk, results); if ( isomorphic(d.basic_small( ), home->configs(p).small.basis) ) break; } if ( k == pound_label_ctr_first ) { String pound_label = pound_label_head + dec(pound_label_ctr++) + "]"; cerr << "creating " << pound_label << " terminal " << d.basic_small( ) << ";\n"; config c( home, d.basic_small( ) ); if ( auto_group_computation ) { pair< Permutationlist, Integer > pp = c.find_automorphism_group( ); c.aut = pp.first; } Pix j = home->merge_config(c); pixlist.append(j); home->labels.append( make_pair(pound_label, j) ); } } } get_out: uu = stack.first( ); /* nonzero (kludge) */ } if ( uu == 0 && yvar > 0 && ybound < wts(yvar) ) { if ( d.small.basis.nrows != home->dim ) { cerr << "Configuration [#" << ++config_count << "] "; for ( i = 0; i < d.part.length; i++ ) { cerr << d.part(i); if ( i < d.part.length - 1 ) cerr << ","; } cerr << " : " << d.small.basis << "\n" << "has weight enumerator " << as_poly(wts) << ".\n"; } ERROR("The constraint y" << yvar << " <= " << ybound << " is violated by this configuration."); } if ( uu == 0 ) { // This code has much in common with // subdivide_basic_local_variable. Something should be // done to eliminate the replication. SLList listn; forPixDef( z, list ) { wordtype v = list(z), vnew = vector(P.length); vnew.c = &d; wordtype vnew2 = vnew; prevector< triple< int, int, prevector< pair > > > t = sblv_triple_maker( P, c.part, v, vnew ); vector indx( t.length ); wordtype vup = v; for ( i = 0; i < v.length; i++ ) if ( w(i) == c.part(i) ) vup(i) = w(i) - v(i); while(1) { for ( i = 0; i < t.length; i++ ) { vnew(t(i).first) = t(i).third(indx(i)).first; vnew(t(i).first + 1) = t(i).third(indx(i)).second; } for ( i = 0; i < t.length; i++ ) vup( t(i).second ) = P( t(i).first ) - vnew(t(i).first) + vnew( t(i).first + 1 ); // Check for admissibility of vup. Note the // following possibly better alternative approach: // Cycle through the list of wordtypes w (given // up to equivalence). Check to see if w is // ``related'' to vup (easy calculation). If not // (for all w), vup is inadmissible. wordtype wu(&c); for ( i = 0; i < c.small.x.nrows; i++ ) { wu.act( c.small.x(i), vup ); if ( !b.share->ww.contains( sum(wu) ) ) break; } if ( i == c.small.x.nrows ) listn.append(vnew); for ( i = t.length - 1; i >= 0; i-- ) if ( indx(i) < t(i).third.length - 1 ) break; if ( i < 0 ) break; for ( j = t.length - 1; j > i; j-- ) indx(j) = 0; ++indx(i); } } TEX( ![ \begin{quotec} Delete wordtypes equivalent to the trivial wordtype. (Do they exist?) \end{quotec} ]! ) SLList listn2; word www( P.length ); forPixDef( qo, listn ) { wordtype wdt = listn(qo); for ( i = 0; i < P.length; i++ ) { if ( 0 < wdt(i) && wdt(i) < P(i) ) break; www(i) = (wdt(i) != 0); } if ( i < P.length || !d.small.basis.rowspace_member( www ) ) listn2.append( wdt ); } TEX( ![ \begin{quotec} Reduce to a list of inequivalent wordtypes. (Is there a way of avoiding them in the first place?) \end{quotec} ]! ) SLList listn3; prevector listn2v(listn2); for ( i = 0; i < listn2v.length; i++ ) d.make_minimal(listn2v(i)); listn2v.unique_sort(&wcmp); for ( i = 0; i < listn2v.length; i++ ) listn3.append(listn2v(i)); stack.append( make_triple( config_core(d), compressed_wordtype_list(d.part, listn3), !listn3.empty( ) ) ); if ( show_terminals_only == 0 ) { cerr << "Configuration " << ++config_count << "\n" << " config "; for ( i = 0; i < d.part.length; i++ ) { cerr << d.part(i); if ( i < d.part.length - 1 ) cerr << ","; } cerr << " : " << d.small.basis << " : " << d.dualsmall.basis << "\n" << "has weight enumerator " << as_poly(wts) << "\nand will have <= " << listn3.length( ) << " configurations directly below it.\n"; } } } stack(q).second.b.set_size(0); stack(q).third = false; } home->implications.append( make_pair(home->current, pixlist) ); time_used_by_build += time(0); home->set_current(0); } index_command(clean) void execute_clean( String commandx ) { String input_file_name, output_file_name; commandx = commandx.after("clean<"); static Regex var_pattern(var); input_file_name = take( commandx, var_pattern ); commandx = commandx.after(">"); output_file_name = take( commandx, var_pattern ); prevector avoids(0); if (!commandx.empty( )) avoids = unpack( String(commandx.after("(")).before(")") ); ifstream infile( input_file_name ); ofstream outfile( output_file_name ); DLList< pair > main; constraint c; Pix p, q, r, s, sa, i; // Read constraints. while( infile.peek( ) != EOF ) { infile >> c; main.append( make_pair( c, Rational(c.RHS) ) ); infile >> ws; } // skip over whitespace infile.close( ); // Eliminate equality constraints. forPix( p, main ) { if ( main(p).first.sense != '=' ) continue; term t; constraint& cc = main(p).first; term_sum& ts = cc.LHS; term_sum ts2; // Delete any leading terms which are zero. while(1) { if ( ts.length( ) == 0 ) { if ( main(p).second == 0 ) goto tail; ERROR( "self-contradictory constraint" ); } if ( ts.front( ).coeff != 0 ) break; ts.del_front( ); } // Find the nonzero term whose rank is highest // on the avoidance list. if ( avoids.length != 0 ) { Pix best_pix; int kk, best_rank = -1; forPix( i, ts ) { if ( ts(i).coeff == 0 ) continue; for ( kk = 0; kk < avoids.length; kk++ ) { if ( ts(i).var == avoids(kk) ) { if ( kk > best_rank ) { best_rank = kk; best_pix = i; } break; } } if ( kk == avoids.length ) { best_pix = i; break; } } if ( best_pix != ts.first( ) ) swap( ts(best_pix), ts(ts.first( )) ); } t = ts.front( ); cerr << "eliminating " << t.var << " by replacing it by "; ts.del_front( ); ts2 = ts; forPix( i, ts2 ) ts2(i).coeff = -ts2(i).coeff / t.coeff; if ( ts2.length( ) != 0 ) cerr << ts2 << " + "; cerr << str( main(p).second / t.coeff ) << "\n"; forPix( q, main ) { if ( q == p ) continue; term_sum& tt = main(q).first.LHS; forPix( r, tt ) if ( tt(r).var == t.var ) break; if ( r != 0 ) { forPix( s, ts2 ) { forPix( sa, tt ) if ( ts2(s).var == tt(sa).var ) { tt(sa).coeff += ts2(s).coeff * tt(r).coeff; break; } if ( sa == 0 ) tt.append( term( ts2(s).coeff * tt(r).coeff, ts2(s).var ) ); } main(q).second -= tt(r).coeff * main(p).second / t.coeff; tt.del(r); // Delete terms with zero coefficient. forPix( sa, tt ) { repete: if ( tt(sa).coeff == 0 ) { tt.del(sa); if ( sa == 0 ) break; goto repete; } } } } // If we've just hit a constraint // like "x = 7", replace it by "0 = 0". if ( ts.length( ) == 0 ) main(p).second = 0; else { if ( t.coeff > 0 ) main(p).first.sense = '<'; else main(p).first.sense = '>'; } tail: continue; } // Test for constraints whose left hand side is zero. constraint d; Pix ww; forPix( p, main ) { repeat: d = main(p).first; forPix( ww, d.LHS ) if ( d.LHS(ww).coeff != 0 ) break; if ( ww == 0 ) { if ( test ( 0, main(p).second, d.sense ) ) { main.del(p); if ( p == 0 ) break; goto repeat; } ERROR( "self-contradictory constraint found" ); } } // Change <= constraints if any into >= constraints. forPix( p, main ) { if ( main(p).first.sense == '<' ) { main(p).first.sense = '>'; main(p).second = -main(p).second; forPix( q, main(p).first.LHS ) main(p).first.LHS(q).coeff = -main(p).first.LHS(q).coeff; } } // Eliminate constraints whose left hand side is nonnegative // but whose right hand side is non-positive. forPix( p, main ) { repeet: if ( main(p).second > 0 ) continue; forPix( q, main(p).first.LHS ) if ( main(p).first.LHS(q).coeff < 0 ) break; if ( q == 0 ) { main.del(p); if ( p == 0 ) break; goto repeet; } } // Check to see if any constraint implies another constraint // according to the rule // c1v1 +...+ cnvn >= e --> c1'v1 +...+ cn'vn >= e' // if there exists r > 0 such that // c1' >= rc1, ..., cn' >= rcn, e' <= re. // Probably we should normalize first. Pix pp, qq; forPix( p, main ) forPix( q, main ) { next_q: if ( p == q ) continue; term_sum& p_LHS = main(p).first.LHS; term_sum& q_LHS = main(q).first.LHS; Rational rmin = 0, rmax = -1; //-1 stands for infinity Rational rmin_new, rmax_new; // Does main(p) imply main(q)? (Several steps.) if ( main(p).second == 0 ) { if ( main(q).second > 0 ) goto no_way; } else if ( main(p).second > 0 ) { rmin_new = main(q).second / main(p).second; rmin = max( rmin, rmin_new ); } else { if ( main(q).second >= 0 ) goto no_way; rmax_new = main(q).second / main(p).second; if ( rmax == -1 ) rmax = rmax_new; else rmax = min( rmax, rmax_new ); } // If there are any variables which have nonnegative // coefficients in main(p) but which have negative // coefficients in main(q), the answer is no. forPix( qq, q_LHS ) { if ( q_LHS(qq).coeff < 0 ) { forPix( pp, p_LHS ) if ( q_LHS(qq).var == p_LHS(pp).var ) { if ( p_LHS(pp).coeff >= 0 ) goto no_way; goto maybe; } goto no_way; } maybe: continue; } forPix( pp, p_LHS ) { if ( p_LHS(pp).coeff == 0 ) continue; forPix( qq, q_LHS ) if ( q_LHS(qq).var == p_LHS(pp).var ) { if ( p_LHS(pp).coeff > 0 ) { if ( q_LHS(qq).coeff == 0 ) goto no_way; rmax_new = q_LHS(qq).coeff / p_LHS(pp).coeff; if (rmax == -1) rmax = rmax_new; else rmax = min(rmax, rmax_new); if (rmax < rmin) goto no_way; } else { rmin_new = q_LHS(qq).coeff / p_LHS(pp).coeff; rmin = max( rmin, rmin_new ); if ( rmax != -1 && rmax < rmin ) goto no_way; } break; } if ( qq == 0 && p_LHS(pp).coeff > 0 ) goto no_way; } main.del(q); if ( q == 0 ) break; goto next_q; no_way: continue; } // Write main constraints. forPix( p, main ) { d = main(p).first; // Normalize. constraint d2; Integer multiplier = main(p).second.denominator( ); Integer divider = main(p).second.numerator( ); forPixDef( j, d.LHS ) { multiplier = lcm( multiplier, d.LHS(j).coeff.denominator( ) ); divider = gcd( divider, d.LHS(j).coeff.numerator( ) ); } forPix( j, d.LHS ) d2.LHS.append( term ( (d.LHS(j).coeff.numerator( ) * multiplier) / (d.LHS(j).coeff.denominator( ) * divider), d.LHS(j).var ) ); d2.RHS = (main(p).second.numerator( ) * multiplier) / (main(p).second.denominator( ) * divider); d2.sense = d.sense; // Print the constraint. outfile << d2 << "\n"; } outfile.close( ); } #define LET(l) char('a' + l) index_command(macaulay) void execute_macaulay( const matrix& M ) { ofstream mac_in("calculations/Split-mac-in"); int i, j; mac_in << "ring R\n" << " 2 ;\n"; mac_in << " " << M.nrows << " ;\n"; mac_in << " " << "a-" << LET(M.nrows - 1) << " ;\n"; mac_in << " ;\n" << " ;\n\n"; mac_in << "ideal I\n"; mac_in << choose( M.nrows, 2 ) << "\n"; for ( i = 0; i < M.nrows; i++ ) for ( j = i + 1; j < M.nrows; j++ ) mac_in << LET(i) << "2" << LET(j) << "+" << LET(i) << LET(j) << "2\n"; mac_in << "std I I\n" << "qring I S\n"; mac_in << "mat M\n" << M.nrows << "\n" << M.ncols << "\n"; for ( i = 0; i < M.ncols; i++ ) for ( j = 0; j < M.nrows; j++ ) mac_in << M(j,i) << "\n"; mac_in << "calculations/Split-mac-out\n"; mac_in.close( ); system( String("Macaulay < calculations/Split-mac-in ") + "> calculations/Split-mac-report" ); ifstream mac_out("calculations/Split-mac-out"); char d; while( mac_out.peek( ) != EOF ) { mac_out.get(d); cerr << d; } mac_out.close( ); } index_command(via varying) void execute_via_varying( String yi, prevector labels, codehome* home, bool gullible, codetable& results ) { if ( home->current == 0 ) ERROR("Current configuration not defined."); int i; prevector pixes(labels.length); for ( i = 0; i < labels.length; i++ ) pixes(i) = home->label_to_Pix(labels(i), results); prevector< pair< constraintlist, Integer > > work( labels.length ); for ( i = 0; i < labels.length; i++ ) { config& ci = home->configs(pixes(i)); if (!ci.basal( )) ERROR( labels(i) << " is not basal." ); work(i).first = ci.assumed_cons; forPixDef( p, work(i).first ) if ( work(i).first(p).simple_global( ) ) { constraint& r = work(i).first(p); if ( r.sense == '=' && r.LHS.front( ).var == yi ) { work(i).second = r.RHS; work(i).first.del(p); goto next_label; } } ERROR( labels(i) << " doesn't have a " << "constraint which fixes " << yi << "." ); next_label: continue; } sort_by_secondx( work ); for ( i = 1; i < work.length; i++ ) if ( work(i).second != work(i-1).second + 1 ) ERROR("Read the command definition again, please."); String dbl = String(dec(work(0).second)) + "<=" + yi + "<=" + dec(work(work.length-1).second); if ( !gullible && !home->show( constraintlist(dbl), results, false, constraintlist( ), false, true ) ) ERROR("I can't show that " << dbl << "."); for ( i = 0; i < labels.length; i++ ) { constraintlist forced(yi + "=" + dec(work(i).second)); if (!gullible && !home->show( work(i).first, results, true, forced, false, true )) ERROR("I can't deduce " << work(i).first << " from " << forced << "."); } home->implications.append( make_pair(home->current, make_listv(pixes)) ); home->set_current(0); } index_command(reduce variable set) void execute_reduce_variable_set( codehome* home ) { if ( home->current == 0 ) ERROR("Current configuration undefined."); config& c = home->configs(home->current); home->activate(true); pair< Permutationlist, Integer > pp = c.find_automorphism_group( ); c.aut = pp.first; mawhometable& vt = home->active->vtable; prevector< pair< wordtype, bool > > adm( vt.length ); int i, j, a; wordtype wt; for ( i = 0; i < vt.length; i++ ) adm(i) = make_pair( vt(i).maw, true ); try_to_reduce_again: for ( i = 0; i < adm.length; i++ ) { if ( adm(i).second ) { for ( j = 0; j < c.aut.length; j++ ) { wt = adm(i).first; c.aut(j).act( wt ); a = vt.mfind( wt ); if ( a == -1 || !adm(a).second ) { adm(i).second = false; goto try_to_reduce_again; } } } } for ( i = 0; i < adm.length; i++ ) if ( !adm(i).second ) { constraint wt_eq_0 = adm(i).first.variable( ) + "=0"; c.con.merge( wt_eq_0 ); } home->deactivate( ); } index_command(round local variables) void execute_round_local( codehome* home, codetable& results ) { if ( home->current == 0 ) ERROR("The current configuration is undefined."); config& c = home->configs(home->current); home->activate(false); opt_table search(home); for ( int j = 1; j < home->active->vtable.length; j++ ) search.add( term_sum( home->active->vtable(j).maw.variable( ) ), "minmax" ); search.compute(results); if ( !search.feasible ) cerr << "Current configuration is infeasible.\n"; else { constraint cc; Rational eps(1,1000), low, high; forPixDef( i, search.data ) { low = search.data(i).min; high = search.data(i).max; if ( abs(low - Rational(round(low))) > eps ) { cc.LHS = search.data(i).var; cc.sense = '>'; cc.RHS = ceil(low); cerr << " " << cc << "\n"; c.con.append(cc); } if ( abs(high - Rational(round(high))) > eps ) { cc.LHS = search.data(i).var; cc.sense = '<'; cc.RHS = floor(high); cerr << " " << cc << "\n"; c.con.append(cc); } } } } index_method(execute_print_joint) void execute_print_joint( codehome* home ) { config& c = home->configs(home->current); int i, j, k, n = home->n; prevector y[n+1][n+1]; for ( i = 0; i <= n; i++ ) for ( j = i; j <= n; j++ ) { y[i][j].set_size(n+1); for ( k = 0; k <= n; k++ ) y[i][j](k) = 0; } vector indx(c.small.basis.nrows), sumx(c.small.basis.ncols), sumy(c.small.basis.ncols), sumxy(c.small.basis.ncols); int wx, wy; do { mul( indx, c.small.basis, sumx ); wx = sumx * c.part; vector indy(c.small.basis.nrows); do { mul( indy, c.small.basis, sumy ); wy = sumy * c.part; if ( wx <= wy ) { for ( i = 0; i < c.small.basis.ncols; i++ ) sumxy(i) = sumx(i) * sumy(i); ++y[wx][wy]( sumxy * c.part ); } } while ( indy.advance( ) ); } while( indx.advance( ) ); for ( i = 0; i <= n; i++ ) for ( j = i; j <= n; j++ ) for ( k = 0; k <= n; k++ ) if ( y[i][j](k) != 0 ) { if ( i == 0 && j == 0 && k == 0 ) cerr << "1"; else { cerr << " + "; if ( y[i][j](k) != 1 ) cerr << y[i][j](k); if ( i != 0 ) cerr << "b^" << i; if ( j != 0 ) cerr << "c^" << j; if ( k != 0 ) cerr << "d^" << k; } } cerr << "\n"; } index_command(random weight enumerator) void execute_random_we( short int n, short int k, short int div, short int modulus, Integer count ) { if ( div != 1 && div != 4 ) ERROR("Illegal value for div."); matrix M(k,n), Mred(k,n); vector w(n+1), wm(modulus); int j, l, m, bad_row_count; { for ( Integer i = 0; i < count; ++i ) { dependent: for ( j = 0; j < k; j++ ) { if ( div == 1 ) M(j).set_random( ); if ( div == 4 ) { matrix M0(j,n); for ( m = 0; m < j; m++ ) M0(m) = M(m); M0.reduce( ); matrix dual(n-j,n); M0.nullspace_equals(dual); vector col(n-j); bad_row_count = 0; bad_row: if (bad_row_count++ == 1000) goto dependent; col.set_random( ); mul( col, dual, M(j) ); if ( M(j).weight( ) % 4 != 0 ) goto bad_row; matrix M1(j+1,n); for ( m = 0; m < j + 1; m++ ) M1(m) = M(m); if ( M1.reduce( ) != j+1 ) goto bad_row; } } Mred = M; if ( Mred.reduce( ) != k ) goto dependent; w = M.enumerate_weights( ); wm.set_zero( ); for ( j = 0; j <= n; j++ ) wm( j % modulus ) += w(j); cerr << wm(0); for ( j = 1; j < modulus; j++ ) cerr << ", " << wm(j); cerr << "\n"; } } } index_method(random macaulay) void execute_random_macaulay( short int n, short int k, short int d, Integer count ) { matrix M(k,n); vector col(k); int c, j, v; for ( Integer i = 0; i < count; ++i ) { try_again: do { for ( c = 0; c < n; c++ ) { do { do col.set_random( ); while ( col.if_zero( ) ); for ( v = 0; v < c; v++ ) { for ( j = 0; j < k; j++ ) if ( M(j,v) != col(j) ) break; if ( j == k ) break; } } while ( v != c ); for ( j = 0; j < k; j++ ) M(j,c) = col(j); } } while ( M.reduce( ) != k ); vector y = M.enumerate_weights( ); for ( c = 1; c < d; c++ ) if ( y(c) != 0 ) goto try_again; cerr << M << "\n"; cerr << "weight enumerator: " << as_poly(y) << "\n"; cerr << "generators for ideal: "; execute_macaulay(M); } } index_method(is_cyclic_print) void is_cyclic_print( Permutation q, word v, word w ) { int i, k, n = q.length; String acp = q.as_cycle_product( ); if ( acp.length( ) == 0 ) return; String a = acp; a.gsub(")(", ","); a.gsub("(", 0); a.gsub(")", 0); vector av(a); String aplus = a; for ( i = 1; i <= n; i++ ) if ( !av.member(i) ) aplus += String(",") + dec(i); Permutation p(aplus); Permutation pi = p.inverse( ); pi.act(v); if ( w.length > 0 ) pi.act(w); SLList t; static Regex cycle_pat( "([0-9,]+)" ); do { String cycle = take( acp, cycle_pat ); t.append( cycle.freq( "," ) + 1 ); } while( acp.length( ) > 0 ); vector tv(t); // The following line does not word for some reason: // String prefix = "(" + String(tv) + ")-"; String prefix = String("(") + dec(int(tv(0))); for ( k = 1; k < tv.length; k++ ) prefix += String(",") + dec(int(tv(k))); prefix += ")-"; for ( k = 1; k < tv.length; k++ ) if ( tv(k) != tv(0) ) break; if ( k == tv.length && tv(0) * tv.length == q.length ) prefix = (tv.length == 1) ? String("") : dec(tv.length) + String("-"); cerr << "--> " << prefix << "cyclic {" << v; if ( w.length > 0 ) cerr << ", " << w; cerr << "}"; } index_method(find cyclic codes) void execute_find_cyclic_codes( codehome* home, int q ) { config& cur = home->configs(home->current); vector wts; int i, j, n = home->n, k = home->dim, qi; if ( n % q != 0 ) ERROR(q << " does not divide " << n << "."); Permutation sigma(n); for ( i = 0; i < n; i++ ) sigma(i) = ((i + q) % n) + 1; int r = n - k + 1, d = home->w.min( ), w; word gen(r), indx(k), v(n); SLList cyclics; config c; c.home = home; c.part.set_all_ones(n); c.small.basis.set_size(k, n); c.dualsmall.basis.set_size(0, n); constraintlist kn = cur.known_cons( ); forPixDef( p, kn ) if ( kn(p).global( ) ) kn(p).LHS = cur.simplify_global_vars(kn(p).LHS); do { w = gen.weight( ); if ( w < d ) continue; indx.set_zero( ); indx.advance( ); do { v.set_zero( ); for ( i = 0; i < k; i++ ) if ( indx(i) ) { if ( q == 1 ) { for ( j = 0; j < r; j++ ) v(i + j) += gen(j); } else { qi = q*i; for ( j = 0; j < r; j++ ) v((qi + j) % n) += gen(j); } } w = v.weight( ); if ( w < d ) goto next_gen; } while (indx.advance( ) != 0); c.small.basis.set_zero( ); for ( i = 0; i < k; i++ ) { if ( q == 1 ) { for ( j = 0; j < r; j++ ) c.small.basis(i, i + j) = gen(j); } else { qi = q*i; for ( j = 0; j < r; j++ ) c.small.basis(i, (qi + j) % n) = gen(j); } } c.small.basis.reduce( ); c.leading1s = c.small.basis.leading_ones( ); wts = c.smallcode_we( ); for ( j = 0; j <= home->n; j++ ) if ( wts(j) != 0 && !home->ww(home->base).contains(j) ) goto next_gen; if ( !home->check_globals( kn, wts, c ) ) goto next_gen; if ( !home->options_satisfied(c) ) goto next_gen; forPix( p, cyclics ) if ( home->isomorphic( c, cyclics(p) ) ) break; if ( p == 0 ) { cyclics.append(c); word vv(n); for ( i = 0; i < gen.length; i++ ) vv(i) = gen(i); is_cyclic_print( sigma, vv, word(0) ); cerr << " :: {"; vector we = c.small.basis.enumerate_weights( ); bool first_nonzero = true; for ( i = 1; i <= n; i++ ) if ( we(i) != 0 ) { if (!first_nonzero) cerr << ", "; first_nonzero = false; cerr << String("y") << dec(i) << " = " << dec( we(i) ); } cerr << "}\n"; } next_gen: continue; } while( gen.advance( ) != 0 ); } index_command(is cyclic) void execute_is_cyclic( codehome* home, bool extra_used, codetable& results ) { if (home->current == 0) ERROR("[current] is undefined."); config& d = home->configs(home->current); if ( !d.terminal( ) ) ERROR("Configuration must be terminal."); if (!extra_used) { config c( home, d.basic_small( ) ); pair< Permutationlist, Integer > pp = c.find_automorphism_group( ); int i, j, k, l, n = home->n; Permutationlist q(n), qq(n); for ( i = 0; i < pp.first.length; i++ ) q.append(pp.first(i)); qq.generate(q); c.small.build( ); matrix M(home->dim, n); for ( i = 0; i < c.small.x.nrows; i++ ) { for ( j = 0; j < qq.length; j++ ) { M(0) = c.small.x(i); for ( l = 1; l < home->dim; l++ ) { M(l) = M(l-1); qq(j).act( M(l) ); } if ( M.reduce( ) == home->dim ) { is_cyclic_print(qq(j), c.small.x(i), word(0)); cerr << ";\n"; } } } } else { matrix A = d.basic_small( ); // We look at all codimension-one subcodes. We should only look // at one representative from each orbit, under the action of the // automorphism group of the given code. vector indx(A.nrows); indx.advance( ); do { matrix B(indx), C, D; B.nullspace_equals(C); mul( C, A, D ); D.reduce( ); codehome xhome( D.ncols, D.nrows, weightlist("1", D.ncols), results ); config c( &xhome, D ); pair< Permutationlist, Integer > pp = c.find_automorphism_group( ); cerr << "subcode has " << pp.second << " automorphisms\n"; if ( pp.second == 1 ) continue; Permutationlist q(xhome.n), qq(xhome.n); int i, j, l; for ( i = 0; i < pp.first.length; i++ ) q.append(pp.first(i)); qq.generate(q); Permutation id(xhome.n); c.small.build( ); matrix M(xhome.dim, xhome.n); for ( j = 0; j < qq.length; j++ ) { if ( qq(j) == id || qq(j).order( ) < xhome.dim ) continue; for ( i = 0; i < c.small.x.nrows; i++ ) { M(0) = c.small.x(i); for ( l = 1; l < xhome.dim; l++ ) { M(l) = M(l-1); qq(j).act( M(l) ); } if ( M.reduce( ) == xhome.dim ) { word w; word perp_indx( indx.length ); for ( l = 0; l < indx.length; l++ ) if ( indx(l) ) break; perp_indx(l) = 1; mul( perp_indx, A, w ); is_cyclic_print(qq(j), c.small.x(i), w); cerr << ";\n"; } } } } while( indx.advance( ) != 0 ); } } index_command(print) void execute_print( String commandx, codehome* home, long int total_time_used ) { commandx = commandx.after( "print" ); if ( commandx == "timeused" ) { cerr << setprecision(5) << (time(0) - total_time_used)/60.0 << " minutes real time used so far\n"; return; } if (home->current == 0) WARNRET("The current configuration is undefined."); config& c = home->configs(home->current); if ( commandx == "weightenumerator" ) { vector y = c.smallcode_we( ); cerr << as_poly(y) << "\n"; } else if ( commandx == "intersectionweightenumerator" ) { matrix n, m = c.basic_small( ); intersect_dual(m, n); vector y = n.enumerate_weights( ); cerr << as_poly(y) << "\n"; } else if ( commandx == "jointweightenumerator" ) execute_print_joint(home); else if ( commandx == "config" ) cerr << c; else if ( commandx == "basis" ) cerr << c.basic_small( ) << "\n"; else if ( commandx == "reducedbasis" ) { matrix T, M = c.basic_small( ); M.transpose_equals(T); prevector cols(T.nrows); for ( int i = 0; i < cols.length; i++ ) cols(i) = T(i); cols.unique_sort(&cmp); matrix A( M.nrows, cols.length ); for ( int i = 0; i < cols.length; i++ ) A.set_col( i, cols(i) ); cerr << A << "\n"; } else if ( commandx == "dualbasis" ) { matrix D; c.basic_small( ).nullspace_equals(D); cerr << D << "\n"; } else if ( commandx == "intersectionbasis" ) { matrix n, m = c.basic_small( ); intersect_dual(m, n); cerr << n << "\n"; } else if ( commandx == "evensubcodebasis" ) { matrix M = c.basic_small( ); int i, j; for ( i = 0; i < M.nrows; i++ ) if ( odd( M(i).weight( ) ) ) break; if ( i == M.nrows ) { cerr << "The code itself is even. Here is its basis:\n"; cerr << M << "\n"; } else { if ( !odd( M( M.nrows-1 ).weight( ) ) ) M( M.nrows-1 ) += M(i); for ( j = 0; j < M.nrows-1; j++ ) if ( odd( M(j).weight( ) ) ) M(j) += M( M.nrows-1 ); M.resize( M.nrows-1, M.ncols ); M.reduce( ); cerr << M << "\n"; } } else if ( commandx == "puncturedcodes" ) { matrix M = c.basic_small( ); matrix P( M.nrows, M.ncols-1 ); SLList< matrix > answer; int i, j, k; EquivRelIntList e( M.ncols ); pair< Permutationlist, Integer > pp = find_automorphism_group(M); for ( i = 0; i < pp.first.length; i++ ) for ( j = 0; j < e.length; j++ ) e.join( j, pp.first(i)(j) - 1 ); for ( i = 0; i < M.ncols; i++ ) { if ( !e.minimal(i) ) continue; for ( j = 0; j < M.nrows; j++ ) { for ( k = 0; k < i; k++ ) P(j, k) = M(j, k); for ( k = i+1; k < M.ncols; k++ ) P(j, k-1) = M(j, k); } forPixDef( p, answer ) if ( isomorphic( P, answer(p) ) ) break; if ( p == 0 ) { cerr << P << "\n"; answer.append(P); } } } else if ( commandx == "codewordorbits" ) { c.small.build( ); int i, j, class_count = 1; prevector cd(c.small.x.nrows); for ( i = 0; i < cd.length; i++ ) cd(i) = c.small.x(i); cd.sort(&cmp); EquivRelIntList e(cd.length); word w(c.part.length); for ( i = 0; i < c.aut.length; i++ ) for ( j = 0; j < cd.length; j++ ) { w = cd(j); c.aut(i).act(w); int k = cd.pos(w, &cmp); if ( k == -1 ) INTERNAL_ERROR("code word orbits"); e.join(j, k); } for ( i = 0; i < e.length; i++ ) { if ( e.minimal(i) ) { cerr << "class " << class_count++ << " (words of weight " << cd(i).weight( ) << "):\n1. " << cd(i) << "\n"; j = i; int l = 2; while( (j = e(j)) != i ) cerr << l++ << ". " << cd(j) << "\n"; } } } else if ( commandx == "variableclasses" ) { home->activate(false); EquivRelIntList e = home->active->auto_equiv( ); int i, j, class_count = 1; for ( i = 0; i < e.length; i++ ) { if ( e.minimal(i) ) { cerr << "class " << class_count++ << ": "; mawhometable& vt = home->active->vtable; cerr << vt(i).maw.variable( ); j = i; while( (j = e(j)) != i ) cerr << ", " << vt(j).maw.variable( ); cerr << ";\n"; } } } else if ( commandx == "automorphismgroup" ) { if ( !c.assumed_cons.joint( ) ) WARNRET( "Local variables are present in an assumed " << "constraint. Command ignored." ); pair< Permutationlist, Integer > pp = c.find_automorphism_group( ); cerr << "Aut(current) has " << pp.second << " elements. " << "Generators are as follows:\n"; c.aut.clear( ); for ( int i = 0; i < pp.first.length; i++ ) { cerr << " " << pp.first(i) << "\n"; c.aut.append( pp.first(i) ); } } else if ( commandx.contains("variablesofweight", 0) ) { commandx = commandx.after("variablesofweight"); if_no_match(commandx, number_pat) WARNRET("Weight doesn't make sense."); int m = as_int(commandx); home->activate(true); const mawhometable& me = home->active->vtable; bool first_variable = true; for ( int i = 0; i < me.length; i++ ) { bool first_in_class = true; forPixDef( p, me(i).w ) { wordtype alttype = me(i).maw; alttype.act( me(i).w(p) ); if ( sum(alttype) == m ) { if (!first_variable) { if (first_in_class) cerr << ", "; else cerr << " ~ "; } cerr << alttype.variable( ); first_variable = false; first_in_class = false; } } } cerr << "\n"; } else if ( commandx.contains("projectionsontowordsofweight", 0) ) { commandx = commandx.after("projectionsontowordsofweight"); if_no_match(commandx, number_pat) WARNRET("Weight doesn't make sense."); int m = as_int(commandx); matrix M = c.basic_small( ); pair< Permutationlist, Integer > pp = find_automorphism_group(M); Permutationlist aut = pp.first; c.small.build( ); int i, j, class_count = 1; prevector cd(c.small.x.nrows); for ( i = 0; i < cd.length; i++ ) cd(i) = c.small.x(i); cd.sort(&cmp); EquivRelIntList e(cd.length); word w(c.part.length); for ( i = 0; i < aut.length; i++ ) for ( j = 0; j < cd.length; j++ ) { w = cd(j); aut(i).act(w); int k = cd.pos(w, &cmp); e.join(j, k); } SLList< matrix > projs; for ( i = 0; i < e.length; i++ ) { if ( e.minimal(i) && cd(i).weight( ) == m ) { matrix A = M.select_col( cd(i) ); A.reduce_nz( ); forPixDef( p, projs ) if ( isomorphic( A, projs(p) ) ) break; if ( p == 0 ) { projs.append(A); vector y = A.enumerate_weights( ); cerr << A << "\n"; cerr << "weight enumerator: " << as_poly(y) << "\n"; } } } } else WARNRET("Unrecognized print option."); } void execute_help( String commandx ) { commandx = commandx.after( "help" ); if ( commandx.empty( ) ) { cerr << "The help command may be used to get information about a " << "particular command. It works by opening the Split report " << "at the appropriate page. To use it, you must " << "have xdvi and ghostscript (gs) installed on your " << "machine. Try \"help print;\" and \"help via;\" " << "to see how it works. The spacebar and backspace " << "key may be used to page forward and backward in " << "the report. Type \"q\" to exit xdvi.\n"; return; } ifstream idx( "tex/t.idxb" ); SLList< pair > plausibles; char* com; String comx, command_name, cname0, pl; while(1) { idx >> ws; // skip over whitespace if ( idx.peek( ) == EOF ) break; idx.gets(&com); comx = com; comx.gsub("$", "" ); if ( !idx ) ERROR("Input error."); comx.del( "\\indexentry{" ); command_name = comx.before("}"); cname0 = command_name; cname0.gsub(RXwhite,""); if ( cname0.contains( commandx, 0 ) ) { forPixDef( p, plausibles ) { pl = plausibles(p).first; pl.gsub(RXwhite,""); if ( pl == cname0 ) break; } if ( p != 0 ) continue; comx = comx.after("}{"); comx = comx.before("}"); plausibles.append( make_pair(command_name, comx) ); } delete com; } if ( plausibles.length( ) == 0 ) cerr << "I can't find an entry in the index which starts with \"" << commandx << "\". Perhaps you should try a shorter string.\n"; else if ( plausibles.length( ) > 1 ) { cerr << "I've found more than one index entry which " << "starts with \"" << commandx << "\". Please choose " << "from the following and use the help command again:\n"; forPixDef( p, plausibles ) cerr << plausibles(p).first << "\n"; } else system("xdvi +" + plausibles.front().second + " tex/t.dvi"); } void execute_test( int n, int k, int d, codetable& results, codehome* home, String& code_label, const constraintlist& test_mask ) { if ( d > n ) ERROR("Minimum weight exceeds length."); forPixDef( p, test_mask ) { Rational sum = 0; forPixDef( q, test_mask(p).LHS ) { term& t = test_mask(p).LHS(q); if ( t.var == "n" ) sum += Integer(n) * t.coeff; else if ( t.var == "k" ) sum += Integer(k) * t.coeff; else if ( t.var == "d" ) sum += Integer(d) * t.coeff; else ERROR( "Illegal variable in test mask." ); } if ( !test( sum, test_mask(p).RHS, test_mask(p).sense ) ) return; } if (doubly_even_test) { if ( d % 4 != 0 ) return; String sss( dec(d) ); sss += "_4"; weightlist wt( sss, n ); if ( results.not_exist(n, k, wt) ) return; if ( no_test_if_classified && results.weakly_classified(codebase(n, k, wt)) ) return; if ( results.new_not_exist( n, k, d, 4, home, code_label, allowed_failures ) ) { results.kill( codebase(n, k, wt) ); WARNING( "There is no [" << n << ", " << k << ", " << d << "_4] code." ); } } else if ( results.not_exist(n-1, k, d) ) { weightlist wt( dec(d), n ); if ( no_test_if_classified && results.weakly_classified(codebase(n, k, wt)) ) return; if ( results.new_not_exist( n, k, d, 1, home, code_label, allowed_failures ) ) { results.kill(n, k, d); WARNING( "There is no [" << n << ", " << k << ", " << d << "] code." ); } } } index_method(set_numerical_parameter) void set_numerical_parameter( const String& parameter, const String& value, const String& mode ) { static Regex number_pattern( number_pat ); if ( !value.matches(number_pattern) ) ERROR( "Illegal parameter value " << value << " for " << parameter << ".\n" ); #define INT_PARAM(uname,mename,low,high) \ if ( parameter == uname ) \ { extern int mename; \ static int mename##_save; \ if ( mode == "set" ) \ { mename = as_int(value); \ if ( mename < low || (high != 0 && mename > high) ) ERROR( \ "Illegal parameter value " << value << " for " << \ parameter << ".\n" ); }\ else if ( mode == "save" ) mename##_save = mename; \ else if ( mode == "restore" ) mename = mename##_save; \ return; } INT_PARAM("refactorizationrate", refactorization_rate, 0, 0) INT_PARAM("dualconstraintbound", dual_constraint_bound, 0, 0) INT_PARAM("dcbdepthlimit", dcb_depth_limit, 0, 0) INT_PARAM("autojointsearch", auto_joint_search, 0, 0) INT_PARAM("autojointtest", auto_joint_test, 0, 0) INT_PARAM("usedualdualforjoint", use_dual_dual_for_joint, 0, 0) INT_PARAM("fillweight", fill_weight, 0, 0) INT_PARAM("pricerefinementcount", price_refinement_count, 0, 0) INT_PARAM("secondarykillmaxvars", secondary_kill_maxvars, 0, 0) INT_PARAM("partialpricing", partial_pricing, 0, 0) INT_PARAM("allowedfailures", allowed_failures, 1, 0) INT_PARAM("nzvlengthmax", nzv_length_max, 1, 0) INT_PARAM("generatenonevenbounds", generate_noneven_bounds, 0, 0) INT_PARAM("dualtransformlengthlimit", dual_transform_length_limit, 1, 0) INT_PARAM("dualtransformdimlow", dual_transform_dim_low, 0, 0) INT_PARAM("dualtransformdimhigh", dual_transform_dim_high, 0, 0) INT_PARAM("autotransformdepth", auto_transform_depth, 0, 0) INT_PARAM("iterationlimit", iteration_limit, 1000, 0) INT_PARAM("tupleorbitmax", tuple_orbit_max, 1, 0) INT_PARAM("nzvlengthmax2", nzv_length_max2, 0, 0) INT_PARAM("transformpasslevel", transform_pass_level, 0, 0) INT_PARAM("autodualcolumndeletion", auto_dual_column_deletion, 0, 2) INT_PARAM("startingtupleorbit", starting_tuple_orbit, 1, 0) Integer ivalue = as_int(value); if (ivalue != 0 && ivalue != 1) ERROR( "Illegal parameter value " << value << " for " << parameter << ".\n" ); #define BOOL_PARAM(uname,mename) \ if ( parameter == uname ) \ { extern int mename; \ static int mename##_save; \ if ( mode == "set" ) mename = as_int(ivalue); \ else if ( mode == "save" ) mename##_save = mename; \ else if ( mode == "restore" ) mename = mename##_save; \ return; } BOOL_PARAM("optimal", optimal) BOOL_PARAM("debug", debug) BOOL_PARAM("notestifclassified", no_test_if_classified) BOOL_PARAM("limitedsecondarykill", limited_secondary_kill) BOOL_PARAM("residualcheckforkill", residual_check_for_kill) BOOL_PARAM("fullsecondarykill", full_secondary_kill) BOOL_PARAM("homebrewfullreport", homebrew_full_report) BOOL_PARAM("warningsarefatal", warnings_are_fatal) BOOL_PARAM("autoprojection", auto_projection) BOOL_PARAM("autojointlist", auto_joint_list) BOOL_PARAM("savebounds", save_bounds) BOOL_PARAM("showconfigcreation", show_config_creation) BOOL_PARAM("showevenifknown", show_even_if_known) BOOL_PARAM("lowerboundcheck", lower_bound_check) BOOL_PARAM("doublyeventest", doubly_even_test) BOOL_PARAM("autodualtransform", auto_dual_transform) BOOL_PARAM("doublecolumnpairs", double_column_pairs) BOOL_PARAM("doublecolumntriples", double_column_triples) BOOL_PARAM("doublecolumngroups", double_column_groups) BOOL_PARAM("smartdual", smart_dual) BOOL_PARAM("showvariables", show_variables) BOOL_PARAM("nonprojectivesearch", nonprojective_search) BOOL_PARAM("autoorbittransform", auto_orbit_transform) BOOL_PARAM("matrixisomorphismsilent", matrix_isomorphism_silent) BOOL_PARAM("autoround", auto_round) BOOL_PARAM("homebrewspeedy", homebrew_speedy) BOOL_PARAM("silent", silent) BOOL_PARAM("gulliblesilent", gullible_silent) BOOL_PARAM("alternateextensionmethod", alternate_extension_method) BOOL_PARAM("secondaryecho", secondary_echo) BOOL_PARAM("automacaulay", auto_macaulay) BOOL_PARAM("depthfirst", depth_first) BOOL_PARAM("homebrew", homebrew) BOOL_PARAM("quad", use_quad) BOOL_PARAM("quietbuild", quiet_build) BOOL_PARAM("tablesonly", tables_only) BOOL_PARAM("showterminalsonly", show_terminals_only) BOOL_PARAM("sort", sort_flag) BOOL_PARAM("secondaryplus", secondary_plus) BOOL_PARAM("autogroupcomputation", auto_group_computation) BOOL_PARAM("automu1", auto_mu1) ERROR( "Unknown parameter -- \"" << parameter << "\"." ); } index_method(save_and_set_parameter) void save_and_set_parameters(String list) { String parameter, value; if_no_match( list, String("<") + ".*>" ) ERROR( "The syntax of the parameter list is incorrect." ); list = list.after("<"); list = list.before(">"); prevector opts = unpack(list); for ( int i = 0; i < opts.length; i++ ) { if ( !opts(i).contains("=") ) { parameter = opts(i); value = "1"; } else { parameter = opts(i).before("="); value = opts(i).after("="); } set_numerical_parameter(parameter, value, "save"); set_numerical_parameter(parameter, value, "set"); } } index_method(restore_parameters) void restore_parameters(String list) { String parameter, value; if_no_match( list, String("<") + ".*>" ) ERROR( "The syntax of the parameter list is incorrect." ); list = list.after("<"); list = list.before(">"); prevector opts = unpack(list); for ( int i = 0; i < opts.length; i++ ) { if ( !opts(i).contains("=") ) { parameter = opts(i); value = "1"; } else { parameter = opts(i).before("="); value = opts(i).after("="); } set_numerical_parameter(parameter, value, "restore"); } } index_command(type) void execute_type( String commandx, codehome*& home, codetable& results, String& code_label, bool fast, bool gullible ) { // First save the previous codehome, if there was one. if (home != 0) results.save( *home, code_label ); String set_pat( "{" + list_of( pos_number + orsign + pos_number + "\\.\\." + pos_number ) + "}" ); static Regex weightlist_pat( pos_number + orsign + pos_number + "_" + pos_number + orsign + set_pat + orsign + pos_number + "-" + set_pat + orsign + pos_number + "_" + pos_number + "-" + set_pat ); static Regex label_pattern( label_pat ); static Regex type_residual_pattern(pos_number + "," + number_pat + ",.*"); static Regex number_pattern( number_pat ); #define n_options 3 static Regex option_pats[n_options] = { "dual_may_be_code_of_design(t=2,k=" + number_pat + ",lambda=" + number_pat + ")", "partition_of_word_by_dual_words(weight=" + number_pat + ",dual_weight=" + number_pat + ")", "doubly_even_part_is_subcode" }; code_label = ""; if ( commandx[0] == '[' ) code_label = take(commandx, label_pattern); if (fast) code_label = ""; forPixDef( p, results.olabels ) if ( code_label == results.olabels(p).first ) { WARNING("I am ignoring the code label " << code_label << " because it has already been defined."); code_label = ""; } commandx = commandx.after("type["); if ( !commandx.matches(type_residual_pattern) ) ERROR("Incorrect syntax."); int n = take_int(commandx, number_pattern); commandx = commandx.after(","); int dim = take_int(commandx, number_pattern); if ( dim == 0 ) ERROR( "Do you need a computer to study zero-dimensional codes?" ); if ( dim > n ) ERROR("Dimension exceeds length."); commandx = commandx.after(","); weightlist w = weightlist( take(commandx, weightlist_pat), n ); require_char(commandx, ']'); if (auto_mu1 && commandx == "") { if (gullible) results.kill(n-1, dim, w.min()); else { if ( results.new_not_exist( n-1, dim, w.min( ), 1, home, code_label, allowed_failures ) ) results.kill(n-1, dim, w.min()); else ERROR( "The parameter \"auto mu1\" is set but I am unable" << " to show that there is no [" << n-1 << "," << dim << "," << w.min( ) << "] code." ); } } constraintlist assumed_cons; if_match( commandx, "{[^}]*}.*" ) { commandx = commandx.after("{"); String conx = commandx.before("}"); assumed_cons = constraintlist(conx); commandx = commandx.after("}"); } if ( !fast && auto_joint_list ) { home = new codehome(n, dim, w, results, assumed_cons); home->joint_vars = home->basic_joint_vars(results); home->joint_vars.sort(&String_cmp); } else home = new codehome(n, dim, w, assumed_cons); int i; if ( !commandx.empty( ) ) { require_char( commandx, '/' ); String options[n_options]; while(1) { for ( i = 0; i < n_options; i++ ) if ( commandx.contains(option_pats[i], 0) ) { if (!options[i].empty( )) ERROR("Option used twice."); options[i] = take(commandx, option_pats[i]); break; } if ( !commandx.empty( ) && commandx[0] != '/' ) require_char(commandx, ','); if (i == n_options) break; } if ( commandx != "/" ) ERROR("Illegal option or missing /."); if ( !options[0].empty( ) ) { home->opt.dual_may_be_code_of_design = true; options[0] = options[0].after("k="); int k = take_int(options[0], number_pattern); if ( k == 0 || k > n ) ERROR( "k value for dual_may_be_code_of_design " << "option doesn't make sense." ); home->opt.k = k; options[0] = options[0].after(",lambda="); int lambda = take_int(options[0], number_pattern); if ( lambda == 0 ) ERROR( "lambda value for " << "dual_may_be_code_of_design " << "option doesn't make sense." ); home->opt.lambda = lambda; } if ( !options[1].empty( ) ) { home->opt.partition_of_word_by_dual_words = true; options[1] = options[1].after("weight="); int wt = take_int(options[1], number_pattern); home->opt.w = wt; options[1] = options[1].after("weight="); int dwt = take_int(options[1], number_pattern); home->opt.d = dwt; if ( wt < 0 || wt > home->n || dwt < 0 || dwt > n || wt/dwt * dwt != wt ) ERROR("Values for weight and/or dual_weight " << "don't make sense."); } if ( !options[2].empty( ) ) home->opt.doubly_even_part_is_subcode = true; } } index_method(we_from_String) vector we_from_String( String s, int n, int k ) { vector we(n + 1); Integer coefficient, exponent; bool positive; we.set_zero( ); static Regex we_term_pat( "1" + orsign + "t^" + pos_number + orsign + number_pat + "t^" + pos_number + orsign + "t" + orsign + number_pat + "t" ); static Regex number_pattern(number_pat); String we_term; while(1) { if ( s.empty( ) ) break; positive = true; if ( s[0] == '+' ) s.del( '+' ); if ( s[0] == '-' ) { positive = false; s.del( '-' ); } if ( !s.contains( we_term_pat, 0 ) ) ERROR("Garbled weight enumerator."); we_term = take( s, we_term_pat ); if ( we_term[0] == 't' ) coefficient = 1; else coefficient = as_int(take(we_term, number_pattern)); if (!positive) coefficient = -coefficient; if ( we_term.empty( ) ) exponent = 0; else if ( we_term == "t" ) exponent = 1; else exponent = as_int( we_term.after( "t^" ) ); if (exponent > n) ERROR("Garbled weight enumerator."); we( as_int(exponent) ) += coefficient; } Integer sum = 0; for ( int j = 0; j <= n; j++ ) sum += we(j); if ( sum != Ipow(2, k) || we(0) != 1 ) ERROR("That weight enumerator doesn't make sense."); return we; } index_command(status) void execute_status( codehome* home, String commandx, DLList& command_queue, bool gullible, codetable& results ) { String set_pat( "{" + list_of( pos_number + orsign + pos_number + "\\.\\." + pos_number ) + "}" ); static Regex weightlist_pat( pos_number + orsign + pos_number + "_" + pos_number + orsign + set_pat + orsign + pos_number + "-" + set_pat + orsign + pos_number + "_" + pos_number + "-" + set_pat ); String wtlist; Pix entering_config = home->current; commandx = commandx.after( "status:" ); while(1) { if ( commandx.empty( ) ) return; if ( commandx.contains( "classified", 0 ) ) { commandx = commandx.after( "classified" ); if (gullible) home->classified = true; else if (!home->classified) ERROR( "The code type has not been classified." ); if ( commandx.empty( ) ) return; require_char( commandx, ',' ); } else if ( commandx[0] == 'w' ) { if ( !commandx.contains( "weights=", 0 ) ) ERROR( "Unrecognized status command." ); commandx = commandx.after( "weights=" ); if ( !commandx.contains( weightlist_pat, 0 ) ) ERROR( "Unrecognized status command." ); wtlist = take( commandx, weightlist_pat ); weightlist w(wtlist, home->n); if (!gullible) { weightlist w1 = diff( w, home->ww(home->base) ); if ( !w1.empty( ) ) WARNING( "You should not have the " << "weights " << w1 << " in your weightlist." ); OSLList w2 = diff( home->ww(home->base), w ); if ( !w2.empty( ) ) { vector v2(w2); for ( int i = v2.length-1; i >= 0; i-- ) { int wx = v2(i); int n = home->n; if ( n == wx ) home->set_config(String(dec(wx)) + ":{1}"); else home->set_config( String(dec(wx)) + "," + dec(n - wx) + ":{10}" ); home->configs(home->current). check_secondary_residuals(results); home->activate(true); if ( home->contradiction(true, results) ) { home->ww(home->base).del(wx); continue; } home->set_current(home->base); home->deactivate( ); home->activate(true); set_numerical_parameter( "usedualdualforjoint", "0", "save" ); set_numerical_parameter( "usedualdualforjoint", "0", "set" ); constraintlist cl( String("y") + dec(wx) + "=0" ); bool answer = home->show(cl, results, true, constraintlist( ), true); set_numerical_parameter( "usedualdualforjoint", "0", "restore" ); if (answer) { home->ww(home->base).del(wx); continue; } set_numerical_parameter( "usedualdualforjoint", "5", "save" ); set_numerical_parameter( "usedualdualforjoint", "5", "set" ); answer = home->show(cl, results, true, constraintlist( ), true); set_numerical_parameter( "usedualdualforjoint", "5", "restore" ); if (!answer) ERROR("I can't get rid of weight " << wx << "."); home->ww(home->base).del(wx); } } } else home->ww(home->base) = w; home->set_current(entering_config); if ( commandx.empty( ) ) return; require_char( commandx, ',' ); } else if ( commandx[0] == 'e' ) { if ( !commandx.contains( "enumerator=", 0 ) ) ERROR( "Unrecognized status command." ); commandx = commandx.after( "enumerator=" ); String wes; if ( commandx.contains(',') ) { wes = commandx.before(','); commandx = commandx.after(','); } else { wes = commandx; commandx = ""; } vector we = we_from_String( wes, home->n, home->dim ); if (gullible) { for ( int i = 1; i <= home->n; i++ ) if (we(i) == 0) home->ww(home->base).del(i); else home->configs(home->base).share->ycon.append( String("y") + dec(i) + "=" + dec(we(i)) ); } else { home->set_current(home->base); int i; for ( i = 1; i <= home->n; i++ ) if (we(i) != 0 && !home->configs(home->base).known ( String("y") + dec(i) + "=" + dec(we(i)) ) ) break; if ( i <= home->n ) { SLList vars0; for ( i = home->n; i >= 1; i-- ) { if ( we(i) == 0 && home->ww(home->base).contains(i) ) vars0.append( String("y") + dec(i) ); } if ( !vars0.empty( ) ) { prevector vars(vars0); execute_kill_variable_by( home, vars, false, results ); } for ( i = 1; i <= home->n; i++ ) { String y_eq = String("y") + dec(i) + "=" + dec(we(i)); if ( we(i) != 0 && !home->configs(home->base).known(y_eq) && !home->show(y_eq, results, true) && !home->show(y_eq, results, true, constraintlist( ), true) ) ERROR( "I can't show that the weight " << "enumerator of the base " << "configuration " << "is " << as_poly(we) << "." ); } } for ( i = 1; i <= home->n; i++ ) if (we(i) == 0) home->ww(home->base).del(i); } home->we_known = true; home->set_current(entering_config); if ( commandx.empty( ) ) return; require_char( commandx, ',' ); } else if ( commandx[0] == 'c' ) { if ( !commandx.contains( "constraints={", 0 ) ) ERROR( "Unrecognized status command." ); commandx = commandx.after("constraints={"); HIDE(![ static String less_op = left + "<" + orsign + "<=" + right; static String compound_constraint_pat = "[-]?" + number_pat + less_op + LHS_pat + less_op + "[-]?" + number_pat; static Regex constraint_list_pat( list_of( constraint_pat + orsign + var + "!=0" + orsign + compound_constraint_pat) ); ]!) if ( !commandx.contains( constraint_list_pat, 0 ) ) ERROR("Constraint list is garbled."); constraintlist cl( take( commandx, constraint_list_pat ) ); require_char( commandx, '}' ); if ( !cl.global( ) ) ERROR("The constraints must be global."); forPixDef( p, cl ) { if (gullible) home->configs(home->base).share->ycon.merge( cl(p) ); else if ( !home->configs(home->base).known( cl(p) ) ) ERROR( "I don't know that " << cl(p) << ".\n" ); } if ( commandx.empty( ) ) return; require_char( commandx, ',' ); } else if ( commandx.contains( "unique", 0 ) ) { commandx = commandx.after( "unique" ); if (gullible) { home->unique = true; home->configs(home->base).share->realizable = 1; } else if (!home->unique) ERROR( "The code type is not known to contain a unique code." ); if ( commandx.empty( ) ) return; require_char( commandx, ',' ); } else { if ( !commandx.contains( "realizable", 0 ) ) ERROR( "Unrecognized status command." ); commandx = commandx.after("realizable"); if (gullible) home->configs(home->base).share->realizable = 1; else if ( home->configs(home->base).share->realizable != 1 ) WARNING( "I don't know that the code type is realizable." ); if ( commandx.empty( ) ) return; require_char( commandx, ',' ); } } } index_method(expand_config_list) prevector expand_config_list( codehome* home, String s ) { HIDE( ![ static Regex config_list_pat(config_list); ]! ) static Regex config_list_piece_pat(config_list_piece); if ( !s.matches( config_list_pat ) ) ERROR( "Syntax of configuration list is wrong." ); prevector answer; SLList pass1, pass2, pass3; while( !s.empty( ) ) { pass1.append( take(s, config_list_piece_pat) ); if ( s.empty( ) ) break; s.del( "," ); } forPixDef( p, pass1 ) { String piece = pass1(p); if ( !piece.contains("{") ) pass2.append(piece); else { String front = piece.before("{"); piece = piece.after("{"); piece.del("]"); if ( !piece.contains("}", -1) ) ERROR( "Syntax of configuration list is wrong." ); piece.del("}", -1); prevector segs = unpack(piece); for ( int i = 0; i < segs.length; i++ ) pass2.append( front + segs(i) + "]" ); } } forPix( p, pass2 ) { String piece = pass2(p); if ( !piece.contains("*") ) pass3.append(piece); else { pass2(p).del("]", -1); if ( !pass2(p).contains("*", -1) ) ERROR( "Syntax of configuration list is wrong." ); pass2(p).del("*", -1); forPixDef( q, home->labels ) if ( home->labels(q).first.contains( pass2(p), 0 ) ) { String s = home->labels(q).first.after( pass2(p) ); if ( s.contains( "!" ) ) continue; pass3.append( home->labels(q).first ); } } } return prevector(pass3); } index_command(via unique wordtypes) void execute_via_unique_wordtypes( String label1, String label2, Pix pix1, Pix pix2, codehome* home, bool gullible ) { if (!gullible) { config& c1 = home->configs(pix1); config& c2 = home->configs(pix2); if ( !c2.terminal( ) ) ERROR(label2 << " is not terminal."); if ( !home->configs(pix2).share->realizable == 1 ) ERROR( label2 << " is not known to be realizable" ); forPixDef( p, home->implications ) if ( home->implications(p).first == pix2 && home->implications(p).second.length( ) == 1 && home->implications(p).second.front( ) == pix1 ) break; if (p == 0) ERROR("I don't know that the realization of " << label2 << " is contained in the realization of " << label1 << "."); vector we = c1.smallcode_we( ); SLList unknowns; for ( int i = 1; i <= home->n; i++ ) { String con = String("y") + dec(i) + "=" + dec(we(i)); if ( !c1.known( con ) ) unknowns.append(con); } if ( unknowns.length( ) > 1 ) { cerr << "The following constraints are unknown:\n"; forPix( p, unknowns ) cerr << " " << unknowns(p) << "\n"; ERROR("At most one such constraint can be unknown."); } } home->implications.append(make_pair(pix1, make_list(pix2) )); home->set_current(0); } set_compile_file(code.c) HIDE( ![ pair< Permutationlist, Integer > find_automorphism_group(const matrix&); prevector expand_config_list(codehome*, String); void execute_infer_command(codehome*, config&, constraint, codetable&, bool); void execute_kill_variable_by(codehome*, prevector, bool, codetable&); void execute_incorporate_command(codehome*, String, String, String, String, Pix, Pix, codetable&, bool); void execute_classification_of(codehome*, String&, prevector&, bool, const codetable&); void execute_via_lp_command(codehome*, String, bool, codetable&,bool); void execute_via_extension(codehome*, String, prevector, bool, bool, codetable&, String, int&); void execute_dump(codehome*); void execute_try_to_kill_current(codehome*, codetable&); void execute_disjoint(codehome*, prevector, bool, const codetable&); void execute_via_weight_enumerator(codehome*, String, String, Pix, Pix, bool); void execute_via_constraint_drop(codehome*, String, String, Pix, Pix, bool, codetable&); void execute_up_to_isomorphism_show(codehome*, String, bool, codetable&); void execute_infer_from_local_variables(codehome*, constraint, bool); void execute_via_variable_split(codehome*, String, prevector, bool, const codetable&); void execute_implies(codehome*, String, String, Pix, Pix, bool); void execute_kill_current_by(codehome*, prevector, bool, codetable&); void execute_equals(codehome*, Pix, Pix, bool); void execute_via_dual_word(codehome*, String, Pix, bool); void execute_via_configuration_search(codehome*, String, String, Pix, Pix, bool); void execute_load_constraints(codehome*, codetable&, String, Pix); void execute_projection_onto(codehome*, word, String, Pix, codetable&, bool, int); void execute_infer_by_residual_code(codehome*, String, Pix, constraintlist, codetable&, bool); void execute_bound(codehome*, String, codetable&); void execute_realizable(codehome*, prevector, bool, const codetable&); void execute_automorphism(codehome*, String, Permutation, bool); void execute_via_dual_nonexistence(codehome*, codetable&, bool); void execute_report_group_size(codehome*, prevector); void execute_propagate(codehome*, constraintlist); void execute_deduce(codehome*, String&, prevector&, bool, const codetable&, bool); void execute_via_building(codehome*, int, bool, String, prevector, bool, bool, const codetable&, String, int&); void execute_known(codehome*, constraintlist, bool); void execute_clean(String); void execute_macaulay(const matrix&); void execute_via_varying(String, prevector, codehome*, bool, codetable&); void execute_reduce_variable_set(codehome*); void execute_print_joint(codehome*); void execute_config_from(codehome*, String, String, bool, codetable&); void execute_round_local(codehome*, codetable&); void execute_random_we(short int, short int, short int, short int, Integer); void execute_random_macaulay(short int, short int, short int, Integer); void execute_find_cyclic_codes(codehome*, int); void execute_is_cyclic(codehome*, bool, codetable&); void execute_print(String, codehome* home, long int); void execute_help(String); void execute_test(int,int,int,codetable&,codehome*, String&, const constraintlist&); void execute_type(String, codehome*&, codetable&, String&, bool, bool); void execute_status(codehome*, String, DLList&, bool, codetable&); void execute_via_unique_wordtypes(String, String, Pix, Pix, codehome*, bool); void set_numerical_parameter(const String&, const String&, const String&); void save_and_set_parameters(String); void restore_parameters(String); void parse_j_var(String, int&, int&, int&); bool isomorphic(const matrix&, const matrix&); int griesmer(int, int); ]! ) TEX( \block{Main program}\label{main-program-section} ) #ifdef ABSOLUTE_PATH_FOR_CPLEX #include #endif HIDE(![#include ]!) int warnings_are_fatal = 1; HIDE( ![ matrix process_matrix_descriptor(String, const codetable&, codehome*, String&); inline bool test(const Rational& a, const Rational& b, char sense) { if ( sense == '=' ) return a == b; if ( sense == '<' ) return a <= b; return a >= b; } vector dual_of_we(vector); ]! ) // The following shouldn't be needed. inline int cmp(const vector& a, const vector& b) { register int i, n = a.length; for ( i = 0; i < n; i++ ) { if ( a(i) > b(i) ) return 1; if ( a(i) < b(i) ) return -1; } return 0; } TEX( ![ \verb|min_distance|:\ Compute the minimum distance of the code defined by the rowspace of the given matrix {\tt M}. But if we find a nonzero codeword of weight less than the given value {\tt d0}, halt and return $0$. ]! ) index_method(min_distance) int min_distance( const matrix& M, int d0 ) { vector indx(M.nrows), sum(M.ncols); indx.advance( ); int d = M.ncols; register gf2* Mk; register int tl; do { register int j, k; sum.set_zero( ); for ( k = 0; k < indx.length; k++ ) if ( indx(k).x ) { Mk = M.x[k].x; tl = sum.length; for ( j = 0; j < tl; j++ ) sum(j).x ^= Mk[j].x; } d = min(d, sum.weight( ) ); if ( d < d0 ) return 0; } while( indx.advance( ) != 0 ); return d; } index_command(n =) void execute_n_equals( codetable& results, DLList& command_queue, short int n, short int k, String inv ) { static Regex number_pattern( number_pat ); prevector vs = unpack(inv); vector v0(vs.length), v1(vs.length); int i; for ( i = 0; i < vs.length; i++ ) { if ( vs(i).matches(number_pattern) ) { v0(i) = v1(i) = as_int( vs(i) ); continue; } if ( vs(i)[0] != '-' ) v0(i) = as_int( take( vs(i), pos_number_pattern ) ); else v0(i) = 1; if ( vs(i) != "-" ) v1(i) = as_int( vs(i).after("-") ); else v1(i) = n; } if ( k + v0.length - 1 >= n ) ERROR( "This command is not for [n,k] codes with k >= n." ); for ( i = v0.length - 1; i >= 0; i-- ) { if (!gullible) { if (optimal && lower_bound_check) command_queue.append( String("test yes[") + dec(n) + "," + dec(k+i) + "," + dec( v0(i).x + 1) + "]" ); if ( optimal && even(int(v1(i))) ) command_queue.append( String("test[") + dec(n) + "," + dec(k+i) + "," + dec( v1(i).x ) + "]" ); } if (lower_bound_check) { if (gullible) results.update_lower_bound(n, k+i, v0(i).x); else command_queue.append( String("yes[") + dec(n) + "," + dec(k+i) + "," + dec( v0(i).x ) + "]" ); } if ( v1(i) != n ) { if (gullible) results.kill( n, k+i, v1(i)+1 ); else command_queue.append( String("no[") + dec(n) + "," + dec(k+i) + "," + dec( v1(i) + 1 ) + "]" ); } } } index_class(IEquivRelIntList) // IEquivRelIntList is the same as EquivRelIntList, except that we use // class "int" instead of class "number" for the entries. class IEquivRelIntList : public vector { public: IEquivRelIntList(int n) : vector(n) { for ( int i = 0; i < length; i++ ) (*this)(i) = i; } IEquivRelIntList(const vector&, bool); // use equality as the // relation on a given list }; TEX( ![ Find orbit representatives for $r$-tuples of column indices of a matrix $M$, under the action of $\Aut(M)$. ]! ) index_method(tuple_orbits) prevector< vector > tuple_orbits( matrix M, int r ) { int i, j; vector< vector > Ctuplev; vector tuple(r); IEquivRelIntList e(1); for ( i = 0; i < r; i++ ) tuple(i) = i; { SLList< vector > Ctuple; while(1) { Ctuple.append(tuple); for ( i = r-1; i >= 0; i-- ) if ( tuple(i) < M.ncols - (r-i) ) break; if ( i == -1 ) break; ++tuple(i); for ( j = i+1; j < r; j++ ) tuple(j) = tuple(j-1) + 1; } Ctuplev = Ctuple; } pair< Permutationlist, Integer > pp = find_automorphism_group(M); Permutationlist au = pp.first; e = IEquivRelIntList(Ctuplev.length); // The following gives a canonical element of an e-equivalence class. // If i is a canonical element, e_size(i) is the size of its // equivalence class. prevector e_can(Ctuplev.length), e_size(Ctuplev.length); for ( i = 0; i < Ctuplev.length; i++ ) { e_can(i) = i; e_size(i) = 1; } for ( int pass = 1; pass <= 2; pass++ ) { for ( i = 0; i < au.length; i++ ) { for ( int j1 = 0; j1 < Ctuplev.length; j1++ ) { if ( pass == 1 && j1 != e_can(j1) ) continue; vector p( Ctuplev(j1) ), p2(r); for ( int kk = 0; kk < r; kk++ ) p2(kk) = au(i)( p(kk) ) - 1; p2.sort( &rcmp ); int j2 = Ctuplev.pos( p2, &cmp ); if ( j2 == -1 ) INTERNAL_ERROR("Ctuplev broken"); // In effect do "e.join( j1, j2 );", but also update e_can // and e_size. int ec1 = e_can(j1), ec2 = e_can(j2); int es1 = e_size(ec1), es2 = e_size(ec2); if ( ec1 != ec2 ) { if ( es2 <= es1 ) { int z = j2; do { e_can(z) = ec1; z = e(z); } while ( z != j2 ); e_size(ec1) = es1 + es2; } else { int z = j1; do { e_can(z) = ec2; z = e(z); } while ( z != j1 ); e_size(ec2) = es1 + es2; } int a = e(j1); e(j1) = e(j2); e(j2) = a; } } } } SLList< vector > answer; for ( int j1 = 0; j1 < Ctuplev.length; j1++ ) if ( j1 == e_can(j1) ) answer.append( Ctuplev(j1) ); return prevector< vector >(answer); } index_method(process_new_matrix) TEX( ![ \verb|process_new_matrix(B,s,results,desc,sort)|:\ Let {\tt B} be a binary matrix, not necessarily in \RREF, with description given by the string {\tt s}. Let $C$ be the rowspace of {\tt B}. Print it if not known to {\tt results}, and if not already printed. Return the deviance $\delta d$ of the minimum distance of $C$ from the best known minimum distance. (If $\delta d$ is negative, $C$ beats the known bound.) Upon entry the allowed descrepancy {\tt desc} is to be a nonnegative integer. If $\delta d > \verb|desc|$, return $\verb|desc| + 1$ instead of $\delta d$. (This allows us to avoid computing the minimum distance of $C$ in many cases.) If the {\tt sort} flag is set, the columns of {\tt B} may be lexicographically sorted. ]!) int process_new_matrix( matrix B, String s, codetable& results, int desc, bool sort, int d_if_known = 0, bool dont_delete_columns = false ) { static SLList< matrix > newcodes; matrix B_save = B; B.reduce_nz( ); if ( B.nrows < dual_transform_dim_low ) return desc + 1; int n = B.ncols; int k = B.nrows; static int n0(0), k0(0); if ( n+1 >= results.lower_bound.nrows || k+1 >= results.lower_bound.ncols ) results.update_lower_bound(n,k,1); // Force table resizing. int d00 = results.lower_bound(n,k); int d0 = d00 - desc; int d; if ( d_if_known != 0 ) d = d_if_known; else d = min_distance( B, d0 ); if ( d == 0 ) return desc + 1; if ( d < d00 - 1 ) return d00 - d; if (debug) // XXX cerr << "{" << n << "," << k << "," << d << "}, d00 = " << // XXX d00 << ", s = " << s << "\n"; // XXX if (!nonprojective_search) { // Add parity check. bool parity_check = odd(d); if ( parity_check ) { matrix Bp = B; Bp.resize( B.nrows, B.ncols+1 ); for ( int j = 0; j < B.nrows; j++ ) if ( odd( B(j).weight( ) ) ) Bp( j, B.ncols ) = 1; B = Bp; n++; d++; d00 = results.lower_bound(n,k); } if ( d > d00 && results.exist(n,k,d,true) ) d00 = results.lower_bound(n,k); if ( d < d00 ) return d00 - d; results.update_lower_bound(n,k,d); if ( n > n0 || k > k0 ) { results.recompute_lower_bound(n, k); n0 = max(n,n0); k0 = max(k,k0); } if ( d == d00 ) { if ( results.lower_bound( n-1, k ) >= d ) return 0; if ( results.lower_bound( n+1, k ) >= d+1 ) return 0; if ( results.lower_bound( n+1, k+1 ) >= d ) return 0; if ( results.is_unique(n,k,d) ) return true; if ( results.known(B) ) return 0; forPixDef( p, newcodes ) if ( isomorphic( B, newcodes(p) ) ) return 0; } newcodes.append(B); cerr << "[" << n << "," << k << "," << d << "]\n" << s; if (parity_check) cerr << " + check"; cerr << "\n" << B << "\n"; return d00 - d; } else { results.update_lower_bound(n,k,d); if ( n > n0 || k > k0 || d > d00 ) { results.recompute_lower_bound(n, k); d00 = results.lower_bound(n,k); if ( d < d00 - 1 ) return d00 - d; n0 = max(n,n0); k0 = max(k,k0); } int i, j; if (debug) cerr << "contemplating sort\n"; // XXX if (sort) { B = B_save; prevector columns(B.ncols); for ( j = 0; j < B.ncols; j++ ) columns(j).set_size(B.nrows); for ( i = 0; i < B.nrows; i++ ) for ( j = 0; j < B.ncols; j++ ) columns(j)(i) = B(i)(j); columns.sort(&cmp); for ( i = 0; i < B.nrows; i++ ) for ( j = 0; j < B.ncols; j++ ) B(i)(j) = columns(j)(i); B.reduce_nz( ); } TEX( ![ \begin{quotea} Create a matrix $M$ whose rows are the minimum weight codewords. \end{quotea} ]! ) if (debug) cerr << "creating min_words\n"; // XXX SLList min_words; word indx(k), w(n); do { mul( indx, B, w ); if ( w.weight( ) == d ) min_words.append(w); } while( indx.advance( ) != 0 ); matrix M( n, min_words ); bool improvable = false; TEX( ![ \begin{quotea} Look for columns $i$ of $M$ which are all zero vectors. These can be removed to give a better code. If these exist, we look for maximal sets of columns which can be deleted to give a better code. Don't do any of this if a column has already been doubled. \end{quotea} ]! ) if ( !s.contains("+ column") && !dont_delete_columns ) { SLList to_remove; for ( i = 0; i < n; i++ ) { for ( j = 0; j < M.nrows; j++ ) if ( M(j,i) == 1 ) break; if ( j == M.nrows ) to_remove.append(i); } if ( !to_remove.empty( ) ) { prevector tdv(to_remove); prevector< OSLList< vector > > deletables(n+1); // Set up deletable sets of size 1. for ( i = 0; i < tdv.length; i++ ) { vector item(1); item(0) = tdv(i); deletables(1).add(item); } // Inductively find deletable sets of size i+1. for ( i = 1; i <= n-1; i++ ) { forPixDef( p, deletables(i) ) { vector st = deletables(i)(p); for ( j = 0; j < tdv.length; j++ ) { if ( st.member(tdv(j)) ) continue; vector stp(st); stp.resize(i+1); stp(i) = tdv(j); stp.sort(&rcmp); if (deletables(i+1).contains(stp)) continue; matrix B2( k, n-(i+1) ); int cx = 0; for ( int lc = 0; lc < n; lc++ ) { if ( stp.member(lc) ) continue; for ( int lr = 0; lr < k; lr++ ) B2(lr,cx) = B(lr,lc); cx++; } if ( min_distance(B2, d) == d ) deletables(i+1).add(stp); } } } // Delete non-maximal deletable sets. for ( i = 2; i <= n; i++ ) { forPixDef( p, deletables(i) ) { SLList non_max; forPixDef( q, deletables(i-1) ) if ( subset ( deletables(i-1)(q), deletables(i)(p) ) ) non_max.append(q); forPix( q, non_max ) deletables(i-1).del( deletables(i-1)(non_max(q)) ); } } if (debug) // XXX { cerr << "maximal sets of deletable columns:\n"; // XXX for ( i = 1; i <= n; i++ ) // XXX { forPixDef( p, deletables(i) ) // XXX cerr << deletables(i)(p) << "\n"; } } // XXX // Generate matrices and invoke process_new_matrix. for ( i = 1; i <= n; i++ ) { forPixDef( p, deletables(i) ) { vector st = deletables(i)(p); matrix B2( k, n-i ); int cx = 0; for ( int lc = 0; lc < n; lc++ ) { if ( st.member(lc) ) continue; for ( int lr = 0; lr < k; lr++ ) B2(lr,cx) = B(lr,lc); cx++; } String ss = s; for ( j = 0; j < st.length; j++ ) ss += String(" - column ") + dec(st(j) + 1 - j); if (debug) cerr << "using " << st << "\n"; // XXX process_new_matrix( B2, ss, results, desc, false, d, true ); } } return d00 - d; } } TEX( ![ \begin{quotea} Look for columns $i$ which are all ones vectors. These can be doubled to give a better code. \end{quotea} ]! ) if (debug) cerr << "trying to double columns\n"; // XXX SLList to_double; for ( i = 0; i < n; i++ ) { for ( j = 0; j < M.nrows; j++ ) if ( M(j,i) == 0 ) break; if ( j == M.nrows ) to_double.append(i); } if ( !to_double.empty( ) ) { improvable = true; prevector tdv(to_double); EquivRelIntList e(tdv.length); for ( i = 0; i < tdv.length; i++ ) { int ii = tdv(i); matrix B2( k, n+1 ); for ( j = 0; j <= ii; j++ ) for ( int l = 0; l < k; l++ ) B2(l,j) = B(l,j); for ( j = ii; j < n; j++ ) for ( int l = 0; l < k; l++ ) B2(l,j+1) = B(l,j); process_new_matrix( B2, s + " + column " + dec(ii+1), results, desc, false, d+1 ); } } TEX( ![ \begin{quotea} Look for pairs of columns whose union is the all ones vector. These can be doubled to give (possibly) a good code. To speed this up, I've put a weight enumerator filter on this. So some new codes may be missed. \end{quotea} ]! ) if (debug) cerr << "trying to double column pairs\n"; // XXX bool double_column_pair_succeeded = false; static SLList< triple< int, int, vector > > wes; if ( !improvable && double_column_pairs ) { if (debug) cerr << "attempting to double column pairs\n"; // XXX for ( i = 0; i < n; i++ ) { for ( j = i; j < n; j++ ) { int l; for ( l = 0; l < M.nrows; l++ ) if ( M(l,i) == 0 && M(l,j) == 0 ) break; if (l == M.nrows) break; } if ( j < n ) break; } if ( i < n ) { if (debug) cerr << "it is possible\n"; // XXX double_column_pair_succeeded = true; // Check to see if weight enumerator has already been // encountered or if it looks like the automorphism // group computer will hang on the matrix. vector w = B.enumerate_weights( ); for ( j = 0; j < w.length; j++ ) if ( odd(j) && (w(j) == 128 || w(j) == 256 || w(j) == 512 ) ) break; forPixDef( p, wes ) if ( wes(p).first == n && wes(p).second == k && wes(p).third == w ) break; if ( j == w.length && p == 0 ) { wes.append(make_triple(n, k, w)); prevector< vector > Ct = tuple_orbits(B, 2); for ( int ee = 0; ee < Ct.length; ee++ ) { i = Ct(ee)(0); j = Ct(ee)(1); int l; for ( l = 0; l < M.nrows; l++ ) if ( M(l,i) == 0 && M(l,j) == 0 ) break; if (l == M.nrows) { matrix B2( k, n+2 ); int cc; for ( cc = 0; cc <= i; cc++ ) for ( l = 0; l < k; l++ ) B2(l,cc) = B(l,cc); for ( cc = i; cc <= j; cc++ ) for ( l = 0; l < k; l++ ) B2(l,cc+1) = B(l,cc); for ( cc = j; cc < n; cc++ ) for ( l = 0; l < k; l++ ) B2(l,cc+2) = B(l,cc); process_new_matrix( B2, s + " + column " + dec(i+1) + " + column " + dec(j+2), results, desc, false, d+1 ); } } } } } if (debug) cerr << "trying to double column triples\n"; // XXX if ( !improvable && double_column_triples && !double_column_pair_succeeded ) { if (debug) cerr << "attempting to double column triples\n"; // XXX int h; for ( i = 0; i < n; i++ ) { for ( j = i; j < n; j++ ) { for ( h = j; h < n; h++ ) { int l; for ( l = 0; l < M.nrows; l++ ) if ( M(l,i) == 0 && M(l,j) == 0 && M(l,h) == 0 ) break; if (l == M.nrows) break; } if ( h < n ) break; } if ( j < n ) break; } if ( i < n ) { if (debug) cerr << "it is possible\n"; // XXX vector w = B.enumerate_weights( ); for ( j = 0; j < w.length; j++ ) if ( odd(j) && (w(j) == 128 || w(j) == 256 || w(j) == 512 ) ) break; forPixDef( p, wes ) if ( wes(p).first == n && wes(p).second == k && wes(p).third == w ) break; if ( j == w.length && p == 0 ) { wes.append(make_triple(n, k, w)); prevector< vector > Ct = tuple_orbits(B, 3); for ( int ee = 0; ee < Ct.length; ee++ ) { i = Ct(ee)(0); j = Ct(ee)(1); h = Ct(ee)(2); int l; for ( l = 0; l < M.nrows; l++ ) if ( M(l,i) == 0 && M(l,j) == 0 && M(l,h) == 0 ) break; if (l == M.nrows) { matrix B2( k, n+3 ); int cc; for ( cc = 0; cc <= i; cc++ ) for ( l = 0; l < k; l++ ) B2(l,cc) = B(l,cc); for ( cc = i; cc <= j; cc++ ) for ( l = 0; l < k; l++ ) B2(l,cc+1) = B(l,cc); for ( cc = j; cc <= h; cc++ ) for ( l = 0; l < k; l++ ) B2(l,cc+2) = B(l,cc); for ( cc = h; cc < n; cc++ ) for ( l = 0; l < k; l++ ) B2(l,cc+3) = B(l,cc); process_new_matrix( B2, s + " + column " + dec(i+1) + " + column " + dec(j+2) + " + column " + dec(h+3), results, desc, false, d+1 ); } } } } } if ( improvable || d < d00 ) return d00 - d; if ( results.lower_bound( n+1, k ) >= d+1 ) return 0; if ( results.lower_bound( n-1, k ) >= d ) return 0; if ( results.lower_bound( n+1, k+1 ) >= d ) return 0; // Add parity check. bool parity_check = odd(d); if (parity_check) { matrix Bp = B; Bp.resize( B.nrows, B.ncols+1 ); for ( j = 0; j < B.nrows; j++ ) if ( odd( B(j).weight( ) ) ) Bp( j, B.ncols ) = 1; B = Bp; n++; d++; d00 = results.lower_bound(n,k); } if ( d == d00 && !show_even_if_known ) { if ( results.is_unique( n, k, d ) ) return 0; if ( results.known(B) ) return 0; forPixDef( p, newcodes ) if ( isomorphic( B, newcodes(p) ) ) return 0; } newcodes.append(B); cerr << "[" << n << "," << k << "," << d << "]\n" << s; if (parity_check) cerr << " + check"; cerr << "\n" << B << "\n"; return d00 - d; } } long int command_start_time; TEX( ![ Given a matrix, and given an equivalence relation on its codewords, look for new good codes whose generator matrices have as their columns the codewords lying in some of the equivalence classes of the codewords. The equivalence classes of codewords are given as the argument {\tt ec}. The arguments \verb|title_head|, \verb|title_type|, \verb|tu|, and \verb|rp| are part of an ad hoc mechanism for titling the new codes. ]! ) index_method(code_search) void code_search( matrix M, prevector< prevector > ec, codetable& results, String title_head, int title_type, vector tu, int rp ) { int i, j, l; SLList nz; vector nzv; int dual_length_low = 1; too_long: nz.clear( ); for ( j = 0; j < ec.length; j++ ) if ( ec(j).length >= dual_length_low && ec(j).length <= dual_transform_length_limit ) nz.append(j); nzv = nz; if ( nzv.length > nzv_length_max ) { dual_length_low += 1; goto too_long; } cerr << "nzv has length " << nzv.length << "\n"; if ( nzv.length == 0 ) return; TEX( ![ \begin{quote} Let $k = \verb|M.nrows|$. We create a matrix {\tt ecwt} which has one row for each element of $\F_2^k - \setof{0}$. Recall that for each $j$, $\verb|ec|(j)$ is of type \verb|prevector| -- which we think of now as a matrix $N_j$, with each {\tt word} comprising a row. Considering now what the \th{i} row of \verb|ecwt| is to be, let $v_i$ be the element of $\F_2^k$ corresponding to $i$. Then $\verb|ecwt|(i,j) = \abs{N_j v_i}$. \end{quote} ]! ) matrix ecwt(as_int(Ipow(2,M.nrows) - 1), ec.length); word indx(M.nrows); indx.advance( ); i = 0; do { for ( j = 0; j < ec.length; j++ ) for ( l = 0; l < ec(j).length; l++ ) ecwt(i,j) += int(ec(j)(l) * indx); i++; } while( indx.advance( ) ); SLList nz2; vector nzv2; int dual_length_low2 = 1; too_long2: nz2.clear( ); for ( j = 0; j < ec.length; j++ ) if ( ec(j).length >= dual_length_low2 && ec(j).length < dual_length_low ) nz2.append(j); nzv2 = nz2; if ( nzv2.length > nzv_length_max2 ) { dual_length_low2 += 1; goto too_long2; } if ( nzv2.length != 0 ) cerr << "nzv2 has length " << nzv2.length << "\n"; vector ix(nzv.length); ix.advance( ); vector w; Integer count = 0; Integer count_max = Ipow(2, nzv.length); long int loop_start_time = time(0); do { ++count; if ( count % 1000000 == 0 ) { cerr << "[" << setprecision(3) << double(Rational(count*100, count_max)) << "% done in "; long time_used = time(0) - loop_start_time; cerr << time_used/60.0 << " minutes]\n"; } int ss = 0, ff = 0, ee; w.set_size(ix.weight( )); for ( ee = 0; ee < nzv.length; ee++ ) { if ( ix(ee) ) { w(ff) = nzv(ee); ss += ec(w(ff)).length; if ( ss > dual_transform_length_limit ) break; ff++; } } if ( ee != nzv.length ) continue; if ( ss <= M.nrows ) continue; int desc = transform_pass_level; if ( nzv_length_max2 == 0 ) desc = 0; int d0x = results.lower_bound(ss, M.nrows) - desc; int d = ss; for ( i = 0; i < ecwt.nrows; i++ ) { int sum = 0; for ( j = 0; j < w.length; j++ ) sum += ecwt(i)(w(j)); if (sum == 0 && M.nrows == dual_transform_dim_low) break; if (sum > 0) d = min(d, sum); if (d < d0x) break; } if ( i != ecwt.nrows ) continue; matrix A(ss, M.nrows), B; int er = 0; for ( int ew = 0; ew < w.length; ew++ ) { int mm = w(ew); for ( int xy = 0; xy < ec(mm).length; xy++ ) { A(er) = ec(mm)(xy); er++; } } A.transpose_equals(B); matrix B0 = B; String s; if (title_type == 1) { s = title_head + "{"; for ( i = 0; i < w.length; i++ ) { s += dec( int(w(i))/rp ) + String("_{"); int res = w(i) % rp; for ( j = 0; j < tu.length; j++ ) { if ( res % 2 ) s += dec(tu(j)+1); else s += dec(-(tu(j)+1)); if ( j != tu.length - 1 ) s += ","; res /= 2; } s += "}"; if ( i != w.length - 1 ) s += ","; } s += "}"; } else if (title_type == 2) { s = title_head + "{"; for ( i = 0; i < w.length; i++ ) { s += ec(w(i))(0); if ( i != w.length-1 ) s += ","; } s += "}"; } int delta_d = process_new_matrix(B, s, results, desc, true, d); if ( delta_d > desc ) continue; // Now we try to double existing column groups. word ixd(w.length); vector wd; do { if ( !double_column_groups && !ixd.if_zero( ) ) break; int ssd = ss; ff = 0; wd.set_size(ixd.weight( )); for ( ee = 0; ee < w.length; ee++ ) { if ( ixd(ee) ) { wd(ff) = w(ee); ssd += ec(wd(ff)).length; ff++; } } if ( ssd > dual_transform_length_limit ) continue; matrix Ad(ssd-ss, M.nrows), Bd, BdB; er = 0; for ( int ew = 0; ew < wd.length; ew++ ) { int mm = wd(ew); for ( int xy = 0; xy < ec(mm).length; xy++ ) { Ad(er) = ec(mm)(xy); er++; } } Ad.transpose_equals(Bd); hcat( B0, Bd, BdB ); B = BdB; matrix B00 = B; String sd; if (title_type == 1) { sd = s; sd.del("}", -1); sd += ","; for ( i = 0; i < wd.length; i++ ) { sd += dec( int(wd(i))/rp ) + String("_{"); int res = wd(i) % rp; for ( j = 0; j < tu.length; j++ ) { if ( res % 2 ) sd += dec(tu(j)+1); else sd += dec(-(tu(j)+1)); if ( j != tu.length - 1 ) sd += ","; res /= 2; } sd += "}"; if ( i != wd.length - 1 ) sd += ","; } sd += "}"; } else if (title_type == 2) { sd = s; sd.del("}", -1); sd += ","; for ( i = 0; i < wd.length; i++ ) { sd += ec(wd(i))(0); if ( i != wd.length-1 ) sd += ","; } sd += "}"; } if ( !ixd.if_zero( ) ) delta_d = process_new_matrix( B, sd, results, desc, true); if ( delta_d > desc || nzv2.length == 0 ) continue; vector ix2(nzv2.length); ix2.advance( ); vector w2; do { int ss2 = ssd; ff = 0; w2.set_size(ix2.weight( )); for ( ee = 0; ee < nzv2.length; ee++ ) { if ( ix2(ee) ) { w2(ff) = nzv2(ee); ss2 += ec(w2(ff)).length; ff++; } } if ( ss2 > dual_transform_length_limit ) continue; matrix A2(ss2-ssd, M.nrows), B2, B2B; er = 0; for ( int ew = 0; ew < w2.length; ew++ ) { int mm = w2(ew); for ( int xy = 0; xy < ec(mm).length; xy++ ) { A2(er) = ec(mm)(xy); er++; } } A2.transpose_equals(B2); hcat( B00, B2, B2B ); B = B2B; String ss; if (title_type == 1) { ss = "tier 2 " + sd; ss.del("}", -1); ss += ","; for ( i = 0; i < w2.length; i++ ) { ss += dec( int(w2(i))/rp ) + String("_{"); int res = w2(i) % rp; for ( j = 0; j < tu.length; j++ ) { if ( res % 2 ) ss += dec(tu(j)+1); else ss += dec(-(tu(j)+1)); if ( j != tu.length - 1 ) ss += ","; res /= 2; } ss += "}"; if ( i != w2.length - 1 ) ss += ","; } ss += "}"; } else if (title_type == 2) { ss = s; ss.del("}", -1); ss += ","; for ( i = 0; i < w2.length; i++ ) { ss += ec(w2(i))(0); if ( i != w2.length-1 ) ss += ","; } ss += "}"; } process_new_matrix(B, ss, results, 0, true); } while( ix2.advance( ) != 0 ); } while( ixd.advance( ) ); } while( ix.advance( ) != 0 ); } TEX( ![ Look for dual transforms of the code defined by the given matrix, which should be in \RREF. This uses various global parameters. ]! ) index_method(auto_dual_search) void auto_dual_search( matrix M, String source, codetable& results ) { codehome h( M.ncols, M.nrows, weightlist("1_1", M.ncols) ); SLList< matrix > newcodes; config c( &h, M ); int i, j, r = min( auto_transform_depth, h.n ); prevector< vector > Ctuplev = tuple_orbits( M, r ); cerr << Ctuplev.length << " tuple orbits found\n"; int tuple_orbit_count = 0; for ( int j1 = 0; j1 < Ctuplev.length; j1++ ) { tuple_orbit_count++; if ( tuple_orbit_count > tuple_orbit_max ) break; if ( tuple_orbit_count < starting_tuple_orbit ) continue; cerr << "processing columns " << Ctuplev(j1) << "\n"; vector tu = Ctuplev(j1); int rp = as_int( Ipow(2,r) ); prevector< SLList > wds(rp*(h.n+1)); word indxx(h.dim), wd; do { mul( indxx, M, wd ); int wt = wd.weight( ); if ( wt == 0 ) continue; int ix = 0; for ( i = tu.length-1; i >= 0; i-- ) { ix += wd(tu(i)); if ( i != 0 ) ix *= 2; } wds(rp*wt+ix).append(indxx); } while ( indxx.advance( ) != 0 ); prevector< prevector > wdsv(rp*(h.n+1)); for ( int aa = 0; aa < rp*(h.n+1); aa++ ) wdsv(aa) = wds(aa); code_search( M, wdsv, results, "dual transform from " + source + " using ", 1, tu, rp ); } starting_tuple_orbit = 1; } index_method(auto_orbit_search) void auto_orbit_search( matrix M, String source, codetable& results ) { // Compute the orbits of the codewords under the automorphism group. code C; C.basis = M; C.basis.reduce( ); C.build( ); prevector< word > wds(C.x.nrows); int i, j; for ( i = 0; i < wds.length; i++ ) wds(i) = C.x(i); wds.sort( &cmp ); pair< Permutationlist, Integer > pp = find_automorphism_group(M); Permutationlist aut = pp.first; cerr << "|Aut(C)| = " << pp.second << "\n"; // XXX if (aut.length == 0) return; vector gen_indx(aut.length); gen_indx.advance( ); do { cerr << "trying gen_indx = " << gen_indx << "\n"; // if ( pp.second < 10 ) return; EquivRelIntList e(wds.length); for ( i = 0; i < aut.length; i++ ) { if ( gen_indx(i) == 0 ) continue; for ( j = 0; j < wds.length; j++ ) { word w = wds(j); aut(i).act(w); int k = wds.pos( w, &cmp ); if ( k == -1 ) INTERNAL_ERROR("pos problem"); e.join( j, k ); } } SLList< prevector > orbits; for ( int j1 = 0; j1 < wds.length; j1++ ) if ( e.minimal(j1) ) { int k1 = e.size(j1); if ( k1 > dual_transform_length_limit ) continue; int e_ptr = j1; SLList orbit; for ( i = 0; i < k1; i++ ) { orbit.append( C.basis.coord_vector(wds(e_ptr)) ); e_ptr = e(e_ptr); } prevector orbitv(orbit); orbits.append(orbitv); } prevector< prevector > orbitsv(orbits); String title_head = String(" multiple orbit code from ") + source; title_head += ", gen_indx = " + gen_indx + "\n" + "acting on "; code_search( C.basis, orbitsv, results, title_head, 2, vector(0), int(0) ); } while ( gen_indx.advance( ) != 0 ); } index_command(accept) void execute_accept( codehome* home, String commandx, DLList& command_queue, int& silent, codetable& results, int brack_count, int& lower_bound_check, char* command, int& gullible, String& code_label ) { String type_pat = String("type\\[") + ".*"; // + to protect tib static Regex type_pattern( label_pat + type_pat + orsign + "type.*" ); command_queue.prepend("set gullible"); bool save_silent = silent, t_only = false; silent = true; int i; commandx = commandx.after("accept"); if ( commandx.contains( "(tablesonly)", 0 ) ) { t_only = true; commandx = commandx.after( "(tablesonly)" ); } ifstream accept_file( commandx ); if ( accept_file.peek( ) == EOF ) WARNING( "There is nothing in the file \"" << commandx << "\"!\n" ); static Regex accept_pat( "no.*" + orsign + "yes.*" ); static Regex interval_list_pat( list_of( pos_number + orsign + "-" + pos_number + orsign + pos_number + "-" + orsign + pos_number + "-" + pos_number ) ); if (brack_count != 0) ERROR("Illegal bracketing."); while(1) { accept_file >> ws; // skip over whitespace if ( accept_file.peek( ) == EOF ) break; accept_file.gets(&command, ';'); commandx = command; if (commandx[0] == '{' || brack_count > 0) { for ( i = 0; i < commandx.length( ); i++ ) { if ( commandx[i] == '{' ) brack_count++; if ( commandx[i] == '}' ) brack_count--; } if ( brack_count < 0 || brack_count > 1 ) ERROR("Illegal bracketing."); delete command; continue; } commandx.gsub(RXwhite,""); if ( !accept_file ) ERROR("Input error."); if (t_only) { if ( commandx == "setlowerboundcheck" ) { lower_bound_check = true; delete command; continue; } if ( commandx == "unsetlowerboundcheck" ) { lower_bound_check = false; delete command; continue; } if ( commandx.matches(type_pattern) ) { execute_type(commandx, home, results, code_label, true, true); delete command; continue; } if ( commandx.contains( "status:", 0 ) ) { if ( home == 0 ) ERROR( "Status command " << "encountered without code type defined." ); if ( commandx[ commandx.length( ) - 1 ] == '>' ) { static Regex tail_pat( String("<") + ".*>" ); commandx.at(tail_pat, -1) = ""; } execute_status( home, commandx, command_queue, true, results ); delete command; continue; } if ( commandx.contains( "n=", 0 ) ) { short int n, k; String inv; if ( parse ( commandx, &( parse_text("n="), parse_short(n), parse_text(",k>="), parse_short( k ), parse_text(":"), parse_pat( &interval_list_pat, inv ) ) ) ) { bool save_gullible = gullible; gullible = true; execute_n_equals( results, command_queue, n, k, inv ); gullible = save_gullible; delete command; continue; } } } if ( !t_only || commandx.matches(accept_pat) ) command_queue.prepend( String(command) ); delete command; } if (!gullible) command_queue.prepend("unset gullible"); if (!save_silent) command_queue.prepend("unset silent"); } main(int argc, char* argv[ ]) { bool interactive = (argc == 2 && argv[1] == String("-i")); HIDE( ![ #ifdef DEMO interactive = true; #endif ]! ) #ifdef ABSOLUTE_PATH_FOR_CPLEX PATH_PREFIX = new char[201]; char* cwdp = getcwd( PATH_PREFIX, 200 ); HIDE( ![ if ( cwdp == 0 ) INTERNAL_ERROR( "Absolute path name of current" << " directory could not be obtained." ); ]! ) for ( int fz = 0; fz < 200; fz++ ) if ( PATH_PREFIX[fz] == 0 ) { PATH_PREFIX[fz] = '/'; PATH_PREFIX[fz+1] = 0; break; } #endif HIDE( ![ #ifdef RLIMIT_CORE // Prevent core dumps. rlimit core; core.rlim_cur = 0; core.rlim_max = 0; setrlimit( RLIMIT_CORE, &core ); #endif ]! ) codetable results; codehome* home = 0; String code_label; DLList command_queue; long int total_time_used = time(0); bool last_command_temp_switched_to_gullible = false; bool question_question, executing_secondary_command; constraintlist test_mask; prevector gullible_commands(0); SLList< pair > aliases; cerr << "Split version VERSION\n\n"; int NeXT_step = 0; #ifdef NeXT NeXT_step = 1; #endif if (NeXT_step) { cerr << "CPLEX not found. Using homebrew simplex.\n"; homebrew = 1; } HIDE( ![ #ifndef DEMO else { system( String("which ") + CPLEX + " > cplex_location" ); ifstream cplex_location("cplex_location"); String first_part; cplex_location >> first_part; cplex_location.close( ); remove("cplex_location"); if ( first_part.contains( "no", 0 ) ) { cerr << "CPLEX not found. Using homebrew simplex.\n"; homebrew = 1; } } #endif #ifdef DEMO system( String("w -h -s split | wc > logins") ); ifstream logins("logins"); int user_count; logins >> user_count; logins.close( ); remove("logins"); if ( user_count != 1 ) ERROR( "It would appear that another " << "demonstration is taking place at this time. Sorry." ); #endif ]! ) if (interactive) { cerr << "Interactive mode. "; warnings_are_fatal = 0; } else cerr << "Commands are echoed. "; cerr << "Output of the form *** command\n"; cerr << "results from expansion of another command.\n"; cerr << "Type \"help;\" for help.\n\n"; HIDE( ![ #ifdef DEMO cerr << "(Sorry, \"help;\" does not work on the demo version -- I" << " don't know how to get xdvi to work over the web.)\n"; #endif DEMO ]! ) // Command parser (main loop) char* command; char ch; String commandx; Regex var_pattern(var); String type_pat = String("type\\[") + ".*"; // + to protect tib Regex type_pattern( label_pat + type_pat + orsign + "type.*" ); Regex alphanumeric = "[a-zA-Z0-9]*"; Regex alphanumericu = "[a-zA-Z0-9_]*"; Regex equals_number_pat( "=" + number_pat ); Regex unset_pattern( "unset.*" ); Regex config_pattern( "config[1-9].*" + orsign + bang_label_pat + "config[1-9].*" + orsign + "=config[1-9].*" + orsign + "=" + label_pat + "config[1-9].*" ); String local_var_seq( left + var + orsign + "(" + list_of( var, "|" ) + ")" + right ); String alt_local_var_seq( left + var + orsign + "(" + list_of( var, "," ) + ")" + right ); String kill_unit(left + var + orsign + var + "by" + local_var_seq + orsign + var + "by" + alt_local_var_seq + right); Regex kill_variable_by_pattern( "kill" + list_of( kill_unit ) ); Regex gen_label_pattern( gen_label_pat ); Regex label_pattern( label_pat ); Regex bang_label_pattern( bang_label_pat ); Regex config_from_pattern( "configfrom" + list_of( var, "|" ) + orsign + label_pat + "configfrom" + list_of( var, "|" ) ); Regex zero_one_pat = "[01]+"; Regex optional_label_pattern( orsign + label_pat ); Regex number_pattern( number_pat ); Regex pos_number_pattern( pos_number ); Regex pos_list_pattern( pos_list ); Regex via_varying_pattern( "viavaryingy" + number_pat + "\\[current\\]implies" + list_of( gen_label_pat, "or" ) ); Regex classification_of_pattern( "classificationof" + gen_label_pat + ":" + config_list ); Regex classification_of_pattern2( "classificationof" + gen_label_pat + ":" + list_of( var, "|" ) + "-->" + config_list ); Regex classification_of_pattern3( "classificationof" + gen_label_pat + ":" + config_list_piece + "-->" + config_list ); Regex config_list_piece_pat(config_list_piece); Regex config_list_pat(config_list); Regex via_lower_bound_pattern( "vialowerboundfory" + number_pat + "[current]implies" + list_of( gen_label_pat, "or" ) ); Regex isomorphic_pattern( "isomorphic" + gen_label_pat + "," + gen_label_pat ); Regex tables_only_pattern( "n=.*" + orsign + "no.*" + orsign + "yes.*" + orsign + "\\?\\?no.*" + orsign + "\\?\\?yes.*" + orsign + "status.*" + orsign + "set.*" + orsign + "unset.*" + orsign + "exit" + orsign + label_pat + type_pat + orsign + "type.*" ); Regex noyes_pattern( "no.*" + orsign + "yes.*" + orsign + "status.*" + orsign + label_pat + type_pat + orsign + "type.*" ); Regex pound_config( "\\[[a-zA-Z_0-9]+#\\]" ); String commandx_save; int brack_count = 0; while(1) { if ( command_queue.length( ) != 0 ) { commandx = command_queue.remove_rear( ); executing_secondary_command = true; commandx_save = commandx; commandx.gsub(RXwhite,""); // delete white space if ( last_command_temp_switched_to_gullible ) gullible = last_command_temp_switched_to_gullible = false; } else { executing_secondary_command = false; if (interactive) cerr << "< "; cin >> ws; // skip over whitespace if ( cin.peek( ) == EOF ) break; cin.gets(&command, ';'); if ( !cin ) ERROR("Input error."); commandx = command; delete command; commandx_save = commandx; commandx.gsub(RXwhite,""); // delete white space got_command: if ( last_command_temp_switched_to_gullible ) gullible = last_command_temp_switched_to_gullible = false; TEX( ![ \begin{quoteb} Process bracketing. \end{quoteb} ]! ) if ( commandx.length( ) >= 1 && commandx[0] == '{' && brack_count == 0 ) { for ( int i = 0; i < commandx.length( ); i++ ) { if ( commandx[i] == '{' ) brack_count++; if ( commandx[i] == '}' ) brack_count--; } if ( brack_count < 0 || brack_count > 1 ) ERROR("Illegal bracketing."); if (gullible) continue; commandx.del( '{' ); if (brack_count == 0) { if ( commandx[ commandx.length( ) - 1 ] != '}' ) ERROR( "Illegal bracketing." ); commandx.at( "}", -1 ) = ""; } } else if ( brack_count != 0 ) { for ( int i = 0; i < commandx.length( ); i++ ) { if ( commandx[i] == '{' ) brack_count++; if ( commandx[i] == '}' ) brack_count--; } if ( brack_count < 0 || brack_count > 1 ) ERROR("Illegal bracketing."); if (gullible) continue; if (brack_count == 0) commandx.at( "}", -1 ) = ""; } if (tables_only && !commandx.matches(tables_only_pattern) ) continue; } if_match( commandx, "\\?\\?.*" ) { commandx.del("??"); question_question = true; } else question_question = false; if ( commandx.length( ) == 0 ) { cerr << "Ignoring null command.\n"; continue; } if (!gullible) { int i; for ( i = 0; i < gullible_commands.length; i++ ) if ( commandx.contains( gullible_commands(i), 0 ) ) break; if ( i != gullible_commands.length || question_question || (tables_only && !executing_secondary_command && commandx.matches(noyes_pattern)) ) gullible = last_command_temp_switched_to_gullible = true; } TEX( ![ \begin{quotea} Process {\tt<}parameters{\tt>} at end of command. \end{quotea} ]! ) bool temporary_parameters = false; String parameter_tail; if ( commandx[ commandx.length( ) - 1 ] == '>' ) { static Regex tail_pat( String("<") + ".*>" ); if (gullible) commandx.at(tail_pat, -1) = ""; else if ( commandx.contains( "<" ) ) { temporary_parameters = true; parameter_tail = commandx.at(tail_pat, -1); if ( parameter_tail[0] != '<' ) ERROR("Syntax error."); commandx.at(tail_pat, -1) = ""; save_and_set_parameters(parameter_tail); } } TEX( ![ \begin{quotea} Echo command. \end{quotea} ]! ) if ( !interactive && !silent && (!gullible || !gullible_silent) ) { if (!executing_secondary_command || secondary_echo) { if (executing_secondary_command) cerr << "*** "; cerr << commandx_save << ";\n"; } } command_start_time = time(0); forPixDef( ap, aliases ) { if ( commandx.contains( aliases(ap).first, 0 ) ) { commandx.at( aliases(ap).first ) = aliases(ap).second; commandx.gsub(RXwhite, ""); int i = 0; while ( i < aliases(ap).first.length( ) ) { if ( !isspace( commandx_save[0] ) ) i++; commandx_save.del( commandx_save[0] ); } commandx_save = aliases(ap).second + " " + commandx_save; cerr << "expanded to " << commandx_save << "\n"; break; } } TEX(![ \block{Process commands that can be executed without a code type being defined} ]! ) index_command(go to) if ( commandx.contains( "goto", 0 ) ) { String looking_for = commandx.after("goto"); do { cin >> ws; // skip over whitespace if ( cin.peek( ) == EOF ) ERROR("I couldn't find a command which started " << "with " << looking_for << "."); cin.gets(&command, ';'); if ( !cin ) ERROR("Input error."); commandx = command; commandx_save = commandx; commandx.gsub(RXwhite,""); delete command; } while( !commandx.contains( looking_for, 0 ) ); goto got_command; } index_command((* ... *)) if_match( commandx, "(\\*.*\\*)" ) continue; // comment index_command(random weight enumerator) { short int n, k, div, modulus; Integer count; if ( parse ( commandx, &( parse_text("randomweightenumerator(n="), parse_short(n), parse_text(",k="), parse_short(k), parse_text(",div="), parse_short(div), parse_text(",modulus="), parse_short(modulus), parse_text(",count="), parse_pos(count), parse_text(")") ) ) ) { execute_random_we( n, k, div, modulus, count ); goto time_report; } } index_command(random macaulay) { short int n, k, d; Integer count; if ( parse ( commandx, &( parse_text("randommacaulay(n="), parse_short(n), parse_text(",k="), parse_short(k), parse_text(",minimumdistance>="), parse_short(d), parse_text(",count="), parse_pos(count), parse_text(")") ) ) ) { execute_random_macaulay( n, k, d, count ); goto time_report; } } index_command(type) if ( commandx.matches( type_pattern ) ) { execute_type( commandx, home, results, code_label, false, gullible ); goto time_report; } index_command(no) { static Regex any_pat(".*"); static Regex wtlist_pat( pos_number + orsign + pos_number + "_4" ); String tail, w; short int n, k, d; if ( parse ( commandx, &( parse_text("no["), parse_short( n ), parse_text(","), parse_short( k ), parse_text(","), parse_pat( &wtlist_pat, w ), parse_text("]") ) ) ) { int div = 1; String w_save = w, parameter, value; if ( w.contains("_") ) { w = w.before("_"); div = 4; } d = as_int(w); if ( d > n ) ERROR("Minimum weight exceeds length."); if ( home != 0 ) results.save( *home, code_label ); home = 0; if (!gullible) { bool outcome = results.new_not_exist( n, k, d, div, home, code_label, allowed_failures ); home = 0; if ( !outcome ) { WARNING("My attempt to prove the nonexistence of a [" << n << "," << k << "," << w_save << "] code has failed."); goto time_report; } } if ( div == 1 ) results.kill(n, k, d); else results.kill( codebase( n, k, weightlist(w_save, n) ) ); goto time_report; } } index_command(yes) { short int n, k, d; if ( parse ( commandx, &( parse_text("yes["), parse_short( n ), parse_text(","), parse_short( k ), parse_text(","), parse_short( d ), parse_text("]") ) ) ) { if ( d > n ) ERROR("Minimum weight exceeds length."); if ( home != 0 ) results.save( *home, code_label ); home = 0; if (gullible) results.update_lower_bound(n, k, d); else if ( !results.exist(n, k, d) ) WARNING("My attempt to prove the existence of a [" << n << "," << k << "," << d << "] code has failed."); goto time_report; } } index_command(test) { short int n, k, d; if ( parse ( commandx, &( parse_text("test["), parse_short( n ), parse_text(","), parse_short( k ), parse_text(","), parse_short( d ), parse_text("]") ) ) ) { if ( home != 0 ) results.save( *home, code_label ); if (!gullible) execute_test( n, k, d, results, home, code_label, test_mask ); home = 0; goto time_report; } } index_command(test yes) { short int n, k, d; if ( parse ( commandx, &( parse_text("testyes["), parse_short( n ), parse_text(","), parse_short( k ), parse_text(","), parse_short( d ), parse_text("]") ) ) ) { if ( d > n ) ERROR("Minimum weight exceeds length."); if (gullible) goto time_report; if ( results.exist(n, k, d) ) WARNING( "There is a [" << n << ", " << k << ", " << d << "] code." ); if ( home != 0 ) results.save( *home, code_label ); home = 0; goto time_report; } } index_command(n =) { short int n, k; String inv; static Regex interval_list_pat( list_of( pos_number + orsign + "-" + pos_number + orsign + pos_number + "-" + orsign + pos_number + "-" + pos_number ) ); if ( parse ( commandx, &( parse_text("n="), parse_short( n ), parse_text(",k>="), parse_short( k ), parse_text(":"), parse_pat( &interval_list_pat, inv ) ) ) ) { execute_n_equals( results, command_queue, n, k, inv ); goto time_report; } } { if_match( commandx, "setring.*" ) { if ( commandx != "setring=F2" ) { ERROR( "You can only set the ring to F2." ); } goto time_report; } } { if ( commandx == "settestmask=" || commandx == "unsettestmask" ) { test_mask = constraintlist( ); goto time_report; } if ( parse ( commandx, &( parse_text( "settestmask=" ), parse_constraint_list(test_mask) ) ) ) { goto time_report; } } { if ( commandx == "unsetgulliblecommands" ) { gullible_commands.set_size(0); goto time_report; } if_match( commandx, "setgulliblecommands=.*" ) { gullible_commands = unpack( commandx.after("setgulliblecommands=") ); goto time_report; } } |-> tex/code.tex \end{svb}\indexb{set}\indexb{unset}\begin{svb} |-> current_compile_file, tex/code.tex if_match( commandx, "set.*" + orsign + "unset.*" ) { Integer value; String parameter; if_match( commandx, "set.*" ) { commandx = commandx.after("set"); parameter = take(commandx, alphanumeric); if ( commandx.empty( ) ) value = 1; else { if ( !commandx.matches( equals_number_pat ) ) ERROR("Incorrect syntax."); value = atoI( String(commandx.after("=")) ); } } else if ( commandx.matches( unset_pattern ) ) { parameter = commandx.after("unset"); value = 0; } if ( parameter == "gullible" ) { if (value != 0 && value != 1) ERROR( "Illegal parameter " << "value for " << parameter << ".\n" ); if (!last_command_temp_switched_to_gullible) gullible = as_int(value); else { if ( value == 1 ) last_command_temp_switched_to_gullible = false; } goto time_report; } set_numerical_parameter(parameter, dec(value), "set"); goto time_report; } index_command(clean) if_match( commandx, "clean<" + var + ">" + var + orsign + "clean<" + var + ">" + var + "(" + list_of(var) + ")" ) { execute_clean( commandx ); goto time_report; } index_command(alias) if_match( commandx, "alias.*=.*" ) { commandx_save = commandx_save.after("alias"); String short_form = commandx_save.before("="); short_form.gsub(RXwhite,""); String long_form = commandx_save.after("="); aliases.append( make_pair( short_form, long_form ) ); goto time_report; } index_command(build web directory) static Regex build_web_pat( "buildwebdirectoryfor" + pos_number + "<=n<=" + pos_number + "," + pos_number + "<=k<=" + pos_number ); if ( commandx.matches( build_web_pat ) ) { commandx = commandx.after( "buildwebdirectoryfor" ); int n0 = take_int(commandx, number_pattern); commandx = commandx.after("<=n<="); int n1 = take_int(commandx, number_pattern); commandx.del(","); int k0 = take_int(commandx, number_pattern); if ( k0 < 1 ) ERROR("k0 is too small"); commandx = commandx.after("<=k<="); int k1 = take_int(commandx, number_pattern); if ( results.upper_bound.nrows <= n1 || results.upper_bound.ncols <= k1 ) { WARNING( "I don't think I know enough to generate " << "this table." ); goto time_report; } system( "mkdir web/binary" ); for ( int n = n0; n <= n1; n++ ) { cerr << "working on n = " << n << "\n"; system( String("mkdir web/binary/") + dec(n) ); for ( int k = k0; k <= k1; k++ ) { if ( k >= n ) continue; int d = results.upper_bound(n,k); weightlist w = results.possible_weights(n,k,d,false); ofstream nkfile( String("web/binary/") + dec(n) + "/" + dec(k) ); nkfile << "There is no binary [" << n << "," << k << "," << d+1 << "] code. If a [" << n << "," << k << "," << d << "] code exists, it has weights" << " in the set " << w << ".\n"; nkfile.close( ); } } goto time_report; } index_command(help) if ( commandx.contains( "help", 0 ) ) { execute_help( commandx ); goto next_command; } index_command(accept) { if_match(commandx, "accept.*") { execute_accept( home, commandx, command_queue, silent, results, brack_count, lower_bound_check, command, gullible, code_label ); goto time_report; } } index_command(exit) if ( commandx.matches( "exit" ) ) break; if ( home == 0 ) { WARNING("I don't recognize the command \"" << commandx_save << "\" as being one which can" << " be executed without a code type being defined."); goto time_report; } index_command(process) { if_match( commandx, "process.*" ) { commandx = commandx.after("process"); String nullstr = ""; if ( !commandx.contains( "@1" ) ) { matrix M = process_matrix_descriptor( commandx, results, 0, nullstr ); process_new_matrix( M, commandx, results, 0, false ); } else { forPixDef( p, results.olabels ) { String hlabel = results.olabels(p).first; codehome* h = results.open(results.olabels(p).second); forPixDef( q, h->labels ) { String clabel = h->labels(q).first; config& c = home->configs(h->labels(q).second); if ( c.small.basis.nrows == h->dim ) { String cx1 = hlabel; cx1.del("]"); String cx2 = clabel; cx2.del("["); String cx = cx1 + "." + cx2; String md = commandx; md.gsub("@1", cx); if ( !commandx.contains( "@2" ) ) { matrix M = process_matrix_descriptor( md, results, 0, nullstr ); if ( M.ncols > dual_transform_length_limit ) continue; process_new_matrix( M, md, results, 0, false ); } else { forPixDef( p2, results.olabels ) { String hlabel2 = results.olabels(p2).first; codehome* h2 = results.open( results.olabels(p2).second); forPixDef( q2, h2->labels ) { String clabel2 = h2->labels(q2).first; config& c2 = home->configs( h2->labels(q2).second); if ( c2.small.basis.nrows != h2->dim ) continue; String cx12 = hlabel2; cx12.del("]"); String cx22 = clabel2; cx22.del("["); String cy = cx12 + "." + cx22; String md2 = md; md2.gsub("@2", cy); matrix M = process_matrix_descriptor ( md2, results, 0, nullstr ); if ( M.ncols > dual_transform_length_limit ) continue; process_new_matrix( M, md2, results, 0, false ); } } } } } } } goto time_report; } } index_command(perturb) // does_not_work_if_match( commandx, "perturb + gen_label_pat" ) if ( commandx.contains( "perturb", 0 ) ) { Pix pix1 = home->label_to_Pix(commandx.after("perturb"),results); config& c = home->configs(pix1); if ( !c.terminal( ) ) ERROR("Configuration must be terminal."); SLList< matrix > Ms; Ms.append( c.basic_small( ) ); Pix p = Ms.first( ); do { matrix A = Ms(p); Ms.next(p); prevector< vector > cols = tuple_orbits(A, 1); for ( int ix = 0; ix < cols.length; ix++ ) { int i = cols(ix)(0); word indx(A.nrows); word current_col(A.nrows); for ( int e = 0; e < A.nrows; e++ ) current_col(e) = A(e,i); do { if ( indx == current_col ) continue; matrix B = A; B.set_col( i, indx ); vector y = B.enumerate_weights( ); int j; for ( j = 0; j <= home->n; j++ ) if (y(j) != 0 && !home->w.contains(j)) break; if ( j > home->n ) { forPixDef( q, Ms ) if ( isomorphic( B, Ms(q) ) ) break; if ( q == 0 ) { Ms.append(B); cerr << B << "\n"; cerr << "weight enumerator = "; cerr << as_poly(B.enumerate_weights( )) << "\n"; } } } while ( indx.advance( ) ); } } while ( p != 0 ); goto time_report; } TEX(![ \block{Process dump, config, :=, at, incorporate, and subdivide along commands} ]! ) index_command(dump) if ( commandx.matches( "dump" ) ) { execute_dump( home ); goto time_report; } index_command(config) if ( commandx.matches( config_pattern ) ) { bool eq = false; Pix oldp = home->current; if ( commandx[0] == '=' ) { commandx.del('='); if (oldp == 0) ERROR("Current configuration is undefined."); eq = true; } String l = ""; if ( commandx[0] == '[' ) { l = take(commandx, bang_label_pattern); if ( (eq || !executing_secondary_command) && l[l.length( ) - 1] == '!' ) ERROR( "Invalid configuration label." ); config dd = config(home, commandx.after("config")); home->set_config(dd, l); } else home->set_config( commandx.after("config") ); config& c = home->configs(home->current); bool nan = false; Pix p; forPix( p, c.assumed_cons ) if ( c.assumed_cons(p).global( ) ) c.add_constraint( c.assumed_cons(p), nan ); if ( c.part.length == 1 ) { constraintlist cshare = c.share->ycon; forPix( p, cshare ) c.add_constraint( cshare(p), nan ); forPix( p, c.assumed_cons ) if ( !c.assumed_cons(p).global( ) ) c.add_constraint( c.assumed_cons(p), nan ); } if (eq) { Pix curp = home->current; execute_equals( home, oldp, curp, gullible ); home->set_current(curp); } if (nan) home->deactivate( ); if ( auto_group_computation && c.assumed_cons.global( ) ) { pair< Permutationlist, Integer > pp = c.find_automorphism_group( ); c.aut = pp.first; } if (auto_orbit_transform && c.home->dim == c.small.basis.nrows && c.home->dim >= dual_transform_dim_low && c.home->dim <= dual_transform_dim_high ) { String source = String("[") + dec(c.home->n) + "," + dec(c.home->dim) + "] "; if ( l != "" ) source += "(config " + l + ")"; if (auto_dual_column_deletion != 2) auto_orbit_search( c.basic_small( ), source, results ); if (auto_dual_column_deletion != 0) { matrix Mx = c.basic_small( ), M; SLList< matrix > Ms; for ( int uu = 0; uu < Mx.ncols; uu++ ) { M = Mx; M.delete_column(uu); M.reduce_nz( ); if ( M.nrows != Mx.nrows ) continue; forPixDef( p, Ms ) if ( isomorphic( M, Ms(p) ) ) break; if ( p == 0 ) { cerr << "deleting column " << uu+1 << "\n"; auto_orbit_search( M, source + "-col" + dec(uu+1), results ); } Ms.append(M); } } } if (auto_dual_transform && c.home->dim == c.small.basis.nrows && c.home->dim >= dual_transform_dim_low && c.home->dim <= dual_transform_dim_high ) { String source = String("[") + dec(c.home->n) + "," + dec(c.home->dim) + "] "; if ( l != "" ) source += "(config " + l + ")"; if (auto_dual_column_deletion != 2) auto_dual_search( c.basic_small( ), source, results ); if (auto_dual_column_deletion != 0) { matrix Mx = c.basic_small( ), M; SLList< matrix > Ms; for ( int uu = 0; uu < Mx.ncols; uu++ ) { M = Mx; M.delete_column(uu); M.reduce_nz( ); if ( M.nrows != Mx.nrows ) continue; forPixDef( p, Ms ) if ( isomorphic( M, Ms(p) ) ) break; if ( p == 0 ) { cerr << "deleting column " << uu+1 << "\n"; auto_dual_search( M, source + "-col" + dec(uu+1), results ); } Ms.append(M); } } } goto time_report; } index_command(:=) { if_match( commandx, label_pat + ":=.*" ) { String lab = take( commandx, label_pattern ); commandx.del( ":=" ); String mat_des = commandx, cons; if ( commandx.contains( "::" ) ) { mat_des = mat_des.before( "::" ); cons = commandx.after( "::" ); } matrix B = process_matrix_descriptor( mat_des, results, home, code_label ); if ( B.ncols != home->n || B.nrows != home->dim ) ERROR( "The dual transform is a [" << B.ncols << "," << B.nrows << "] code." ); String Bstring = B; if ( cons != "" ) Bstring += " :: " + cons; command_queue.append( "at " + lab ); if ( cons != "" ) { String lab_bang = lab; lab_bang.at("]") = "!]"; command_queue.append( lab + " implies " + lab_bang ); command_queue.append( lab_bang + " config " + String(dec(home->n)) + ":::" + cons ); } command_queue.append( "realizable " + lab ); command_queue.append( lab + " config 1" + replicate(",1", home->n - 1) + " : " + Bstring ); goto time_report; } } index_command(at) { String label; Pix p; if ( parse ( commandx, &( parse_text("at"), parse_known_config( results, *home, label, p ) ) ) ) { home->set_current(p); config& c = home->configs(home->current); bool nan = false; if ( c.part.length == 1 ) { constraintlist cshare = c.share->ycon; cshare.merge( c.assumed_cons ); forPixDef( p, cshare ) c.add_constraint( cshare(p), nan ); } if (nan) home->deactivate( ); goto time_report; } if ( parse ( commandx, &( parse_text("attype"), parse_open_code_type( results, label, p ) ) ) ) { if (home != 0) results.save( *home, code_label ); home = results.open(p); code_label = label; results.open.del(p); forPixDef( q, results.olabels ) { if ( code_label == results.olabels(q).first ) { results.olabels.del(q); break; } } goto time_report; } } index_command(incorporate) { String label1, label2, label3, sub_var; Pix pix2, pix3; if ( parse ( commandx, &( parse_pat( &label_pattern, label1 ), parse_text( "incorporate" ), parse_open_code_type( results, label2, pix2 ), parse_text( "below" ), parse_known_config( results, *home, label3, pix3 ), parse_text( "viasub" ), parse_pat( &zero_one_pat, sub_var ) ) ) ) { execute_incorporate_command( home, label1, label2, label3, sub_var, pix2, pix3, results, gullible ); goto time_report; } } index_command(subdivide along) { String label, v; if ( parse ( commandx, &( parse_pat( &optional_label_pattern, label ), parse_text("subdividealong"), parse_pat( &var_pattern, v ) ) ) ) { if ( home->current == 0 ) ERROR("Current configuration is undefined."); home->configs(home->current).check_variable( v ); if ( v[0] != 'x' ) ERROR(v << " is not a basic local variable."); wordtype wt(&(home->configs(home->current)), v); home->set_current( subdivide(home->configs(home->current), wt) ); if ( label != "" ) { forPixDef( j, home->labels ) if ( home->labels(j).first == label ) ERROR("Same label for configuration used twice."); home->labels.append( make_pair(label, home->current) ); } goto time_report; } } index_command(macaulay) if ( commandx.matches( "macaulay" ) ) { if ( home->current == 0 ) ERROR("The current configuration is undefined."); config& c = home->configs(home->current); if ( !c.terminal( ) ) ERROR("The current configuration must be terminal."); matrix M = c.basic_small( ); execute_macaulay( M ); goto time_report; } TEX( \block{Process group manipulation commands} ) index_command(automorphism) { String label, perm; if ( parse ( commandx, &( parse_pat( &optional_label_pattern, label ), parse_text("automorphism"), parse_pat( &pos_list_pattern, perm ) ) ) ) { execute_automorphism( home, label, Permutation(perm), gullible ); goto time_report; } } index_command(group size) { Integer size; if ( parse ( commandx, &( parse_text( "groupsize=" ), parse_pos( size, 1, 1000000 ) ) ) ) { if ( home->current == 0 ) ERROR("The current configuration is undefined."); config& c = home->configs(home->current); if (!gullible) { Permutationlist gp(c.part.length); gp.generate(c.aut); if ( gp.length != size ) ERROR("Actual size is " << gp.length << "." ); } goto time_report; } } index_command(report group size) { if_match( commandx, "reportgroupsize" + list_of(gen_label_pat) ) { commandx = commandx.after("reportgroupsize"); prevector labels = unpack(commandx); execute_report_group_size( home, labels ); goto time_report; } } index_command(reduce variable set) if ( commandx.matches( "reducevariableset" ) ) { execute_reduce_variable_set( home ); goto time_report; } index_command(show full automorphism group) if ( commandx.matches( "showfullautomorphismgroup" ) ) { if (home->current == 0) ERROR("[current] is undefined."); config& c = home->configs(home->current); if ( !c.assumed_cons.global( ) ) { WARNING( "Local variables are present in an assumed " << "constraint. Command ignored." ); goto time_report; } pair< Permutationlist, Integer > pp = c.find_automorphism_group( ); Permutationlist gp(c.part.length), gen(c.part.length); int i; for ( i = 0; i < pp.first.length; i++ ) gen.append( pp.first(i) ); gp.generate(gen); for ( i = 0; i < gp.length; i++ ) cerr << gp(i).as_cycle_product( ) << "\n"; goto time_report; } index_command(is cyclic?) if ( commandx.matches( "iscyclic?" ) ) { execute_is_cyclic( home, false, results ); goto time_report; } if ( commandx.matches( "iscyclic?(useextra)" ) ) { execute_is_cyclic( home, true, results ); goto time_report; } index_command(full group size) { Integer size; if ( parse ( commandx, &( parse_text( "fullgroupsize=" ), parse_pos( size, 1 ) ) ) ) { if ( home->current == 0 ) ERROR("The current configuration is undefined."); config& c = home->configs(home->current); if ( !c.assumed_cons.global( ) ) { WARNING( "Local variables are present in an assumed " << "constraint. Command ignored." ); goto time_report; } if (!gullible) { pair< Permutationlist, Integer > pp = c.find_automorphism_group( ); if ( pp.second != size ) WARNING( "No, there are " << pp.second << " elements." ); } goto time_report; } } index_command(isomorphic) if ( commandx.matches( isomorphic_pattern ) ) { commandx = commandx.after("isomorphic"); String label1 = take(commandx, gen_label_pattern); String label2 = commandx.after(","); Pix pix1 = home->label_to_Pix(label1, results); Pix pix2 = home->label_to_Pix(label2, results); bool answer = home->isomorphic( home->configs(pix1), home->configs(pix2) ); cerr << "They are" << (answer ? " " : " not ") << "isomorphic.\n"; goto time_report; } TEX( \block{Process configuration relation makers} ) index_command(kill current by) { if_match( commandx, "killcurrentby" + list_of(var) ) { prevector vars = unpack( commandx.after("killcurrentby") ); execute_kill_current_by( home, vars, gullible, results ); goto time_report; } } index_command(config from) if ( commandx.matches( config_from_pattern ) ) { String label; if ( commandx[0] != 'c' ) label = take(commandx, label_pattern); String vars = commandx.after("configfrom"); execute_config_from( home, vars, label, gullible, results ); goto time_report; } index_command(=) { String label1, label2; Pix pix1, pix2; if ( parse ( commandx, &( parse_known_config( results, *home, label1, pix1 ), parse_text( "=" ), parse_known_config( results, *home, label2, pix2 ) ) ) ) { execute_equals( home, pix1, pix2, gullible ); goto time_report; } } index_command(via dual nonexistence infer) if ( commandx.matches( "viadualnonexistenceinfer[base]=" ) ) { execute_via_dual_nonexistence( home, results, gullible ); goto time_report; } index_command(via dual word) { String label2; Pix pix2; if ( parse ( commandx, &( parse_text( "viadualword[base]implies" ), parse_known_config( results, *home, label2, pix2 ) ) ) ) { execute_via_dual_word( home, label2, pix2, gullible ); goto time_report; } } index_command(via configuration search) { String label1, label2; Pix pix1, pix2; if ( parse( commandx, &( parse_text( "viaconfigurationsearch" ), parse_known_config( results, *home, label1, pix1 ), parse_text( "implies" ), parse_known_config( results, *home, label2, pix2 ) ) ) ) { execute_via_configuration_search( home, label1, label2, pix1, pix2, gullible ); goto time_report; } } index_command(via extension) { if_match( commandx, !["viaextension" + config_list + "implies" + config_list + orsign + "viaextension" + config_list + "implies" + config_list + ",\\[[a-zA-Z_0-9]+#\\]" + orsign + "viaextension" + config_list + "implies" + "\\[[a-zA-Z_0-9]+#\\]"]! ) { commandx = commandx.after( "viaextension" ); prevector sources = expand_config_list( home, commandx.before( "implies" ) ); commandx = commandx.after( "implies" ); String pound_label_head; int pound_label_ctr = 1; if ( commandx.contains( pound_config ) ) { pound_label_head = commandx.at( pound_config ); commandx.del( pound_config ); if ( commandx.contains( ",", -1 ) ) commandx.del( ",", -1 ); pound_label_head = pound_label_head.before( "#" ); forPixDef( q, home->labels ) if ( home->labels(q).first.contains( pound_label_head, 0 ) ) { String s = home->labels(q).first; s = s.after(pound_label_head); if ( s.matches( pos_number_pattern ) ) ERROR( "The configuration " << home->labels(q).first << " has already been defined." ); } } prevector labels = expand_config_list( home, commandx ); for ( int i = 0; i < sources.length; i++ ) { if ( sources.length > 1 && !silent && !gullible ) cerr << "Running via extension on " << sources(i) << "\n"; execute_via_extension( home, sources(i), labels, alternate_extension_method, gullible, results, pound_label_head, pound_label_ctr ); } goto time_report; } } index_command(via varying) { if ( commandx.matches( via_varying_pattern ) ) { commandx = commandx.after( "viavaryingy" ); String yi = "y" + take( commandx, number_pattern ); commandx = commandx.after( "[current]implies" ); prevector labels = unpack( commandx, "or" ); execute_via_varying( yi, labels, home, gullible, results ); goto time_report; } } index_command(via building) { if_match( commandx, !["viabuilding" + config_list + "implies" + config_list + orsign + "viabuilding" + config_list + "implies" + config_list + ",\\[[a-zA-Z_0-9]+#\\]" + orsign + "viabuilding" + config_list + "implies" + "\\[[a-zA-Z_0-9]+#\\]"]! ) { commandx = commandx.after( "viabuilding" ); prevector sources = expand_config_list( home, take(commandx, config_list_pat) ); commandx = commandx.after( "implies" ); String pound_label_head; int pound_label_ctr = 1; if ( commandx.contains( pound_config ) ) { pound_label_head = commandx.at( pound_config ); commandx.del( pound_config ); if ( commandx.contains( ",", -1 ) ) commandx.del( ",", -1 ); pound_label_head = pound_label_head.before( "#" ); forPixDef( q, home->labels ) if ( home->labels(q).first.contains( pound_label_head, 0 ) ) { String s = home->labels(q).first; s = s.after(pound_label_head); if ( s.matches( pos_number_pattern ) ) ERROR( "The configuration " << home->labels(q).first << " has already been defined." ); } } prevector labels = expand_config_list( home, commandx ); for ( int i = 0; i < sources.length; i++ ) { if ( sources.length > 1 && !silent && !gullible) cerr << "Running via building on " << sources(i) << "\n"; execute_via_building( home, show_terminals_only, gullible, sources(i), labels, quiet_build, depth_first, results, pound_label_head, pound_label_ctr ); } goto time_report; } } index_command(via lp) { String clist, joint_string; static Regex joint_pat( "(joint)" + orsign + "(joint:" + number_pat + ")" + orsign ); if ( parse( commandx, &( parse_text( "vialp" ), parse_pat( &joint_pat, joint_string), parse_pat( &config_list_pat, clist ), parse_text( "=" ) ) ) ) { prevector labels = expand_config_list(home, clist); for ( int i = 0; i < labels.length; i++ ) { if (!silent) cerr << "(Processing via lp on " << labels(i) << ".)\n"; bool joint = (joint_string != ""); bool joint_set = joint && joint_string != "(joint)"; if (joint_set && !gullible) { joint_string = joint_string.after("(joint:"); joint_string = joint_string.before(")"); set_numerical_parameter( "usedualdualforjoint", joint_string, "save" ); set_numerical_parameter( "usedualdualforjoint", joint_string, "set" ); } execute_via_lp_command( home, labels(i), gullible, results, joint ); if (joint_set && !gullible) set_numerical_parameter( "usedualdualforjoint", joint_string, "restore" ); } goto time_report; } } index_command(via constraint drop) { String label1, label2; Pix pix1, pix2; if ( parse( commandx, &( parse_text( "viaconstraintdrop" ), parse_known_config( results, *home, label1, pix1 ), parse_text( "=" ), parse_known_config( results, *home, label2, pix2 ) ) ) ) { execute_via_constraint_drop( home, label1, label2, pix1, pix2, gullible, results ); goto time_report; } } index_command(via variable split) { if_match( commandx, "viavariablesplit" + gen_label_pat + "=" + list_of( gen_label_pat, "or" ) ) { commandx = commandx.after( "viavariablesplit" ); String label0 = take( commandx, gen_label_pattern ); commandx = commandx.after("="); prevector labels = unpack( commandx, "or" ); execute_via_variable_split( home, label0, labels, gullible, results ); goto time_report; } } index_command(implies) { String label1, label2; Pix pix1, pix2; if ( parse ( commandx, &( parse_known_config( results, *home, label1, pix1 ), parse_text( "implies" ), parse_known_config( results, *home, label2, pix2 ) ) ) ) { execute_implies( home, label1, label2, pix1, pix2, gullible ); goto time_report; } } index_command(via unique wordtypes) { String label1, label2; Pix pix1, pix2; if ( parse ( commandx, &( parse_text( "viauniquewordtypes" ), parse_known_config( results, *home, label1, pix1 ), parse_text( "implies" ), parse_known_config( results, *home, label2, pix2 ) ) ) ) { execute_via_unique_wordtypes( label1, label2, pix1, pix2, home, gullible ); goto time_report; } } index_command(via weight enumerator) { String label1, label2; Pix pix1, pix2; if ( parse ( commandx, &( parse_text( "viaweightenumerator" ), parse_known_config( results, *home, label1, pix1 ), parse_text( "implies" ), parse_known_config( results, *home, label2, pix2 ) ) ) ) { execute_via_weight_enumerator( home, label1, label2, pix1, pix2, gullible ); goto time_report; } } index_command(disjoint) { if_match( commandx, "disjoint" + list_of(gen_label_pat) ) { commandx = commandx.after("disjoint"); prevector labels = unpack(commandx); execute_disjoint( home, labels, gullible, results ); goto time_report; } } index_command(realizable) { if_match( commandx, "realizable" + list_of(gen_label_pat) ) { prevector labels = unpack(commandx.after("realizable")); execute_realizable( home, labels, gullible, results ); goto time_report; } } index_command(classification of) { static Regex var_list_pat( list_of( var, "|" ) ); if ( commandx.matches( classification_of_pattern2 ) ) { commandx.del( "classificationof" ); String mlabel = take( commandx, gen_label_pat ); commandx.del( ":" ); String var_list = take( commandx, var_list_pat ); commandx.del("-->"); command_queue.append( "classification of " + mlabel + ": " + commandx ); command_queue.append( "via building [current] implies " + commandx ); command_queue.append( "config from " + var_list ); command_queue.append( "at" + mlabel ); goto time_report; } } if ( commandx.matches( classification_of_pattern3 ) ) { commandx.del( "classificationof" ); String mlabel = take( commandx, gen_label_pat ); Pix mpix = home->label_to_Pix(mlabel, results); if ( !home->configs(mpix).basal( ) ) ERROR( mlabel << " must be basal." ); commandx.del( ":" ); String source = take( commandx, config_list_piece_pat ); commandx.del("-->"); if ( !source.contains(".") ) ERROR( "Syntax error." ); String tlabel = source.before(".") + "]"; String clistlabel = "[" + source.after("."); codehome* xhome; forPixDef( p, results.olabels ) { if ( results.olabels(p).first == tlabel ) { xhome = results.open(results.olabels(p).second); break; } } if (p == 0) ERROR("Code type " << tlabel << " is not a known open type."); int n = home->n, k = home->dim, n0 = xhome->n, k0 = xhome->dim; int r = n - n0; if ( r != k-k0 && r != k-k0+1 ) ERROR("Illegal parameters for code type " << tlabel << "."); constraintlist& T = home->configs(mpix).assumed_cons; command_queue.append( "classification of " + mlabel + ": " + commandx ); command_queue.append( "via extension " + source + " implies " + commandx ); command_queue.append( tlabel + " incorporate " + tlabel + " below [current] via sub10" ); String mid = (r == k-k0+1) ? String(" :: {01} : {") : String(" ::: {"); command_queue.append( String("=config ") + dec(n0) + ", " + dec(n-n0) + mid + String(T) + "}" ); if ( r == k - k0 + 1 ) command_queue.append( String("show mu") + dec(r) + " != 0" ); command_queue.append( "at" + mlabel ); goto time_report; } if ( commandx.matches( classification_of_pattern ) ) { commandx = commandx.after("classificationof"); String mlabel = take(commandx, gen_label_pat); commandx = commandx.after(":"); prevector labels = expand_config_list(home, commandx); execute_classification_of( home, mlabel, labels, gullible, results ); goto time_report; } index_command(deduce) { if_match( commandx, "deduce" + gen_label_pat + "=" + zero_or_more( gen_label_pat, "or" ) ) { commandx = commandx.after("deduce"); String mlabel = take(commandx, gen_label_pat); commandx = commandx.after("="); prevector labels = unpack(commandx, "or"); execute_deduce( home, mlabel, labels, gullible, results, true ); goto time_report; } } TEX( \block{Process constraint generators and weight killers} ) index_command(kill) if ( commandx.matches( kill_variable_by_pattern ) && !commandx.contains("killcurrent", 0) ) { commandx = commandx.after("kill"); int parencount = 0; SLList vars0; String cur_string; for ( int i = 0; i < commandx.length( ); i++ ) { if ( commandx[i] == ',' && parencount == 0 ) { vars0.append(cur_string); cur_string = ""; } else { cur_string += commandx[i]; if ( commandx[i] == '(' ) parencount++; if ( commandx[i] == ')' ) parencount--; } } vars0.append(cur_string); prevector vars(vars0); execute_kill_variable_by( home, vars, gullible, results ); goto time_report; } index_command(propagate) { constraintlist clist; if ( parse ( commandx, &( parse_text( "propagate" ), parse_constraint_list(clist) ) ) ) { execute_propagate( home, clist ); goto time_report; } } index_command(infer) { String label; constraint c; if ( parse ( commandx, &( parse_text( "@" ), parse_pat( &gen_label_pattern, label ), parse_text( "infer" ), parse_constraint( c ) ) ) ) { command_queue.append( "infer " + String(c) ); command_queue.append("at " + label); goto time_report; } } { constraint c; if ( parse ( commandx, &( parse_text( "infer" ), parse_constraint( c ) ) ) ) { if ( home->current == 0 ) ERROR("The current configuration is undefined."); config& cur = home->configs(home->current); execute_infer_command( home, cur, c, results, gullible ); goto time_report; } } index_command(show) { constraintlist clist; String joint_string; static Regex joint_pat( "(joint)" + orsign + "(joint:" + number_pat + ")" + orsign ); if ( parse ( commandx, &( parse_text( "show" ), parse_pat( &joint_pat, joint_string), parse_constraint_list( clist ) ) ) ) { if ( home->current == 0 ) ERROR("The current configuration is undefined."); bool joint = (joint_string != ""); bool joint_set = joint && joint_string != "(joint)"; if (joint_set && !gullible) { joint_string = joint_string.after("(joint:"); joint_string = joint_string.before(")"); set_numerical_parameter( "usedualdualforjoint", joint_string, "save" ); set_numerical_parameter( "usedualdualforjoint", joint_string, "set" ); } bool new_active_needed = false; config& c = home->configs(home->current); forPixDef( p, clist ) { forPixDef( q, clist(p).LHS ) c.check_variable( clist(p).LHS(q).var ); } bool answer; if (!gullible) { answer = home->show(clist, results, false, constraintlist( ), joint); if (joint_set) set_numerical_parameter( "usedualdualforjoint", joint_string, "restore" ); if (!answer) { WARNING( "Show failed." ); goto time_report; } } forPix( p, clist ) c.add_constraint( clist(p), new_active_needed, !show_config_creation ); if (new_active_needed) home->deactivate( ); goto time_report; } } index_command(check secondary residuals) if ( commandx == "checksecondaryresiduals" ) { if ( home->current == 0 ) ERROR( "[current] is undefined" ); home->configs(home->current).check_secondary_residuals(results); goto time_report; } index_command(infer dual min $<$=) { short int dp; if ( parse ( commandx, &( parse_text("inferdualmin<="), parse_short(dp) ) ) ) { if ( home->current == 0 ) ERROR("The current configuration is undefined."); if ( !gullible && !results.not_exist(home->n, home->n - home->dim, dp + 1) ) ERROR("I don't know how to do that."); short int& dmh = home->configs(home->current).share->dual_min_high; dmh = min( dmh, dp ); goto time_report; } } index_command(up to isomorphism show) { if_match( commandx, "uptoisomorphismshow" + var + "!=0" ) { commandx = commandx.after("uptoisomorphismshow"); String variable = take(commandx, var_pattern); execute_up_to_isomorphism_show(home, variable, gullible, results); goto time_report; } } index_command(projection onto) { word wd; String cd; Pix p; int status; if ( parse ( commandx, &( parse_text( "projectiononto" ), parse_word( wd ), parse_text( "is" ), parse_code_type( results, cd, p, status ) ) ) ) { execute_projection_onto( home, wd, cd, p, results, gullible, status ); goto time_report; } } index_command(load constraints by parity check from) { String cd; Pix p; if ( parse ( commandx, &( parse_text( "loadconstraintsbyparitycheckfrom" ), parse_open_code_type( results, cd, p ) ) ) ) { execute_load_constraints( home, results, cd, p ); goto time_report; } } index_command(infer by residual code) { String cd; Pix op; constraintlist l; if ( parse ( commandx, &( parse_text( "inferbyresidualcode" ), parse_open_code_type( results, cd, op ), parse_text( "that" ), parse_constraint_list( l ) ) ) ) { execute_infer_by_residual_code( home, cd, op, l, results, gullible ); goto time_report; } } TEX( \block{Process remaining commands} ) index_command(status) if ( commandx.contains( "status:", 0 ) ) { execute_status(home, commandx, command_queue, gullible, results); goto time_report; } index_command(print) { if_match( commandx, "print.*" ) { execute_print( commandx, home, total_time_used ); goto time_report; } } index_command(try to kill) { if_match( commandx, "trytokill.*" ) { commandx = commandx.after( "trytokill" ); if ( commandx == "x*" ) execute_try_to_kill_current( home, results ); else if ( commandx == "jy*" ) { prevector jvars = home->basic_joint_vars(results); bool nan; for ( int i = 0; i < jvars.length; i++ ) { int r, s, t; parse_j_var( jvars(i), r, s, t ); int a = (r + t - s)/2; int b = (r + s - t)/2; int c = (s + t - r)/2; int d = home->n - a - b - c; if ( a == 0 || b == 0 || c == 0 || d == 0 ) continue; home->set_config( String(dec(a)) + "," + dec(b) + "," + dec(c) + "," + dec(d) + ":{1100,0110}" ); home->configs(home->current).check_secondary_residuals (results); if ( home->contradiction(true, results) ) { cerr << "[" << jvars(i) << " killed]"; home->set_current(home->base); home->configs(home->base).add_constraint( jvars(i) + "=0", nan ); } } } else WARNING( "Your variable list is not one of the allowed " << "formats." ); goto time_report; } } index_command(!config) { if_match( commandx, "!config.*" ) { String s = "via lp [current] = "; command_queue.append(s); String s0 = commandx_save.after("!"); command_queue.append(s0); goto time_report; } } index_command(find cyclic codes) { static Regex find_cyclic_pat( "findcycliccodes" + orsign + "find" + number_pat + "-cycliccodes" ); if ( commandx.matches( find_cyclic_pat ) ) { if ( home->current != home->base ) ERROR("Current configuration must be base."); commandx = commandx.after("find"); int q = 1; if ( commandx[0] != 'c' ) q = take_int(commandx, number_pattern); execute_find_cyclic_codes( home, q ); goto time_report; } } index_command(round local variables) if ( commandx.matches( "roundlocalvariables" ) ) { execute_round_local( home, results ); goto time_report; } index_command(bound) { if_match( commandx, "bound.*" ) { execute_bound( home, commandx.after("bound"), results ); goto time_report; } } |-> current_compile_file, tex/code.tex WARNING("Unknown command or incorrect syntax -- \"" << commandx_save << "\". Command ignored."); // Report time used on command, in appropriate units, if > 10 seconds. time_report: if (!silent) { long time_used = time(0) - command_start_time; if ( time_used < 10 ); else if ( time_used < 60 ) cout << time_used << " seconds used on last command (real time).\n"; else if (time_used < 3600) cout << setprecision(3) << time_used/60.0 << " minutes used on last command (real time).\n"; else cout << setprecision(3) << time_used/3600.0 << " hours used on last command (real time).\n"; } next_command: if (temporary_parameters) restore_parameters(parameter_tail); continue; } cout << "End of command file, normal termination.\n"; total_time_used = time(0) - total_time_used; if ( total_time_used < 60 ) cout << total_time_used << " seconds used (real time)\n"; else if (total_time_used < 3600) cout << setprecision(3) << total_time_used/60.0 << " minutes used (real time)\n"; else cout << setprecision(4) << total_time_used/3600.0 << " hours used (real time)\n"; if ( total_time_used != 0 ) { cout << "Partial breakdown of real time usage, in mostly " << "non-overlapping categories:\n"; float percent_of_time; #define TIME_USED(param,by) \ percent_of_time = 100.0 * param / total_time_used; \ if ( percent_of_time >= 1.0 ) \ { cout << setprecision(3) << percent_of_time \ << "% used " << by << "\n"; } TIME_USED(time_used_by_list_extensions, "finding extensions (as in \"via extension\")") TIME_USED(time_used_generating_Krawtchouk_table, "generating Krawtchouk coefficient table") TIME_USED(time_used_generating_constraints, "generating constraints for split linear programming") TIME_USED(time_used_by_CPLEX, "by CPLEX") TIME_USED(time_used_by_simple_simplex, "by homebrew lp solver") TIME_USED(time_used_setting_up_simplex_problem, "setting up simplex problems") TIME_USED(time_used_by_subdivide, "by subdivide") TIME_USED(time_used_by_build, "by via building commands") TIME_USED(time_used_by_igs, "by invariant_generating_set") TIME_USED(time_used_by_smallcode_we, "by smallcode_we") TIME_USED(time_used_by_Isomorphic, "by Isomorphic") TIME_USED(time_used_presolving, "presolving for homebrew simplex") TIME_USED(time_used_by_check_infeasible, "checking infeasibility for homebrew simplex") } } |-> tex/code.tex \end{svb} \newpage \section*{References} \addtocontents{toc}{\protect\vspace*{2.25em}} \addcontentsline{toc}{special}{References} \ \par\noindent\vspace*{-0.25in} \hfuzz 8pt .[] \tolerance=100000 \hbadness=100000 %\catcode`\_=11 {\footnotesize \catcode`\@=11 \@input{\jobname.indz} \catcode`\@=12 } {\footnotesize \catcode`\@=11 \@input{\jobname.inda} \catcode`\@=12 } {\footnotesize \catcode`\@=11 \@input{\jobname.indb} \catcode`\@=12 } %\catcode`\_=8 \end{document} |-> tex/begin.tex \special{! TeXDict begin /nmv { 0 0 moveto } def /cmtxb { /cmtx matrix currentmatrix def } def /cot { dup cos exch sin div } def /csc { sin 1 exch div } def /tan { dup sin exch cos div } def /edef { exch def } def /twin { 2 array astore } def /inc { 1 add } def /dec { 1 sub } def /unload { aload pop } def /haf { 2 div } def /dub { 2 mul } def /sq { dup mul } def /xtr { 0 translate } def /ytr { 0 exch translate } def /upto { 0 exch rlineto } def /aras { array astore } def /egu { exch get unload } def /troll { 3 -1 roll } def /xmv { 0 moveto } def /mstroke { currentlinewidth dup troll mul setlinewidth stroke setlinewidth } def /widestroke { 3 mstroke } def /halfstroke { 0.5 mstroke } def /param { { edef } forall } def /ublankstroke { gsave 1 setgray stroke grestore } def /ublankfill { gsave 1 setgray fill grestore } def /rect { dup sin exch cos troll dup troll mul exch troll mul } def /dist { sq exch sq add sqrt } def /recip { 1 exch div } def /DEFAULTS { 0.2 setlinewidth } def /HPageCenter { 190 xtr } def /RectAngle {100 dict begin [/D /THETA /H /L] param /XSIGN 1 def /YSIGN 1 def /DONE 0 def THETA 180 gt {/THETA 360 THETA sub def /YSIGN -1 def} if THETA 90 gt {/THETA 180 THETA sub def /XSIGN -1 def} if THETA 0 ne {/C THETA cot def /Y D H haf add def /X Y C mul def X L haf le {X Y /DONE 1 def} if } if DONE 0 eq {/C THETA tan def /X D L haf add def /Y X C mul def Y H haf le {X Y /DONE 1 def} if } if DONE 0 eq {C sq D sq 4 mul L sq sub mul H sq sub C H mul L mul dub add D sq 4 mul add /W edef C H C L mul sub mul W sqrt add C sq inc dub div /U edef U L haf add D sq U sq sub sqrt H haf add} if exch XSIGN mul exch YSIGN mul end } def /SetSmallFont { /Times-Roman findfont 8 scalefont setfont } def /SetFont { /Times-Roman findfont 12 scalefont setfont } def /SetBigFont { /Times-Roman findfont 20 scalefont setfont } def /Print { nmv SetFont show } def /SmallCenterPrint { newpath SetSmallFont dup stringwidth pop haf neg xmv show } def /CenterPrint { newpath SetFont dup stringwidth pop haf neg xmv show } def /BigCenterPrint { newpath SetBigFont dup stringwidth pop haf neg xmv show } def /CenterPrintTwo { nmv exch SetFont dup stringwidth pop haf neg xmv show 0 -15 translate nmv dup stringwidth pop haf neg xmv show 0 15 translate } def /AnglePrint { newpath /FontSize 10 def /Times-Roman findfont FontSize scalefont setfont dup stringwidth pop FontSize dub 3 div 2 copy 7 -2 roll exch RectAngle exch 4 1 roll exch haf sub 3 1 roll haf sub exch moveto show } def /MAnglePrint { /mss {firstpass {stringwidth pop add} {show} ifelse} def dup /firstpass true def 0 exch exec dup 8 6 -2 roll exch RectAngle 4 sub exch troll haf sub exch /firstpass false def newpath moveto exec } def /UnderCenterPrint { -15 ytr newpath SetFont dup stringwidth pop haf neg xmv show 15 ytr } def /UnderCenterPrintTwo { -15 ytr nmv exch SetFont dup stringwidth pop haf neg xmv show -15 ytr nmv dup stringwidth pop haf neg xmv show 30 ytr } def /CircleEssence { dup xmv 0 0 troll 0 360 arc } def /ReverseCircleEssence { dup xmv 0 0 troll 360 0 arcn } def /Circle { CircleEssence stroke } def /Disk { CircleEssence StrokeFill } def /DarkDisk { CircleEssence DarkStrokeFill } def /OpenDisk { dup currentlinewidth 4 div sub CircleEssence FillEssence newpath CircleEssence [2 2] 3 setdash stroke [] 0 setdash } def /Square { newpath dup dup dup dup dup haf neg dup moveto 0 rlineto upto neg 0 rlineto neg upto closepath stroke } def /Rect { newpath 2 copy haf exch haf exch moveto dup neg upto exch dup neg 0 rlineto exch dup upto exch 0 rlineto closepath stroke } def /Box { nmv 2 copy exch 0 lineto 0 exch rlineto exch neg 0 rlineto neg 0 exch rlineto closepath stroke } def /FillAB { [/BXXX /AXXX] param gsave currentscreen 3 1 roll pop pop AXXX 0 3 2 roll setscreen BXXX setgray fill grestore } def /DarkFillEssence { 300 0.95 FillAB } def /FillEssence { 150 0.95 FillAB } def /LightFillEssence { 100 0.99 FillAB } def /WhiteFillEssence { 100 1 FillAB } def /Fill { FillEssence newpath } def % Fill --- fill interior of path with gray /StrokeFill { FillEssence stroke } def /DarkStrokeFill { DarkFillEssence stroke } def /DotStroke { ublankstroke [4 4] 6 setdash stroke [] 0 setdash } def /AltDotStroke { ublankstroke [1 3] 0 setdash halfstroke [] 0 setdash } def /AltDotStrokeX { [1 3] 0 setdash halfstroke [] 0 setdash } def /SouthSegment { nmv neg 0 exch lineto stroke } def /NorthSegment { nmv 0 exch lineto stroke } def /EastSegment { nmv 0 lineto stroke } def /WestSegment { nmv neg 0 lineto stroke } def /EastWestSegment { newpath dup haf neg xmv 0 rlineto stroke } def /NorthSouthSegment { newpath dup haf neg 0 exch moveto upto stroke } def /Segment { nmv rlineto stroke } def /DotSegment { nmv rlineto [1 3] 0 setdash halfstroke [] 0 setdash } def /MCenterPrint { /mss {firstpass {stringwidth pop add} {show} ifelse} def dup /firstpass true def 0 exch exec /firstpass false def haf neg 0 newpath moveto exec } def /mtmi {/RMTMI findfont 12 scalefont setfont mss} def /t-r {/Times-Roman findfont 12 scalefont setfont mss} def /t-rten {/Times-Roman findfont 10 scalefont setfont mss} def /t-rbig {/Times-Roman findfont 40 scalefont setfont mss} def /t-r20 {/Times-Roman findfont 20 scalefont setfont mss} def /cm-r {/cmr10 findfont 12 scalefont setfont mss} def /cm-mi {/cmmi10 findfont 12 scalefont setfont mss} def /t-rsub {/Times-Roman findfont 7 scalefont setfont firstpass {stringwidth pop add} {0 -3 rmoveto show 0 3 rmoveto} ifelse} def /kern-t-r {/Times-Roman findfont 12 scalefont setfont firstpass {stringwidth pop add} {2 0 rmoveto show} ifelse} def /t-rsup {/Times-Roman findfont 7 scalefont setfont firstpass {stringwidth pop add} {0 3 rmoveto show 0 -3 rmoveto} ifelse} def /t-rssub {/Times-Roman findfont 5 scalefont setfont firstpass {stringwidth pop add} {0 -5 rmoveto show 0 5 rmoveto} ifelse} def /sym {/Symbol findfont 12 scalefont setfont mss} def /sym20 {/Symbol findfont 20 scalefont setfont mss} def /sym30 {/Symbol findfont 30 scalefont setfont mss} def /labelsquid 15 def %% offset for labelling things /LabelBelow { 0 labelsquid neg translate MCenterPrint 0 labelsquid translate } def /LabelAbove { 0 labelsquid translate MCenterPrint 0 labelsquid neg translate } def /LabelLeft { /mss {firstpass {stringwidth pop add} {show} ifelse} def dup /firstpass true def 0 exch exec /firstpass false def labelsquid add neg 0 newpath moveto exec } def /LabelRight { /firstpass false def /mss {show} def newpath labelsquid xmv exec } def /alpha {<61> sym} def /beta {<62> sym} def /theta {<71> sym} def /sigma {<73> sym} def /doubleprime { sym} def /partial { sym} def /times { sym} def /prime { sym} def /plus {<2b> sym} def /minus {<2d> sym} def /bigplus {<2b> sym20} def /bigminus {<2d> sym20} def /pi {<70> sym} def /lambda {<6c> sym} def /cap { sym} def /xput { dup xtr exch exec neg xtr } def /yput { dup ytr exch exec neg ytr } def /xyput { 2 copy translate troll exec neg exch neg exch translate } def /WideSouthSegment { nmv neg 0 exch lineto widestroke } def /WideEastSegment { nmv 0 lineto widestroke } def /TextMetalShow { 100 dict begin /height exch def dup length 1 sub 0 1 3 -1 roll { 1 index exch 1 getinterval dup stringwidth pop /width exch def Pattern stringwidth pop 0 rmoveto } for pop end } bind def /Pattern { gsave currentpoint translate dup true charpath clip /delta 1.44 def /bot 0 def /top height 0.4375 mul def bot delta top { dup bot sub top bot sub div 55 mul 55 exch sub sin setgray newpath 0 exch moveto width 0 rlineto 0 delta rlineto width neg 0 rlineto closepath fill } for /bot top def /top height 0.5625 mul def bot delta top { dup bot sub top bot sub div setgray 0 exch moveto width 0 rlineto 0 delta rlineto width neg 0 rlineto closepath fill } for /bot top def /top height def bot delta top { dup bot sub top bot sub div 78 mul cos setgray 0 exch moveto width 0 rlineto 0 delta rlineto width neg 0 rlineto closepath fill } for nmv dup true charpath gsave 0 setgray 2 setlinewidth stroke grestore grestore } bind def end } \def\hexnumberZ#1{\ifnum#1<10 \number#1\else \ifnum#1=10 A\else\ifnum#1=11 B\else\ifnum#1=12 C\else \ifnum#1=13 D\else\ifnum#1=14 E\else\ifnum#1=15 F\fi\fi\fi\fi\fi\fi\fi} \newcounter{alphactr} \def\thealphactr{\alph{alphactr}} \newcounter{Alphactr} \newcounter{romanctr} \def\theromanctr{\roman{romanctr}} \newcounter{Romanctr} \newcounter{arabicctr} \newcounter{arabicbrctr} \def\geom{g\'eom\'etrie} \def\EXPOSE{expos\'e} \def\SGA{S\'em\-in\-aire de G\'eom\'e\-trie Al\-g\'e\-bri\-que} \def\PLUS{+} \def\TIMES{*} \def\seealso#1#2{{\em see also\/} #1} \def\begindiagram{\def\normalbaselines{\baselineskip20pt \lineskip3pt \lineskiplimit3pt}} \font\bigmath=cmsy10 scaled\magstep2 \def\SWarrow{\hbox{\bigmath \char"2E}} \def\NWarrow{\hbox{\bigmath -}} \def\SEarrow{\hbox{\bigmath \&}} \def\NEarrow{\hbox{\bigmath \%}} \hyphenation{Durch-schnitte} \hyphenation{Prim-zahl-char-akter-istik} \hyphenation{Schmie-gungs} \hyphenation{abeli-an} \hyphenation{funct-ors} {\catcode`\!=0 \catcode`\\=12 !gdef!({\(} !gdef!){\)} } \catcode`\@=11 \def\operatoratfont{\operator@font} \let\@afterindentfalse\@afterindenttrue \@afterindenttrue \catcode`\@=12 \def\op{\operatoratfont} \catcode`\@=11 \def\cpicture(#1,#2){\center\@ifnextchar({\@picture(#1,#2)}% {\@picture(#1,#2)(0,0)}} \def\endcpicture{\egroup\hss\egroup\ht\@picbox\@picht \dp\@picbox\z@\leavevmode\box\@picbox\endcenter} \def\matrixx#1{\null\,\vcenter{\normalbaselines\m@th \ialign{\hfil$\displaystyle ##$\hfil&&\quad\hfil$\displaystyle ##$\hfil\crcr \mathstrut\crcr\noalign{\kern-\baselineskip} #1\crcr\mathstrut\crcr\noalign{\kern-\baselineskip}}}\,} \catcode`\@=12 \newdimen\rotdimen \font\cy=wncyr10 scaled\magstep1 \def\o#1{\if#1\PLUS\oplus\else\if#1\TIMES\otimes\fi\fi} \def\many#1{\manyxx#1 \cdots \manyxx#1} \def\manyxx#1{\if#1\PLUS{+}\else\if#1\TIMES{*}\fi\fi} \catcode`\@=11 \def\backcases#1{\left.\vcenter{\normalbaselines\m@th \ialign{$##\hfil$\hfil\crcr#1\crcr}}\,\right\}} \catcode`\@=12 \def\xhmode#1{\relax\ifmmode{#1}\else{\snap\hbox{$#1$}}\fi} \def\snap{\hskip 0pt plus 4cm\penalty1000\hskip 0pt plus -4cm} \def\PP{\xmode{\Bbb P\kern1pt}} \def\email{jaffe{\kern0.5pt}@{\kern0.5pt}cpthree.unl.edu} \newif\ifnocommaindate % used in \today \newif\ifwrongmonth \newcount\feb \newcount\fdayofweekno \newcount\daynumber \newcount\monthnumber \def\emptyset{\varnothing} \def\Q{{\Bbb Q}\kern1pt} \def\F{{\Bbb F}\kern1pt} \def\N{\xmode{\Bbb N}} \def\Z{\xmode{\Bbb Z}} \def\R{\xmode{\Bbb R}} \def\Aut{\mathop{\operatoratfont Aut}\nolimits} \def\Even{\mathop{\operatoratfont Even}\nolimits} \def\Lex{\mathop{\operatoratfont Lex}\nolimits} \def\Mat{\mathop{\operatoratfont Mat}\nolimits} \def\Proj{\mathop{\operatoratfont Proj}\nolimits} \def\Simp{\mathop{\operatoratfont Simp}\nolimits} \def\Sym{\mathop{\operatoratfont Sym}\nolimits} \def\min{\mathop{\operatoratfont min}\nolimits} \def\rank{\mathop{\operatoratfont rank}\nolimits} \def\rowspace{\mathop{\operatoratfont rowspace}\nolimits} \def\weight{\mathop{\operatoratfont weight}\nolimits} \def\mp[[#1||#2||#3]]{\snap\hbox{$#1:\kern3pt #2\ \to\ #3$}} \def\mapE#1{{\smash{\mathop{\longrightarrow}\limits^{#1}}}} \def\mapS#1{\Big\downarrow\rlap{$\vcenter{\hbox{$\scriptstyle{#1}$}}$}} \def\diagramx#1{{$$\begindiagram\matrixx{#1}$$}} \def\BRMAT#1{\left[\matrixx{#1}\right]} \def\mapx[[#1||#2]]{\snap\hbox{$#1\ \to\ #2$}} \def\qed{{\hfill$\square$}} \def\manycup{\cup \cdots \cup} \def\manycdot{\cdot \ldots \cdot} \def\brmat#1{\xxmode{\hbox{$\displaystyle\left[\matrixx{#1}\right]$}}} \def\oD{{\overline{D}}} \def\oI{{\overline{I}}} \def\oL{{\overline{L}}} \def\oP{{\overline{P}}} \def\oQ{{\overline{Q}}} \def\oU{{\overline{U}}} \def\loB{{\overline{\lowercase{B}}}} \def\loC{{\overline{\lowercase{C}}}} \def\loD{{\overline{\lowercase{D}}}} \def\loF{{\overline{\lowercase{F}}}} \def\loI{{\overline{\lowercase{I}}}} \def\loP{{\overline{\lowercase{P}}}} \def\loW{{\overline{\lowercase{W}}}} \def\loY{{\overline{\lowercase{Y}}}} \def\lhF{{\hat{\lowercase{F}}}} \def\IFF{if and only if} \def\LI{linearly independent} \def\LP{linear programming} \def\WRT{with respect to} \def\LHS{left hand side} \def\RHS{right hand side} \def\WMAT{we may assume that} \def\WLOG{without loss of generality} \def\RREF{reduced row-echelon form} \def\th#1{\xmode{{#1}^{\operatoratfont th}}} \def\second{\xmode{{2}^{\operatoratfont nd}}} \def\IN{\subset} \def\notIN{\not\IN} \def\setof#1{\xmode{\{#1\}}} \def\setofh#1{\xmode{\{\hbox{#1}\}}} \def\VEC#1#2#3{#1_{#2}, \ldots, #1_{#3}} \def\xmode#1{\relax\ifmmode{#1}\else{$#1$}\fi} \def\xxmode#1{\ifmmode{#1}\else{$$#1$$}\fi} \def\block#1{\section{#1}} \def\abs#1{{\vert{#1}\vert}} \def\norm#1{\Vert{#1}\Vert} \def\iso{\cong} \def\floor#1{\lfloor#1\rfloor} \def\ceiling#1{\lceil#1\rceil} \def\inn#1{\langle #1 \rangle} \def\widepost#1#2#3{\par\vspace{0.1in}\hbox{\vbox to #1bp{\vss% \special{" HPageCenter 0 #2 translate DEFAULTS #3 }}}\vspace{0.1in}} \def\wpost#1#2#3{\par\vspace{0.1in}\hbox{\vbox to #1bp{\vss% \special{" 0 #2 translate 0.2 setlinewidth #3 }}}\vspace{0.1in}} \newenvironment{proof}{\trivlist \item[\hskip \labelsep{\sc Proof.\kern1pt}]}{\endtrivlist} %\proof \newenvironment{alphalist}{\begin{list}{(\alph{alphactr})}{\usecounter{alphactr}}}{\end{list}} %\alphalist \newenvironment{romanlist}{\begin{list}{(\roman{romanctr})}{\usecounter{romanctr}}}{\end{list}} %\romanlist \def\midhead#1{\vspace{0.1in}\par\noindent{\bf #1}\vspace{0.1in}} \def\ol{\overline} \def\arrow(#1,#2){\ncline[nodesep=5pt]{->}{#1}{#2}} \def\circno#1{\pscirclebox[linewidth=.3pt,framesep=2pt]{\small\bf #1}} \hfuzz 3pt \textwidth 6.7in \hoffset=-0.65in \textheight 8.3in \voffset=-0.5in \catcode`\@=11 DEFINE(index_setup, ![ \def\makeindex$*{% \newwrite\@indexfile$* \immediate\openout\@indexfile$*=\jobname.idx$* \def\index$*{\@bsphack\begingroup \@sanitize \@wrindex$*}\typeout {Writing index file \jobname.idx$*}% } \@onlypreamble\makeindex$* \def\@wrindex$*#1{% \protected@write\@indexfile$*{}% {\string\indexentry{#1}{\thepage}}% \endgroup \@esphack} \def\index$*{\@bsphack\begingroup \@sanitize\@index$*} \def\@index$*#1{\endgroup\@esphack} ]! ) index_setup(a) index_setup(b) index_setup(z) \makeindexz \makeindexa \makeindexb \catcode`\@=12 \newtheorem{theorem}{Theorem}[section] \setlength{\parindent}{9mm} \setcounter{tocdepth}{3} \newtheorem{fact}[theorem]{Fact} %\fact \newtheorem{proposition}[theorem]{Proposition} %\proposition \newtheorem{lemma}[theorem]{Lemma} %\lemma \newtheorem{sublemma}[theorem]{Sublemma} %\sublemma \newtheorem{conjecture}[theorem]{Conjecture} %\conjecture \newtheorem{cor}[theorem]{Corollary} %\cor \newtheorem{corollary}[theorem]{Corollary} %\corollary \newtheorem{warning}[theorem]{Warning} %\warning \newtheorem{prop}[theorem]{Proposition} %\prop \newtheorem{claim}[theorem]{Claim} %\claim \newtheorem{examplen}[theorem]{Example} %numbered example \newtheorem{problemx}[theorem]{Problem} %numbered problem \newtheorem{exampleth}[theorem]{Example} \newenvironment{example}{\begin{exampleth}\shape{n}\selectfont}{\end{exampleth}} \def\ifundefined#1{\expandafter\ifx\csname#1\endcsname\relax} \catcode`\@=11 DEFINE(index_setup, ![ \def\makeindex$*{% \newwrite\@indexfile$* \immediate\openout\@indexfile$*=\jobname.idx$* \def\index$*{\@bsphack\begingroup \@sanitize \@wrindex$*}\typeout {Writing index file \jobname.idx$*}% } \@onlypreamble\makeindex$* \def\@wrindex$*#1{% \protected@write\@indexfile$*{}% {\string\indexentry{#1}{\thepage}}% \endgroup \@esphack} \def\index$*{\@bsphack\begingroup \@sanitize\@index$*} \def\@index$*#1{\endgroup\@esphack} ]! ) index_setup(a) index_setup(b) index_setup(z) \catcode`\@=12 \makeindexz \makeindexa \makeindexb \begin{document} \vskip 0.15in |-> tex/sed.in s/\\Lcitemark /[/g s/\\Rcitemark /]/g s/\\Rcitemark/]/g s/ \\Rspace{}//g |-> tex/run_tex # # This is not yet usable by anyone except me. setkeyx tr %  < code.tex > tempx tib -x -z -s choices.tib begin tempx > t.tex0 echo \\documentstyle\[longtable,amssymb,makeidx,fancybox,pstricks, > t.tex #echo \\documentstyle\[amssymb,makeidx,fancybox,timesmt,pstricks, > t.tex echo pst-node,multido,12pt\]\{invent\} >> t.tex tr  % < t.tex0 | cat -s | sed -f sed.in > t.tex1 # The following awk command corrects for a bug in tib which (at least on my # machine) causes the first author's name in the bibliography to be replaced # by an underline. This command was kindly provided by Alois Steindl. If your # installation of tib does not have this bug, you should replace the awk # command by "cat t.tex1 >> t.tex". awk 'BEGIN {found=0} \ {if ($1 ~ /\\def\\Astr\{\\Underlinemark\}\%/) \ {if (found) {print} else {found=1}} else {print}}' < t.tex1 >> t.tex if ($status != 0) goto fail if(-f t.idxz)makeindex -o t.indz -t t.ilgz -s t.istz t.idxz if(-f t.idxa)makeindex -o t.inda -t t.ilga -s t.ista t.idxa if(-f t.idxb)makeindex -o t.indb -t t.ilgb -s t.istb t.idxb latex t | tail +8 endif fail: /bin/rm -f tempx t.tex0 t.tex1 temp >& /dev/null |-> tex/choices.tib # include word-definition file (journals and publishers) I TMACLIB amsabb.ttz AA abbreviate authors' first names EA abbreviate editors' first names SAHD sort on authors, special field H, dates U replace successive identical authors with underlines AR1 reverse first author's name D SPRINGER Spring\-er-Ver\-lag\ %C New York D CAMBRIDGE Cambridge Univ.\ Press D ADDISONWESLEY Addison-Wesley\ %C Reading, Mass. D LNMATH Lecture Notes in Mathematics\ %I |SPRINGER| D LSNAPNMATH Lecture \snap Notes in Mathematics\ %I |SPRINGER| # \def\Underlinemark{\vrule height .7pt depth 0pt width 3pc\kern1pt} \def\annotations{} \def\Flagstyle#1{\par\noindent\hbox to 30pt{[#1]\hfil}% \hangindent=30pt\hangafter=1} \input /export/home/jaffe/tib/my1.ttx |-> doc/backward-compatibility This file contains a list of most commands from earlier versions that have been eliminated or changed in a way that has resulted in a backward incompatibility. build with words of weight --> via building (cf. set fill weight) compute automorphism group --> print automorphism group cyclic --> := display basis --> print basis display dual --> print dual basis find automorphisms --> print automorphism group infer dual min >= --> (automatic) infer from local variables -> show infer kill weights --> (automatic) is pseudocyclic --> is cyclic? kill variable by --> kill known --> status list variable classes --> print variable classes list variables of weight --> print variables of weight search --> bound y*, [x*] set building gullible --> set gullible commands = via build set extensions gullible --> set gullible commands = via ext set group parameter set homebrew quiet set linear programming forced set lowest k for optimal --> test mask set no gullible --> set gullible commands = no supercyclic --> := terminal --> := try to kill current --> try to kill x* up to isomorphism infer --> up to isomorphism show up to isomorphism search --> bound y*, [~x*] via griesmer via refinement --> = |-> doc/INSTALL #!/bin/csh if ($1 != "")goto $1 echo " " echo Hello! This is an automated script for installing Split on your echo system. There are a number of stages, some requiring action on your echo "part. Should the script be interrupted (and you wish to start it up" echo "again), you may restart it with 'install woof', where 'woof' is the" echo "name of the stage you wish to start at. You'll know where this is" echo "because I will periodically issue messages of the form 'stage = woof'." echo " " echo "I am hoping that this script is portable. If not (or there are any other" echo "problems), please let me know\!" echo " " ; echo "David Jaffe (e-mail: jaffe@cpthree.unl.edu)" echo " "; echo -n "Press return to proceed (or x, followed by return to exit)...."; set input = $<; if ($input == "x")exit; echo " "; acknowledge: ; echo stage = acknowledge; echo " " echo Software acknowledgments: Split makes use of the following free software echo which was not written by the author: echo "--- various GNU (Free Software Foundation) products, including g++ and" echo " libg++" echo "--- Brendan McKay's graph isomorphism package **nauty**" echo "--- Keith Briggs double-double precision floating point package **quad**." echo " "; echo -n Press return to proceed....; set input = $<; if ($input == "x")exit; echo " "; hardware_check: ; echo stage = hardware_check; echo " " echo "This program should run on any reasonably modern Unix machine. " echo "(However, spurious segmentation faults have been encountered under " echo "NeXTStep-Intel.)" echo " " echo This program requires at least 32 megabytes of RAM to install and use. echo If you have less than 32 megabytes of RAM, go buy some echo more before proceeding. If you have between 32 and 64 megabytes, you echo are probably OK, but the compilation may be slow, as there is likely echo to be a lot of swapping to disk. echo " "; echo -n Press return to proceed....; set input = $<; if ($input == "x")exit; echo " "; cplex_check: ; echo stage = cplex_check; echo " " echo Split functions best if the commercial linear programming solver CPLEX echo is installed. For academic users, a echo "'Linear Optimizer Single CPU License' costs about 500 dollars; you can " echo send e-mail to info@cplex.com if you want to get it. Otherwise, echo Split will work without CPLEX, but it will be slower. Split has been echo tested with versions 2.1 and 4.04 of CPLEX. Hopefully other versions echo will work as well. echo " "; echo -n Press return to proceed....; set input = $<; if ($input == "x")exit; echo " "; gnu_check: ; echo stage = gnu_check; echo " " echo "Now I'm going to ask if you have various programs installed on your" echo computer, all available for free, and mostly produced by the Free Software echo "Foundation (GNU). All are essential, except as noted, and you will need" echo "the indicated version. For more recent version (released since this was" echo "written), some adjustments may be necessary." echo "g++ (version 2.7.2)" echo " (Testing for g++ version...)" g++ --version echo " (If that's not 2.7.2, you should upgrade before proceeding.)" echo " (As of 10/29/97, the latest version is 2.7.2.3, which should " echo " work too, but I haven't tested it.)" echo "libg++ (version 2.7.1)" echo -n "sort (the GNU version). I find the following binaries: " which sort | tr '\n' ' ' echo "." echo "Press return if the gnu binary appears first, which it should...." set input = $< echo -n "fold (the GNU version). I find the following binaries: " which fold | tr '\n' ' ' echo -n ". Press return if the gnu binary appears first, which it should...." set input = $< echo -n "gzip. I find the following binaries: " which gzip | tr '\n' ' ' echo "m4 (the GNU version): I find: " m4 --version echo -n Press return if you the word GNU appears on the above line.... set input = $< echo "GNU binutils package (contains c++ filt)" echo "xdvi (version 20 or later -- only used by 'help' command)" echo "gs (ghostscript) -- only used by 'help' command)" echo echo Otherwise, go install the programs you do not have, and come back and echo try again. echo " "; echo -n Press return to proceed....; set input = $<; if ($input == "x")exit; echo " "; download: ; echo stage = download; echo " " echo You should now be in the directory where you want to install Split. echo This could be an empty directory or it could be a directory where you echo "previously installed Split. I won't delete anything, but I might" echo accidentally overwrite a file you care about. echo I will now download files into this directory by anonymous ftp. echo In total, about 1500 kilobytes will be transferred. echo " "; echo -n Press return to proceed....; set input = $<; if ($input == "x")exit; echo " "; echo user ftp `whoami`@`hostname` > ftp_in echo cd pub >> ftp_in echo cd coding >> ftp_in echo binary >> ftp_in foreach i (MACROS CODE DATA_F2_1 NOT_MINE LOG t.dvi) echo get $i.gz >> ftp_in end echo get disect.cc >> ftp_in echo get t.idxb >> ftp_in echo bye >> ftp_in ftp -n -v cpthree.unl.edu < ftp_in rm ftp_in echo " "; unpack: ; echo stage = unpack; echo " " echo "File transfer complete. Now I'll make subdirectories, unzip some files," echo "and put some files in them. Please wait..." mkdir cc doc inc obj tex calculations web log foreach i (CODE DATA_F2_1 MACROS NOT_MINE LOG t.dvi) gunzip $i.gz end mv t.dvi tex mv t.idxb tex echo " "; echo -n Done. Press return to proceed....; set input = $<; if ($input == "x")exit; echo " "; nextstep: ; echo stage = nextstep; echo " " echo If your platform is NeXTSTep-Intel, change nan.h to math.h in cc/quad.cc. echo " "; echo -n Press return to proceed....; set input = $<; if ($input == "x")exit; echo " "; modify: ; echo stage = modify; echo " " echo Now you may need to modify CODE to suit your system, by editing the echo "#define lines, as indicated below. In the case where something should not" echo "be defined, put // in front of #define to comment out the line. In the" echo case where something should be defined, remove the // if present. echo " " echo --- CPLEX should be set to the name of your CPLEX executable file echo " (probably cplex or cplexmip)" echo --- CPLEX_VERSION should be set to the version number of your copy of CPLEX echo --- ABSOLUTE_PATH_FOR_CPLEX will need to be set if CPLEX refuses to echo " recognize relative file names" echo " " echo -n Make any needed changes to CODE and then press return to proceed.... set input = $<; if ($input == "x")exit; echo " "; disect: ; echo stage = disect; echo " " echo Now I am ready to unpack the file CODE. First I will compile the program echo disect, and then execute it on CODE. This takes 7 seconds on my echo machine, but disect is rather badly written, and could take forever if echo "files are being shuffled across a network. (I'll also unpack some other" echo "files.)" echo " "; echo -n Press return to proceed with the disection....; set input = $<; if ($input == "x")exit; echo " "; g++ disect.cc -s -o disect foreach i (CODE DATA_F2_1 NOT_MINE LOG) disect $i end chmod 755 prep chmod 555 log/* echo " "; echo -n Done. Press return to proceed....; set input = $<; if ($input == "x")exit; echo " "; compile: ; echo stage = compile echo "And now it's time to compile Split\! This takes 12 minutes on my machine." echo "If it is incredibly slow on your machine, try reading the file 'prep'" echo " "; echo -n Press return to proceed with the compilation....; set input = $<; if ($input == "x")exit; echo " "; prep all echo " " echo Assuming that no error messages appeared above, Split has now been echo "successfully installed\!" echo " " echo If you do not wish to modify and thence recompile the program, only echo the following files/directories are absolutely essential: echo Split, code.data, code.data1, calculations, tex, tex/t.dvi, and tex/t.idxb. echo "You could (if you wished) copy these to another place on your computer" echo for someone else to use. echo " "; echo You may wish to look at the file doc/backward-compatibility, which echo contains a record of incompatibilities with earlier versions that have echo been introduced. echo " "; echo -n Press return to proceed....; set input = $<; if ($input == "x")exit; echo " "; echo "Now look at the section of the report (tex/t.dvi) entitled" echo "'Execution of the proofs in this report'", where you will find a echo battery of tests to carry out. echo " "; echo Have fun! |-> web/codes.cc #include #include #include #include "stdio.h" #include "stdlib.h" extern "C" char *getenv(const char *name); main( ) { cout << "Content-type: text/html" << char(10) << char(10); String com = getenv("QUERY_STRING"); char c; int count = 0; String my_address = "/Net/mathstat/Users/Fac1/djaffe"; if ( com.length( ) < 3 || com[0] != 'n' || com[1] != '=' || !com.contains("&k=") ) { cout << "Illegal request."; exit(0); } String html1_addr = my_address + "/Library/Public_html/codes/codeform.html1"; ![FILE]! *html1; html1 = fopen( (&(html1_addr[0])), "r" ); while( (c=getc(html1)) != EOF ) cout << c; fclose(html1); com.del( "n=" ); String ns = com.before("&k="); String ks = com.after("&k="); int n = int( atoI(ns).as_long( ) ); int k = int( atoI(ks).as_long( ) ); cout << "Answer when n = " << n << " and k = " << k << ":\n"; cout << "

\n"; String nkfile = my_address + "/Library/Public_html/binary/" + dec(n) + "/" + dec(k); ![FILE]! *fp; ![FILE]! *html2; if ( n <= 0 ) { cout << "Your value for n must be at least 1.\n"; goto tail; } if ( k <= 0 || k >= n ) { cout << "Your value for k must be between 1 and n-1.\n"; goto tail; } fp=fopen((&(nkfile[0])), "r"); if ( fp == 0 ) { cout << "I'm sorry, but I have no information for codes with " << "n = " << n << " and k = " << k << ".\n"; goto tail; } while( (c=getc(fp)) != EOF ) { if ( c == '{' ) cout << "
"; cout << c; count++; if ( c == '\n' ) count = 0; if ( count >= 80 && c == ',' ) { count = 0; cout << "\n"; } } fclose(fp); tail: cout << "


\n"; String html2_addr = my_address + "/Library/Public_html/codes/codeform.html2"; html2 = fopen( (&(html2_addr[0])), "r" ); while( (c=getc(html2)) != EOF ) cout << c; fclose(html2); } |-> web/codeform.html, web/codeform.html1 Weights which can occur in binary linear codes

Weights which can occur in binary linear codes

Fill in n and k below. I will give you some information about binary linear codes having length n and dimension k. For now, you must have n <= 85 or (n <= 200 and k <= 14).


n k


|-> web/codeform.html, web/codeform.html2 This is a preliminary version! Information about existence and uniqueness of codes will be added later. For information about how this data was generated, see the documentation for Split. For more information about the existence of [n,k,d] codes (not just in the binary case), see Brouwer's tables. |-> web/script accept (tables only) code.data1; accept (tables only) code.data; build web directory for 2 <= n <= 85, 1 <= k <= 85; build web directory for 2 <= n <= 200, 1 <= k <= 14; |-> doc/DISTRIBUTE # # This is the master installation script. This is designed for use # by the author, but could be modified for use by someone else. set web_place = "~/mathlab/Library/Public_html/code-archive/VERSION" if ($1 != "")goto $1 echo "I assume that there are files in the directory log in accordance with" echo "section 'Execution of...' of the main report." echo " "; echo -n Press return to proceed....; set input = $<; echo " "; /bin/rm -f LOG cd log foreach i (*) echo "|-> log/$i" >> ../LOG fold -s $i >> ../LOG end cd .. mkdir $web_place tex: echo attempting to compile reports.... echo " " foreach i (CODE DATA_F2_1 NOT_MINE) disect $i end cd tex /bin/rm t.aux t.idx* t.toc echo "tex1, pass 1" run_tex1 echo "tex1, pass 2" run_tex1 cp t.dvi code1.dvi /bin/rm t.aux t.idx* t.toc echo "main, pass 1" run_tex echo "main, pass 2" run_tex echo "main, pass 3" run_tex cd .. echo " "; echo -n If there were no errors, press return to proceed....; set input = $<; echo " "; demo: echo "attempting to compile DEMO..." echo " " chmod 755 dprep dprep echo " "; echo -n If there were no errors, press return to proceed....; echo "(The following few lines require superuser access.)" set input = $<; echo " "; /bin/mv DSplit /export/home/split/Split cp code.data1 code.data /export/home/split mkdir /export/home/split/calculations echo "attempting to compile code..." echo " " prep echo " "; echo -n If there were no errors, press return to proceed....; set input = $<; echo " "; ftp: ; echo "updating ftp site..." echo " " /bin/rm /export/ftp/pub/coding/* foreach i (CODE DATA_F2_1 MACROS NOT_MINE LOG) cp $i /export/ftp/pub/coding gzip /export/ftp/pub/coding/$i end cp disect.cc tex/t.dvi tex/t.idxb tex/code1.dvi /export/ftp/pub/coding gzip /export/ftp/pub/coding/t.dvi /export/ftp/pub/coding/code1.dvi chmod 755 /export/ftp/pub/coding/* echo " "; echo -n If there were no errors, press return to proceed....; set input = $<; echo " "; web: ; echo "updating web site..." doc cp doc/INSTALL /export/ftp/pub/coding/* $web_place cp tex/t.dvi $web_place/code.dvi dvips $web_place/code.dvi -o $web_place/code.ps gzip $web_place/code.dvi $web_place/code.ps chmod 755 $web_place/* web /bin/rm codes ln -s code-archive/VERSION codes bwd: echo "Clearing and rebuilding web directory..." doc /bin/rm -rf web/binary Split < web/script cd web cp codes.cc codeform.html* ~/mathlab/Library/Public_html/codes cp -r binary ~/mathlab/Library/Public_html rsh mathlab60.unl.edu -l djaffe \ "cd Library/Public_html/codes; g++ codes.cc -o codes.cgi" echo " " echo "Done! Now adjust Welcome.html to update the version number, page" echo "count, and date." echo " " echo "Go to an empty directory on mathlab and attempt to install."