在 Isabelle 中使用 simprocs 重写正弦
Rewriting sine using simprocs in Isabelle
我想实现一个能够将 sin 的参数重写为线性组合 x + k * pi + k' * pi / 2(理想情况下 k' = 0 或 k' = 1)的 simproc,然后应用关于在正弦中添加参数的现有引理。
步骤如下:
- 模式匹配目标以提取 sin(expr) 的参数:
fun dest_sine t =
case t of
(@{term "(sin):: real ⇒ real"} $ t') => t'
| _ => raise TERM ("dest_sine", [t]) ;
证明对于某些 x, k, k': expr = x + k*pi + k' * pi/2.
使用现有引理重写为更简单的三角函数:
fun rewriter x k k' =
if (k mod 2 = 0 andalso k' = 0) then @{term "sin"} $ x
else if (k mod 2 = 0 andalso k' = 1) then @{term "cos"} $ x
else if (k mod 2 = 1 andalso k' = 0) then @{term "-sin"} $ x
else @{term "-cos"} $ x
我卡在了第二步。这个想法是使用代数简化来获得定理成立的 x,k,k'。我相信原理图目标应该可以做到这一点,但我从未使用过它们。
我的想法
我是否可以假设表达式是这种形式,让简化器找到它,以便触发 simproc?
如果我首先开始假设线性形式 x + k*pi + k' * pi/2 那么:
- 从此组合中提取 x,k,k'。
- 申请rewriter,获取对应的待改写term 2
- 按顺序应用:处理 + pi/2 的规则,处理 + 2 pi
的规则
我会从简单开始,暂时忽略 pi / 2
部分。
您可能想要构建一个匹配任何形式 sin x
的 simproc。然后你想写一个 conversion 接受那个术语 x
(假设它是几个术语的总和)并将它变成 a + of_int b * p
的形式。
转换本质上是一个类型为 cterm → thm
的函数,它采用 cterm ct
和 returns 形式为 ct ≡ …
的定理,即它是一种确定性形式重写(按照惯例,转换也可能因抛出 CTERM
异常而失败)。在 Pure/conv.ML
.
中有很多用于构建和使用它们的组合器
这可能有点繁琐。你基本上必须通过这个术语下降,并且对于每个原子(即任何不是 _ + _
形式的东西)你必须弄清楚它是否可以被带入 of_int … * pi
形式(例如再次通过写一个进行这种转换的转换——为了简单起见,您可以省略这部分,这样您的过程仅在术语已经采用该形式时才有效)然后将 of_int … * pi
形式的所有术语分组到右边,所有使用结合律和交换律向左不是那种形式的项。
我建议这样做:
- 定义函数
SIN_SIMPROC_ATOM x n = x + of_int n * pi
- 编写一个转换
sin_atom_conv
,将 of_int n * pi
重写为 SIN_SIMPROC_ATOM 0 n
并将其他所有内容重写为 SIN_SIMPROC_ATOM x 0
- 写一个通过
+
下降的转换,将 sin_atom_conv
应用于每个原子,然后应用某种组合规则,如 SIN_SIMPROC_ATOM x1 n1 + SIN_SIMPROC_ATOM x2 n2 = SIN_SIMPROC_ATOM (x1 + x2) (n1 + n2)
- 最后,您已将整个表单重写为
sin (SIN_SIMPROC_ATOM x n)
表单,然后您可以对其应用一些合适的规则。
我不太清楚如何最好地处理 n
的奇偶校验。您可以重写 sin (SIN_SIMPROC_ATOM x n) = (-1) ^ nat ¦n¦ * sin x
但我不确定在大多数情况下这是否是用户真正想要的。如果您可以静态地推导出 n
的奇偶校验(例如,通过使用简化器)然后直接简化为 sin x
或 -sin x
.[=41=,那么这样做可能更有意义]
如果你想包括 π 的一半,情况会变得更加复杂。您当然可以将 SIN_SIMPROC_ATOM
扩展为 π 的一半(以及 π 的两倍,以使其更统一)。或者你可以将它们全部加在一起,这样你就只有一个整数 n
来描述你的 π/2 的倍数,而 k
个 π 的倍数简单地为该项贡献 2k
。然后你必须弄清楚 n mod 4
是什么——可能再次使用简化器或一些聪明的静态方法。
我想实现一个能够将 sin 的参数重写为线性组合 x + k * pi + k' * pi / 2(理想情况下 k' = 0 或 k' = 1)的 simproc,然后应用关于在正弦中添加参数的现有引理。
步骤如下:
- 模式匹配目标以提取 sin(expr) 的参数:
fun dest_sine t =
case t of
(@{term "(sin):: real ⇒ real"} $ t') => t'
| _ => raise TERM ("dest_sine", [t]) ;
证明对于某些 x, k, k': expr = x + k*pi + k' * pi/2.
使用现有引理重写为更简单的三角函数:
fun rewriter x k k' =
if (k mod 2 = 0 andalso k' = 0) then @{term "sin"} $ x
else if (k mod 2 = 0 andalso k' = 1) then @{term "cos"} $ x
else if (k mod 2 = 1 andalso k' = 0) then @{term "-sin"} $ x
else @{term "-cos"} $ x
我卡在了第二步。这个想法是使用代数简化来获得定理成立的 x,k,k'。我相信原理图目标应该可以做到这一点,但我从未使用过它们。
我的想法
我是否可以假设表达式是这种形式,让简化器找到它,以便触发 simproc?
如果我首先开始假设线性形式 x + k*pi + k' * pi/2 那么:
- 从此组合中提取 x,k,k'。
- 申请rewriter,获取对应的待改写term 2
- 按顺序应用:处理 + pi/2 的规则,处理 + 2 pi 的规则
我会从简单开始,暂时忽略 pi / 2
部分。
您可能想要构建一个匹配任何形式 sin x
的 simproc。然后你想写一个 conversion 接受那个术语 x
(假设它是几个术语的总和)并将它变成 a + of_int b * p
的形式。
转换本质上是一个类型为 cterm → thm
的函数,它采用 cterm ct
和 returns 形式为 ct ≡ …
的定理,即它是一种确定性形式重写(按照惯例,转换也可能因抛出 CTERM
异常而失败)。在 Pure/conv.ML
.
这可能有点繁琐。你基本上必须通过这个术语下降,并且对于每个原子(即任何不是 _ + _
形式的东西)你必须弄清楚它是否可以被带入 of_int … * pi
形式(例如再次通过写一个进行这种转换的转换——为了简单起见,您可以省略这部分,这样您的过程仅在术语已经采用该形式时才有效)然后将 of_int … * pi
形式的所有术语分组到右边,所有使用结合律和交换律向左不是那种形式的项。
我建议这样做:
- 定义函数
SIN_SIMPROC_ATOM x n = x + of_int n * pi
- 编写一个转换
sin_atom_conv
,将of_int n * pi
重写为SIN_SIMPROC_ATOM 0 n
并将其他所有内容重写为SIN_SIMPROC_ATOM x 0
- 写一个通过
+
下降的转换,将sin_atom_conv
应用于每个原子,然后应用某种组合规则,如SIN_SIMPROC_ATOM x1 n1 + SIN_SIMPROC_ATOM x2 n2 = SIN_SIMPROC_ATOM (x1 + x2) (n1 + n2)
- 最后,您已将整个表单重写为
sin (SIN_SIMPROC_ATOM x n)
表单,然后您可以对其应用一些合适的规则。
我不太清楚如何最好地处理 n
的奇偶校验。您可以重写 sin (SIN_SIMPROC_ATOM x n) = (-1) ^ nat ¦n¦ * sin x
但我不确定在大多数情况下这是否是用户真正想要的。如果您可以静态地推导出 n
的奇偶校验(例如,通过使用简化器)然后直接简化为 sin x
或 -sin x
.[=41=,那么这样做可能更有意义]
如果你想包括 π 的一半,情况会变得更加复杂。您当然可以将 SIN_SIMPROC_ATOM
扩展为 π 的一半(以及 π 的两倍,以使其更统一)。或者你可以将它们全部加在一起,这样你就只有一个整数 n
来描述你的 π/2 的倍数,而 k
个 π 的倍数简单地为该项贡献 2k
。然后你必须弄清楚 n mod 4
是什么——可能再次使用简化器或一些聪明的静态方法。