- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试使用SBV Library解决Haskell中涉及祖先关系的以下csp (7.12 版):
给我所有不是斯蒂芬后裔的人的集合。
我的解决方案(见下文)出现以下异常
*** Exception: SBV.Mergeable.List: No least-upper-bound for lists of differing size (1,0)
问题:是否可以使用 SBV/使用 SMT 求解器来解决这样的约束,如果 - 我需要如何制定问题?
我尝试的解决方案:
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveAnyClass #-}
module Main where
import Data.SBV
data Person
= Mary
| Richard
| Claudia
| Christian
| Stephen
mkSymbolicEnumeration ''Person
-- symbolic shorthands for person constructors
[mary, richard, claudia, christian, stephen] =
map literal [Mary, Richard, Claudia, Christian, Stephen]
childOf :: [(Person, Person)]
childOf = [
(Mary, Richard) ,
(Richard, Christian),
(Christian, Stephen)]
getAncestors :: Person -> [Person]
getAncestors p = go childOf p []
where
go [] _ acc = nub acc
go ((p1, p2): rels) a acc
| p1 == p = go rels p (p2:acc) ++ getAncestors p2
| otherwise = go rels a acc
-- symbolic version of getAncestors
getSAncestors :: SBV Person -> [SBV Person]
getSAncestors p = ite (p .== mary) (map literal (getAncestors Mary))
$ ite (p .== richard) (map literal (getAncestors Richard))
$ ite (p .== claudia) (map literal (getAncestors Claudia))
$ ite (p .== christian) (map literal (getAncestors Christian))
(map literal (getAncestors Stephen))
cspAncestors :: IO AllSatResult
cspAncestors = allSat $ do
(person :: SBV Person) <- free_
constrain $ bnot $ stephen `sElem` (getSAncestors person)
非常感谢!
最佳答案
不幸的是,您从 SBV 收到的错误消息确实很神秘,这并没有真正的帮助。我刚刚向 github 推送了一个补丁,我希望新的错误消息会好一点:
*** Exception:
*** Data.SBV.Mergeable: Cannot merge instances of lists.
*** While trying to do a symbolic if-then-else with incompatible branch results.
***
*** Branches produce different sizes: 1 vs 0
***
*** Hint: Use the 'SList' type (and Data.SBV.List routines) to model fully symbolic lists.
SBV 试图告诉您的是,当您有一个符号 if-then-else(如在您的 getSAncestor
函数中)时,它会返回 Haskell 列表 SBV Person
的,那么它无法合并这些分支,除非 ite
的每个分支具有完全相同的元素数量。
当然,您可能会问为什么会有这样的限制。考虑以下表达式:
ite cond [s0, s1] [s2, s3, s4]
直观上,这应该意味着:
[ite cond s0 s2, ite cond s1 s3, ite cond ??? s4]
不幸的是,SBV 没有任何东西可以替代 ???
,因此会出现错误消息。我希望这是有道理的!
SBV实际上有两种方式来表示符号项列表。一个是一个很好的旧 Haskell 符号值列表,正如您所使用的;它受到我上面为每个符号项目描述的基数约束。另一个是完全符号列表,映射到 SMTLib 序列。请注意,在这两种情况下,列表的大小都是任意但有限的,但是我们是否以符号方式处理列表的主干是有区别的。
当您使用像[SBV a]
这样的类型时,您本质上是在说“这个列表的主干是具体的,而元素本身是象征性的”。当您确切知道每个分支将有多少个元素并且它们都具有完全相同的大小时,此数据类型最合适。
这些列表通过后端映射到更简单的表示,本质上“列表”部分全部在 Haskell 中处理,并且元素以符号方式逐点表示。这允许使用许多 SMT 求解器,甚至是那些不理解符号序列的求解器。另一方面,正如您发现的那样,您不能拥有象征性的脊柱。
正如您所猜到的,第二种列表的主干本身是符号性的,因此可以支持任意的ite条件而没有基数限制。这些直接映射到 SMTLib 序列,并且更加灵活。缺点是,并非所有 SMT 求解器都支持序列,并且序列逻辑通常不可判定,因此如果查询超出其算法可以处理的范围,求解器可能会响应未知
。 (另一个缺点是 z3 和 cvc4 支持的序列逻辑相当不成熟,因此求解器本身可能存在错误。但这些错误总是可以报告的!)
要解决您的问题,您只需使用 SBV 的脊柱符号列表(称为 SList
)即可。您的示例程序所需的修改相对简单:
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE ScopedTypeVariables #-}
import Data.SBV
import Data.List
import Data.SBV.List as L
data Person
= Mary
| Richard
| Claudia
| Christian
| Stephen
mkSymbolicEnumeration ''Person
-- symbolic shorthands for person constructors
[mary, richard, claudia, christian, stephen] =
map literal [Mary, Richard, Claudia, Christian, Stephen]
childOf :: [(Person, Person)]
childOf = [
(Mary, Richard) ,
(Richard, Christian),
(Christian, Stephen)]
getAncestors :: Person -> [Person]
getAncestors p = go childOf p []
where
go [] _ acc = nub acc
go ((p1, p2): rels) a acc
| p1 == p = go rels p (p2:acc) ++ getAncestors p2
| otherwise = go rels a acc
-- symbolic version of getAncestors
getSAncestors :: SBV Person -> SList Person
getSAncestors p = ite (p .== mary) (literal (getAncestors Mary))
$ ite (p .== richard) (literal (getAncestors Richard))
$ ite (p .== claudia) (literal (getAncestors Claudia))
$ ite (p .== christian) (literal (getAncestors Christian))
(literal (getAncestors Stephen))
cspAncestors :: IO AllSatResult
cspAncestors = allSat $ do
(person :: SBV Person) <- free "person"
constrain $ sNot $ L.singleton stephen `L.isInfixOf` (getSAncestors person)
(注意:我必须将 bnot
更改为 sNot
,因为我使用的是 hackage 提供的 SBV 8.0;该名称已更改。如果您使用的是 7.12 ,您应该保留 bnot
。另请注意 SList Person
的使用,而不是 [SBV Person]
,它告诉 SBV 使用 spin 符号列表。)
当我运行这个时,我得到:
*Main> cspAncestors
Solution #1:
person = Claudia :: Person
Solution #2:
person = Stephen :: Person
Found 2 different solutions.
我还没有真正检查过答案是否正确,但我相信应该是正确的! (如果没有,请报告。)
我希望能够概述该问题以及如何解决它。虽然 SMT 求解器无法击败自定义 CSP 求解器,但我认为当您没有专用算法时,它可能是一个很好的替代方案。希望 Haskell/SBV 让它更容易使用!
关于haskell - 尝试用SBV解决祖先关系的约束,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54352167/
使用 SBV 库,我试图满足状态符号列表上的条件: data State = Intro | Start | Content | Comma | Dot mkSymbolicEnumeration '
我的数据类型如下 data X = X {foo :: SInteger, bar :: SInteger} 我想证明例如 forAll_ $ \x -> foo x + bar x .== bar
我有这个定理(不确定这个词是否正确),并且我想得到所有的解决方案。 pairCube limit = do m Symbolic SBool pairCube limit = do
我的数据类型如下 data X = X {foo :: SInteger, bar :: SInteger} 我想证明例如 forAll_ $ \x -> foo x + bar x .== bar
我正在使用 SBV (使用 Z3 后端)在 Haskell 中创建一些理论证明。我想检查一下是否为 x和 y在给定的约束条件下(如 x + y = y + x ,其中 + 是“加号运算符”,而不是加法
假设一棵树,其中节点可能存在也可能不存在,我想生成一个公式,其中: 每个节点都有一个 bool 变量(表示它是否存在), 根(如果空闲)(可能存在也可能不存在),并且 只有当其父节点存在时,节点才能存
以下代码(使用 SBV): {-# LANGUAGE ScopedTypeVariables #-} import Data.SBV main :: IO () main = do res =
我看到很多使用 SBV 库的示例,如下所示: f :: IO SatResult f = sat $ do x IO SatResult f i = sat $ do
为了学习 Z3,我尝试使用 Haskell 绑定(bind) sbv 解决我最喜欢的代码出现问题之一(一个特别困难的问题,2018 day 23, part 2)。 .前面代码中的剧透... modu
在 my last question我问我如何解析一个命题表达式,然后在 SBV 库的帮助下找到公式的所有模型。我使用 hatt 库来解析 bool 表达式。 不幸的是,SBV 似乎不适合相当快速的
我想解析 String它描述了一个命题公式,然后使用 SAT 求解器找到该命题公式的所有模型。 现在我可以用 hatt 解析一个命题公式包裹;见testParse下面的功能。 我还可以使用 SBV 库
我是一名优秀的程序员,十分优秀!