z3 C++學習筆記

因為項目需要使用z3庫來解決問題,所以自己學習了一下,結果發現網上教程比較少,而且大部分都是使用Python,而我本人是C++的忠實信徒,在知道C++也可以使用z3庫以后我毫不猶豫地著手用C++使用z3,但是我很快發現,網上基本沒有關于C++使用z3的教程(中文社區一點都沒有),因此我記錄一下我自己的學習過程希望能夠幫助到其他學習的人。

教程鏈接

網上現有的有三個教程:
官方example.cpp文檔:https://github.com/Z3Prover/z3/blob/master/examples/c%2B%2B/example.cpp
入門筆記:
http://www.cs.utah.edu/~vinu/research/formal/tools/notes/z3-notes.html
API接口:
https://z3prover.github.io/api/html/group__cppapi.html

其中主要教程是官方的example.cpp
第二個入門教程也非常不錯,里面包含了環境的搭建,例子的說明(其實就是example.cpp的說明)
第三個API沒有什么用覺得

不過上面的教程都沒有說如何在一個普通文件中使用z3庫,我在StackOverflow上找到一個回答解決了這個問題:https://stackoverflow.com/questions/17514923/need-help-in-using-z3-api-in-a-c-program。簡單來講在install之后要在文件中包含z3++.h頭文件,而且在編譯參數上要加上-lz3

我一開始是學習使用Python使用z3的,因此也發現一些很好的教程,其中對我幫助最大的是一個用z3解決背包問題的博客,讓我明白如何用z3解決極值問題:https://blog.csdn.net/weixin_41950078/article/details/111416573

性能測試

