【免费下载链接】xquadA rust implementation of the Quip Networks quantum virtual machine.项目地址https://gitcode.com/gh_mirrors/xq/xquad点击查看免费下载本文以 xquad 仓库中的 Portfolio Rebalance 示例 为主线讲解如何用 XQCP 约束编程 DSL 为一类**允许空头负权重**的投资组合再平衡问题建立二次无约束二元优化QUBO模型为每只资产选择一个[-5, 5]区间内的整数权重在权重之和等于预算的约束下用预期收益与风险矩阵权衡取舍。读完本文你将掌握Domain.INTEGERlo/hi区间整数域的建模方法、手写预算平方约束的展开技巧、三程序流水线encoder / verifier / decoder的调用方式以及该示例当前能证明什么、不能证明什么。问题定义为什么必须用带符号的整数权重投资组合再平衡的目标是给每只资产分配一个带符号的整数权重在预期收益与风险之间取得平衡同时要求所有权重之和恰好等于一个预算值。关键点在于负权重代表空头short position——正是这一点决定了该问题不能退化成选或不选的二元模型二元模型只能表达x_i ∈ {0, 1}即持不持有而再平衡需要x_i ∈ [-5, 5]这样的区间整数域才能表达做多、空仓、做空三种状态。因此该示例成为 xquad 中首个、也是核心的一个非二元示例它完整展示了在Domain.INTEGER上建模、编译、验证与解码的完整链路。QUBO 形式化输入、模型、目标与约束根据 示例 README 与 runner.py 的实现问题的形式化如下要素定义输入资产数量N、每只资产的预期收益r_i、按行优先展平的对称N × N风险矩阵C模型N个整数变量x_i ∈ [-5, 5]用lo-5, hi5声明模型内部存储y_i x_i - lo ∈ {0, ..., 10}系数写在x上sample.value()在输出端把y平移回x目标-sum(r_i * x_i) sum_{i j} C_ij * x_i * x_j最小化约束sum(x_i) B以惩罚项P * (sum_i x_i - B)^2表达能量被平移了两次因此数值上与其他任何示例不可比详见下文在 runner.py 中这些参数是编译期常量_LO -5 _HI 5 _K _HI - _LO 1 # 域宽 11模型实际持有 y ∈ {0, ..., 10} _BUDGET 1 # 权重之和必须等于的预算 _PENALTY 50 # 预算约束的惩罚强度能量的两次平移argmin 精确数值不可比README 明确指出该示例的能量被平移了两次因此最终数字不是目标函数的真实值也不与其他示例可比区间域平移代入x y lo后二次项展开会产生一个常数w*lo^2因为 XQMX 模型没有偏移offset字段这个常数被丢弃。参见 problem.py 中 define_model 的文档The uniform energy shift the ranged form drops is unrepresentable, since XQMX carries no offset term; argmin is unaffected.预算平方平移P * (sum_i x_i - B)^2展开后包含常数P*B^2与EQUALITY展开丢弃自己的P*b²常数项一致见 spec/xqvm/HLF.md 中 EQUALITY 展开的说明。两次平移对所有可行赋值都施加相同的偏移所以虽然返回的能量数字不是目标函数的真实值argmin 却是精确的——排序结果不受影响。编码策略手写预算平方而非 apply_equality这是本示例最有技术含量的一节预算约束sum(x_i) B是手写展开的而不是交给apply_equality()。为什么不能交给 EQUALITY在 xqcp/compiler.py 中所有高层约束onehot_row、onehot_col、exclude、implies、equality、atleast、atleastw、reduce等都被标记为_BINARY_ONLY_KINDS。原因在 spec/xqvm/HLF.md 中写得很清楚所有高层函数展开都建立在x² x之上而该等式只对二元变量成立。ONEHOTR、EQUALITY、ATLEAST等展开在推导时都利用了二元变量的幂等性一旦应用到整数域模型上生成的惩罚项就不再表达用户写下的约束。因此 xqcp 会拒绝在非二元模型上使用任何高层约束——这也是 spec/xqcp/SPEC.md 中记录的开放问题per-domain expansions每个域是否都存在正确的展开尚无定论。手写展开的系数P * (sum_i x_i - B)^2展开后为每个对角项P每个非对角对2P每个线性系数-2PB这与EQUALITY展开linear[idx_k] P*a_k*(a_k - 2b)、quad[idx_k, idx_m] 2P*a_k*a_m在a_k 1、b B时是同一套数学。README 说得很直白Writing that square is the same work the HLF would have done——手写这份展开正是 HLF 本来要做的工作。在 runner.py 中这份展开与目标项一起写入# 收益目标 预算平方的线性项-r_i * x_i - 2*P*B * x_i problem.model.linear[i].add(-ri - 2 * _PENALTY * _BUDGET) # 风险目标上三角 预算平方的对角项C_ii P problem.model.quadratic[i, i].add(cov_in.get(xq_grid(i, i, num_assets)) _PENALTY) # 非对角项C_ij 2P problem.model.quadratic[i, j].add(cij 2 * _PENALTY)注意xq_grid(i, j, n)把二维风险矩阵按行优先映射成一维协方差输入向量——这正是 README 中风险矩阵按行优先展平的实际落地。区间域在底层的二次重写区间域在 DSL 之下还有一层自动重写。看 xqcp/symbols.py 中 CoefficientRef.add 的实现当模型带lo_expr时每次二次项写入除了记录w本身还会把w*lo追加到两个命名索引的线性系数上因为代入x y lo后w * x_i * x_j w*y_i*y_j w*lo*y_i w*lo*y_j w*lo²非对角写入两条修正分别落在i和j的线性系数上对角写入i j两条修正落在同一个索引上正好给出平方展开所要求的2*w*lo。这些重写对模型构建代码完全不可见——你写的依然是model.quadratic[i, j].add(...)平移由记录层自动完成。这种设计带来的一个直接限制是区间整数模型上不支持linear[i] w和quadratic[i, j] w的赋值式写法setitem因为设置会替换掉系数而lo修正只能累加两者会互相矛盾LinearProxy.__setitem__和QuadraticProxy.__setitem__会直接抛出ValueError提示改用.add(w)。lo 和 hi 必须是字面量README 特别强调lo与hi是字面量。运行时的lo会占用 decoder 唯一的 calldata 标量——而那个标量已经被输出循环的上界N用掉了。从源码看problem.py 的 define_model 中字面量lo不需要寄存器会被内联替换到所有需要平移的位置而运行时lo则必须分配寄存器。xqcp 的策略是宁可直接报错也不在两个需求中二选一。DSL 方法速查区间整数域用到的三个 API本示例只使用了非二元模型支持的全部操作# 1. 声明区间整数模型sizeN 个变量域 [-5, 5] problem.define_model(sizenum_assets, domainDomain.INTEGER, lo_LO, hi_HI) # 2. 写入系数非二元模型唯一支持的两种操作 problem.model.linear[i].add(w) problem.model.quadratic[i, j].add(w) # 3. 读取样本值返回声明域内的权重 x而不是存储值 y problem.sample.value(i)背后机制Domain.INTEGER在 xqcp/problem.py 中定义映射到 VM 层的XQMXDomain.INTEGERdefine_model会做参数合法性检查lo/hi必须成对、hi lo 1、不允许k与lo/hi同时出现见 problem.py 的 _check_domain_args。sample.value(i)在 xqcp/symbols.py 中实现getline(index) lo_expr——只有当define_model给了lo/hi时才做平移否则与getline完全一致。整数模型的k由hi - lo 1计算得出域宽在编译期嵌入 XQMX 分配allocator 弹出k后再弹size宽度最后入栈见 compiler.py 的 _emit_model_allocation。六步流水线CP → 汇编 → 编码 → 采样跳过→ 验证 → 解码与 xquad 其他示例一致本示例遵循三程序架构encoder / verifier / decoder参见 docs/book/src/concepts/three-programs.md步骤动作说明1. CPxqcp生成收益与对称风险矩阵声明N个区间整数权重写入目标与预算平方系数2. Assemblexquad.asm把.xqasm文本汇编成字节码3. Encode运行 encoder在所选 XQVM 后端上产出 XQMX 模型4. Sample跳过没有求解器能采样整数模型runner 直接提供手工挑选的赋值5. Verify运行 verifier依据define_model重放的k检查每个权重落在{0, ..., 10}再计算能量6. Decode运行 decoder读取每个权重并加上lo还原带符号的权重在 runner.py 的 run() 中这段流水线有清晰的实现vm VM(backendbackend) vm.set_calldata([n, returns, cov]) vm.set_output_slots(1) vm.run(programs.encoder) model vm.outputs()[0] sample XQMX.integer_sample(n, _K) for index, weight in enumerate(weights): sample.linear[index] weight - _LO # 手工构造 y x - lo vm VM(backendbackend) vm.set_calldata([n, returns, cov, model, sample]) vm.set_output_slots(2) vm.run(programs.verifier) energy, valid vm.outputs()[0], vm.outputs()[1] vm VM(backendbackend) vm.set_calldata([sample, n]) # sample 唯一的标量 n vm.run(programs.decoder)三个细节值得注意手工采样XQMX.integer_sample(n, _K)创建{0, ..., k-1}域的样本见 xqvm_py/xqmx.py随后把手工挑选的权重减去lo存入sample.linear即y x - lo。手工挑选的赋值pick_assignmentrunner.py对n 2返回weights[0] BUDGET 1 2、weights[1] -1——故意携带一个空头让解码输出覆盖整个域而不只是非负半边并且总和恰好等于预算。decoder 的 calldata 布局[sample, n]其中n是唯一的标量被输出循环上界占用——这正是前文运行时lo没有标量可用的原因。decoder 的 calldata 契约见 compiler.py 的 compile_decoder。运行方式与命令行参数从仓库根目录运行两种典型用法uv run python examples/portfolio_rebalance/runner.py --seed 42 uv run python examples/portfolio_rebalance/runner.py --n 6 --interpreter rust参数默认值说明--n5资产数量--solverdwave-cpu接受但被忽略详见下文--interpreterpythonXQVM 后端python纯 Python 参考 VM或rust经xqffi调用 Rust 解释器--seed42随机种子决定收益与协方差矩阵的生成-ostdout把 JSON 结果写入文件--interpreter选择的是执行编译后程序的 VM而不是求解模型的后端——正确模型在两个解释器上总是产生相同的valid与energy。输出的 JSON 字段包括_seed、n、lo、hi、budget、returns、weights、sums_to_budget、energy、valid见 runner.py 的 main()。本示例证明什么、不证明什么证明valid 1说明域检查domain check、记录层平移record-layer shift与解码decode三者能够组合在一条手工挑选的赋值上正确工作——一个包含空头、落在域内且总和等于预算的赋值通过了验证器并解码回带符号的权重。不证明它不证明任何优化能力。README 明确写道It proves nothing about optimisation: no solver samples an integer model yet, so--solveris accepted, ignored, and the pipeline runs against a hand-picked weight vector that sits inside the domain and sums to the budget. Integer lowering is XQSA v0.5.0 work.即目前没有任何求解器能采样整数模型整数域在 spec/xqsa/DOMAINS.md 中的求解器支持状态为 Reserved_validate_model()会对 INTEGER 域抛出ValueError所以--solver仅为接口一致性而接受并忽略。runner 启动时会向 stderr 打印提示runner.py。整数下界integer lowering是 XQSA v0.5.0 的计划工作。规范输出与 CI 守护make example-smoke对应 scripts/example-smoke.py验证两个解释器在--seed 42 --solver dwave-cpu下都产生valid 1。该冒烟测试是基于不变式的只检查合法性valid 1不比较精确输出——因为能量数值经过两次平移不可比且手工赋值的意义在于链路正确性而非最优性。延伸阅读示例总览与通用运行方式每个示例目录的公共结构、--interpreter语义与改编方法三程序架构encoder / verifier / decoder 的职责与调用链XQCP 建模文档本 runner 所用的 DSL 完整说明整数域与样本编码{0, ..., k-1}域、integer_sample与域校验规则HLF 展开规范EQUALITY等展开为何只对二元域成立XQCP 规格约束仅限二元模型的开放问题记录赞分享【免费下载链接】xquadA rust implementation of the Quip Networks quantum virtual machine.项目地址https://gitcode.com/gh_mirrors/xq/xquad点击查看免费下载相关推荐Claude for Financial Services 财富管理插件实战用 /rebalance 命令与 portfolio-rebalance 技能完成税务感知的组合再平衡Claude for Financial Services 财富管理插件实战用 /rebalance 命令与 portfolio rebalance 技能完成人工智能AI 应用AI 技能/插件AI Agent金融科技XQuad Portfolio Rebalance 示例深度解析XQVM 整数域建模与带符号权重的端到端流水线XQuad Portfolio Rebalance 示例深度解析XQVM 整数域建模与带符号权重的端到端流水线 本篇技术指南围绕 xquad 仓库中的 PorFinRobot 财富管理技能详解用 Portfolio Rebalance 技能实现组合漂移分析与再平衡交易建议FinRobot 财富管理技能详解用 Portfolio Rebalance 技能实现组合漂移分析与再平衡交易建议 导读 本文以 FinRobot 桌面端人工智能AI Agent金融科技AI 应用大模型RAG上一篇Windows 11 PL2303驱动问题终极解决方案告别黄色感叹号的完整指南下一篇Windows系统驱动兼容性重构高效解决PL-2303停产芯片识别问题创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考