如何将这些附加约束添加到我的零售产品/购物Z3规范中?
所以我创建了一个基本的Z3规范来指导我购买一些特定的零售产品。到目前为止,它所能做的只是在不超过我可用资金的情况下任意告诉我该买什么:如何将这些附加约束添加到我的零售产品/购物Z3规范中?,z3,Z3,所以我创建了一个基本的Z3规范来指导我购买一些特定的零售产品。到目前为止,它所能做的只是在不超过我可用资金的情况下任意告诉我该买什么: (declare-datatypes () ((Retailer FooMart BazTrading))) (declare-datatypes () ((Cartridge .223Rem .7.62x39mm))) (declare-datatypes () ((Casing Brass Steel))) (declare-datatypes () ((O
(declare-datatypes () ((Retailer FooMart BazTrading)))
(declare-datatypes () ((Cartridge .223Rem .7.62x39mm)))
(declare-datatypes () ((Casing Brass Steel)))
(declare-datatypes () ((Offer (Offer
(getRetailer Retailer)
(getCartridge Cartridge)
(getRounds Int) ; # of rounds
(getPrice Int) ; price in cents
(getCasing Casing)
(getQuantityAvail Int)
))))
(declare-const x1 Offer)
(declare-const x2 Offer)
(declare-const x3 Offer)
(declare-const x4 Offer)
(declare-const x5 Offer)
(assert (= x1 (Offer FooMart .223Rem 1000 17000 Steel 50)))
(assert (= x2 (Offer BazTrading .223Rem 500 13000 Brass 10)))
(assert (= x3 (Offer FooMart .7.62x39mm 1000 18000 Steel 15)))
(assert (= x4 (Offer BazTrading .7.62x39mm 100 1850 Steel 20)))
(assert (= x5 (Offer BazTrading .7.62x39mm 20 190 Steel 20)))
; the quantity purchased of each offer/product will be
; between 0 and the max quantity of the offer
(declare-const x1Qty Int)
(assert (>= x1Qty 0))
(assert (<= x1Qty (getQuantityAvail x1)))
(declare-const x2Qty Int)
(assert (>= x2Qty 0))
(assert (<= x2Qty (getQuantityAvail x2)))
(declare-const x3Qty Int)
(assert (>= x3Qty 0))
(assert (<= x3Qty (getQuantityAvail x3)))
(declare-const x4Qty Int)
(assert (>= x4Qty 0))
(assert (<= x4Qty (getQuantityAvail x4)))
(declare-const x5Qty Int)
(assert (>= x5Qty 0))
(assert (<= x5Qty (getQuantityAvail x5)))
; let's say i've got $500 to spend
(declare-const moneyToSpend Int)
(assert (= moneyToSpend 50000))
(declare-const amountSpent Int)
(assert (= amountSpent
(+ (* x1Qty (getPrice x1))
(* x2Qty (getPrice x2))
(* x3Qty (getPrice x3))
(* x4Qty (getPrice x4))
(* x5Qty (getPrice x5)))
))
(assert (< amountSpent moneyToSpend))
(maximize amountSpent)
(check-sat)
(get-model)
也许更好的例子是尝试实施批量折扣。假设我想获取优惠的批量折扣x1
:
; at this point i'm hardcoding prices in a bag-on-the-side
; function instead of in the x1 Offer itself :/
(define-fun x1Pricing ((qty Int)) Int
(if (>= 10 qty)
(* qty 16500)
(if (>= 5 qty)
(* qty 16800)
(* qty (getPrice x1))))
)
(declare-const amountSpent Int)
(assert (= amountSpent
(+ (x1Pricing x1Qty)
(* x2Qty (getPrice x2))
(* x3Qty (getPrice x3))
(* x4Qty (getPrice x4))
(* x5Qty (getPrice x5)))
))
(assert (< amountSpent moneyToSpend))
(注意,该模型在rise4fun在线编辑器中并不令人满意,但在使用最新Z3源代码的本地机器上运行良好)
现在我真的认为我做错了什么,因为
shippingCost
总是12600。当我摆弄amountspend
max和min值断言,试图让它只使用BazTrading或FooMart提供的服务(以降低运输成本)时,它会挂起几分钟,然后我将其终止 SMTLib不适合编写此类规范。它应该更多地被视为一种“汇编”语言,并且应该从其他工具生成。这就是高级API的用武之地,具体取决于您选择的语言。有高级绑定从C、C++、java、python、Haskell、斯卡拉…您基本上应该使用这些API来生成约束,并通过API使用z3。每个绑定都有自己的优缺点,所以我建议您从您最熟悉的主机语言开始,并使用它 好的,谢谢,我会在更高级别的绑定中重写,如果还有问题,我会回来。你可能想看看这种问题是否可以用Minizin语言表达,这是一种非常高级的语言。在这种情况下,您仍然可以使用OptiMathSAT从MiniZin模型开始生成问题的SMT-LIB编码。生成的SMT-LIB公式可以用z3求解。@PatrickTrentin我非常欣赏Patrick的指针。我甚至不特别需要使用Z3,只是在谷歌搜索之后,它似乎是约束求解的一个流行选择。迷你锌看起来很棒;我要试一试!
; at this point i'm hardcoding prices in a bag-on-the-side
; function instead of in the x1 Offer itself :/
(define-fun x1Pricing ((qty Int)) Int
(if (>= 10 qty)
(* qty 16500)
(if (>= 5 qty)
(* qty 16800)
(* qty (getPrice x1))))
)
(declare-const amountSpent Int)
(assert (= amountSpent
(+ (x1Pricing x1Qty)
(* x2Qty (getPrice x2))
(* x3Qty (getPrice x3))
(* x4Qty (getPrice x4))
(* x5Qty (getPrice x5)))
))
(assert (< amountSpent moneyToSpend))
(declare-const shippingCost Int)
(assert (= shippingCost
; FooMart charges a flat $75 shipping fee
(+ (if (or (= (getRetailer x1) FooMart)
(= (getRetailer x2) FooMart)
(= (getRetailer x3) FooMart)
(= (getRetailer x4) FooMart)
(= (getRetailer x5) FooMart))
7500
0
)
; BazTrading charges a flat $20 + $5 per 100 rounds
(if (or (= (getRetailer x1) BazTrading)
(= (getRetailer x2) BazTrading)
(= (getRetailer x3) BazTrading)
(= (getRetailer x4) BazTrading)
(= (getRetailer x5) BazTrading))
2000
0
)
(* (/ (+ (if (= (getRetailer x1) BazTrading)
(getRounds x1)
0)
(if (= (getRetailer x2) BazTrading)
(getRounds x2)
0)
(if (= (getRetailer x3) BazTrading)
(getRounds x3)
0)
(if (= (getRetailer x4) BazTrading)
(getRounds x4)
0)
(if (= (getRetailer x5) BazTrading)
(getRounds x5)
0))
100)
500)
)
))
(declare-const amountSpent Int)
(assert (= amountSpent
(+ (x1Pricing x1Qty)
(* x2Qty (getPrice x2))
(* x3Qty (getPrice x3))
(* x4Qty (getPrice x4))
(* x5Qty (getPrice x5))
shippingCost)))
(assert (< amountSpent moneyToSpend))
(declare-const totalRounds Int)
(assert (= totalRounds
(+ (* x1Qty (getRounds x1))
(* x2Qty (getRounds x2))
(* x3Qty (getRounds x3))
(* x4Qty (getRounds x4))
(* x5Qty (getRounds x5)))
))
(declare-const amountSpentPerRound Real)
(assert (= amountSpentPerRound
(div amountSpent totalRounds)
))
(assert (> amountSpent 20000))
(assert (< amountSpent 30000))
(minimize amountSpentPerRound)