同時我測試了Python和C++的性能差距,以上面學習到的01背包問題為例,在數據量為40的時候,Python的運行時間是5830.4131779670715s(我沒有寫錯),C++的運行時間是57s。
希望的我的測試能夠堅定大家用C++使用z3庫的決心(狗頭
下符測試代碼和運行截圖:

Python

測試代碼

import timefrom z3 import *
def zero_one_knapsack(weights, values, cap):solver = Optimize()# the decision variablesflags = [Int(f"x_{i}") for i in range(len(weights))]for flag in flags:solver.add(Or(flag == 0, flag == 1))weight_arr = []i = 0for w in weights:weight_arr.append(w * flags[i])i += 1# add weight constraintsolver.add(sum(weight_arr) <= cap)value_arr = []i = 0for v in values:value_arr.append(v * flags[i])i += 1solver.maximize(sum(value_arr))start = time.time()# calculateresult = solver.check()print(f"use {time.time() - start}s to calculate")if result == sat:model = solver.model()print("\n".join([f"Index: {index}, weight: {weights[index]}, value: {values[index]}"for index, flag in enumerate(flags) if model[flag] == 1]))else:print("empty")if __name__ == '__main__':C = 300W = [71,34,82,23,1,88,12,57,10,68,5,33,37,69,98,24,26,83,16,26,18,43,52,71,22,65,68,8,40,40,24,72,16,34,10,19,28,13,34,98]V = [26,59,30,19,66,85,94,8,3,44,5,1,41,82,76,1,12,81,73,32,74,54,62,41,19,10,65,53,56,53,70,66,58,22,72,33,96,88,68,45]zero_one_knapsack(W, V, C)

運行結果

在這里插入圖片描述

C++

運行代碼

#include <iostream>
#include <typeinfo>
#include <string>
#include <z3++.h>
#include <vector>
#include <ctime>using namespace z3;
using std::cout;
using std::cin;
using std::endl;
using std::string;
using std::vector;void knapsack(const vector<int> &weights, const vector<int> &values, int cap) 
{context c;optimize opt(c);vector<expr> flags;for (decltype(weights.size()) i = 0; i < weights.size(); ++i) {flags.push_back(c.int_const( ("x" + std::to_string(i)).c_str() ));}for (auto &flag : flags) {opt.add(flag == 0 || flag == 1);}expr tmp = c.int_const("tmp");tmp = c.int_val(0);for (decltype(weights.size()) i = 0; i < weights.size(); ++i) {tmp = tmp + weights[i] * flags[i];}opt.add(tmp <= cap);tmp = c.int_val(0);for (decltype(values.size()) i = 0; i < values.size(); ++i) {tmp = tmp + values[i] * flags[i];}opt.maximize(tmp);//cout << opt << endl;clock_t begin = clock();auto result = opt.check();clock_t end = clock();if (result == sat) {model m = opt.get_model();//cout << m << endl;for (unsigned i = 0; i < flags.size(); ++i) {auto item = flags[i];if (m.eval(item).get_numeral_int() == 0) continue;cout << i << ":\t"  << weights[i] << "\t" << values[i] << endl;}} else {cout << "no solution" << endl;}cout << "cost time:" << static_cast<double>(end - begin) / CLOCKS_PER_SEC << "s" << endl;
}void work()
{vector<int> W,V;int C,n,w,v;cin >> C >> n;while (n--) {cin >> w >> v;W.push_back(w);V.push_back(v);}knapsack(W, V, C);
}int main()
{std::ios::sync_with_stdio(false);work();return 0;
}

為了在輸出結果的時候判斷是否選擇該物品需要從model中獲取結果,但是我不知道如何比較結果是否為0(在程序中0表示不選),在網上找來找去都沒有,最后沒有辦法只能自己嘗試,終于在成員列表里面找到了一個好像能夠把expr轉換成int的函數,即上面的if (m.eval(item).get_numeral_int() == 0) continue;語句,卡了好久,沒有教程太慘了。

運行結果

在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/383566.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/383566.shtml
英文地址,請注明出處:http://en.pswp.cn/news/383566.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

C++Primer學習筆記:第6章 函數

通過調用運算符()調用函數 函數的調用完成兩項工作&#xff1a; 用實參初始化函數對應的形參將控制權轉移給被調用函數&#xff1a;主調函數的執行被暫時中斷&#xff0c;被調函數開始執行 盡管實參與形參存在對應關系&#xff0c;但是并沒有規定實參的求值順序。編譯器能以任…

C++Primer學習筆記:第8章 IO庫

C語言不直接處理輸入輸出&#xff0c;而是通過一族定義在標準庫中的類型來處理IO iostream定義了用于讀寫流的基本類型fstream定義了讀寫命名文件的類型sstream定義了讀寫內存string對象的類型 標準庫使得我們能夠忽略這些不同類型的流之間的差異&#xff0c;是通過繼承機制實…

C++Primer學習筆記:第7章 類

類的基本思想是數據抽象data abstraction和封裝encapsulation。數據抽象是一種依賴于接口interface和實現implementation分離的編程技術 在類中&#xff0c;由類的設計者負責考慮類的實現過程&#xff0c;使用該類的程序員只需要抽象地思考類型做了什么&#xff0c;而無須了解…

每日一題:leetcode191.位1的個數

題目描述 題目分析 很自然地想到了二進制枚舉&#xff0c;直接循環檢查每一個二進制位。 class Solution { public:int hammingWeight(uint32_t n) {int ret 0;uint32_t t 1;for (int i 0; i < 32; i, t << 1) {if (n & t) {ret;}}return ret;} };AC之后看了…

每日一題:leetcode341.扁平化嵌套列表迭代器

題目描述 題目分析 這個題目自己大概花了一個小時&#xff0c;雖然是一遍AC&#xff0c;但是速度有點慢&#xff0c;太長時間不寫代碼導致自己對代碼不太敏感&#xff0c;寫起來慢騰騰的。 看到這個的想法就是&#xff0c;要用棧來保存列表的迭代器&#xff0c;這樣將孩子列表…

每日一題:leetcode82. 刪除排序鏈表中的重復元素 II

題目描述 題目分析 這才是正常的中等題難度嘛&#xff0c;昨天的中等題題解我半天看不懂。。。 首先&#xff0c;需要增加一個啞節點&#xff08;操作鏈表的常規操作&#xff09;&#xff0c;因為有可能刪除首節點&#xff0c;我們不想要為首節點添加單獨的邏輯。其次&#xf…

每日一題:leetcode456.132模式

題目描述 題目分析 我覺得這道題應該是我做過最難的中等題之一了&#xff0c;這是昨天的每日一題&#xff0c;但是昨天用nlogn的做法做出來以后在看題解&#xff0c;發現有些看不懂&#xff08;覺得題解有點故弄玄虛&#xff09;。然后今天中午又花了一點時間才搞懂&#xff0…

leetcode283.移動零

題目描述 題目分析 在寫簡單題放松&#xff0c;看到這道題第一個想法是用STL庫函數&#xff0c;雖然知道大概要用雙指針之類的&#xff0c;但是庫函數爽哇。 class Solution { public:void moveZeroes(vector<int>& nums) {stable_sort(nums.begin(), nums.end(), …

每日一題:leetcode61.旋轉鏈表

題目描述 題目分析 很容易發現&#xff0c;如果k是n的整數倍&#xff0c;相當于沒有移動。這樣直接對k%n使得k在一個可以接受的范圍。 因為是順序移動&#xff0c;各元素之間的相對位置保持不變&#xff0c;所以就想著將鏈表先變成一個環。然后再移動頭指針&#xff0c;最后再…

每日一題:leetcode173.二叉搜索樹迭代器

題目描述 題目分析 更加地覺得編程重要的不在于如何寫代碼&#xff0c;用什么具體的技巧&#xff0c;編碼本身只是一種將思維呈現的方式&#xff0c;但是如果思維是不清晰的&#xff0c;那么就算懂得再多的編碼的奇技淫巧也是沒有什么幫助的。相反&#xff0c;如果有一個清晰的…

Ubuntu20.04 Clion/Pycharm/IDEA 輸入中文+光標跟隨解決方案

ibus輸入法&#xff08;棄用&#xff09; 之前一直用的搜狗輸入法&#xff0c;但是搜狗輸入法無法在Jetbrains全家桶下使用&#xff0c;但是又需要輸入中文&#xff0c;沒有辦法我只能下載了谷歌輸入法&#xff0c;十分難用&#xff0c;但是也沒有其他辦法&#xff0c;經常到網…

leetcode11.盛最多水的容器

題目描述 題目分析 看到題目后第一個想法當然是O(n2)O(n^2)O(n2)的&#xff0c;但是數據范圍是3e4&#xff0c;應該會超時&#xff0c;而且這種數據范圍也不是讓暴力求解的 。 相當于求解∑i<jmax((j?i)?min(a[i],a[j]))\sum_{i<j}{max((j-i)*min(a[i],a[j]))}∑i<…

每日一題:leetcode190.顛倒二進制位

題目描述 題目分析 題目本身很簡單&#xff0c;沒覺得有什么技巧可以再進行優化了&#xff0c;覺得位運算是無法打亂相對順序的&#xff0c;而這里需要進行鏡像顛倒的操作。因此就踏實地寫了一個循環。 在使用位運算得到每一位的時候&#xff0c;我吸取了經驗&#xff0c;用一…

結構屈曲分析

結構屈曲分析主要用于判定結構受載后是否有失穩風險&#xff0c;作為工程應用&#xff0c;一般分為線性屈曲分析和非線性屈曲分析。 線性屈曲分析需要具備較多的前提條件&#xff0c;如載荷無偏心、材料無缺陷等&#xff0c;在實際工程應用中結構制作過程和加載方式很難達到線性…

每日一題:leetcode74.搜索二維矩陣

題目描述 題目分析 感覺這是一個放錯標簽的簡單題。題目非常簡單&#xff0c;思路應該很明確是二分&#xff0c;我很快寫了一個&#xff08;雖然不小心把!打成調試了一會&#xff09;。 class Solution { public:bool searchMatrix(vector<vector<int>>& mat…

每日一題:leetcode90.子集貳

題目描述 題目分析 感覺這道題讓自己對枚舉排列有了一個更好的認識&#xff0c;感覺自己的這種思路不錯。 假設沒有重復元素&#xff08;退化成78.子集&#xff09;&#xff0c;我們應該怎么做&#xff1f;初始的時候冪集中只有一個空集&#xff0c;然后對每個元素&#xff0…

每日一題:leetcode1006.笨階乘

題目描述 題目分析 因為順序一定且沒有括號&#xff0c;所以邏輯很簡單。我們要順序處理的矛盾在于&#xff0c;減號后面會再出現乘法和除法&#xff0c;我們不妨將對乘法和除法用一個臨時值進行計算&#xff0c;計算結束后再合并到值里面&#xff0c;一般來講乘法和除法的處理…

每日一題:leetcode80.刪除有序數組中的重復元素貳

題目描述 題目分析 又是一道貼錯標簽的簡單題&#xff0c;很明顯的雙指針&#xff0c;我的做法是用兩個變量保存是否需要記錄&#xff0c;官方題解的做法是直接判斷&#xff0c;人家的高明一些 class Solution { public:int removeDuplicates(vector<int>& nums) {…

每日一題:leetcode81.搜索旋轉排序數組Ⅱ

題目描述 題目分析 不含重復元素的題解&#xff08;leetcode33&#xff09; 這道題也是我們算法課的一道編程題&#xff0c;寫完以后發現當時的思路和現在沒有什么變化&#xff0c;果然是自己啊。我的想法是先判斷區間整體是升序的還是旋轉的&#xff0c;如果是升序的就按照正…

C++ JSON庫:JSON for Morden C++

緒論 最近因為項目的需要&#xff0c;需要對JSON進行一定的數據處理&#xff0c;因為想要用C進行編碼&#xff0c;便對C的JSON庫進行的調研&#xff0c;發現這個庫比較好用&#xff1a;JSON for Morder C。 使用指南 想要使用這個json庫&#xff0c;只需要在源文件中包含jso…