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.mzph.cn/news/383566.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

每日一题: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;如果有一个清晰的…

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;用一…

每日一题: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;如果是升序的就按照正…

Linux创建多个子线程并回收

创建子线程的逻辑相比子进程要更容易理解一些&#xff0c;因为线程没有像进程那样复制很多东西另起炉灶&#xff0c;子线程从传入的开始函数开始运行&#xff0c;但是难点在于传入参数和回收时获取退出状态&#xff0c;因为这两个原本都是void *类型的&#xff0c;而我们在使用…

Qt for Android环境配置

最近想写一个小APP&#xff0c;但是又不想用Android Studio进行开发&#xff0c;想要用C进行开发&#xff0c;听说Qt可以进行Android开发&#xff0c;就想尝试一下&#xff0c;结果花了一天时间来配置环境。。。而且发现windows下配置环境更简单一些&#xff08;我中途还切换到…

Leetcode第284场周赛

绪论 最近发现Leetcode每周的周赛难度挺适合我的&#xff0c;而且时间也比较友好&#xff08;不像Codeforces每次都是半夜&#xff09;。所以连续参加了三周的周赛。这次才想起来应该记录一下自己的参赛历程。一方面是总结经验&#xff0c;另一方面有了记录就更有动力去提升&a…

Leetcode第286场周赛

绪论 上周因为有事没有参加周赛&#xff0c;这周没有错过。这次周赛拿到了人生第一个AK&#xff0c;参加大大小小的比赛这么多次&#xff0c;从来没有AK过&#xff0c;泪目了。 感觉这次比赛的思维难度对我来讲稍高一些&#xff0c;前三道题就花了一个小时&#xff0c;而以往…

第287场周赛

绪论 虽然是上周日参加的比赛&#xff0c;但是这周没有怎么学习&#xff0c;每天就是玩耍。也导致对周赛的总结迟迟没有进行。想着再拖下去下次周赛都要开始了&#xff0c;在这里补一下。 这场比赛总体比上场简单一些&#xff0c;但是最后一道题因为忘记初始化类内变量导致调试…

第288场周赛

绪论 虽然没有AK&#xff0c;但是不知道为什么排名比以前AK了都靠前。可能是因为最后一道题有些难度&#xff0c;缩小了我和大佬之间的差距。最后一个小时写最后一道题&#xff0c;累死累活想了一个贪心遍历的算法&#xff0c;当时是一直RE&#xff0c;后来下来调了调又WA了。 …