diff --git a/.github/workflows/tex.yml b/.github/workflows/tex.yml index b0ad665..742f82e 100644 --- a/.github/workflows/tex.yml +++ b/.github/workflows/tex.yml @@ -16,11 +16,11 @@ jobs: name: Build document runs-on: ubuntu-latest container: - image: registry.gitlab.com/islandoftex/images/texlive:TL2023-historic + image: registry.gitlab.com/islandoftex/images/texlive:TL2025-historic steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v7 - name: Build id: build @@ -31,8 +31,10 @@ jobs: make - name: Upload artifacts - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: LALU-build-${{ github.run_number }}-${{ steps.build.outputs.sha }} if-no-files-found: error - path: ${{ github.workspace }}/讲义/*.pdf + path: | + 讲义/LALU.pdf + 讲义/LALU-answers.pdf diff --git a/.gitignore b/.gitignore index 13dd339..375ac0b 100644 --- a/.gitignore +++ b/.gitignore @@ -3,11 +3,8 @@ 讲义/*.pdf 习题参考答案/*.pdf -build -gh-actions-build -讲义/LALU.tex -讲义/LALU-ans-contents.tex -习题参考答案/LALU-answers.tex +build/ +docs/ ## latexindent.pl backup files *.bak* diff --git "a/\350\256\262\344\271\211/.latexmkrc" "b/\350\256\262\344\271\211/.latexmkrc" new file mode 100644 index 0000000..ca49cb9 --- /dev/null +++ "b/\350\256\262\344\271\211/.latexmkrc" @@ -0,0 +1,28 @@ +# imakeidx writes one .idx file per index. Let latexmk run xindy so +# failures become build failures instead of being hidden by TeX shell escape. +$makeindex = 'internal lalu_xindy %S %D %O'; + +sub lalu_xindy { + my ($source, $destination, @latexmk_options) = @_; + + my @modules = $source =~ m{(?:^|[\\/])sym[.]idx\z} + ? ('-M', 'numeric-sort', + '-M', 'latex', + '-M', 'latex-loc-fmts', + '-M', 'makeindex') + : ('-M', 'texindy'); + + my $status = system( + 'xindy', + @latexmk_options, + @modules, + '-I', 'xelatex', + '-C', 'utf8', + '-o', $destination, + $source, + ); + + return 127 if $status == -1; + return 128 + ($status & 127) if $status & 127; + return $status >> 8; +} diff --git "a/\350\256\262\344\271\211/LALU-answers.tex" "b/\350\256\262\344\271\211/LALU-answers.tex" index 78b00cb..998e8cc 100644 --- "a/\350\256\262\344\271\211/LALU-answers.tex" +++ "b/\350\256\262\344\271\211/LALU-answers.tex" @@ -1,7 +1,3 @@ -\makeatletter - \def\input@path{{..}} % 搜索上层目录的 LALUbook -\makeatother - \documentclass[ % colors = false, geometry = 16k, @@ -17,38 +13,327 @@ \title{\heiti 浙江大学 2023--2024 学年 \\ 线性代数荣誉课辅学习题答案} \author{2023--2024 学年线性代数 I/II(H)辅学授课 \\ 吴一航 \quad \verb|yhwu_is@zju.edu.cn|} -\AtEndPreamble{\hypersetup{ - pdfauthor = {吴一航}, - pdftitle = {线性代数荣誉课辅学习题答案}, -}} +% The main document publishes this generated manifest only after a successful +% build. Keeping the path overrideable makes out-of-tree builds possible. +\providecommand*{\LALUAnswerManifestPath}{build/answers/LALU.manifest.tex} +\providecommand*{\LALUAnswerManifestJob}{LALU} -\newcounter{LUsection} +\newcounter{LALUanswerunit} -\makeatletter -\newcommand*{\LUgroupsancheck}{% -\expandafter\@ifundefined{@exist@LUsection@\arabic{section}}% - {} - {\endgroup} -} -\let\@std@section\section -\renewcommand*{\section}{% - \LUgroupsancheck% - \@std@section -} -\makeatother - -\NewDocumentCommand{\LUsection}{m}{% -\LUgroupsancheck -\begingroup -\addtocounter{section}{-1} -\refstepcounter{LUsection} -\renewcommand*{\thesection}{未竟专题\zhnumber{\arabic{LUsection}}} -\renewcommand*{\theHsection}{LU.\arabic{LUsection}} -\ctexset{ - section={format={\centering\Huge\bfseries},name={未竟专题,},number={\zhnumber{\arabic{LUsection}}}}, -} -\csname @std@section\endcsname{#1} -\expandafter\xdef\csname @exist@LUsection@\arabic{section}\endcsname{\null} +\ExplSyntaxOn +\msg_new:nnn { lalu-answer } { manifest-missing } + { Answer~manifest~'#1'~does~not~exist.~Build~the~main~document~first. } +\msg_new:nnn { lalu-answer } { manifest-version } + { Unsupported~answer~manifest~schema~'#1'. } +\msg_new:nnn { lalu-answer } { manifest-job } + { Answer~manifest~is~for~job~'#1',~not~'#2'. } +\msg_new:nnn { lalu-answer } { manifest-order } + { Invalid~answer~manifest~event~order~near~'#1'. } +\msg_new:nnn { lalu-answer } { manifest-status } + { Unsupported~answer~status~'#1'. } +\msg_new:nnn { lalu-answer } { manifest-count } + { Answer~manifest~count~'#1'~is~#2;~expected~#3. } +\msg_new:nnn { lalu-answer } { manifest-data } + { Invalid~answer~manifest~data~'#1'~near~'#2'. } + +\bool_new:N \g_lalu_answer_manifest_open_bool +\bool_new:N \g_lalu_answer_manifest_ended_bool +\bool_new:N \g_lalu_answer_first_unit_bool +\bool_new:N \g_lalu_answer_unit_seen_bool +\bool_new:N \g_lalu_answer_group_open_bool +\tl_new:N \l_lalu_answer_reference_tl +\tl_new:N \l_lalu_answer_anchor_tl +\tl_new:N \l_lalu_answer_heading_tl +\tl_new:N \l_lalu_answer_manifest_path_tl +\tl_new:N \l_lalu_answer_group_id_tl +\tl_new:N \l_lalu_answer_group_items_tl +\int_new:N \g_lalu_answer_unit_int +\int_new:N \g_lalu_answer_group_int +\int_new:N \g_lalu_answer_item_int +\int_new:N \g_lalu_answer_answered_int +\int_new:N \g_lalu_answer_todo_int +\int_new:N \g_lalu_answer_omitted_int +\int_new:N \l_lalu_answer_group_number_int +\int_new:N \l_lalu_answer_group_expected_int +\int_new:N \l_lalu_answer_group_item_int +\prop_new:N \g_lalu_answer_unit_id_prop +\prop_new:N \g_lalu_answer_group_id_prop +\prop_new:N \g_lalu_answer_item_id_prop +\cs_generate_variant:Nn \file_if_exist:nTF { V } +\cs_generate_variant:Nn \file_input:n { V } + +\cs_new:Npn \lalu_answer_greek:n #1 + { + \ifcase #1 \or + \texorpdfstring{$\boldsymbol{\varepsilon}$}{ε}\or + \texorpdfstring{$\boldsymbol{\delta}$}{δ}\or + \texorpdfstring{$\boldsymbol{\lambda}$}{λ}\or + \texorpdfstring{$\boldsymbol{\mu}$}{μ}\or + \texorpdfstring{$\boldsymbol{\varphi}$}{φ}\or + \texorpdfstring{$\boldsymbol{\theta}$}{θ}\else + \msg_expandable_error:nnn { lalu-answer } { manifest-order } + { unfinished-slot-#1 } + \fi + } + +\cs_set:Npn \theLALUanswerunit { \tl_use:N \l_lalu_answer_reference_tl } +\cs_if_exist:NTF \theHLALUanswerunit + { \cs_set:Npn \theHLALUanswerunit { \tl_use:N \l_lalu_answer_anchor_tl } } + { \cs_new:Npn \theHLALUanswerunit { \tl_use:N \l_lalu_answer_anchor_tl } } + +\cs_new_protected:Npn \lalu_answer_require_open:n #1 + { + \bool_if:NF \g_lalu_answer_manifest_open_bool + { \msg_fatal:nnn { lalu-answer } { manifest-order } {#1} } + \bool_if:NT \g_lalu_answer_manifest_ended_bool + { \msg_fatal:nnn { lalu-answer } { manifest-order } {#1-after-end} } + } + +\cs_new_protected:Npn \lalu_answer_assert_count:nnn #1#2#3 + { + \int_compare:nNnF {#2} = {#3} + { \msg_fatal:nnnnn { lalu-answer } { manifest-count } {#1}{#2}{#3} } + } + +\cs_new_protected:Npn \lalu_answer_claim_id:Nnn #1#2#3 + { + \prop_if_in:NnTF #1 {#2} + { \msg_fatal:nnnn { lalu-answer } { manifest-data } { duplicate-id } {#2} } + { \prop_gput:Nnn #1 {#2} {#3} } + } + +\cs_new_protected:Npn \LALUAnswerManifestBegin #1#2 + { + \bool_if:NT \g_lalu_answer_manifest_open_bool + { \msg_fatal:nnn { lalu-answer } { manifest-order } { duplicate-begin } } + \str_if_eq:nnF {#1} {2} + { \msg_fatal:nnn { lalu-answer } { manifest-version } {#1} } + \str_if_eq:eeF {#2} { \LALUAnswerManifestJob } + { + \msg_fatal:nnnn { lalu-answer } { manifest-job } + {#2} { \LALUAnswerManifestJob } + } + \bool_gset_true:N \g_lalu_answer_manifest_open_bool + \bool_gset_false:N \g_lalu_answer_manifest_ended_bool + \bool_gset_true:N \g_lalu_answer_first_unit_bool + \bool_gset_false:N \g_lalu_answer_unit_seen_bool + \bool_gset_false:N \g_lalu_answer_group_open_bool + \int_gzero:N \g_lalu_answer_unit_int + \int_gzero:N \g_lalu_answer_group_int + \int_gzero:N \g_lalu_answer_item_int + \int_gzero:N \g_lalu_answer_answered_int + \int_gzero:N \g_lalu_answer_todo_int + \int_gzero:N \g_lalu_answer_omitted_int + \prop_gclear:N \g_lalu_answer_unit_id_prop + \prop_gclear:N \g_lalu_answer_group_id_prop + \prop_gclear:N \g_lalu_answer_item_id_prop + \group_begin: + % The legacy answer PDF deliberately displayed chapter-based counters as + % ``.1'', ``.2'', ... in this generated section. Preserve that visible + % form, while giving Hyperref a unique answer-unit parent. + \cs_set:Npn \thechapter { } + \cs_set:Npn \theHchapter { \theHLALUanswerunit } + } + +\cs_new_protected:Npn \LALUAnswerUnit #1#2#3#4#5#6 + { + \lalu_answer_require_open:n { unit } + \bool_if:NT \g_lalu_answer_group_open_bool + { \msg_fatal:nnn { lalu-answer } { manifest-order } { unit-inside-group } } + \int_gincr:N \g_lalu_answer_unit_int + \str_if_eq:eeF + {#5} { answer-unit:\int_use:N \g_lalu_answer_unit_int } + { \msg_fatal:nnnn { lalu-answer } { manifest-data } { unit-id } {#5} } + \lalu_answer_claim_id:Nnn \g_lalu_answer_unit_id_prop {#5} { unit } + \bool_gset_true:N \g_lalu_answer_unit_seen_bool + \bool_if:NTF \g_lalu_answer_first_unit_bool + { \bool_gset_false:N \g_lalu_answer_first_unit_bool } + { \clearpage } + + \str_case:nnF {#1} + { + { normal } + { + \int_compare:nNnF {#2} > {0} + { \msg_fatal:nnnn { lalu-answer } { manifest-data } { normal-base } {#2} } + \int_compare:nNnF {#3} = {0} + { \msg_fatal:nnnn { lalu-answer } { manifest-data } { normal-serial } {#3} } + \int_compare:nNnF {#4} = {0} + { \msg_fatal:nnnn { lalu-answer } { manifest-data } { normal-slot } {#4} } + \tl_set:Nn \l_lalu_answer_reference_tl {#2} + \tl_set:Nn \l_lalu_answer_anchor_tl { answer.#5 } + \tl_set:Nn \l_lalu_answer_heading_tl { 第~#2~讲 } + } + { unfinished } + { + \int_compare:nNnF {#2} > {0} + { \msg_fatal:nnnn { lalu-answer } { manifest-data } { unfinished-base } {#2} } + \int_compare:nNnF {#3} > {0} + { \msg_fatal:nnnn { lalu-answer } { manifest-data } { unfinished-serial } {#3} } + \int_compare:nNnF {#4} > {0} + { \msg_fatal:nnnn { lalu-answer } { manifest-data } { unfinished-slot } {#4} } + \int_compare:nNnF {#4} < {7} + { \msg_fatal:nnnn { lalu-answer } { manifest-data } { unfinished-slot } {#4} } + \tl_set:Nn \l_lalu_answer_reference_tl + { #2\lalu_answer_greek:n {#4} } + \tl_set:Nn \l_lalu_answer_anchor_tl { answer.#5 } + \tl_set:Nn \l_lalu_answer_heading_tl + { 未竟专题\zhnumber{#3} } + } + } + { \msg_fatal:nnn { lalu-answer } { manifest-order } { unit-kind-#1 } } + + \refstepcounter{LALUanswerunit} + \setcounter{equation}{0} + \clist_map_inline:nn + { tcb@cnt@definition, tcb@cnt@example, tcb@cnt@lemma, + tcb@cnt@theorem, tcb@cnt@corollary, tcb@cnt@axiom } + { \cs_if_exist:cT { c@##1 } { \setcounter{##1}{0} } } + + % Write the TOC entry while the dedicated answer-unit href is current; + % \section* may create its own internal anchor afterwards. + \addcontentsline{toc}{section} + { \protect\numberline{\tl_use:N \l_lalu_answer_heading_tl}#6 } + \section*{\tl_use:N \l_lalu_answer_heading_tl \quad #6} + \markright{\tl_use:N \l_lalu_answer_heading_tl \quad #6} + } + +\cs_new_protected:Npn \LALUAnswerGroupBegin #1#2#3 + { + \lalu_answer_require_open:n { group-begin } + \bool_if:NF \g_lalu_answer_unit_seen_bool + { \msg_fatal:nnn { lalu-answer } { manifest-order } { group-before-unit } } + \bool_if:NT \g_lalu_answer_group_open_bool + { \msg_fatal:nnn { lalu-answer } { manifest-order } { nested-group } } + \int_gincr:N \g_lalu_answer_group_int + \str_if_eq:eeF + {#1} { answer-group:\int_use:N \g_lalu_answer_group_int } + { \msg_fatal:nnnn { lalu-answer } { manifest-data } { group-id } {#1} } + \lalu_answer_claim_id:Nnn \g_lalu_answer_group_id_prop {#1} { group } + \int_compare:nNnF {#2} > {0} + { \msg_fatal:nnnn { lalu-answer } { manifest-data } { group-number } {#2} } + \int_compare:nNnF {#3} > {0} + { \msg_fatal:nnnn { lalu-answer } { manifest-data } { group-size } {#3} } + \tl_set:Nn \l_lalu_answer_group_id_tl {#1} + \int_set:Nn \l_lalu_answer_group_number_int {#2} + \int_set:Nn \l_lalu_answer_group_expected_int {#3} + \int_zero:N \l_lalu_answer_group_item_int + \tl_clear:N \l_lalu_answer_group_items_tl + \bool_gset_true:N \g_lalu_answer_group_open_bool + } + +\cs_new_protected:Npn \LALUAnswerItem #1#2#3#4 + { + \lalu_answer_require_open:n { item } + \bool_if:NF \g_lalu_answer_group_open_bool + { \msg_fatal:nnn { lalu-answer } { manifest-order } { item-outside-group } } + \int_gincr:N \g_lalu_answer_item_int + \int_incr:N \l_lalu_answer_group_item_int + \str_if_eq:eeF + {#1} { answer-item:\int_use:N \g_lalu_answer_item_int } + { \msg_fatal:nnnn { lalu-answer } { manifest-data } { item-id } {#1} } + \lalu_answer_claim_id:Nnn \g_lalu_answer_item_id_prop {#1} { item } + \int_compare:nNnF {#2} > {0} + { \msg_fatal:nnnn { lalu-answer } { manifest-data } { item-number } {#2} } + \str_case:nnF {#3} + { + { answered } + { + \int_gincr:N \g_lalu_answer_answered_int + \tl_put_right:Nn \l_lalu_answer_group_items_tl + { \item[#2.] #4 } + } + { todo } + { + \int_gincr:N \g_lalu_answer_todo_int + \tl_put_right:Nn \l_lalu_answer_group_items_tl + { \item[#2.] \emph{暂无答案} } + } + % The legacy generator placed consecutive empty \item tokens next to + % one another. Accumulating raw item tokens and expanding them only + % at GroupEnd preserves that (slightly odd) visible layout exactly. + { omitted } + { + \int_gincr:N \g_lalu_answer_omitted_int + \tl_put_right:Nn \l_lalu_answer_group_items_tl + { \item[#2.] #4 } + } + } + { \msg_fatal:nnn { lalu-answer } { manifest-status } {#3} } + } + +\cs_new_protected:Npn \LALUAnswerGroupEnd #1#2 + { + \lalu_answer_require_open:n { group-end } + \bool_if:NF \g_lalu_answer_group_open_bool + { \msg_fatal:nnn { lalu-answer } { manifest-order } { group-end-without-begin } } + \str_if_eq:eeF {#1} { \tl_use:N \l_lalu_answer_group_id_tl } + { \msg_fatal:nnnn { lalu-answer } { manifest-data } { group-end-id } {#1} } + \lalu_answer_assert_count:nnn + { group-declared } {#2} { \l_lalu_answer_group_expected_int } + \lalu_answer_assert_count:nnn + { group-items } { \l_lalu_answer_group_item_int } + { \l_lalu_answer_group_expected_int } + \subsection*{\int_to_Alph:n { \l_lalu_answer_group_number_int }组} + \begin{enumerate} + \tl_use:N \l_lalu_answer_group_items_tl + \end{enumerate} + \tl_clear:N \l_lalu_answer_group_items_tl + \bool_gset_false:N \g_lalu_answer_group_open_bool + } + +\cs_new_protected:Npn \LALUAnswerManifestEnd #1#2#3#4#5#6#7 + { + \lalu_answer_require_open:n { end } + \bool_if:NT \g_lalu_answer_group_open_bool + { \msg_fatal:nnn { lalu-answer } { manifest-order } { end-inside-group } } + \lalu_answer_assert_count:nnn + { units } { \g_lalu_answer_unit_int } {#1} + \int_compare:nNnT {#3} > {#2} + { \msg_fatal:nnnn { lalu-answer } { manifest-data } { group-totals } {#3/#2} } + \lalu_answer_assert_count:nnn + { emitted-groups } { \g_lalu_answer_group_int } {#3} + \lalu_answer_assert_count:nnn + { items } { \g_lalu_answer_item_int } {#4} + \lalu_answer_assert_count:nnn + { answered } { \g_lalu_answer_answered_int } {#5} + \lalu_answer_assert_count:nnn + { todo } { \g_lalu_answer_todo_int } {#6} + \lalu_answer_assert_count:nnn + { omitted } { \g_lalu_answer_omitted_int } {#7} + \lalu_answer_assert_count:nnn + { item-status-sum } {#4} { \int_eval:n { #5 + #6 + #7 } } + \par + \group_end: + \bool_gset_true:N \g_lalu_answer_manifest_ended_bool + \iow_term:x + { + LALU~answers:~units~#1,~groups~#3/#2,~ + answered~#5,~todo~#6,~omitted~#7. + } + } + +\cs_new_protected:Npn \lalu_answer_input_manifest: + { + \tl_set:Ne \l_lalu_answer_manifest_path_tl + { \LALUAnswerManifestPath } + \file_if_exist:VTF \l_lalu_answer_manifest_path_tl + { \file_input:V \l_lalu_answer_manifest_path_tl } + { + \msg_fatal:nnn { lalu-answer } { manifest-missing } + { \LALUAnswerManifestPath } + } + \bool_if:NF \g_lalu_answer_manifest_ended_bool + { \msg_fatal:nnn { lalu-answer } { manifest-order } { missing-end } } + } +\cs_new_protected:Npn \LALUInputAnswerManifest + { \lalu_answer_input_manifest: } +\ExplSyntaxOff + +\LALUFinalizePreamble +\hypersetup{ + pdfauthor = {吴一航}, + pdftitle = {线性代数荣誉课辅学习题答案}, } \begin{document} @@ -70,19 +355,14 @@ \chapter{《线性代数:未竟之美》习题参考答案} \titleformat{\subsection}[block]{\centering\heiti\bfseries}{}{1em}{} -\input{LALU-ans-contents.tex} - -\LUgroupsancheck - -\makeatletter -\let\section\@std@section -\let\@std@section\relax -\makeatother +% Read author tokens with ordinary LaTeX catcodes. In particular, spaces in +% label keys and prose must not be ignored as they would be under expl3 syntax. +\LALUInputAnswerManifest \ctexset{ section={format={\raggedright\Large\bfseries},name={,},number={}}, } -\renewcommand*{\thesection}{} % FIXME: this breaks equation numbering +\renewcommand*{\thesection}{} % 嵌套 enumerate 环境的 label \setlist[enumerate,1]{label=\chinese*、} diff --git "a/\350\256\262\344\271\211/LALU.tex" "b/\350\256\262\344\271\211/LALU.tex" new file mode 100644 index 0000000..821e400 --- /dev/null +++ "b/\350\256\262\344\271\211/LALU.tex" @@ -0,0 +1,922 @@ +\documentclass[ + % colors = false, + geometry = 16k, +]{LALUbook} + +\usepackage{mathdots} +\usepackage{booktabs} % Excel 导出的大表格 +\usepackage{rotating} +\usepackage{extarrows} +\usepackage{blkarray} +\usepackage{cases} + +\usepackage{float} +\usepackage{diagbox} +\usepackage{caption} + +\usepackage{pgfplots} +\usetikzlibrary{cd, arrows, arrows.meta, calc, intersections, decorations.pathreplacing, patterns, decorations.markings,angles,quotes, graphs, positioning, shapes.geometric} +\pgfplotsset{compat=newest} + +\usepackage[xindy, noautomatic, quiet]{imakeidx} +\makeindex[ + columns=1, + program=truexindy, + intoc=true, + options=-M texindy -I xelatex -C utf8, + title={名词索引} +] % 名词索引 +\makeindex[ + columns=3, + program=truexindy, + intoc=true, + options=-M numeric-sort -M latex -M latex-loc-fmts -M makeindex -I xelatex -C utf8, + name=sym, + title={符号索引} +] % 符号索引 + +% 标题格式 +% \chapter 正常专题 +% \LUchapter 未竟专题 + +% 结构 chapter 只记录所有有编号顶层单元的次序;各类可见编号独立维护。 +\newcounter{LALUnormalchapter} +\newcounter{LALUunfinishedchapter} +\newcounter{LALUunfinishedslot} +\newcounter{LALUappendixchapter} +\newcounter{LALUunnumberedunit} + +\makeatletter +\ExplSyntaxOn +\tl_new:N \g_lalu_chapter_phase_tl +\tl_new:N \g_lalu_chapter_kind_tl +\tl_new:N \g_lalu_chapter_title_tl +\tl_new:N \g_lalu_chapter_short_title_tl +\tl_new:N \g_lalu_chapter_unit_id_tl +\tl_gset:Nn \g_lalu_chapter_phase_tl { initial } +\tl_gset:Nn \g_lalu_chapter_kind_tl { unnumbered } + +% 正文字形和 PDF 字符串字形在这一张表中同步维护。 +\cs_new:Npn \lalu_chapter_greek:n #1 + { + \int_case:nnF {#1} + { + {1}{\texorpdfstring{$\boldsymbol{\varepsilon}$}{ε}} + {2}{\texorpdfstring{$\boldsymbol{\delta}$}{δ}} + {3}{\texorpdfstring{$\boldsymbol{\lambda}$}{λ}} + {4}{\texorpdfstring{$\boldsymbol{\mu}$}{μ}} + {5}{\texorpdfstring{$\boldsymbol{\varphi}$}{φ}} + {6}{\texorpdfstring{$\boldsymbol{\theta}$}{θ}} + } + { } + } + +% 供答案生成器等 supporting structure 读取的语义接口。 +\NewExpandableDocumentCommand \LALUCurrentUnitKind { } + { \tl_use:N \g_lalu_chapter_kind_tl } +\NewExpandableDocumentCommand \LALUNormalChapterNumber { } + { \int_to_arabic:n { \value{LALUnormalchapter} } } +\NewExpandableDocumentCommand \LALUCurrentNormalBase { } + { \int_to_arabic:n { \value{LALUnormalchapter} } } +\NewExpandableDocumentCommand \LALUCurrentUnfinishedSerial { } + { + \str_if_eq:VnTF \g_lalu_chapter_kind_tl { unfinished } + { \int_to_arabic:n { \value{LALUunfinishedchapter} } } + { 0 } + } +\NewExpandableDocumentCommand \LALUCurrentUnfinishedSlot { } + { + \str_if_eq:VnTF \g_lalu_chapter_kind_tl { unfinished } + { \int_to_arabic:n { \value{LALUunfinishedslot} } } + { 0 } + } +\NewExpandableDocumentCommand \LALUCurrentReferenceNumber { } + { + \str_case:VnF \g_lalu_chapter_kind_tl + { + { normal } + { \int_to_arabic:n { \value{LALUnormalchapter} } } + { unfinished } + { + \int_to_arabic:n { \value{LALUnormalchapter} } + \lalu_chapter_greek:n { \value{LALUunfinishedslot} } + } + { appendix } + { \int_to_Alph:n { \value{LALUappendixchapter} } } + } + { } + } +\NewExpandableDocumentCommand \LALUCurrentUnitTitle { } + { \tl_use:N \g_lalu_chapter_title_tl } +\cs_new_protected:Npn \LALUGetCurrentUnitTitle:N #1 + { \tl_set:NV #1 \g_lalu_chapter_title_tl } +\NewExpandableDocumentCommand \LALUCurrentUnitID { } + { \tl_use:N \g_lalu_chapter_unit_id_tl } +\NewExpandableDocumentCommand \LALUIfCurrentAnswerUnitTF { m m } + { + \str_if_eq:VnTF \g_lalu_chapter_kind_tl { normal } + {#1} + { + \str_if_eq:VnTF \g_lalu_chapter_kind_tl { unfinished } + {#1} + {#2} + } + } + +\cs_new:Npn \lalu_chapter_anchor_number: + { + \str_case:VnF \g_lalu_chapter_kind_tl + { + { normal } + { \int_to_arabic:n { \value{LALUnormalchapter} } } + { unfinished } + { LU.\int_to_arabic:n { \value{LALUunfinishedchapter} } } + { appendix } + { APP.\int_to_Alph:n { \value{LALUappendixchapter} } } + { unnumbered } + { UNNUMBERED.\int_to_arabic:n { \value{LALUunnumberedunit} } } + } + { UNNUMBERED.0 } + } + +\cs_new_protected:Npn \lalu_chapter_install_number_commands: + { + \cs_gset:Npn \thechapter { \LALUCurrentReferenceNumber } + \cs_gset:Npn \theHchapter { \lalu_chapter_anchor_number: } + % CTeX makes \p@chapter discard \thechapter in favour of the Chinese + % title number. Current LaTeX/cleveref recomputes label data from this + % prefix inside every \label, so restore the standard empty prefix and + % keep the semantic reference number supplied by \thechapter. + \cs_gset:Npn \p@chapter { } + } + +% cleveref 自身会在 \appendix 中切换类型,但新 LaTeX 内核的 +% first-aid label hook 会从 counter alias 重建数据。在阶段切换时同步 +% alias,避免将附录章误记为 chapter。 +\cs_new_protected:Npn \lalu_chapter_set_main_cref_aliases: + { + \cs_if_exist:NT \crefalias + { + \crefalias{chapter}{chapter} + \crefalias{section}{section} + \crefalias{subsection}{subsection} + \crefalias{subsubsection}{subsubsection} + } + } +\cs_new_protected:Npn \lalu_chapter_set_appendix_cref_aliases: + { + \cs_if_exist:NT \crefalias + { + \crefalias{chapter}{appendix} + \crefalias{section}{subappendix} + \crefalias{subsection}{subsubappendix} + \crefalias{subsubsection}{subsubsubappendix} + } + } + +\cs_new_protected:Npn \lalu_chapter_apply_normal_style: + { + \ctexset + { + chapter = + { + format = { \centering \Huge \bfseries }, + name = { 第,讲 }, + number = { \arabic{LALUnormalchapter} } + } + } + } +\cs_new_protected:Npn \lalu_chapter_apply_unfinished_style: + { + \ctexset + { + chapter = + { + format = { \centering \Huge \bfseries }, + name = { 未竟专题, }, + number = { \zhnumber{\arabic{LALUunfinishedchapter}} } + } + } + } +\cs_new_protected:Npn \lalu_chapter_apply_appendix_style: + { + \ctexset + { + chapter = + { + format = { \centering \Huge \bfseries }, + name = { 附录, }, + number = { \Alph{LALUappendixchapter} } + } + } + } + +\cs_new_protected:Npn \lalu_chapter_clear_current_unit: + { + \tl_gset:Nn \g_lalu_chapter_kind_tl { unnumbered } + \tl_gclear:N \g_lalu_chapter_title_tl + \tl_gclear:N \g_lalu_chapter_short_title_tl + \tl_gclear:N \g_lalu_chapter_unit_id_tl + } +\cs_new_protected:Npn \lalu_chapter_set_titles:nn #1#2 + { + \tl_gset:Nn \g_lalu_chapter_title_tl {#2} + \tl_if_novalue:nTF {#1} + { \tl_gset:Nn \g_lalu_chapter_short_title_tl {#2} } + { \tl_gset:Nn \g_lalu_chapter_short_title_tl {#1} } + } +\cs_new_protected:Npn \lalu_chapter_set_normal:nn #1#2 + { + \stepcounter{LALUnormalchapter} + \setcounter{LALUunfinishedslot}{0} + \tl_gset:Nn \g_lalu_chapter_kind_tl { normal } + \tl_gset:Nx \g_lalu_chapter_unit_id_tl + { normal:\int_to_arabic:n { \value{LALUnormalchapter} } } + \lalu_chapter_set_titles:nn {#1}{#2} + \lalu_chapter_apply_normal_style: + } +\cs_new_protected:Npn \lalu_chapter_set_unfinished:nn #1#2 + { + \stepcounter{LALUunfinishedchapter} + \stepcounter{LALUunfinishedslot} + \tl_gset:Nn \g_lalu_chapter_kind_tl { unfinished } + \tl_gset:Nx \g_lalu_chapter_unit_id_tl + { lu:\int_to_arabic:n { \value{LALUunfinishedchapter} } } + \lalu_chapter_set_titles:nn {#1}{#2} + \lalu_chapter_apply_unfinished_style: + } +\cs_new_protected:Npn \lalu_chapter_set_appendix:nn #1#2 + { + \stepcounter{LALUappendixchapter} + \tl_gset:Nn \g_lalu_chapter_kind_tl { appendix } + \tl_gset:Nx \g_lalu_chapter_unit_id_tl + { appendix:\int_to_Alph:n { \value{LALUappendixchapter} } } + \lalu_chapter_set_titles:nn {#1}{#2} + \lalu_chapter_apply_appendix_style: + } +\cs_new_protected:Npn \lalu_chapter_set_unnumbered:nn #1#2 + { + \stepcounter{LALUunnumberedunit} + \lalu_chapter_clear_current_unit: + \lalu_chapter_set_titles:nn {#1}{#2} + } + +% 与 CTeX 的标准章编号判定保持一致。 +\cs_new_protected:Npn \lalu_chapter_if_numbered:TF #1#2 + { + \if@mainmatter + \ifnum \c@secnumdepth > \m@ne + \ifodd \CTEX@chapter@numbering + #1 + \else + #2 + \fi + \else + #2 + \fi + \else + #2 + \fi + } +\cs_new_protected:Npn \lalu_chapter_call_standard:nn #1#2 + { + \tl_if_novalue:nTF {#1} + { \LALU@standardchapter{#2} } + { \LALU@standardchapter[#1]{#2} } + } + +% CTeX 会把 chapter 的 label 值设成标题中文编号;这里恢复数字引用语义。 +\cs_new_protected:Npn \lalu_chapter_restore_current_label: + { + \protected@xdef \@currentlabel + { \LALUCurrentReferenceNumber } + \cs_if_exist:NT \cref@constructprefix + { + \cref@constructprefix{chapter}{\cref@result} + \str_if_eq:VnTF \g_lalu_chapter_kind_tl { appendix } + { \def\lalu@creftype{appendix} } + { \def\lalu@creftype{chapter} } + \protected@xdef \cref@currentlabel + { + [\lalu@creftype][\arabic{chapter}][\cref@result] + \LALUCurrentReferenceNumber + } + } + } +\cs_new_protected:Npn \lalu_chapter_clear_current_label: + { + \global\let\@currentlabel\@empty + % LaTeX 2025+ label hooks use this counter name to reconstruct package + % metadata. An unnumbered chapter must not inherit the previous chapter. + \global\let\@currentcounter\@empty + \cs_if_exist:NT \cref@currentlabel + { \global\let\cref@currentlabel\@empty } + } + +\cs_new_protected:Npn \lalu_chapter_numbered:nn #1#2 + { + \str_case:VnF \g_lalu_chapter_phase_tl + { + { initial } + { + \tl_gset:Nn \g_lalu_chapter_phase_tl { mainmatter } + \lalu_chapter_set_normal:nn {#1}{#2} + } + { mainmatter } + { \lalu_chapter_set_normal:nn {#1}{#2} } + { appendix } + { \lalu_chapter_set_appendix:nn {#1}{#2} } + } + { + \lalu_chapter_set_unnumbered:nn {#1}{#2} + } + \lalu_chapter_call_standard:nn {#1}{#2} + \str_if_eq:VnTF \g_lalu_chapter_kind_tl { unnumbered } + { \lalu_chapter_clear_current_label: } + { \lalu_chapter_restore_current_label: } + } +\cs_new_protected:Npn \lalu_chapter_unstarred:nn #1#2 + { + \lalu_chapter_if_numbered:TF + { \lalu_chapter_numbered:nn {#1}{#2} } + { + \lalu_chapter_set_unnumbered:nn {#1}{#2} + \lalu_chapter_call_standard:nn {#1}{#2} + \lalu_chapter_clear_current_label: + } + } +\cs_new_protected:Npn \lalu_chapter_starred:n #1 + { + \lalu_chapter_set_unnumbered:nn { \NoValue }{#1} + \LALU@standardchapter*{#1} + \lalu_chapter_clear_current_label: + } + +\cs_new_protected:Npn \lalu_unfinished_chapter:nn #1#2 + { + \str_if_eq:VnTF \g_lalu_chapter_phase_tl { mainmatter } + { + \int_compare:nNnTF { \value{LALUnormalchapter} } > { 0 } + { + \lalu_chapter_if_numbered:TF + { + \int_compare:nNnTF { \value{LALUunfinishedslot} } < { 6 } + { + \lalu_chapter_set_unfinished:nn {#1}{#2} + \lalu_chapter_call_standard:nn {#1}{#2} + \lalu_chapter_restore_current_label: + } + { + \PackageError{LALU} + {Too~many~unfinished~topics~after~chapter~\LALUNormalChapterNumber} + {Only~six~Greek~slots~are~configured.~Extend~the~central~mapping~before~adding~another~topic.} + } + } + { + \PackageError{LALU} + {An~unfinished~topic~cannot~be~unnumbered} + {Restore~chapter~numbering~before~using~\string\LUchapter.} + } + } + { + \PackageError{LALU} + {An~unfinished~topic~requires~a~preceding~normal~chapter} + {Start~a~numbered~normal~chapter~before~using~\string\LUchapter.} + } + } + { + \PackageError{LALU} + {\string\LUchapter~is~only~valid~in~mainmatter} + {Move~the~unfinished~topic~after~\string\mainmatter~and~a~numbered~normal~chapter.} + } + } + +\cs_new_protected:Npn \lalu_phase_error:n #1 + { + \PackageError{LALU} + {Invalid~document~phase~transition~from~\tl_use:N\g_lalu_chapter_phase_tl~to~#1} + {The~supported~order~is~frontmatter,~mainmatter,~appendix,~backmatter;~each~phase~command~is~idempotent.} + } +\cs_new_protected:Npn \lalu_frontmatter: + { + \str_if_eq:VnTF \g_lalu_chapter_phase_tl { frontmatter } + { } + { + \str_if_eq:VnTF \g_lalu_chapter_phase_tl { initial } + { + \LALU@standardfrontmatter + \tl_gset:Nn \g_lalu_chapter_phase_tl { frontmatter } + \lalu_chapter_clear_current_unit: + } + { \lalu_phase_error:n { frontmatter } } + } + } +\cs_new_protected:Npn \lalu_mainmatter: + { + \str_if_eq:VnTF \g_lalu_chapter_phase_tl { mainmatter } + { } + { + \str_case:VnF \g_lalu_chapter_phase_tl + { + { initial } + { + \LALU@standardmainmatter + \setcounter{chapter}{0} + \setcounter{LALUnormalchapter}{0} + \setcounter{LALUunfinishedchapter}{0} + \setcounter{LALUunfinishedslot}{0} + \setcounter{LALUappendixchapter}{0} + \tl_gset:Nn \g_lalu_chapter_phase_tl { mainmatter } + \lalu_chapter_clear_current_unit: + \lalu_chapter_set_main_cref_aliases: + } + { frontmatter } + { + \LALU@standardmainmatter + \setcounter{chapter}{0} + \setcounter{LALUnormalchapter}{0} + \setcounter{LALUunfinishedchapter}{0} + \setcounter{LALUunfinishedslot}{0} + \setcounter{LALUappendixchapter}{0} + \tl_gset:Nn \g_lalu_chapter_phase_tl { mainmatter } + \lalu_chapter_clear_current_unit: + \lalu_chapter_set_main_cref_aliases: + } + } + { \lalu_phase_error:n { mainmatter } } + } + } +\int_new:N \l_lalu_structural_chapter_int +\cs_new_protected:Npn \lalu_appendix: + { + \str_if_eq:VnTF \g_lalu_chapter_phase_tl { appendix } + { } + { + \str_if_eq:VnTF \g_lalu_chapter_phase_tl { mainmatter } + { + \int_set:Nn \l_lalu_structural_chapter_int { \value{chapter} } + \LALU@standardappendix + \setcounter{chapter}{\int_use:N \l_lalu_structural_chapter_int} + \setcounter{LALUappendixchapter}{0} + \tl_gset:Nn \g_lalu_chapter_phase_tl { appendix } + \lalu_chapter_clear_current_unit: + \lalu_chapter_install_number_commands: + \lalu_chapter_set_appendix_cref_aliases: + \lalu_chapter_apply_appendix_style: + } + { \lalu_phase_error:n { appendix } } + } + } +\cs_new_protected:Npn \lalu_backmatter: + { + \str_if_eq:VnTF \g_lalu_chapter_phase_tl { backmatter } + { } + { + \str_case:VnF \g_lalu_chapter_phase_tl + { + { frontmatter } + { + \LALU@standardbackmatter + \tl_gset:Nn \g_lalu_chapter_phase_tl { backmatter } + \lalu_chapter_clear_current_unit: + \lalu_chapter_set_main_cref_aliases: + } + { mainmatter } + { + \LALU@standardbackmatter + \tl_gset:Nn \g_lalu_chapter_phase_tl { backmatter } + \lalu_chapter_clear_current_unit: + \lalu_chapter_set_main_cref_aliases: + } + { appendix } + { + \LALU@standardbackmatter + \tl_gset:Nn \g_lalu_chapter_phase_tl { backmatter } + \lalu_chapter_clear_current_unit: + \lalu_chapter_set_main_cref_aliases: + } + } + { \lalu_phase_error:n { backmatter } } + } + } + +\NewDocumentCommand \LUchapter { o m } + { \lalu_unfinished_chapter:nn {#1}{#2} } + +% 所有宏包完成 chapter/phase 补丁后再保存最终标准实现。 +\AddToHook{begindocument/end} + { + \let\LALU@standardchapter\chapter + \let\LALU@standardfrontmatter\frontmatter + \let\LALU@standardmainmatter\mainmatter + \let\LALU@standardappendix\appendix + \let\LALU@standardbackmatter\backmatter + \RenewDocumentCommand \chapter { s o m } + { + \IfBooleanTF{#1} + { \lalu_chapter_starred:n {#3} } + { \lalu_chapter_unstarred:nn {#2}{#3} } + } + \RenewDocumentCommand \frontmatter { } { \lalu_frontmatter: } + \RenewDocumentCommand \mainmatter { } { \lalu_mainmatter: } + \RenewDocumentCommand \appendix { } { \lalu_appendix: } + \RenewDocumentCommand \backmatter { } { \lalu_backmatter: } + \lalu_chapter_install_number_commands: + } +\ExplSyntaxOff +\makeatother + +% 内容总结 +\newenvironment{summary}{% + \hypersetup{bookmarksnumbered=false}% + \titleformat{\subsection}[block]{\centering\heiti\Large}{}{1em}{}% + \phantomsection% + \subsection*{内容总结}% +}{} + +% 习题环境 +% \begin{exercise} +% \exquote[somebody]{...} +% \begin{exgroup} +% \item ... +% \item ... +% \end{exgroup} +% \begin{exgroup} +% ... +% \end{exgroup} +% \end{exercise} +\newcounter{exgroupcounter} +\ExplSyntaxOn +\msg_new:nnn { lalu-answer } { invalid-unit } + { The~exercise~environment~requires~a~numbered~normal~or~unfinished~chapter. } +\msg_new:nnn { lalu-answer } { invalid-nesting } + { Invalid~exercise~environment~nesting~near~'#1'. } +\msg_new:nnn { lalu-answer } { invalid-status } + { Unknown~answer~status~'#1'. } + +\bool_new:N \g_lalu_ans_in_exercise_bool +\bool_new:N \l_lalu_ans_in_group_bool +\seq_new:N \g_lalu_ans_group_seq +\tl_new:N \l_lalu_ans_status_tl +\tl_new:N \l_lalu_ans_body_probe_tl +\tl_new:N \l_lalu_ans_unit_kind_tl +\tl_new:N \l_lalu_ans_unit_normal_tl +\tl_new:N \l_lalu_ans_unit_serial_tl +\tl_new:N \l_lalu_ans_unit_slot_tl +\tl_new:N \l_lalu_ans_unit_id_tl +\tl_new:N \l_lalu_ans_unit_title_tl +\int_new:N \g_lalu_ans_total_unit_int +\int_new:N \g_lalu_ans_total_group_int +\int_new:N \g_lalu_ans_emitted_group_int +\int_new:N \g_lalu_ans_total_item_int +\int_new:N \g_lalu_ans_answered_int +\int_new:N \g_lalu_ans_todo_int +\int_new:N \g_lalu_ans_omitted_int +\int_new:N \g_lalu_ans_group_number_int +\tl_new:N \l_lalu_ans_group_id_tl + +\keys_define:nn { lalu / answer } + { status .tl_set:N = \l_lalu_ans_status_tl } + +\cs_new_protected:Npn \lalu_ans_write_marker:n #1 + { + \iow_now:Nx \g_lalu_ans_iow + { \c_percent_str \c_space_tl LALU-MANIFEST-EVENT \c_space_tl #1 } + } + +\cs_new_protected:Npn \lalu_ans_write_unit: + { + \lalu_ans_write_marker:n + { unit~id=\l_lalu_ans_unit_id_tl } + \iow_now:Nx \g_lalu_ans_iow + { + \exp_not:N \LALUAnswerUnit + { \exp_not:V \l_lalu_ans_unit_kind_tl } + { \exp_not:V \l_lalu_ans_unit_normal_tl } + { \exp_not:V \l_lalu_ans_unit_serial_tl } + { \exp_not:V \l_lalu_ans_unit_slot_tl } + { \exp_not:V \l_lalu_ans_unit_id_tl } + { \exp_not:V \l_lalu_ans_unit_title_tl } + } + } + +\cs_new_protected:Npn \lalu_ans_write_item:nnnn #1#2#3#4 + { + \lalu_ans_write_marker:n + { + item~id=#1~group=\l_lalu_ans_group_id_tl + \c_space_tl number=#2~status=#3 + } + \iow_now:Nx \g_lalu_ans_iow + { + \exp_not:N \LALUAnswerItem + {#1}{#2}{#3}{ \exp_not:n {#4} } + } + } + +\cs_new_protected:Npn \lalu_ans_begin_exercise: + { + \bool_if:NT \g_lalu_ans_in_exercise_bool + { \msg_fatal:nnn { lalu-answer } { invalid-nesting } { exercise } } + \LALUIfCurrentAnswerUnitTF + { + \bool_gset_true:N \g_lalu_ans_in_exercise_bool + \int_gincr:N \g_lalu_ans_total_unit_int + \tl_set:Ne \l_lalu_ans_unit_kind_tl { \LALUCurrentUnitKind } + \tl_set:Ne \l_lalu_ans_unit_normal_tl { \LALUCurrentNormalBase } + \tl_set:Ne \l_lalu_ans_unit_serial_tl + { \LALUCurrentUnfinishedSerial } + \tl_set:Ne \l_lalu_ans_unit_slot_tl { \LALUCurrentUnfinishedSlot } + % Record IDs deliberately follow manifest order rather than chapter + % identity. This keeps them unique even if a chapter contains more + % than one exercise environment; cross-version stability is outside + % the current schema contract. + \tl_set:Nx \l_lalu_ans_unit_id_tl + { answer-unit:\int_use:N \g_lalu_ans_total_unit_int } + \LALUGetCurrentUnitTitle:N \l_lalu_ans_unit_title_tl + \lalu_ans_write_unit: + } + { \msg_fatal:nn { lalu-answer } { invalid-unit } } + \setcounter{exgroupcounter}{0} + \hypersetup{bookmarksnumbered=false} + \titleformat{\section}[block]{\centering\heiti\Large}{}{1em}{} + \titleformat{\subsection}[block]{\centering\heiti\bfseries}{}{1em}{} + \phantomsection + \section*{习题} + \addcontentsline{toc}{section}{习题} + } + +\cs_new_protected:Npn \lalu_ans_end_exercise: + { + \bool_if:NF \g_lalu_ans_in_exercise_bool + { \msg_fatal:nnn { lalu-answer } { invalid-nesting } { exercise-end } } + \bool_gset_false:N \g_lalu_ans_in_exercise_bool + } + +\NewDocumentEnvironment{exercise} { } + { \lalu_ans_begin_exercise: } + { \lalu_ans_end_exercise: } + +\cs_new_protected:Npn \lalu_ans_begin_group:n #1 + { + \bool_if:NF \g_lalu_ans_in_exercise_bool + { \msg_fatal:nnn { lalu-answer } { invalid-nesting } { exgroup } } + \bool_if:NT \l_lalu_ans_in_group_bool + { \msg_fatal:nnn { lalu-answer } { invalid-nesting } { nested-exgroup } } + \bool_set_true:N \l_lalu_ans_in_group_bool + \int_gincr:N \g_lalu_ans_total_group_int + \seq_gclear:N \g_lalu_ans_group_seq + \tl_if_novalue:nTF {#1} + { \stepcounter{exgroupcounter} } + { \setcounter{exgroupcounter}{#1} } + \int_gset:Nn \g_lalu_ans_group_number_int { \value{exgroupcounter} } + \subsection*{\Alph{exgroupcounter}组} + \begin{enumerate} + } + +\cs_new_protected:Npn \lalu_ans_end_group: + { + \end{enumerate} + \seq_if_empty:NF \g_lalu_ans_group_seq + { + \int_gincr:N \g_lalu_ans_emitted_group_int + \tl_set:Nx \l_lalu_ans_group_id_tl + { answer-group:\int_use:N \g_lalu_ans_emitted_group_int } + \lalu_ans_write_marker:n + { + group-begin~id=\l_lalu_ans_group_id_tl + \c_space_tl unit=\l_lalu_ans_unit_id_tl + \c_space_tl number=\int_use:N \g_lalu_ans_group_number_int + \c_space_tl items=\int_eval:n { \seq_count:N \g_lalu_ans_group_seq } + } + \iow_now:Nx \g_lalu_ans_iow + { + \exp_not:N \LALUAnswerGroupBegin + { \exp_not:V \l_lalu_ans_group_id_tl } + { \int_use:N \g_lalu_ans_group_number_int } + { \int_eval:n { \seq_count:N \g_lalu_ans_group_seq } } + } + \seq_map_inline:Nn \g_lalu_ans_group_seq {##1} + \lalu_ans_write_marker:n + { + group-end~id=\l_lalu_ans_group_id_tl + \c_space_tl items=\int_eval:n { \seq_count:N \g_lalu_ans_group_seq } + } + \iow_now:Nx \g_lalu_ans_iow + { + \exp_not:N \LALUAnswerGroupEnd + { \exp_not:V \l_lalu_ans_group_id_tl } + { \int_eval:n { \seq_count:N \g_lalu_ans_group_seq } } + } + } + \seq_gclear:N \g_lalu_ans_group_seq + \bool_set_false:N \l_lalu_ans_in_group_bool + } + +\NewDocumentEnvironment{exgroup} { o } + { \lalu_ans_begin_group:n {#1} } + { \lalu_ans_end_group: } + +\cs_new_protected:Npn \lalu_ans_store_answer:nn #1#2 + { + \bool_if:NF \l_lalu_ans_in_group_bool + { \msg_fatal:nnn { lalu-answer } { invalid-nesting } { answer } } + \int_gincr:N \g_lalu_ans_total_item_int + \tl_set:Nn \l_lalu_ans_status_tl { answered } + \tl_if_blank:nF {#1} { \keys_set:nn { lalu / answer } {#1} } + % xparse represents a visually empty long-environment body as one or more + % \par tokens. Ignore those only for status classification; the original + % token list is still written unchanged for non-empty inline answers. + \tl_set:Nn \l_lalu_ans_body_probe_tl {#2} + \tl_remove_all:Nn \l_lalu_ans_body_probe_tl { \par } + \tl_if_blank:VT \l_lalu_ans_body_probe_tl + { + \tl_if_eq:NnT \l_lalu_ans_status_tl { answered } + { \tl_set:Nn \l_lalu_ans_status_tl { omitted } } + } + \str_case:VnF \l_lalu_ans_status_tl + { + { answered } { \int_gincr:N \g_lalu_ans_answered_int } + { todo } { \int_gincr:N \g_lalu_ans_todo_int } + { omitted } { \int_gincr:N \g_lalu_ans_omitted_int } + } + { + \msg_fatal:nnn { lalu-answer } { invalid-status } + { \l_lalu_ans_status_tl } + } + \seq_gput_right:Nx \g_lalu_ans_group_seq + { + \exp_not:N \lalu_ans_write_item:nnnn + { answer-item:\int_use:N \g_lalu_ans_total_item_int } + { \int_eval:n { \value{enumi} } } + { \exp_not:V \l_lalu_ans_status_tl } + { \exp_not:n {#2} } + } + } + +\NewDocumentEnvironment{answer} { O{} +b } + { \lalu_ans_store_answer:nn {#1}{#2} } + { } + +\NewDocumentCommand{\exquote}{om} + { + \vspace{2ex} + {\sffamily\kaishu #2} + \IfValueT{#1} + { + \begin{flushright} + \sffamily\kaishu ——#1 + \end{flushright} + } + } + +\iow_new:N \g_lalu_ans_iow +\tl_new:N \g_lalu_ans_manifest_path_tl +\cs_generate_variant:Nn \iow_open:Nn { NV } +\cs_if_exist:NTF \LALUAnswerManifestTempPath + { \tl_gset:Ne \g_lalu_ans_manifest_path_tl { \LALUAnswerManifestTempPath } } + { + \tl_gset:Nx \g_lalu_ans_manifest_path_tl + { \c_sys_jobname_str .answer-manifest.pending.tex } + } +\iow_open:NV \g_lalu_ans_iow \g_lalu_ans_manifest_path_tl +\iow_now:Nx \g_lalu_ans_iow + { + \c_percent_str \c_space_tl LALU-ANSWER-MANIFEST + \c_space_tl schema=2 \c_space_tl job=\c_sys_jobname_str + } +\iow_now:Nx \g_lalu_ans_iow + { \exp_not:N \LALUAnswerManifestBegin {2}{\c_sys_jobname_str} } +\AtEndDocument + { + \iow_now:Nx \g_lalu_ans_iow + { + \exp_not:N \LALUAnswerManifestEnd + { \int_use:N \g_lalu_ans_total_unit_int } + { \int_use:N \g_lalu_ans_total_group_int } + { \int_use:N \g_lalu_ans_emitted_group_int } + { \int_use:N \g_lalu_ans_total_item_int } + { \int_use:N \g_lalu_ans_answered_int } + { \int_use:N \g_lalu_ans_todo_int } + { \int_use:N \g_lalu_ans_omitted_int } + } + \iow_now:Nx \g_lalu_ans_iow + { + \c_percent_str \c_space_tl LALU-ANSWER-MANIFEST-END + \c_space_tl total-units=\int_use:N \g_lalu_ans_total_unit_int + \c_space_tl total-groups=\int_use:N \g_lalu_ans_total_group_int + \c_space_tl emitted-groups=\int_use:N \g_lalu_ans_emitted_group_int + \c_space_tl total-items=\int_use:N \g_lalu_ans_total_item_int + \c_space_tl answered=\int_use:N \g_lalu_ans_answered_int + \c_space_tl todo=\int_use:N \g_lalu_ans_todo_int + \c_space_tl omitted=\int_use:N \g_lalu_ans_omitted_int + } + \iow_close:N \g_lalu_ans_iow + \iow_term:x + { + LALU~answer~manifest:~units~ + \int_use:N \g_lalu_ans_total_unit_int,~groups~ + \int_use:N \g_lalu_ans_emitted_group_int / + \int_use:N \g_lalu_ans_total_group_int,~answered~ + \int_use:N \g_lalu_ans_answered_int,~todo~ + \int_use:N \g_lalu_ans_todo_int,~empty~ + \int_use:N \g_lalu_ans_omitted_int. + } + } +\ExplSyntaxOff + +\ctexset{ + chapter={format={\centering\Huge\bfseries},name={第,讲},number=\arabic{LALUnormalchapter}}, + section={format={\raggedright\Large\bfseries},name={,},number={\thechapter.\arabic{section}}}, + subsection={format={\raggedright\large\bfseries},name={,},number={\thesection.\arabic{subsection}}}, + subsubsection={format={\raggedright\normalsize\bfseries},name={,},number={\thesubsection.\arabic{subsubsection}}}, +} + +\title{线性代数:未竟之美} +\author{线性代数荣誉课辅学讲义 \\ 吴一航 \quad \verb|yhwu_is@zju.edu.cn|} + +\LALUFinalizePreamble +\hypersetup{ + hypertexnames=true, + pdfauthor={吴一航}, + pdftitle={线性代数:未竟之美}, +} + +\begin{document} +\frontmatter + +% 封面,代替 \maketitle +\includepdf[ + pages={1}, + noautoscale=true, + width=\paperwidth, +]{./figs/cover-16k.pdf} + +\songti + +% 插入空页 +\thispagestyle{empty} +\null +\clearpage + +\input{./其它/扉页.tex} +\clearpage + +\pagenumbering{Roman} +\input{./其它/序.tex} +\input{./其它/致读者.tex} +\clearpage + +\pdfbookmark[0]{目录}{contents} +\tableofcontents + +\addtolength{\parskip}{.5em} + +\mainmatter +\input{./专题/1 预备知识.tex} +\input{./其它/未竟专题1 预备思想.tex} +\input{./专题/2 线性空间.tex} +\input{./专题/3 有限维线性空间.tex} +\input{./专题/4 线性空间的运算.tex} +\input{./专题/5 线性映射.tex} +\input{./专题/6 对偶空间.tex} +\input{./专题/7 线性映射矩阵表示与矩阵运算基础.tex} +\input{./专题/8 相抵标准形.tex} +\input{./专题/9 矩阵运算进阶.tex} +\input{./其它/未竟专题2 有限域上的矩阵.tex} +\input{./专题/10 行列式.tex} +\input{./其它/未竟专题3 矩阵空间.tex} +\input{./专题/11 朝花夕拾.tex} +\input{./其它/未竟专题4 特定域上的线性代数.tex} +\input{./专题/12 史海拾遗.tex} +\input{./专题/13 多项式.tex} +\input{./其它/未竟专题5 纽结的多项式不变量.tex} +\input{./专题/14 相似标准形:动机与基础.tex} +\input{./其它/未竟专题6 控制法及其在矩阵理论中的应用.tex} +\input{./专题/15 相似标准形:复数域上的尝试与理论.tex} +\input{./专题/16 若当标准形.tex} +\input{./专题/17 多项式的进一步讨论.tex} +\input{./专题/18 有理标准形.tex} +\input{./其它/未竟专题7 对称多项式和Young图.tex} +\input{./专题/19 内积空间.tex} +\input{./专题/20 内积空间上的算子.tex} +\input{./其它/未竟专题8 希尔伯特空间引论.tex} +\input{./专题/21 线性代数与几何.tex} +\input{./专题/22 二次型.tex} +\input{./专题/23 多重线性映射与张量的计算.tex} +\input{./其它/未竟专题9 射影几何的代数方法.tex} +\input{./其它/未竟专题10 有限域上的二次型.tex} +\input{./其它/未竟专题11 二次型的几何.tex} +\input{./其它/未竟专题12 实数域的诸扩域.tex} +\input{./其它/未竟专题13 线性动力系统.tex} +\input{./专题/24 线性代数与微积分.tex} +\input{./专题/25 线性代数与最优化问题.tex} +\input{./其它/未竟专题14 范畴论视角下的线性代数.tex} + +\backmatter +{\small +\printindex +\printindex[sym] +} + +\end{document} diff --git a/LALUbook.cls "b/\350\256\262\344\271\211/LALUbook.cls" similarity index 54% rename from LALUbook.cls rename to "\350\256\262\344\271\211/LALUbook.cls" index 356ef8c..22f5791 100644 --- a/LALUbook.cls +++ "b/\350\256\262\344\271\211/LALUbook.cls" @@ -19,14 +19,29 @@ % Declaration of options % ---------------------- -\DeclareBoolOption[false]{draft} % 是否打上未定稿标记 +\DeclareBoolOption[false]{draft} % 预留:尚无自定义未定稿标记;全局 draft 仍会影响支持它的宏包 \DeclareBoolOption[true]{colors} % 是否让链接带颜色 -\DeclareBoolOption[false]{CJKthechapter} % 是否让天眉的各章编号使用中文数字 -\DeclareStringOption{coverpage} % 封面档档名, 默认为空 -\DeclareStringOption{fontsetup} % 字体设定档档名 -\DeclareStringOption{titlesetup} % 章节标题设定档档名 +\DeclareBoolOption[false]{CJKthechapter} % 预留:目前尚未实现中文章编号天眉 +\DeclareStringOption{coverpage} % 预留:目前尚未使用的封面档档名 +\DeclareStringOption{fontsetup} % 预留:目前尚未使用的字体设定档档名 +\DeclareStringOption{titlesetup} % 预留:目前尚未使用的章节标题设定档档名 \DeclareStringOption[16k]{geometry} % 版面(默认 16k) +% 将 10pt/11pt/12pt、oneside/twoside、openany/openright 等标准选项 +% 交由底层 ctexbook 处理。 +\newcommand*{\LALU@rejectpaperoption}{% + \ClassError{LALUbook}{Class option `\CurrentOption' conflicts with `geometry'}% + {Use `geometry=a4' for A4 paper. Supported layouts are `geometry=16k' and `geometry=a4'.}% +} +\DeclareVoidOption{a4paper}{\LALU@rejectpaperoption} +\DeclareVoidOption{a5paper}{\LALU@rejectpaperoption} +\DeclareVoidOption{b5paper}{\LALU@rejectpaperoption} +\DeclareVoidOption{letterpaper}{\LALU@rejectpaperoption} +\DeclareVoidOption{legalpaper}{\LALU@rejectpaperoption} +\DeclareVoidOption{executivepaper}{\LALU@rejectpaperoption} +\DeclareVoidOption{landscape}{\LALU@rejectpaperoption} +\DeclareDefaultOption{\PassOptionsToClass{\CurrentOption}{ctexbook}} + \PassOptionsToPackage{dvipsnames}{xcolor} % 让 xcolor 带 dvipsnames 选项; tikz 随后会载入之. \ProcessKeyvalOptions* @@ -43,12 +58,15 @@ \RequirePackage{mathrsfs} \RequirePackage{amssymb} \RequirePackage{mathtools} +\RequirePackage{amsthm} % 加入字串处理功能 \RequirePackage{xstring} +\RequirePackage{xspace} % 设置天眉所需 \RequirePackage{fancyhdr} +\RequirePackage{emptypage} \RequirePackage{graphicx} \RequirePackage{float} @@ -56,7 +74,6 @@ \RequirePackage{multicol} \RequirePackage{pdfpages} \RequirePackage{indentfirst} -\RequirePackage{ntheorem} \RequirePackage{titlesec} \RequirePackage{mismath} % 包含 rank, span 等运算符 \RequirePackage{zhnumber} @@ -76,10 +93,6 @@ % 首行缩进 2 字符 \setlength{\parindent}{2em} -% 定理字体 -\theoremheaderfont{\bfseries\heiti} -\theorembodyfont{\fangsong} - \usetikzlibrary{shapes.symbols} % 设置页面尺寸 @@ -93,21 +106,16 @@ right = 20mm, headheight = 5ex, headsep = 5ex, - textwidth = 132mm, - textheight = 198mm, - twoside, - asymmetric, % 单双数页不分 % bindingoffset = 18pt, - }}{} - -\IfStrEq{\@LALU@geometry}{a4}{% 载入 a4 版面设置 - \geometry{ - a4paper, - twoside, - asymmetric, - }}{} - -% 使空页恒空 + }}{% 载入 A4 版面设置或报告不支持的值 + \IfStrEq{\@LALU@geometry}{a4}{ + \geometry{a4paper} + }{ + \ClassError{LALUbook}{Unknown geometry `\@LALU@geometry'}% + {Supported geometry values are `16k' and `a4'.} + }} + +% 章首页不显示页眉;由 emptypage 保证双面排版所插入的空页恒空 \fancypagestyle{plain}{ \fancyhead{} \renewcommand{\headrulewidth}{0pt} @@ -161,8 +169,30 @@ #3, } -\NewDocumentEnvironment{proof}{O{}O{}}{\begin{tcblaluthmbox}{{\heiti 证明}}{#1}{#2}\fangsong}{\hspace*{\fill}$\square$\end{tcblaluthmbox}} -\NewDocumentEnvironment{solution}{O{}O{}}{\begin{tcblaluthmbox}{{\heiti 解}}{#1}{#2}\fangsong}{\end{tcblaluthmbox}} +% amsthm 负责 QED 栈和 \qedhere,tcolorbox 只负责外观。 +\renewcommand*{\qedsymbol}{$\square$} +\RenewDocumentEnvironment{proof}{O{}}{% + \pushQED{\qed}% + \begin{tcblaluthmbox}{{\heiti 证明}}{#1}{}% + \fangsong\ignorespaces +}{% + \popQED + \end{tcblaluthmbox}% +} +\NewDocumentEnvironment{solution}{O{}}{% + \begin{tcblaluthmbox}{{\heiti 解}}{#1}{}% + \fangsong\ignorespaces +}{% + \end{tcblaluthmbox}% +} + +% 定理环境的名称、颜色、标签前缀与引用名称由同一处声明。 +\newcommand*{\LALU@DeclareBoxedTheorem}[4]{% + \newtcbtheorem[number within=chapter]{#1}{#2}{laluthmstyle={#3}}{#4}% + \expandafter\def\csname tcb@cnt@#1autorefname\endcsname{#2}% + \crefname{tcb@cnt@#1}{#2}{#2}% + \Crefname{tcb@cnt@#1}{#2}{#2}% +} \NewDocumentCommand{\term}{m}{{\sffamily\heiti\bfseries{#1}}} @@ -176,7 +206,15 @@ \newcommand{\Set}{\mathsf{Set}} \newcommand{\FSet}{\mathsf{FSet}} -\AtEndPreamble{ +% 文档入口在自身的宏包和定义之后显式调用此命令,以保持 +% hyperref/cleveref 的载入次序,而不依赖隐式的 begin-document 钩子。 +\newif\ifLALU@preamble@finalized +\newcommand*{\LALUFinalizePreamble}{% + \ifLALU@preamble@finalized + \ClassError{LALUbook}{Preamble already finalized}% + {Call \string\LALUFinalizePreamble\space exactly once, after document-specific packages and definitions.}% + \else + \global\LALU@preamble@finalizedtrue \RequirePackage[Bjornstrup]{fncychap} % found on Internet % hyperref 与 cleveref 需要最后引入 @@ -184,12 +222,30 @@ \RequirePackage{bookmark} \RequirePackage{cleveref} - \newtcbtheorem[number within=chapter]{definition}{定义}{laluthmstyle={red}}{def} - \newtcbtheorem[number within=chapter]{example}{例}{laluthmstyle={blue}}{ex} - \newtcbtheorem[number within=chapter]{lemma}{引理}{laluthmstyle={orange}}{lem} - \newtcbtheorem[number within=chapter]{theorem}{定理}{laluthmstyle={violet}}{thm} - \newtcbtheorem[number within=chapter]{corollary}{推论}{laluthmstyle={green}}{cor} - \newtcbtheorem[number within=chapter]{axiom}{公理}{laluthmstyle={olive}}{axm} + % hyperref 在链接组内组装引用文字,XeCJK 因此无法总是从 + % 后继中文字符自动推断边界间距。xspace 在正文前补等价空格, + % 而在中英文标点和括号前保持紧贴。 + \xspaceaddexceptions{% + ,.;:!?()[]% + ,。.、;:?!% + ()[]〔〕【】〖〗〘〙〚〛% + 〈〉《》「」『』“”‘’% + …—·% + } + \NewCommandCopy{\LALU@hyperref@autoref}{\autoref} + \RenewDocumentCommand{\autoref}{s m}{% + \IfBooleanTF{##1} + {\LALU@hyperref@autoref*{##2}} + {\LALU@hyperref@autoref{##2}}% + \xspace + } + + \LALU@DeclareBoxedTheorem{definition}{定义}{red}{def} + \LALU@DeclareBoxedTheorem{example}{例}{blue}{ex} + \LALU@DeclareBoxedTheorem{lemma}{引理}{orange}{lem} + \LALU@DeclareBoxedTheorem{theorem}{定理}{violet}{thm} + \LALU@DeclareBoxedTheorem{corollary}{推论}{green}{cor} + \LALU@DeclareBoxedTheorem{axiom}{公理}{olive}{axm} \hypersetup{ unicode, @@ -214,23 +270,14 @@ \renewcommand{\equationautorefname}{式} \renewcommand{\chapterautorefname}{章} \renewcommand{\sectionautorefname}{节} - \makeatletter - \newcommand{\tcb@cnt@theoremautorefname}{定理} - \newcommand{\tcb@cnt@lemmaautorefname}{引理} - \newcommand{\tcb@cnt@corollaryautorefname}{推论} - \newcommand{\tcb@cnt@exampleautorefname}{例} - \newcommand{\tcb@cnt@definitionautorefname}{定义} - \newcommand{\tcb@cnt@axiomautorefname}{公理} - \makeatother - % https://tex.stackexchange.com/a/2244/316373 - \makeatletter \renewcommand*\env@matrix[1][*\c@MaxMatrixCols c]{% \hskip -\arraycolsep \let\@ifnextchar\new@ifnextchar - \array{#1}} - \makeatother + \array{##1}} - \crefrangeformat{equation}{式~#3#1#4--#5#2#6} - \crefrangeformat{example}{例~#3#1#4--#5#2#6} + \crefrangeformat{equation}{式~##3##1##4--##5##2##6} + \crefrangeformat{example}{例~##3##1##4--##5##2##6} + \fi } +\@onlypreamble\LALUFinalizePreamble diff --git "a/\350\256\262\344\271\211/Makefile" "b/\350\256\262\344\271\211/Makefile" index 8beee4f..632c3f4 100644 --- "a/\350\256\262\344\271\211/Makefile" +++ "b/\350\256\262\344\271\211/Makefile" @@ -1,27 +1,42 @@ -# FIXME: xindy can't handle UTF-8 filenames -FILENAME := 线性代数荣誉课辅学讲义 -CPNAME := LALU +MAIN_JOB := LALU LATEXMK := latexmk -LATEXMK_FLAGS := -xelatex -shell-escape -interaction=nonstopmode -file-line-error +LATEXMK_FLAGS := \ + -xelatex \ + -interaction=nonstopmode \ + -halt-on-error \ + -file-line-error \ + -no-shell-escape +ANSWER_BUILD_DIR := build/answers +ANSWER_MANIFEST := $(ANSWER_BUILD_DIR)/$(MAIN_JOB).manifest.tex +ANSWER_PUBLISHER := scripts/publish-answer-manifest.pl .PHONY: all clean all: - # Building $(FILENAME).pdf -ifdef CPNAME - @cp -p $(FILENAME).tex $(CPNAME).tex - $(LATEXMK) $(LATEXMK_FLAGS) $(CPNAME).tex - @rm -f $(CPNAME).tex - -@mv $(CPNAME).pdf $(FILENAME).pdf -else - $(LATEXMK) $(LATEXMK_FLAGS) $(FILENAME).tex -endif - # Building answers.pdf - $(LATEXMK) $(LATEXMK_FLAGS) LALU-answers.tex + @mkdir -p $(ANSWER_BUILD_DIR) + @set -eu; \ + answer_tmp=$$(mktemp "$(ANSWER_BUILD_DIR)/$(MAIN_JOB).manifest.XXXXXX"); \ + answer_stage=$$(mktemp -d "$(ANSWER_BUILD_DIR)/$(MAIN_JOB).answers.XXXXXX"); \ + cleanup() { \ + rm -f "$$answer_tmp"; \ + rm -rf -- "$$answer_stage"; \ + }; \ + trap cleanup EXIT HUP INT TERM; \ + $(LATEXMK) -g $(LATEXMK_FLAGS) \ + -usepretex="\\def\\LALUAnswerManifestTempPath{$$answer_tmp}" \ + $(MAIN_JOB).tex; \ + perl $(ANSWER_PUBLISHER) --check "$$answer_tmp"; \ + $(LATEXMK) -g $(LATEXMK_FLAGS) \ + -outdir="$$answer_stage" \ + -usepretex="\\def\\LALUAnswerManifestPath{$$answer_tmp}\\def\\LALUAnswerManifestJob{$(MAIN_JOB)}" \ + LALU-answers.tex; \ + test -s "$(MAIN_JOB).pdf"; \ + test -s "$$answer_stage/LALU-answers.pdf"; \ + mv "$$answer_stage/LALU-answers.pdf" LALU-answers.pdf; \ + perl $(ANSWER_PUBLISHER) --publish "$$answer_tmp" "$(ANSWER_MANIFEST)" clean: rm -f *.aux *.log *.idx *.ind *.ilg *.thm *.toc *.blg *.bbl *.bcf *.out *.fls *.fdb_latexmk *.run.xml *.synctex.gz *.xdv *~ *.lof *.lot -ifdef CPNAME - rm -f $(CPNAME).pdf $(CPNAME).tex -endif + rm -f LALU-ans-contents.tex *.answer-manifest.pending.tex + rm -rf -- $(ANSWER_BUILD_DIR) diff --git "a/\350\256\262\344\271\211/figs/cover-16K.pdf" "b/\350\256\262\344\271\211/figs/cover-16k.pdf" similarity index 100% rename from "\350\256\262\344\271\211/figs/cover-16K.pdf" rename to "\350\256\262\344\271\211/figs/cover-16k.pdf" diff --git "a/\350\256\262\344\271\211/scripts/publish-answer-manifest.pl" "b/\350\256\262\344\271\211/scripts/publish-answer-manifest.pl" new file mode 100644 index 0000000..1b3ae19 --- /dev/null +++ "b/\350\256\262\344\271\211/scripts/publish-answer-manifest.pl" @@ -0,0 +1,323 @@ +#!/usr/bin/env perl + +use strict; +use warnings; +use File::Basename qw(dirname); +use File::Spec; + +sub usage { + die "usage: $0 --check TEMP_MANIFEST\n" + . " $0 --publish TEMP_MANIFEST PUBLISHED_MANIFEST\n"; +} + +sub read_manifest { + my ($path) = @_; + + -f $path or die "answer manifest was not generated: $path\n"; + open my $input, '<:raw', $path + or die "cannot read answer manifest '$path': $!\n"; + local $/; + my $contents = <$input>; + close $input or die "cannot close answer manifest '$path': $!\n"; + + defined $contents && length $contents + or die "answer manifest is empty: $path\n"; + $contents !~ /\0/ + or die "answer manifest contains a NUL byte: $path\n"; + return $contents; +} + +sub parse_reader_command { + my ($line, $name, $arity, $line_number) = @_; + my $prefix = "\\$name"; + + index($line, $prefix) == 0 + or die "expected $prefix at line $line_number\n"; + + my $length = length $line; + my $position = length $prefix; + if ($position < $length) { + my $next = substr($line, $position, 1); + $next =~ /[ \t{]/ + or die "invalid reader command name at line $line_number\n"; + } + + my @arguments; + for (1 .. $arity) { + ++$position while $position < $length + && substr($line, $position, 1) =~ /[ \t]/; + $position < $length && substr($line, $position, 1) eq '{' + or die "reader command '$name' has no argument $_ at line $line_number\n"; + + my $start = ++$position; + my $depth = 1; + while ($position < $length) { + my $character = substr($line, $position, 1); + + # A control symbol such as \{ does not contribute a grouping brace. + # Skipping the next byte is also sufficient for control words: the + # remaining letters cannot affect brace depth. + if ($character eq '\\') { + $position + 1 < $length + or die "reader command '$name' ends in a bare backslash at line $line_number\n"; + $position += 2; + next; + } + $character ne '%' + or die "reader command '$name' contains an unescaped comment at line $line_number\n"; + if ($character eq '{') { + ++$depth; + } + elsif ($character eq '}') { + --$depth; + if ($depth == 0) { + push @arguments, substr($line, $start, $position - $start); + ++$position; + last; + } + } + ++$position; + } + $depth == 0 + or die "reader command '$name' has an unclosed argument $_ at line $line_number\n"; + } + + ++$position while $position < $length + && substr($line, $position, 1) =~ /[ \t]/; + $position == $length + or die "reader command '$name' has trailing input at line $line_number\n"; + + return @arguments; +} + +sub is_uint { + my ($value) = @_; + return $value =~ /\A(?:0|[1-9]\d*)\z/; +} + +sub validate_manifest { + my ($path) = @_; + my $contents = read_manifest($path); + + # The manifest is read as raw UTF-8 bytes. Perl's \R also matches byte + # 0x85, which commonly occurs as a UTF-8 continuation byte in Chinese + # text, so only actual TeX input line endings may delimit records here. + my @lines = split /\r\n|\n|\r/, $contents, -1; + pop @lines if @lines && $lines[-1] eq ''; + @lines >= 3 + or die "answer manifest is incomplete: $path\n"; + + my $line_index = 0; + my $header = $lines[$line_index++]; + $header =~ /\A% LALU-ANSWER-MANIFEST schema=2 job=([A-Za-z0-9_.-]+)\z/ + or die "answer manifest has no valid schema header: $path\n"; + my $job = $1; + + my @reader_begin = parse_reader_command( + $lines[$line_index], 'LALUAnswerManifestBegin', 2, $line_index + 1 + ); + ++$line_index; + $reader_begin[0] eq '2' + or die "answer manifest reader has unsupported schema '$reader_begin[0]'\n"; + $reader_begin[1] =~ /\A[A-Za-z0-9_.-]+\z/ + or die "answer manifest reader has an invalid job name\n"; + $reader_begin[1] eq $job + or die "answer manifest header job '$job' does not match reader job '$reader_begin[1]'\n"; + + my (%unit_ids, %group_ids, %item_ids); + my ($current_unit, $current_group); + my ($expected_group_items, $seen_group_items) = (0, 0); + my ($unit_events, $group_events, $item_events) = (0, 0, 0); + my %status_events = (answered => 0, todo => 0, omitted => 0); + + my @reader_end; + while ($line_index < @lines) { + my $line = $lines[$line_index]; + if (index($line, '\\LALUAnswerManifestEnd') == 0) { + defined $current_group + and die "answer manifest ends inside group '$current_group'\n"; + @reader_end = parse_reader_command( + $line, 'LALUAnswerManifestEnd', 7, $line_index + 1 + ); + for my $value (@reader_end) { + is_uint($value) + or die "answer manifest reader end contains a non-canonical count at line " + . ($line_index + 1) . "\n"; + } + ++$line_index; + last; + } + + $line =~ /\A% LALU-MANIFEST-EVENT (.+)\z/ + or die "unexpected top-level input at line " . ($line_index + 1) . "\n"; + my $event = $1; + my $human_line = $line_index + 1; + ++$line_index; + $line_index < @lines + or die "event at line $human_line has no reader command\n"; + my $command = $lines[$line_index++]; + + if ($event =~ /\Aunit id=(answer-unit:([1-9]\d*))\z/) { + my ($id, $sequence) = ($1, $2); + defined $current_group + and die "unit '$id' begins before group '$current_group' ends\n"; + ++$unit_events; + $id eq "answer-unit:$unit_events" + or die "unit ID '$id' is out of sequence at line $human_line\n"; + !$unit_ids{$id}++ + or die "duplicate unit ID '$id' at line $human_line\n"; + my ($kind, $normal, $serial, $slot, $command_id) = + parse_reader_command($command, 'LALUAnswerUnit', 6, $human_line + 1); + $kind =~ /\A(?:normal|unfinished)\z/ + && is_uint($normal) && is_uint($serial) && is_uint($slot) + && $command_id eq $id + or die "unit marker at line $human_line does not match its reader command\n"; + if ($kind eq 'normal') { + $normal > 0 && $serial == 0 && $slot == 0 + or die "invalid normal-unit metadata at line $human_line\n"; + } + else { + $normal > 0 && $serial > 0 && $slot >= 1 && $slot <= 6 + or die "invalid unfinished-unit metadata at line $human_line\n"; + } + $current_unit = $id; + } + elsif ($event =~ /\Agroup-begin id=(answer-group:([1-9]\d*)) unit=(answer-unit:[1-9]\d*) number=([1-9]\d*) items=([1-9]\d*)\z/) { + my ($id, $sequence, $unit, $number, $items) = ($1, $2, $3, $4, $5); + defined $current_unit + or die "group '$id' appears before the first unit\n"; + !defined $current_group + or die "nested group '$id' at line $human_line\n"; + $unit eq $current_unit + or die "group '$id' belongs to '$unit', not current unit '$current_unit'\n"; + ++$group_events; + $id eq "answer-group:$group_events" + or die "group ID '$id' is out of sequence at line $human_line\n"; + !$group_ids{$id}++ + or die "duplicate group ID '$id' at line $human_line\n"; + my @arguments = parse_reader_command( + $command, 'LALUAnswerGroupBegin', 3, $human_line + 1 + ); + join("\0", @arguments) eq join("\0", $id, $number, $items) + or die "group-begin marker at line $human_line does not match its reader command\n"; + $current_group = $id; + $expected_group_items = $items; + $seen_group_items = 0; + } + elsif ($event =~ /\Aitem id=(answer-item:([1-9]\d*)) group=(answer-group:[1-9]\d*) number=([1-9]\d*) status=(answered|todo|omitted)\z/) { + my ($id, $sequence, $group, $number, $status) = ($1, $2, $3, $4, $5); + defined $current_group + or die "item '$id' appears outside a group\n"; + $group eq $current_group + or die "item '$id' belongs to '$group', not current group '$current_group'\n"; + ++$item_events; + ++$seen_group_items; + $id eq "answer-item:$item_events" + or die "item ID '$id' is out of sequence at line $human_line\n"; + !$item_ids{$id}++ + or die "duplicate item ID '$id' at line $human_line\n"; + ++$status_events{$status}; + my @arguments = parse_reader_command( + $command, 'LALUAnswerItem', 4, $human_line + 1 + ); + join("\0", @arguments[0 .. 2]) eq join("\0", $id, $number, $status) + or die "item marker at line $human_line does not match its reader command\n"; + } + elsif ($event =~ /\Agroup-end id=(answer-group:[1-9]\d*) items=([1-9]\d*)\z/) { + my ($id, $items) = ($1, $2); + defined $current_group + or die "group-end '$id' appears without a group-begin\n"; + $id eq $current_group + or die "group-end '$id' does not match current group '$current_group'\n"; + $items == $expected_group_items && $seen_group_items == $expected_group_items + or die "group '$id' item count mismatch\n"; + my @arguments = parse_reader_command( + $command, 'LALUAnswerGroupEnd', 2, $human_line + 1 + ); + join("\0", @arguments) eq join("\0", $id, $items) + or die "group-end marker at line $human_line does not match its reader command\n"; + undef $current_group; + ($expected_group_items, $seen_group_items) = (0, 0); + } + else { + die "unknown answer manifest event at line $human_line: $event\n"; + } + } + + @reader_end + or die "answer manifest has no reader end record: $path\n"; + $line_index < @lines + or die "answer manifest has no end sentinel: $path\n"; + my $footer = $lines[$line_index++]; + my ($total_units, $total_groups, $emitted_groups, $total_items, + $answered, $todo, $omitted) = + $footer =~ /\A% LALU-ANSWER-MANIFEST-END total-units=(0|[1-9]\d*) total-groups=(0|[1-9]\d*) emitted-groups=(0|[1-9]\d*) total-items=(0|[1-9]\d*) answered=(0|[1-9]\d*) todo=(0|[1-9]\d*) omitted=(0|[1-9]\d*)\z/; + defined $omitted + or die "answer manifest has no valid end sentinel at line $line_index: $path\n"; + $line_index == @lines + or die "unexpected input after answer manifest footer at line " + . ($line_index + 1) . "\n"; + + my @footer_counts = ($total_units, $total_groups, $emitted_groups, + $total_items, $answered, $todo, $omitted); + join("\0", @reader_end) eq join("\0", @footer_counts) + or die "answer manifest reader statistics do not match its end sentinel\n"; + + $unit_events == $total_units + or die "answer manifest unit count mismatch: found $unit_events, expected $total_units\n"; + $group_events == $emitted_groups + or die "answer manifest group count mismatch: found $group_events, expected $emitted_groups\n"; + $emitted_groups <= $total_groups + or die "answer manifest emitted more groups than it observed\n"; + $item_events == $total_items + or die "answer manifest item count mismatch: found $item_events, expected $total_items\n"; + $answered + $todo + $omitted == $total_items + or die "answer manifest status counts do not add up\n"; + $status_events{answered} == $answered + or die "answered item count mismatch\n"; + $status_events{todo} == $todo + or die "todo item count mismatch\n"; + $status_events{omitted} == $omitted + or die "omitted item count mismatch\n"; + + return { + job => $job, + units => $total_units, + total_groups => $total_groups, + emitted_groups => $emitted_groups, + answered => $answered, + todo => $todo, + omitted => $omitted, + }; +} + +my ($mode, $temporary, $published); +if (@ARGV == 2 && $ARGV[0] eq '--check') { + ($mode, $temporary) = @ARGV; +} +elsif (@ARGV == 3 && $ARGV[0] eq '--publish') { + ($mode, $temporary, $published) = @ARGV; +} +else { + usage(); +} + +my $stats = validate_manifest($temporary); + +if ($mode eq '--publish') { + my $temporary_directory = File::Spec->rel2abs(dirname($temporary)); + my $published_directory = File::Spec->rel2abs(dirname($published)); + -d $published_directory + or die "published answer manifest directory does not exist: $published_directory\n"; + $temporary_directory eq $published_directory + or die "temporary and published manifests must be in the same directory\n"; + rename $temporary, $published + or die "cannot atomically publish '$temporary' as '$published': $!\n"; + print "Published answer manifest: $published\n"; +} +else { + print "Validated answer manifest: $temporary\n"; +} + +print " units $stats->{units}, groups $stats->{emitted_groups}/$stats->{total_groups}, " + . "answers $stats->{answered}, todo $stats->{todo}, omitted $stats->{omitted}\n"; diff --git "a/\350\256\262\344\271\211/\344\270\223\351\242\230/10 \350\241\214\345\210\227\345\274\217.tex" "b/\350\256\262\344\271\211/\344\270\223\351\242\230/10 \350\241\214\345\210\227\345\274\217.tex" index 9023c9a..500c41b 100644 --- "a/\350\256\262\344\271\211/\344\270\223\351\242\230/10 \350\241\214\345\210\227\345\274\217.tex" +++ "b/\350\256\262\344\271\211/\344\270\223\351\242\230/10 \350\241\214\345\210\227\345\274\217.tex" @@ -843,7 +843,7 @@ \subsection{打洞法} O & A \\ B & C \end{vmatrix} = (-1)^{kr} \begin{vmatrix} A & O \\ C & B - \end{vmatrix} = (-1)^{kr} |A||B|. + \end{vmatrix} = (-1)^{kr} |A||B|. \qedhere \] \end{proof} @@ -1054,7 +1054,7 @@ \subsection{行列式与函数} 与第一部分合并可得 \[ - \dfrac{\mathrm{d}}{\mathrm{d}t}F(t)=\sum\limits_{j=1}^nF_j(t). + \dfrac{\mathrm{d}}{\mathrm{d}t}F(t)=\sum\limits_{j=1}^nF_j(t). \qedhere \] \end{proof} @@ -2608,7 +2608,7 @@ \section{Cauchy-Binet 公式} \begin{pmatrix} j_1 & j_2 & \cdots & j_m \\ 1 & 2 & \cdots & m - \end{pmatrix}. + \end{pmatrix}. \qedhere \] \end{proof} @@ -2685,7 +2685,7 @@ \section{Cauchy-Binet 公式} \begin{pmatrix} k_1 & k_2 & \cdots & k_r \\ j_1 & j_2 & \cdots & j_r - \end{pmatrix}. \] + \end{pmatrix}. \qedhere \] \end{proof} 矩阵 $A$ 的子式 @@ -4019,7 +4019,7 @@ \section{Cauchy-Binet 公式} 将上述行列式展开即有 \[ - \left( \sum_{i=1}^{n}\limits a_i^2 \right) \left( \sum_{i=1}^{n}\limits b_i^2 \right) - \left( \sum_{i=1}^{n}\limits a_i b_i \right)^2 \geqslant 0. + \left( \sum\limits_{i=1}^{n} a_i^2 \right) \left( \sum\limits_{i=1}^{n} b_i^2 \right) - \left( \sum\limits_{i=1}^{n} a_i b_i \right)^2 \geqslant 0. \] 故 Cauchy-Schwarz 不等式成立. diff --git "a/\350\256\262\344\271\211/\344\270\223\351\242\230/13 \345\244\232\351\241\271\345\274\217.tex" "b/\350\256\262\344\271\211/\344\270\223\351\242\230/13 \345\244\232\351\241\271\345\274\217.tex" index c9ebe71..309733b 100644 --- "a/\350\256\262\344\271\211/\344\270\223\351\242\230/13 \345\244\232\351\241\271\345\274\217.tex" +++ "b/\350\256\262\344\271\211/\344\270\223\351\242\230/13 \345\244\232\351\241\271\345\274\217.tex" @@ -158,7 +158,7 @@ \section{整除与互素} f(x)\in \mathbf{F}[x]$,证明:$g(x)$是$f^2(x)$的因式的充要条件是$g(x)$是$f(x)$的因式. \end{example} \begin{proof} - 根据带余除法可知存在唯一的$q(x),r(x)(r(x)\neq 0)\in\mathbf{F}[x]$使得$f(x)=g(x)q(x)+r(x)$,且$\deg r<\deg g=1$,故$\deg r=0$,即$r(x)$是一个常数多项式,记为$c$,则$f^2(x)=g^2(x)q^2(x)+2cg(x)q(x)+c^2=(g(x)q^2(x)+2cq(x))g(x)+c^2$. 从而\[g(x) \mid f^2(x) \iff c^2=0 \iff c=0 \iff g(x) \mid f(x).\] + 根据带余除法可知存在唯一的$q(x),r(x)(r(x)\neq 0)\in\mathbf{F}[x]$使得$f(x)=g(x)q(x)+r(x)$,且$\deg r<\deg g=1$,故$\deg r=0$,即$r(x)$是一个常数多项式,记为$c$,则$f^2(x)=g^2(x)q^2(x)+2cg(x)q(x)+c^2=(g(x)q^2(x)+2cq(x))g(x)+c^2$. 从而\[g(x) \mid f^2(x) \iff c^2=0 \iff c=0 \iff g(x) \mid f(x). \qedhere\] \end{proof} 关于带余除法的具体计算方法此处不具体展开,因为与我们在小学中学习的整数竖式除法是基本一致的. 接下来我们利用已经定义的整除、因式、带余除法等概念进一步引进公因式、公倍式、最大公因式和最小公倍式等概念: @@ -538,7 +538,7 @@ \section{实数域与有理数域上的多项式函数} 证明非常直接,我们直接验证 \begin{align*} p(\overline{\lambda}) & =a_n\overline{\lambda}^n+a_{n-1}\overline{\lambda}^{n-1}+\cdots+a_1\overline{\lambda}+a_0 \\ - & =\overline{a_n\lambda^n+a_{n-1}\lambda^{n-1}+\cdots+a_1\lambda+a_0}=0. + & =\overline{a_n\lambda^n+a_{n-1}\lambda^{n-1}+\cdots+a_1\lambda+a_0}=0. \qedhere \end{align*} \end{proof} 这一引理表明,实数域上的多项式的复根是成对出现的(实根的共轭是其本身,上面的定理不再具有意义). 下面我们来研究实数域上不可约多项式的形式,事实上中学阶段我们都学习过这一点: diff --git "a/\350\256\262\344\271\211/\344\270\223\351\242\230/14 \347\233\270\344\274\274\346\240\207\345\207\206\345\275\242\357\274\232\345\212\250\346\234\272\344\270\216\345\237\272\347\241\200.tex" "b/\350\256\262\344\271\211/\344\270\223\351\242\230/14 \347\233\270\344\274\274\346\240\207\345\207\206\345\275\242\357\274\232\345\212\250\346\234\272\344\270\216\345\237\272\347\241\200.tex" index 92aee98..a942f24 100644 --- "a/\350\256\262\344\271\211/\344\270\223\351\242\230/14 \347\233\270\344\274\274\346\240\207\345\207\206\345\275\242\357\274\232\345\212\250\346\234\272\344\270\216\345\237\272\347\241\200.tex" +++ "b/\350\256\262\344\271\211/\344\270\223\351\242\230/14 \347\233\270\344\274\274\346\240\207\345\207\206\345\275\242\357\274\232\345\212\250\346\234\272\344\270\216\345\237\272\347\241\200.tex" @@ -76,7 +76,7 @@ \section{相似的定义与性质} P_1^{-1}A_1P_1 & O \\ O & P_2^{-1}A_2P_2 \end{pmatrix}=\begin{pmatrix} B_1 & O \\ O & B_2 - \end{pmatrix}.\] + \end{pmatrix}. \qedhere\] \end{proof} \item 与数量矩阵相似的为其自身,与幂等矩阵相似的仍幂等,与对合矩阵相似的仍对合,与幂零矩阵相似的仍幂零,与正交矩阵正交相似的仍正交(但与正交矩阵相似的不一定正交). diff --git "a/\350\256\262\344\271\211/\344\270\223\351\242\230/18 \346\234\211\347\220\206\346\240\207\345\207\206\345\275\242.tex" "b/\350\256\262\344\271\211/\344\270\223\351\242\230/18 \346\234\211\347\220\206\346\240\207\345\207\206\345\275\242.tex" index 6e4c7ea..9e84f81 100644 --- "a/\350\256\262\344\271\211/\344\270\223\351\242\230/18 \346\234\211\347\220\206\346\240\207\345\207\206\345\275\242.tex" +++ "b/\350\256\262\344\271\211/\344\270\223\351\242\230/18 \346\234\211\347\220\206\346\240\207\345\207\206\345\275\242.tex" @@ -16,7 +16,7 @@ \section{推广的广义特征子空间与第二有理标准形} \begin{definition}{}{推广广义特征子空间} 设$V$是一个有限维线性空间,$T\in\mathcal{L}(V)$. 设$T$的特征多项式为 \[f(\lambda)=p_1(\lambda)^{n_1}p_2(\lambda)^{n_2}\cdots p_k(\lambda)^{n_k},\] - 其中$p_i(\lambda)$是首一不可约多项式,$n_i$是正整数. 对于每一个不可约多项式$p_i(\lambda)$,我们定义\term{广义特征子空间}$G_{p_i}$为 + 其中$p_i(\lambda)$是首一不可约多项式,$n_i$是正整数. 对于每一个不可约多项式$p_i(\lambda)$,我们定义\term{广义特征子空间} $G_{p_i}$为 \[G_{p_i}=\{v\in V\mid\exists m\in\mathbf{N}^+,(p_i(T))^mv=0\},\] $G_{p_i}$中的向量则称为\term{广义特征向量}. \end{definition} diff --git "a/\350\256\262\344\271\211/\344\270\223\351\242\230/19 \345\206\205\347\247\257\347\251\272\351\227\264.tex" "b/\350\256\262\344\271\211/\344\270\223\351\242\230/19 \345\206\205\347\247\257\347\251\272\351\227\264.tex" index 1e5ea65..18f84f6 100644 --- "a/\350\256\262\344\271\211/\344\270\223\351\242\230/19 \345\206\205\347\247\257\347\251\272\351\227\264.tex" +++ "b/\350\256\262\344\271\211/\344\270\223\351\242\230/19 \345\206\205\347\247\257\347\251\272\351\227\264.tex" @@ -190,7 +190,7 @@ \subsection{正交的定义 \quad 基于正交的性质} \begin{align*} \lVert u + v \rVert^2 & = \langle u + v, u + v \rangle \\ & = \langle u, u \rangle + \langle u, v \rangle + \langle v, u \rangle + \langle v, v \rangle \\ - & = \lVert u \rVert^2 + \lVert v \rVert^2 + & = \lVert u \rVert^2 + \lVert v \rVert^2 \qedhere \end{align*} \end{proof} @@ -275,7 +275,7 @@ \subsection{正交的定义 \quad 基于正交的性质} & = (\lVert u \rVert + \lVert v \rVert)^2, \end{align*} 因为 $\lVert u + v \rVert$ 和 $\lVert u \rVert + \lVert v \rVert$ 都是非负实数,两边开平方,即得: - \[\lVert u + v \rVert \le \lVert u \rVert + \lVert v \rVert.\] + \[\lVert u + v \rVert \le \lVert u \rVert + \lVert v \rVert. \qedhere\] \end{proof} 其几何解释就是俗称的三角形两边之和小于第三边. @@ -395,7 +395,7 @@ \section{标准正交基} \lVert u \rVert^2 = \sum_{i=1}^{m} a_i \overline{a_i} \langle e_i, e_i \rangle = \sum_{i=1}^{m} a_i \overline{a_i} \cdot 1 = \sum_{i=1}^{m} \lvert a_i \rvert^2, \] 即 - \[ \lVert a_1e_1 + \cdots + a_m e_m\rVert^2 = \lvert a_1 \rvert^2 + \cdots + \lvert a_m \rvert^2. \] + \[ \lVert a_1e_1 + \cdots + a_m e_m\rVert^2 = \lvert a_1 \rvert^2 + \cdots + \lvert a_m \rvert^2. \qedhere \] \end{proof} 其本质可以看作勾股定理的推广,该定理也有一个重要推论: diff --git "a/\350\256\262\344\271\211/\344\270\223\351\242\230/20 \345\206\205\347\247\257\347\251\272\351\227\264\344\270\212\347\232\204\347\256\227\345\255\220.tex" "b/\350\256\262\344\271\211/\344\270\223\351\242\230/20 \345\206\205\347\247\257\347\251\272\351\227\264\344\270\212\347\232\204\347\256\227\345\255\220.tex" index 155a970..b9eebe1 100644 --- "a/\350\256\262\344\271\211/\344\270\223\351\242\230/20 \345\206\205\347\247\257\347\251\272\351\227\264\344\270\212\347\232\204\347\256\227\345\255\220.tex" +++ "b/\350\256\262\344\271\211/\344\270\223\351\242\230/20 \345\206\205\347\247\257\347\251\272\351\227\264\344\270\212\347\232\204\347\256\227\345\255\220.tex" @@ -52,7 +52,7 @@ \subsection{内积空间的同构} \end{theorem} \begin{proof} - \begin{itemize} + \begin{itemize} % FIXME: horizontal overflow \item[\ref*{item:20:保积同构条件:1}$\implies$\ref*{item:20:保积同构条件:2}] 由内积的保持可知范数的保持,从而对于任意 $v\in V$,$ Sv=\vec{0} \iff \|Sv\|=\|v\|=\vec{0} \iff v=\vec{0}$,所以 $ S $ 是单射. 而 $ V $ 和 $ U $ 维数相同,进而是双射. \item[\ref*{item:20:保积同构条件:2}$\implies$\ref*{item:20:保积同构条件:3}] 设 $ e_1, \ldots , e_n $ 是 $ V $ 的任意一组标准正交基,则 @@ -1239,7 +1239,7 @@ \subsection{正算子} % 从这里我们进一步加深类比. \begin{example}{镜像变换}{镜像变换} - 镜像变换(或镜面反射)--$\mathbf{R}^2$中每个向量关于过原点的直线$L$(看作镜面)相对称的变换 $\varphi$,即 + 镜像变换(或镜面反射)--$\mathbf{R}^2$中每个向量关于过原点的直线$L$(看作镜面)相对称的变换 $\varphi$,即 \[ \varphi: \forall \alpha = \vec{OA} \in \mathbf{R}^2,\\ \varphi(\alpha) = \alpha'= \vec{OB} @@ -1271,7 +1271,7 @@ \subsection{正算子} \end{example} \begin{proof} - 事实上,设直线 $L$ 的某个方向的单位向量为$\omega$,则$\vec{OC}=(\alpha,\omega)\omega$,其中$(\alpha,\omega)$为向量$\alpha$和$\omega$的内积,对于刚接触内积的读者来说,这可能并不是这么显然,但是稍加思考,我们发现这是很自然的,因为$\vec{OC}$是$\vec{OA}$在$\omega$方向上的投影,而求一个向量在另一个向量上的投影,我们高中时已经见了无数遍了,不妨设$\vec{OA}$与$\omega$的夹角为$\theta$,则$\vec{OC}=\vert\alpha \vert cos\theta\omega$,又 + 事实上,设直线 $L$ 的某个方向的单位向量为$\omega$,则$\vec{OC}=(\alpha,\omega)\omega$,其中$(\alpha,\omega)$为向量$\alpha$和$\omega$的内积,对于刚接触内积的读者来说,这可能并不是这么显然,但是稍加思考,我们发现这是很自然的,因为$\vec{OC}$是$\vec{OA}$在$\omega$方向上的投影,而求一个向量在另一个向量上的投影,我们高中时已经见了无数遍了,不妨设$\vec{OA}$与$\omega$的夹角为$\theta$,则$\vec{OC}=\vert\alpha \vert \cos\theta\omega$,又 \[ \vert\alpha \vert\cos\theta=\vert\alpha \vert\dfrac{\alpha\cdot\omega}{\vert \alpha\vert\cdot\vert\omega\vert}=\dfrac{(\alpha,\omega)}{\vert\omega\vert}. \] @@ -1898,7 +1898,7 @@ \subsubsection*{算子范数} \] 因而 $\lVert T \rVert \geqslant s_1$. 综上 \[ - \lVert T \rVert = s_1. + \lVert T \rVert = s_1. \qedhere \] \end{proof} diff --git "a/\350\256\262\344\271\211/\344\270\223\351\242\230/21 \347\272\277\346\200\247\344\273\243\346\225\260\344\270\216\345\207\240\344\275\225.tex" "b/\350\256\262\344\271\211/\344\270\223\351\242\230/21 \347\272\277\346\200\247\344\273\243\346\225\260\344\270\216\345\207\240\344\275\225.tex" index e50fb93..3c4e9ad 100644 --- "a/\350\256\262\344\271\211/\344\270\223\351\242\230/21 \347\272\277\346\200\247\344\273\243\346\225\260\344\270\216\345\207\240\344\275\225.tex" +++ "b/\350\256\262\344\271\211/\344\270\223\351\242\230/21 \347\272\277\346\200\247\344\273\243\346\225\260\344\270\216\345\207\240\344\275\225.tex" @@ -45,7 +45,7 @@ \section{欧氏空间上的运算} \vec{a}\cdot\vec{b} & = (a_1 \vec{e}_1 + a_2 \vec{e}_2 + a_3 \vec{e}_3)\cdot(b_1 \vec{e}_1 + b_2 \vec{e}_2 + b_3 \vec{e}_3) \\ & = \sum_{i=1}^3 \sum_{j=1}^3 a_i b_j (\vec{e}_i \cdot \vec{e}_j) - = \sum_{i=1}^3 \sum_{j=1}^3 g_{ij} a_i b_j. + = \sum_{i=1}^3 \sum_{j=1}^3 g_{ij} a_i b_j. \qedhere \end{align*} \end{proof} @@ -119,7 +119,7 @@ \section{欧氏空间上的运算} + (a_2 b_3 - a_3 b_2)\,\vec{e}_2 \times \vec{e}_3 \\ & = (a_2 b_3 - a_3 b_2)\,\vec{e}_2 \times \vec{e}_3 + (a_3 b_1 - a_1 b_3)\,\vec{e}_3 \times \vec{e}_1 - + (a_1 b_2 - a_2 b_1)\,\vec{e}_1 \times \vec{e}_2. + + (a_1 b_2 - a_2 b_1)\,\vec{e}_1 \times \vec{e}_2. \qedhere \end{align*} \end{proof} @@ -245,7 +245,7 @@ \section{欧氏空间上的运算} b_1 & b_2 & b_3 \\ c_1 & c_2 & c_3 \end{vmatrix} - [\vec{e}_1, \vec{e}_2, \vec{e}_3]. + [\vec{e}_1, \vec{e}_2, \vec{e}_3]. \qedhere \end{align*} \end{proof} @@ -489,7 +489,7 @@ \subsection{点到直线和平面的距离} \[ d(P, \Pi) = \frac{|\langle \vec{n}, \vec{p} \rangle + D|}{|\vec{n}|} - = \frac{|A x_0 + B y_0 + C z_0 + D|}{\sqrt{A^2 + B^2 + C^2}}. + = \frac{|A x_0 + B y_0 + C z_0 + D|}{\sqrt{A^2 + B^2 + C^2}}. \qedhere \] \end{proof} @@ -817,7 +817,7 @@ \section{仿射变换} \] 因而 $T$ 是线性映射. 于是存在矩阵 $A$ 使得 $T(x) = A x$,从而 \[ - F(x) = A x + \vec{b}. + F(x) = A x + \vec{b}. \qedhere \] \end{proof} diff --git "a/\350\256\262\344\271\211/\344\270\223\351\242\230/22 \344\272\214\346\254\241\345\236\213.tex" "b/\350\256\262\344\271\211/\344\270\223\351\242\230/22 \344\272\214\346\254\241\345\236\213.tex" index 1d2d7da..fc407eb 100644 --- "a/\350\256\262\344\271\211/\344\270\223\351\242\230/22 \344\272\214\346\254\241\345\236\213.tex" +++ "b/\350\256\262\344\271\211/\344\270\223\351\242\230/22 \344\272\214\346\254\241\345\236\213.tex" @@ -521,7 +521,6 @@ \section{相合规范形 \quad 惯性定理} \] 这两者显然矛盾,所以 $p > k$ 不成立,必然有 $p \leqslant k$,同理可证 $k \leqslant p$,所以 $p = k$,也就有实对称矩阵的相合规范形唯一. - \end{proof} \begin{example}{}{} @@ -988,7 +987,7 @@ \subsection{与特征值有关的进一步结论} \] 当 $X$ 取 $A$ 对应于 $\lambda_1$ 或 $\lambda_n$ 的特征向量时,上下界分别取到,因此 \[ - \lambda_1=\max_{X\neq 0}R_A(X), \qquad \lambda_n=\min_{X\neq 0}R_A(X). + \lambda_1=\max_{X\neq 0}R_A(X), \qquad \lambda_n=\min_{X\neq 0}R_A(X). \qedhere \] \end{proof} @@ -1044,7 +1043,7 @@ \subsection{与特征值有关的进一步结论} \] 再取 $X=\xi_k$,便知这里的最小值恰为 $\lambda_k$. 因而 \[ - \max_{\dim U=k}\ \min_{0\neq X\in U}R_A(X)=\lambda_k. + \max_{\dim U=k}\ \min_{0\neq X\in U}R_A(X)=\lambda_k. \qedhere \] \end{proof} @@ -1107,7 +1106,7 @@ \subsection{与特征值有关的进一步结论} \] 由\nameref{thm:Courant-Fischer}, \[ - \gamma_{i+j-1}=\min_{\dim W'=n-(i+j-1)+1}\ \max_{0\neq X\in W'}R_{A+B}(X)\leqslant \alpha_i+\beta_j. + \gamma_{i+j-1}=\min_{\dim W'=n-(i+j-1)+1}\ \max_{0\neq X\in W'}R_{A+B}(X)\leqslant \alpha_i+\beta_j. \qedhere \] \end{proof} diff --git "a/\350\256\262\344\271\211/\344\270\223\351\242\230/24 \347\272\277\346\200\247\344\273\243\346\225\260\344\270\216\345\276\256\347\247\257\345\210\206.tex" "b/\350\256\262\344\271\211/\344\270\223\351\242\230/24 \347\272\277\346\200\247\344\273\243\346\225\260\344\270\216\345\276\256\347\247\257\345\210\206.tex" index 0334684..43479ae 100644 --- "a/\350\256\262\344\271\211/\344\270\223\351\242\230/24 \347\272\277\346\200\247\344\273\243\346\225\260\344\270\216\345\276\256\347\247\257\345\210\206.tex" +++ "b/\350\256\262\344\271\211/\344\270\223\351\242\230/24 \347\272\277\346\200\247\344\273\243\346\225\260\344\270\216\345\276\256\347\247\257\345\210\206.tex" @@ -335,7 +335,7 @@ \section{多元函数微分学} 由于欧氏空间的紧子集都是有界闭的,所以我们知道 $Jf$ 在 $C$ 上一致连续,所以任给 $\varepsilon>0$,存在 $\delta>0$ 使得只要 $u',u\in C$ 且 $\Vert u'-u\Vert < \delta$,就有\[\Vert Jf(u') - Jf(u)\Vert < \varepsilon.\] 暂时固定 $u\in C$,当 $x\in D$ 时,记 $F(x) = f(x) - f(u) - J(u)(x - u)$,则 $JF(x) = Jf(x) - Jf(u)$,当 $v\in C$ 时,使用拟微分中值定理,有 \[\Vert F(v)\Vert = \Vert F(v) - F(u)\Vert \leqslant \Vert JF(\xi)\Vert\cdot \Vert v - u\Vert = \Vert Jf(\xi) - Jf(u)\Vert\cdot \Vert v - u\Vert.\] - 其中 $\xi = \theta u + (1-\theta)v$,$\theta\in (0, 1)$,由于 $Jf$ 在 $C$ 上一致连续,所以只要 $\Vert v - u\Vert < \delta$,就有 $\Vert \xi - u\Vert = \theta \Vert v - u\Vert < \delta$,所以\[\Vert F(v)\Vert = \Vert f(v) - f(u) - Jf(u)(v - u)\Vert \leqslant \varepsilon\Vert v - u\Vert.\] + 其中 $\xi = \theta u + (1-\theta)v$,$\theta\in (0, 1)$,由于 $Jf$ 在 $C$ 上一致连续,所以只要 $\Vert v - u\Vert < \delta$,就有 $\Vert \xi - u\Vert = \theta \Vert v - u\Vert < \delta$,所以\[\Vert F(v)\Vert = \Vert f(v) - f(u) - Jf(u)(v - u)\Vert \leqslant \varepsilon\Vert v - u\Vert. \qedhere\] \end{proof} 既然我们可以对一个函数的反函数求微分,回想起对于一元函数,如果它可微并且导数处处非零,那么该函数存在反函数并且反函数可微. 那么一个自然的问题就是:在什么样的条件下,多元向量值函数存在反函数并且反函数可微呢?这就是\term{反函数定理}. 在考虑反函数定理之前,我们先看一个小小的比喻. diff --git "a/\350\256\262\344\271\211/\344\270\223\351\242\230/5 \347\272\277\346\200\247\346\230\240\345\260\204.tex" "b/\350\256\262\344\271\211/\344\270\223\351\242\230/5 \347\272\277\346\200\247\346\230\240\345\260\204.tex" index 45cfc87..e1622dd 100644 --- "a/\350\256\262\344\271\211/\344\270\223\351\242\230/5 \347\272\277\346\200\247\346\230\240\345\260\204.tex" +++ "b/\350\256\262\344\271\211/\344\270\223\351\242\230/5 \347\272\277\346\200\247\346\230\240\345\260\204.tex" @@ -127,7 +127,7 @@ \subsection{线性映射举例} \draw node[below left] at (O) {$O$}; \end{tikzpicture} \end{center} - \item 镜像变换(或镜面反射)--$\mathbf{R}^2$中每个向量关于过原点的直线$L$(看作镜面)相对称的变换 $\varphi$,即 + \item 镜像变换(或镜面反射)--$\mathbf{R}^2$中每个向量关于过原点的直线$L$(看作镜面)相对称的变换 $\varphi$,即 \[ \varphi: \forall \alpha = \vec{OA} \in \mathbf{R}^2,\\ \varphi(\alpha) = \alpha'= \vec{OB} @@ -335,7 +335,7 @@ \subsection{线性映射的基本运算} 注意:在上述定义中一定注意$\sigma$和$\tau$的顺序,我们需要先使用$\sigma$将$V_1$中的元素映射到$V_2$,然后再用外层的$\tau$将这个结果映射到$V_3$. 此外,有时也会将复合映射记作$\tau \circ \sigma$(一般是为了强调这是复合运算),这里为了简化记号直接使用$\tau\sigma$. -接下来定义线性映射的逆运算,也就是定义逆映射,事实上与反函数的定义类似. 设 $\sigma \in \mathcal{L}(V_1,V_2)$. 若存在 $\tau \in \mathcal{L}(V_2,V_1)$ 使得 $\sigma \tau = I_{V_2}$ 且 $\tau \sigma = I_{V_1}$,则称 $\sigma$\term{可逆}\index{ni!ke@可逆 (invertible)},并称 $\tau$ 为 $\sigma$ 的逆映射\index{ni!yingshe@映射 (inverse map)}. 其中 $I_{V_1}$ 和 $I_{V_2}$ 分别是 $V_1$ 和 $V_2$ 上的恒等映射,即 $I_{V_i}(\alpha)=\alpha,\enspace \forall \alpha \in V_i,\ i = 1, 2$. +接下来定义线性映射的逆运算,也就是定义逆映射,事实上与反函数的定义类似. 设 $\sigma \in \mathcal{L}(V_1,V_2)$. 若存在 $\tau \in \mathcal{L}(V_2,V_1)$ 使得 $\sigma \tau = I_{V_2}$ 且 $\tau \sigma = I_{V_1}$,则称 $\sigma$\term{可逆}\index{ni@逆!ke@可逆 (invertible)},并称 $\tau$ 为 $\sigma$ 的逆映射\index{ni@逆!yingshe@映射 (inverse map)}. 其中 $I_{V_1}$ 和 $I_{V_2}$ 分别是 $V_1$ 和 $V_2$ 上的恒等映射,即 $I_{V_i}(\alpha)=\alpha,\enspace \forall \alpha \in V_i,\ i = 1, 2$. \begin{theorem}{}{逆映射是线性映射} 上述定义的逆映射 $\sigma^{-1}$ 为线性映射. diff --git "a/\350\256\262\344\271\211/\344\270\223\351\242\230/6 \345\257\271\345\201\266\347\251\272\351\227\264.tex" "b/\350\256\262\344\271\211/\344\270\223\351\242\230/6 \345\257\271\345\201\266\347\251\272\351\227\264.tex" index e2600fe..22f3e74 100644 --- "a/\350\256\262\344\271\211/\344\270\223\351\242\230/6 \345\257\271\345\201\266\347\251\272\351\227\264.tex" +++ "b/\350\256\262\344\271\211/\344\270\223\351\242\230/6 \345\257\271\345\201\266\347\251\272\351\227\264.tex" @@ -183,7 +183,7 @@ \section{对偶空间与对偶映射} \begin{proof} 对于类似形式(在几何中称为推出和拉回)的映射,我们证明等式的思路都是直接代入定义展开证明: \[ - (f \circ g)^* (\varphi) = \varphi \circ (f \circ g) = (\varphi \circ f) \circ g = (f^*(\varphi)) \circ g = g^* (f^*(\varphi)) = (g^* \circ f^*)(\varphi). + (f \circ g)^* (\varphi) = \varphi \circ (f \circ g) = (\varphi \circ f) \circ g = (f^*(\varphi)) \circ g = g^* (f^*(\varphi)) = (g^* \circ f^*)(\varphi). \qedhere \] \end{proof} @@ -199,7 +199,7 @@ \section{对偶空间与对偶映射} 我们直接按照定义展开验证即可: \begin{gather*} \sigma^*(f_1+f_2)=(f_1+f_2)\circ\sigma=f_1\circ\sigma+f_2\circ\sigma=\sigma^*(f_1)+\sigma^*(f_2) \\ - \sigma^*(\lambda f)=(\lambda f)\circ\sigma=\lambda(f\circ\sigma)=\lambda\sigma^*(f) + \sigma^*(\lambda f)=(\lambda f)\circ\sigma=\lambda(f\circ\sigma)=\lambda\sigma^*(f) \qedhere \end{gather*} \end{proof} diff --git "a/\350\256\262\344\271\211/\344\270\223\351\242\230/7 \347\272\277\346\200\247\346\230\240\345\260\204\347\237\251\351\230\265\350\241\250\347\244\272\344\270\216\347\237\251\351\230\265\350\277\220\347\256\227\345\237\272\347\241\200.tex" "b/\350\256\262\344\271\211/\344\270\223\351\242\230/7 \347\272\277\346\200\247\346\230\240\345\260\204\347\237\251\351\230\265\350\241\250\347\244\272\344\270\216\347\237\251\351\230\265\350\277\220\347\256\227\345\237\272\347\241\200.tex" index 48e211a..5a6f83b 100644 --- "a/\350\256\262\344\271\211/\344\270\223\351\242\230/7 \347\272\277\346\200\247\346\230\240\345\260\204\347\237\251\351\230\265\350\241\250\347\244\272\344\270\216\347\237\251\351\230\265\350\277\220\347\256\227\345\237\272\347\241\200.tex" +++ "b/\350\256\262\344\271\211/\344\270\223\351\242\230/7 \347\272\277\346\200\247\346\230\240\345\260\204\347\237\251\351\230\265\350\241\250\347\244\272\344\270\216\347\237\251\351\230\265\350\277\220\347\256\227\345\237\272\347\241\200.tex" @@ -374,7 +374,7 @@ \subsection{同构的说明} \begin{proof} 这一结论可以直接从交换图中得到. 事实上 $X = \varphi_{B_1}(\alpha)$,而 - \[Y = \varphi_{B_2}(\sigma(\alpha)) = \varphi_{B_2}(\varphi_{B_2}^{-1}(\sigma_\mathbf{M}(\varphi_{B_1}(\alpha)))) = \sigma_\mathbf{M}(\varphi_{B_1}(\alpha)) = \sigma_\mathbf{M}(X) = AX\] + \[Y = \varphi_{B_2}(\sigma(\alpha)) = \varphi_{B_2}(\varphi_{B_2}^{-1}(\sigma_\mathbf{M}(\varphi_{B_1}(\alpha)))) = \sigma_\mathbf{M}(\varphi_{B_1}(\alpha)) = \sigma_\mathbf{M}(X) = AX \qedhere\] \end{proof} 其中第二个等号来源于交换图的要求,最后一个等号因为 $A$ 是 $\sigma$ 在 $B_1$ 和 $B_2$ 下的矩阵表示,回忆矩阵表示的流程即得. 总结一下,\autoref{thm:线性映射对向量坐标的影响} 表明,$\sigma(\alpha) = \beta$ 中 $\beta$ 和 $\alpha$ 坐标间的关联为 $Y = AX$,这就相当于在 $\mathbf{F}^n$ 和 $\mathbf{F}^m$ 中向量之间建立了一个与 $\sigma: V_1 \to V_2$同步的映射 $X \mapsto \mathbf{M}(\sigma)X$,每当$V$中向量经过 $\sigma$ 映射后,它的坐标也就经过了 $\mathbf{M}(\sigma)$ 的映射. @@ -861,7 +861,7 @@ \subsection{矩阵的逆的定义} \end{gather*} 不难验证恒等映射在出发空间和到达空间取同一组基下的矩阵表示一定为单位矩阵,故 $AB = \mathbf{M}_{B_1,B_1}(I_{V_1}) = E_n = \mathbf{M}_{B_2,B_2}(I_{V_2}) = BA$,由此我们从可逆映射的角度引入矩阵的逆的概念: \begin{definition}{矩阵的逆}{} - 设 $A \in \mathbf{M}_n(\mathbf{F})$. 若存在 $B \in \mathbf{M}_n(\mathbf{F})$ 使得 $AB = BA = E_n$(不刻意强调时可以省略 $n$),则称矩阵 $A$ 可逆,并把 $B$ 称为 $A$ 的\term{逆矩阵}\index{ni!juzhen@矩阵 (inverse matrix)},记作 $B = A^{-1}$. + 设 $A \in \mathbf{M}_n(\mathbf{F})$. 若存在 $B \in \mathbf{M}_n(\mathbf{F})$ 使得 $AB = BA = E_n$(不刻意强调时可以省略 $n$),则称矩阵 $A$ 可逆,并把 $B$ 称为 $A$ 的\term{逆矩阵}\index{ni@逆!juzhen@矩阵 (inverse matrix)},记作 $B = A^{-1}$. \end{definition} 在一些比较经典的教材中可逆矩阵也被称为非奇异矩阵,不可逆矩阵被称为\term{奇异矩阵}\index{qiyijuzhen@奇异矩阵 (singular matrix)}. @@ -1112,7 +1112,7 @@ \subsection{对偶映射的矩阵表示} a_1 x_1 + a_2 x_2 + \cdots + a_n x_n = 1 \] -我们记 $a = (a_1,a_2,\ldots,a_n)^\mathrm{T}, x = (x_1,x_2,\ldots,x_n)^\mathrm{T}$,于是上面的方程可以简化为 $a^\mathrm{T} x = 1$. 根据线性空间同构于其对偶,$a \in \mathbf{F}^n$ 与 $a^\mathrm{T} x = 1$(视为 $(\mathbf{F}^n)^*$ 中的元素,回忆\autoref{eq:6:线性泛函与超平面对应} )是一一对应的关系. 于是我们接下来可以给出\autoref{thm:对偶映射的矩阵表示} 从几何上的理解. 考虑超平面方程 $a^\mathrm{T} x = 1$,则与这个超平面对偶的点是 $a$. 设 $\sigma \in \mathcal{L}(\mathbf{F}^n,\mathbf{F}^m)$,根据\autoref{lem:向量空间线性映射的矩阵表示},$\sigma$ 与一个矩阵 $M$ 对应. +我们记 $a = (a_1,a_2,\ldots,a_n)^\mathrm{T}, x = (x_1,x_2,\ldots,x_n)^\mathrm{T}$,于是上面的方程可以简化为 $a^\mathrm{T} x = 1$. 根据线性空间同构于其对偶,$a \in \mathbf{F}^n$ 与 $a^\mathrm{T} x = 1$(视为 $(\mathbf{F}^n)^*$ 中的元素,回忆\autoref{eq:6:线性泛函与超平面对应})是一一对应的关系. 于是我们接下来可以给出\autoref{thm:对偶映射的矩阵表示} 从几何上的理解. 考虑超平面方程 $a^\mathrm{T} x = 1$,则与这个超平面对偶的点是 $a$. 设 $\sigma \in \mathcal{L}(\mathbf{F}^n,\mathbf{F}^m)$,根据\autoref{lem:向量空间线性映射的矩阵表示},$\sigma$ 与一个矩阵 $M$ 对应. 我们对 $a \in \mathbf{F}^n$ 作用上 $\sigma$,得到了 $\sigma(a) = Ma \in \mathbf{F}^m$. 而与 $\sigma(a)$ 对应的超平面方程是 $(Ma)^\mathrm{T} x' = 1$,即 $(a^\mathrm{T}M^\mathrm{T}) x' = 1$,即新的超平面和原来的超平面相差一个 $M^\mathrm{T}$,即 $(\mathbf{F}^m)^*$ 与 $(\mathbf{F}^n)^*$ 之间相差了 $M^\mathrm{T}$. 因此,从几何直观上,我们也验证了转置和对偶映射的对应关系. diff --git "a/\350\256\262\344\271\211/\344\270\223\351\242\230/8 \347\233\270\346\212\265\346\240\207\345\207\206\345\275\242.tex" "b/\350\256\262\344\271\211/\344\270\223\351\242\230/8 \347\233\270\346\212\265\346\240\207\345\207\206\345\275\242.tex" index 9d823d3..70c26c5 100644 --- "a/\350\256\262\344\271\211/\344\270\223\351\242\230/8 \347\233\270\346\212\265\346\240\207\345\207\206\345\275\242.tex" +++ "b/\350\256\262\344\271\211/\344\270\223\351\242\230/8 \347\233\270\346\212\265\346\240\207\345\207\206\345\275\242.tex" @@ -233,7 +233,7 @@ \section{过渡矩阵和基变换} \begin{align*} \mathbf{M}_{B_1',B_2'}(\sigma) &= \mathbf{M}_{B_2,B_2'}(I)\mathbf{M}_{B_1',B_2}(\sigma) \\ &= \mathbf{M}_{B_2,B_2'}(I)\mathbf{M}_{B_1,B_2}(\sigma)\mathbf{M}_{B_1',B_1}(I) \\ - &= Q^{-1} \mathbf{M}_{B_1,B_2}(\sigma)P + &= Q^{-1} \mathbf{M}_{B_1,B_2}(\sigma)P \qedhere \end{align*} \end{proof} @@ -912,7 +912,7 @@ \section{相抵标准形的应用} 从而 \[A^{2}=\widetilde{P} \widetilde{Q} \widetilde{P} \widetilde{Q}=\tr(A) \widetilde{P} \widetilde{Q}=\tr(A) A,\] 进一步地 - \[A^{k}=\widetilde{P} \widetilde{Q} \widetilde{P} \widetilde{Q} \cdots \widetilde{P} \widetilde{Q}=\tr(A)^{k-1} \widetilde{P} \widetilde{Q}=\tr(A)^{k-1} A.\] + \[A^{k}=\widetilde{P} \widetilde{Q} \widetilde{P} \widetilde{Q} \cdots \widetilde{P} \widetilde{Q}=\tr(A)^{k-1} \widetilde{P} \widetilde{Q}=\tr(A)^{k-1} A. \qedhere\] \end{proof} 事实上,本题的解答过程给我们了一个很重要的启示,那就是秩为1的矩阵一定可以分解为一个列向量和一个行向量的乘积. 之后我们将利用这一结论来解决一些问题,例如便于矩阵求幂等. 此外,若 $\tr(A) = 1$,则 $A^k = A$,这表明秩为 1 且迹为 1 的矩阵一定是幂等矩阵. diff --git "a/\350\256\262\344\271\211/\344\270\223\351\242\230/9 \347\237\251\351\230\265\350\277\220\347\256\227\350\277\233\351\230\266.tex" "b/\350\256\262\344\271\211/\344\270\223\351\242\230/9 \347\237\251\351\230\265\350\277\220\347\256\227\350\277\233\351\230\266.tex" index 53cb78d..9855783 100644 --- "a/\350\256\262\344\271\211/\344\270\223\351\242\230/9 \347\237\251\351\230\265\350\277\220\347\256\227\350\277\233\351\230\266.tex" +++ "b/\350\256\262\344\271\211/\344\270\223\351\242\230/9 \347\237\251\351\230\265\350\277\220\347\256\227\350\277\233\351\230\266.tex" @@ -440,7 +440,7 @@ \subsection{提逆思想} \begin{proof} 因为没有关于矩阵减法的逆的公式,$(E - A^{-1})^{-1}$ 无法直接化简,我们可以考虑将其提逆,提出一个 $A^{-1}$:$(E-A^{-1})^{-1} = (A^{-1}(A-E))^{-1} = (A-E)^{-1}A$,从而 - \[(E-A^{-1})^{-1}+(E-A)^{-1}=(A-E)^{-1}A+(E-A)^{-1}=(E-A)^{-1}(E-A)=E.\] + \[(E-A^{-1})^{-1}+(E-A)^{-1}=(A-E)^{-1}A+(E-A)^{-1}=(E-A)^{-1}(E-A)=E. \qedhere\] \end{proof} 最后,除了上述介绍的方法之外,在接下来介绍了分块矩阵初等变换之后,我们还会介绍其它与逆矩阵相关的一些技巧. @@ -1258,7 +1258,7 @@ \section{秩等式与不等式} \end{pmatrix}=r\begin{pmatrix} O & -AB \\ BC & B \end{pmatrix} \\ - & \geqslant r(AB)+r(BC). + & \geqslant r(AB)+r(BC). \qedhere \end{align*} \end{proof} diff --git "a/\350\256\262\344\271\211/\345\205\266\345\256\203/\346\234\252\347\253\237\344\270\223\351\242\2301 \351\242\204\345\244\207\346\200\235\346\203\263.tex" "b/\350\256\262\344\271\211/\345\205\266\345\256\203/\346\234\252\347\253\237\344\270\223\351\242\2301 \351\242\204\345\244\207\346\200\235\346\203\263.tex" index f20f9ea..6dddf1d 100644 --- "a/\350\256\262\344\271\211/\345\205\266\345\256\203/\346\234\252\347\253\237\344\270\223\351\242\2301 \351\242\204\345\244\207\346\200\235\346\203\263.tex" +++ "b/\350\256\262\344\271\211/\345\205\266\345\256\203/\346\234\252\347\253\237\344\270\223\351\242\2301 \351\242\204\345\244\207\346\200\235\346\203\263.tex" @@ -46,7 +46,7 @@ \section{数学证明初探} 以高中可能未接触过的两个逻辑运算符$\to$和$\leftrightarrow$为例,其真值表如下: -\begin{center} +\begin{center} % FIXME \begin{minipage}[c]{0.45\textwidth} \centering \begin{tabular}{|c|c|c|} diff --git "a/\350\256\262\344\271\211/\345\216\206\345\271\264\345\215\267/2011-2012-1final-answer.tex" "b/\350\256\262\344\271\211/\345\216\206\345\271\264\345\215\267/2011-2012-1final-answer.tex" index 472c943..b034897 100644 --- "a/\350\256\262\344\271\211/\345\216\206\345\271\264\345\215\267/2011-2012-1final-answer.tex" +++ "b/\350\256\262\344\271\211/\345\216\206\345\271\264\345\215\267/2011-2012-1final-answer.tex" @@ -9,7 +9,7 @@ \section{2011-2012学年线性代数I(H)期末答案} $A(1,-1,0)^\mathrm{T}=(2, a-b, d-e)^\mathrm{T}=\lambda_3(1,-1,0)^\mathrm{T}\implies a-b=-2, d=e$. - 综合上述结果可知 $a=c=-\dfrac{1}{3}, b=\dfrac{5}{3}, d=e=f=\dfrac{1}{3}$. + 综合上述结果可知 $a=c=-\dfrac{1}{3}$,$b=\dfrac{5}{3}$,$d=e=f=\dfrac{1}{3}$. \item \begin{enumerate} diff --git "a/\350\256\262\344\271\211/\347\272\277\346\200\247\344\273\243\346\225\260\350\215\243\350\252\211\350\257\276\350\276\205\345\255\246\350\256\262\344\271\211.tex" "b/\350\256\262\344\271\211/\347\272\277\346\200\247\344\273\243\346\225\260\350\215\243\350\252\211\350\257\276\350\276\205\345\255\246\350\256\262\344\271\211.tex" deleted file mode 100644 index 018c405..0000000 --- "a/\350\256\262\344\271\211/\347\272\277\346\200\247\344\273\243\346\225\260\350\215\243\350\252\211\350\257\276\350\276\205\345\255\246\350\256\262\344\271\211.tex" +++ /dev/null @@ -1,270 +0,0 @@ -\makeatletter - \def\input@path{{..}} % 搜索上层目录的 LALUbook -\makeatother - -\documentclass[ - % colors = false, - geometry = 16k, -]{LALUbook} - -\usepackage{mathdots} -\usepackage{booktabs} % Excel 导出的大表格 -\usepackage{rotating} -\usepackage{extarrows} -\usepackage{blkarray} -\usepackage{cases} - -\usepackage{float} -\usepackage{diagbox} -\usepackage{caption} - -\usepackage{pgfplots} -\usetikzlibrary{cd, arrows, arrows.meta, calc, intersections, decorations.pathreplacing, patterns, decorations.markings,angles,quotes, graphs, positioning, shapes.geometric} -\pgfplotsset{compat=newest} - -\usepackage[xindy, splitindex]{imakeidx} -\makeindex[ - columns=1, - program=truexindy, - intoc=true, - options=-M texindy -I xelatex -C utf8, - title={名词索引} -] % 名词索引 -\makeindex[ - columns=3, - program=truexindy, - intoc=true, - options=-M numeric-sort -M latex -M latex-loc-fmts -M makeindex -I xelatex -C utf8, - name=sym, - title={符号索引} -] % 符号索引 - -% 标题格式 -% \chapter 正常专题 -% \LUchapter 未竟专题 - -\newcounter{LUchapter} -\newcounter{LUgreekchap} - -\makeatletter -% 此处可按需增改 -% \texorpdfstring 的两个参数分别显示在正文中与 PDF 书签中 -\newcommand*{\@LUgreek}[1]{% - \ifcase#1\or\texorpdfstring{$\boldsymbol{\varepsilon}$}{ε}% - \or\texorpdfstring{$\boldsymbol{\delta}$}{δ}% - \or\texorpdfstring{$\boldsymbol{\lambda}$}{λ}% - \or\texorpdfstring{$\boldsymbol{\mu}$}{μ}% - \or\texorpdfstring{$\boldsymbol{\varphi}$}{φ}% - \or\texorpdfstring{$\boldsymbol{\theta}$}{θ}% - \else\@ctrerr\fi% -} -\newcommand*{\LUgreek}[1]{% - \expandafter\@LUgreek\csname c@#1\endcsname -} -\newcommand*{\LUchapsancheck}{% -\expandafter\@ifundefined{@exist@LUchapter@\arabic{chapter}.\arabic{LUgreekchap}}% - {\setcounter{LUgreekchap}{1}} - {\stepcounter{LUgreekchap}} -} -\newcommand*{\LUgroupsancheck}{% -\expandafter\@ifundefined{@exist@LUchapter@\arabic{chapter}}% - {} - {\endgroup} -} -\let\@std@chapter\chapter -\renewcommand*{\chapter}{% - \LUgroupsancheck% - \@std@chapter -} -\let\@std@chaptermark\chaptermark -\def\chaptermark#1{\def\@LALU@chaptername{#1}\@std@chaptermark{#1}} -\makeatother - -% 内容总结 -\newenvironment{summary}{% - \hypersetup{bookmarksnumbered=false}% - \titleformat{\subsection}[block]{\centering\heiti\Large}{}{1em}{}% - \phantomsection% - \subsection*{内容总结}% -}{} - -% 习题环境 -% \begin{exercise} -% \exquote[somebody]{...} -% \begin{exgroup} -% \item ... -% \item ... -% \end{exgroup} -% \begin{exgroup} -% ... -% \end{exgroup} -% \end{exercise} -\newcounter{exgroupcounter} -\ExplSyntaxOn -\newenvironment{exercise}{ - \iow_now:Nx \g_lalu_ans_iow { \cs_if_exist:cTF { @exist@LUchapter@\arabic{chapter} } { \exp_not:N \setcounter{LUsection}{ \theLUchapter-1 } \exp_not:N \LUsection } { \exp_not:N \setcounter{section}{ \thechapter-1 } \exp_not:N \section } { \cs:w @LALU@chaptername \cs_end: } } - \setcounter{exgroupcounter}{0} - \NewDocumentEnvironment{exgroup}{o}{ - \IfValueTF{##1}{ - \setcounter{exgroupcounter}{##1} - }{ - \refstepcounter{exgroupcounter} - } - \subsection*{\Alph{exgroupcounter}组} - \begin{enumerate} - }{ - \end{enumerate} - \seq_if_empty:NF \g_lalu_ans_seq { - \iow_now:Nx \g_lalu_ans_iow { \exp_not:N \subsection*{ \Alph{exgroupcounter} 组 } \exp_not:N \begin{enumerate} } - \seq_map_tokens:Nn \g_lalu_ans_seq { \iow_now:Nn \g_lalu_ans_iow } - \iow_now:Nn \g_lalu_ans_iow { \end{enumerate} } - } - \seq_gclear:N \g_lalu_ans_seq - } - \NewDocumentEnvironment{answer}{+b}{}{ - \seq_gput_right:Nx \g_lalu_ans_seq { \exp_not:N \item [\theenumi.] \tl_to_str:n { ##1 } } - } - \NewDocumentCommand{\exquote}{om}{ - \vspace{2ex} - {\sffamily\kaishu ##2} - \IfValueT{##1}{ - \begin{flushright} - \sffamily\kaishu ——##1 - \end{flushright} - } - } - \hypersetup{bookmarksnumbered=false} - \titleformat{\section}[block]{\centering\heiti\Large}{}{1em}{} - \titleformat{\subsection}[block]{\centering\heiti\bfseries}{}{1em}{} - \phantomsection - \section*{习题} - \addcontentsline{toc}{section}{习题} -}{ - \iow_now:Nn \g_lalu_ans_iow { \clearpage } -} -\seq_new:N \g_lalu_ans_seq % stores the answers, shipped at the end of the exgroup -\iow_new:N \g_lalu_ans_iow -\iow_open:Nn \g_lalu_ans_iow { LALU-ans-contents.tex } -\AtEndDocument{ -\iow_close:N \g_lalu_ans_iow -} -\ExplSyntaxOff - -\NewDocumentCommand{\LUchapter}{m}{% -\LUgroupsancheck -\begingroup -\LUchapsancheck -\addtocounter{chapter}{-1} -\refstepcounter{LUchapter} -\renewcommand*{\thechapter}{\arabic{chapter}\LUgreek{LUgreekchap}} -\renewcommand*{\theHchapter}{LU.\arabic{LUchapter}} -\ctexset{ - chapter={format={\centering\Huge\bfseries},name={未竟专题,},number={\zhnumber{\arabic{LUchapter}}}}, -} -\csname @std@chapter\endcsname{#1} -\expandafter\xdef\csname @exist@LUchapter@\arabic{chapter}\endcsname{\null} -\expandafter\xdef\csname @exist@LUchapter@\arabic{chapter}.\arabic{LUgreekchap}\endcsname{\null} -} - -\ctexset{ - chapter={format={\centering\Huge\bfseries},name={第,讲},number=\arabic{chapter}}, - section={format={\raggedright\Large\bfseries},name={,},number={\thechapter.\arabic{section}}}, - subsection={format={\raggedright\large\bfseries},name={,},number={\thesection.\arabic{subsection}}}, - subsubsection={format={\raggedright\normalsize\bfseries},name={,},number={\thesubsection.\arabic{subsubsection}}}, -} - -\title{\heiti 浙江大学 2023--2024 学年 \\ 线性代数荣誉课辅学讲义} -\author{2023--2024 学年线性代数 I/II(H)辅学授课 \\ 吴一航 \quad \verb|yhwu_is@zju.edu.cn|} - -\AtEndPreamble{\hypersetup{ - hypertexnames=true, - pdfauthor={吴一航}, - pdftitle={线性代数荣誉课辅学讲义}, -}} - -\begin{document} -\frontmatter - -% 封面,代替 \maketitle -\includepdf[ - pages={1}, - noautoscale=true, - trim=0 0 0 10mm, - clip, -]{./figs/cover-16k.pdf} - -\songti - -% 插入空页 -\thispagestyle{empty} -\null -\clearpage - -\input{./其它/扉页.tex} -\clearpage - -\pagenumbering{Roman} -\input{./其它/序.tex} -\input{./其它/致读者.tex} -\clearpage - -\pdfbookmark[0]{目录}{contents} -\tableofcontents - -\addtolength{\parskip}{.5em} - -\mainmatter -\input{./专题/1 预备知识.tex} -\input{./其它/未竟专题1 预备思想.tex} -\input{./专题/2 线性空间.tex} -\input{./专题/3 有限维线性空间.tex} -\input{./专题/4 线性空间的运算.tex} -\input{./专题/5 线性映射.tex} -\input{./专题/6 对偶空间.tex} -\input{./专题/7 线性映射矩阵表示与矩阵运算基础.tex} -\input{./专题/8 相抵标准形.tex} -\input{./专题/9 矩阵运算进阶.tex} -\input{./其它/未竟专题2 有限域上的矩阵.tex} -\input{./专题/10 行列式.tex} -\input{./其它/未竟专题3 矩阵空间.tex} -\input{./专题/11 朝花夕拾.tex} -\input{./其它/未竟专题4 特定域上的线性代数.tex} -\input{./专题/12 史海拾遗.tex} -\input{./专题/13 多项式.tex} -\input{./其它/未竟专题5 纽结的多项式不变量.tex} -\input{./专题/14 相似标准形:动机与基础.tex} -\input{./其它/未竟专题6 控制法及其在矩阵理论中的应用.tex} -\input{./专题/15 相似标准形:复数域上的尝试与理论.tex} -\input{./专题/16 若当标准形.tex} -\input{./专题/17 多项式的进一步讨论.tex} -\input{./专题/18 有理标准形.tex} -\input{./其它/未竟专题7 对称多项式和Young图.tex} -\input{./专题/19 内积空间.tex} -\input{./专题/20 内积空间上的算子.tex} -\input{./其它/未竟专题8 希尔伯特空间引论.tex} -\input{./专题/21 线性代数与几何.tex} -\input{./专题/22 二次型.tex} -\input{./专题/23 多重线性映射与张量的计算.tex} -\input{./其它/未竟专题9 射影几何的代数方法.tex} -\input{./其它/未竟专题10 有限域上的二次型.tex} -\input{./其它/未竟专题11 二次型的几何.tex} -\input{./其它/未竟专题12 实数域的诸扩域.tex} -\input{./其它/未竟专题13 线性动力系统.tex} -\input{./专题/24 线性代数与微积分.tex} -\input{./专题/25 线性代数与最优化问题.tex} -\input{./其它/未竟专题14 范畴论视角下的线性代数.tex} - -\LUgroupsancheck - -\makeatletter -\let\chapter\@std@chapter -\let\@std@chapter\relax -\makeatother - -\backmatter -{\small -\printindex -\printindex[sym] -} - -\end{document}