我喜欢你的方法,但我认为你通过定义自己的排序,特别是使用数组理论,使情况变得过于复杂。
Also, mathematically, the integer theories are harder than their real counterparts. For example "n = pq, solve for p" is trivial if n, p, and q are reals, but if they're integers then it's integer factoring, which is hard. Similarly xn + yn = zn, n > 2 is easy to solve in the reals, but in the integers, that's Fermat's last theorem. These examples are nonlinear, but I claim you're better-off to be in QF_LRA than QF_LIA, if you consider that the techniques used to solve QF_LRA are taught to middle-school and high-school students. Time is closer to a real number than it is to a bunch of integers, anyway.
根据我对 SMT 求解器(特别是 Z3)的经验,您最好使用更简单的理论。它将允许 Z3 使用其最强大的内部求解器。如果您使用更复杂的理论(例如数组),您可能会得到惊人的结果,或者您可能会发现求解器超时并且您不知道原因,就像您提出的解决方案的情况一样。
从软件工程的角度来看,这并不那么好,但从数学上来说,我建议对您提出的问题使用以下简单的解决方案,其中所有时间都表示为实数,以感兴趣的日期午夜以来的秒数表示:
; Output all real-valued numbers in decimal-format.
(set-option :pp.decimal true)
; Convenience function for converting hh:mm:ss formatted times to seconds since midnight.
(define-fun time_hms ((hour Real) (minute Real) (second Real)) Real
(+ (+ (* 3600.0 hour) (* 60.0 minute)) second)
)
; Convenience function for converting durations in minutes to seconds.
(define-fun duration_m ((minute Real)) Real
(* 60.0 minute)
)
; Variable declarations. Durations are in seconds. Times are in seconds since midnight.
(declare-fun write_start () Real)
(declare-fun write_end () Real)
(declare-fun write_duration () Real)
(declare-fun check_start () Real)
(declare-fun check_end () Real)
(declare-fun check_duration () Real)
(declare-fun phone_start () Real)
; Constraints.
; 1. John started writing an essay at 13:03:41, and it took him 20 min to complete it.
(assert (= write_start (time_hms 13 03 41)))
(assert (= write_duration (duration_m 20)))
(assert (= write_end (+ write_start write_duration)))
; 2. After writing, he checked his emails, which took him more than 40 min.
(assert (> check_start write_end))
(assert (> check_duration (duration_m 40)))
(assert (= check_end (+ check_start check_duration)))
; 3. After checking his emails, he phoned his wife.
(assert (> phone_start check_end))
; 4. He phoned his wife after 14:00:00.
(assert (> phone_start (time_hms 14 00 00)))
(check-sat)
(get-value (write_start write_duration write_end check_start check_end check_duration phone_start))
(exit)
Z3和CVC4都很快找到了解决方案:
sat
((write_start 47021.0)
(write_duration 1200.0)
(write_end 48221.0)
(check_start 48222.0)
(check_end 50623.0)
(check_duration 2401.0)
(phone_start 50624.0))