通过例子学TLA+(十一)--命题逻辑与实例

命题逻辑与实例

逻辑符在之前的例子中已经用过了,主要是 \A ,\E, => 等符号。

\E

E是"exists"的首字母,意思是存在。当写下 \E x \in S : P(x) 意味着在S中至少存在一个x使得P为真。采用\E 开头的表达式返回值是布尔类型。

\E x \in {1,2} : x > 0  为 true
\E x \in {} : x > 0  为 false

\E 是存在一个满足条件的元素的意思,~\E 则是不存在满足条件的元素

\A

A的"All"的首字母,当写下 \A x \in S : P(x) 意味着对于S中的所有元素,P都为真。 当存在一个元素使得P为假时,则表达式返回FALSE。

\A x \in {} : FALSE  = TRUE  

~\A 与 \A 的意思相反。

=> 和 <=>

P => Q 意思是 如果P为真,那么Q也为真。注意:P为假时,Q也可以为真。在TLC中 P => Q 等价于 ~P / Q。

P <=> Q 意思是 P和Q同为真或者同为假。 相当于 (~P /\ ~Q) / (P /\ Q)

注意:=> 与 <=> 作为逻辑连接符,与/\和\/有着同样的优先级,缩进规则也相同。

实例

1、给定一个数字集合S和一个数字N,定义一个表达式,返回是否能在S中找到N个元素使得这N个元素的和为0。

\* 可以将题目分解为:1、从S中找到一个子集,2 子集的长度为N,3,求子集的元素之和 4、存在一个子集,元素之和等于0
\* 找到一个子集长度为N的集合的集合
Op2(S,n) == { e \in SUBSET S : Cardinality(e) = n }
\* 求集合元素之和
RECURSIVE Sum(_)
Sum(S) == IF S = {} THEN 0
          ELSE LET x == CHOOSE x \in S : TRUE
                         IN  x + Sum(S \ {x})
\* 定义表达式
Sum2Zero(S,N) == \E e \in Op2(S,N) : Sum(e)=0

2、给定一个表达式Op(,_) 和一个集合S,定义一个表达式,返回表达式对于集合S中的所有元素是否可交换。例如 IsCommutative(Add(_,_),{1,2}) = TRUE ,因为Add(1,2) 和 Add(2,1) 相等。

IsCommutative(Op(_,_), S) == \A x \in S, y \in S : Op(x,y) = Op(y,x)

3、给定一个集合,返回集合中最大的数

Max(S) == CHOOSE x \in S : \A y \in S : y <= x 
\* 注意这里判断必须是<= ,不能是<。因为不存在一个数比自身还大。

4、给定一个集合S,如果集合中元素p是素数,p-2是素数或者p+2是素数,则p是孪生素数。求S中最大的孪生素数。

\* 1、求一个数是否为素数
IsPrime(x) == x > 1 /\ ~\E d \in 2..(x-1) : x % d = 0
\* 2、求一个数是否为孪生素数
IsTwinPrime(a) == /\ IsPrime(a) /\ (IsPrime(a-2) \/ IsPrime(a+2))
\* 3、求孪生素数的集合
GetTwinPrime(S) == { a \in S : IsTwinPrime(a)}
\* 4、求最大孪生素数
LargestTwinPrime(S) == CHOOSE x \in GetTwinPrime(S): \A y \in GetTwinPrime(S) : x >=y 

5、返回上述集合中最大的一对孪生素数,如果缺少一个孪生素数,则该对无效。例如:{3,5,13}的最大孪生素数对是<<3,5>>,因为13的孪生素数11不在集合中。

\* 1、从孪生素数集合中求孪生素数对的集合,如果a,a+2都在集合中,则保留a。
GetPairTwinPrime(S) == { a \in GetTwinPrime(S): a+2 \in GetTwinPrime(S)}
\* 2、从孪生素数对集合中找出最大的值x,那<<x,x+2>>就是所求
LargestPariTwinPrime(S) == LET x == CHOOSE x \in GetPairTwinPrime(S) : 
						     \A y \in GetPairTwinPrime(S) : x >=y
                           	IN <<x,x+2>>

6、给定正整数元组stockprices用来表示一天中股票价值的变化,编写一个运算符来确定可以获得的最大利润,假设只能先买在卖而且最多买卖一次。

\* 只能买卖1次,只需要找到两个数之差最大即可,
\* 只能先买后买,需要用后面的数减去前面的数
\* 1、将元组转化为元组对,且第一个元素在第二个元素的前面
\* 例如<<1,2,3>> 转化为 <<1,2>>,<<1,3>>,<<2,3>>等价于{1} \X {2,3} \union {2} \X {3} 
RECURSIVE newSxS(_)
newSxS(S) == IF Len(S) > 1 
                THEN LET newset== <<{Head(S)},{S[t]:t \in 2..Len(S)}>>
                       IN newset[1] \X newset[2] \union  newSxS(Tail(S))
                      
             ELSE {}
\* 从二元集合中选择<<x,y>>中差值最大的即可             
MaxProfit(stockprices) == LET sxs == newSxS(stockprices)
                             IN LET res == CHOOSE <<x,y>> \in sxs: 
                                         \A <<a,b>> \in sxs : y-x >= b-a 
                                IN IF res[2]-res[1] > 0 THEN res[2]-res[1]
                                   ELSE 0  \* 如果没有利润就不操作。如果必须买卖一次,则返回res[2]-res[1]即可
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值