---
title: "SCIPソルバーとは？PySCIPOptでPythonから使う手順とCBC・HiGHSとの比較【SCIP 10.1】"
url: "https://www.issoh.co.jp/tech/details/3037/"
published: 2024-07-12
updated: 2026-10-16
categories: ["Python"]
publisher: "株式会社一創"
---

# SCIPソルバーとは？PySCIPOptでPythonから使う手順とCBC・HiGHSとの比較【SCIP 10.1】

SCIPは、ドイツのZuse Institute Berlin（ZIB）が開発している数理最適化ソルバーです。混合整数計画（MIP）と混合整数非線形計画（MINLP）を解けて、バージョン8.0.3からはApache-2.0で配布されているため、商用製品に組み込んでも許諾料はかかりません。最新版は2026年9月18日公開のSCIP 10.1.0です。ただし、Pythonで `pip install pyscipopt` を実行して入るのはSCIP 10.0.2で、最新版とは一致しません。この記事では、その入手経路の違いから、PySCIPOptでの書き方、実行不能なモデルの原因特定、CBC・HiGHSとの速度比較まで、公式資料とpip環境での実行結果をもとに説明します（condaの組み合わせは依存指定の確認までで、実行はしていません）。

## まとめ

先に結論を5つ挙げます。

- SCIPはApache-2.0のオープンソースで、商用利用も再配布もできます（8.0.3以降）。
- Pythonからは `pip install pyscipopt` の1行で使えます。2026年10月11日公開のPySCIPOpt 6.3.0でも、同梱されているのはSCIP 10.0.2でした。10.1系を使いたいなら、conda-forgeか公式バイナリから入れます。
- SCIP 10系の目玉である厳密解モードは、pipで入る版では有効にできません。一方、実行不能の原因を絞り込むIIS（`generateIIS()`）はpip版のまま使えます。
- 同じナップサック問題をSCIP・CBC・HiGHSで解くと、変数150本ではCBCが47.0秒、SCIPが180.1秒、HiGHSが314.7秒でした。速度だけでSCIPを選ぶ根拠はありません。SCIPを選ぶ理由は、非線形の制約を扱えることと、IISや独自プラグインを組み込める拡張性にあります。
- python-mip 2.0.0では `solver_name=mip.SCIP` を指定してもエラーにならず、そのままCBCで解かれます。SCIPを使うなら、PySCIPOptを直接使うか、PuLPの `SCIP_PY` を使います。

以下で、それぞれの根拠と手順を説明します。

## SCIPという略語が指す3つの対象と見分け方

「SCIP」は分野のまったく違う3つのものを指します。検索で出てきた資料がどれのことかを先に確かめないと、見当違いのページを読むことになります。

### 最適化ソルバーのSCIP（ZIB・Solving Constraint Integer Programs）

この記事で扱うSCIPです。Solving Constraint Integer Programsの略で、起動時には `Copyright (c) 2002-2026 Zuse Institute Berlin (ZIB)` と表示されます。分枝限定法に、カット生成、ヒューリスティック、制約伝播を組み合わせて解きます。単体のソルバーとして使えるだけでなく、独自の制約ハンドラや分枝ルールを差し込めるフレームワークとして作られているのが特徴です。一緒に出てくる語は `pyscipopt`、`scipoptsuite`、`soplex` です。

### コード索引フォーマットのSCIP（Sourcegraph）

Sourcegraphが策定した、ソースコードの索引データをやり取りするためのプロトコルです。[公式リポジトリのREADME](https://github.com/sourcegraph/scip)には `SCIP (pronunciation: "skip") is a language-agnostic protocol` と書かれており、LSIFの後継にあたります。`scip-java` や `scip-python` のように言語名が付いたものは、すべてこちらの索引ツールです。

### 化学物質データベースのSCIP（ECHA・欧州化学品庁）

Substances of Concern In articles as such or in complex objects (Products) の略で、EUの廃棄物枠組み指令（2008/98/EC）に基づく届出データベースです。REACHの候補リストに載った高懸念物質（SVHC）を重量比0.1%超含む成形品をEU市場に供給する製造者・輸入者・流通業者などに、2021年1月5日から届出義務があります（消費者にだけ直接供給する小売業者などは対象外）。欧州委員会は、2025年12月10日に公表した環境オムニバスで、このデータベースを廃止する指令改正案を出しています（[Mayer Brownの解説](https://www.mayerbrown.com/ja/insights/publications/2025/12/european-commission-presents-environmental-omnibus-news-for-epr-scip-industrial-emissions-and-environmental-assessments)）。2026年10月時点では審議中で、届出義務は残っています。検索語に echa、svhc、reach が付いていれば、こちらのSCIPです。

## SCIP 10.1の現在地：ライセンスと版の対応

業務で使えるかどうかは、性能より先にライセンスと手に入る版で決まります。どちらもここ数年で変わりました。

### Apache-2.0への移行時期と商用利用の条件

SCIPは長くZIB Academic Licenseで配布され、商用で使うには別途許諾が必要でした。[公式サイト](https://www.scipopt.org/)には `Since version 8.0.3, SCIP is licensed under the Apache 2.0 License.` と書かれており、8.0.2までの版は引き続きZIB Academic Licenseです。8.0.3のGitHubタグは2022年12月13日に付けられました。現行版なら、社内システムへの組み込みも、SCIPを含む製品の配布もできます。再配布するときは、ライセンス文の同梱、変更したファイルへの明示、NOTICEファイルがあればその引き継ぎといったApache-2.0の条件を守ります。PythonインターフェースのPySCIPOptは、SCIP本体とは別のMITライセンスです。

### SCIP 10.0〜10.1で追加された機能

10.0系は、2025年11月24日の10.0.0から、10.0.1（2026年2月3日）、10.0.2（4月2日）、10.0.3（7月6日）と続きました。10.0で入った大きな機能は2つあります。1つは、混合整数線形計画を対象に、有理数・拡張精度・安全な浮動小数点の演算を組み合わせて、丸め誤差に結果を左右させない厳密解モード（[公式ドキュメント](https://www.scipopt.org/scip/doc/html/EXACT.php)）、もう1つは、実行不能の原因になっている制約の組（IIS）を抽出する機能です。2026年9月18日の[10.1.0のリリースノート](https://github.com/scipopt/scip/releases/tag/v10.1.0)で、Featuresに挙がっているのは1項目だけです。コマンドラインに `-t` オプションが追加され、スレッド数を指定すると `SCIPsolveConcurrent()` による並列求解が動くようになりました。そのほかは性能改善とバグ修正です。

PySCIPOpt 6.3.0のリリースノートによると、次のSCIP 11は2027年初めの予定です。今から書くコードは10系のAPIを前提にしてかまいません。

## PySCIPOptのインストール：pip・conda・公式バイナリの違い

以前のようにSCIPOptSuiteをCMakeでビルドする手順は要りません。ただし、入手経路によって入るSCIPの版が違います。

### pip install pyscipopt で入るもの（6.3.0でもSCIP 10.0.2）

macOS 26.6.2（Intel）とPython 3.15.0で仮想環境を作り、次のコマンドを実行しました。

```
python3 -m venv scipenv
source scipenv/bin/activate
pip install pyscipopt
```

入ったのはPySCIPOpt 6.3.0と、その依存パッケージのnumpy 2.5.4です。パッケージには `libscip.10.0.dylib` が同梱されており、SCIP本体を別に入れる必要はありません。版を表示すると次のようになりました。

```
from pyscipopt import Model
m = Model()
m.printVersion()
# SCIP version 10.0.2 [precision: 8 byte] [memory: block] [mode: optimized] [LP solver: SoPlex 8.0.2] [GitHash: NoGitInfo]
# Copyright (c) 2002-2026 Zuse Institute Berlin (ZIB)
print(m.version())   # 10.0（パッチ番号は返らない）
```

2026年10月11日に公開された最新のPySCIPOptでも、中身は4月のSCIP 10.0.2のままで、10.0.3も10.1.0も入っていません。[PySCIPOptのドキュメントにある互換表](https://pyscipopt.readthedocs.io/en/latest/build.html)も、6.2とSCIP 10.0.2の組み合わせまでしか載っていません。`printExternalCodeVersions()` を見ると、LP用のSoPlex 8.0.2と非線形用のIpopt 3.14.19も同梱されていて、線形から非線形まで追加の設定なしで解けます。

pipでの1行インストールはmacOS以外でも使えます。6.3.0は、Python 3.9から3.15まで（3.14と3.15はフリースレッド版も）について、Windows（win\_amd64）、Linux（x86\_64・aarch64）、macOS（arm64・x86\_64）のwheelを配布しています。注意が必要なのはPython 3.8です。6.3.0には3.8用のwheelが無く、wheelだけに絞ってダウンロードすると6.2.1が選ばれました。

### SCIP 10.1や対話シェルが必要なときの入手経路

pipで入るのは、Pythonから呼び出す共有ライブラリだけです。仮想環境の bin には `scip` という対話シェルの実行ファイルが入りません。最新の10.1系を使いたい場合、対話シェルで `read model.lp` や `optimize` を打ちたい場合、GCGやUGを使いたい場合は、次のどちらかで入れます。

| 入手経路                  | SCIPの版（2026年10月） | 対象                  |
| --------------------- | ---------------- | ------------------- |
| pip install pyscipopt | 10.0.2（6.3.0に同梱） | Pythonのみ            |
| conda-forge の scip    | 10.1.0           | Linux・macOS・Windows |
| 公式バイナリ                | 10.1.0           | macOSはarm64のみ       |
| ソースからビルド              | 任意               | 厳密解モードなど            |

conda-forgeでは、scipパッケージが2026年9月19日に10.1.0になっています。pyscipoptパッケージ（6.2.1）の依存指定は `scip >=10.0.0,<11.0a0` なので、`conda install conda-forge::pyscipopt` を実行すると、依存条件の上では10.1.0との組み合わせが許容されます。実際に選ばれる版は既存環境の依存関係にも左右されるので、導入後に `printVersion()` で確かめてください。公式の配布バイナリは、Ubuntu・Debian向けの.deb、GLIBC 2.28以上のLinux向けtarball、Windows（x64）向けインストーラーがあります。macOS向けはApple Silicon（arm64）用しか無いため、Intel Macではpipかcondaを使うことになります。

## PySCIPOptのモデル記述と求解：線形・整数・非線形

以下のコードは、どれも前述の環境で実行して出力を確認したものです。決定変数・目的関数・制約条件の区別に自信がない場合は、先に[決定変数・目的関数・制約条件の違いと定式化の手順](/tech/details/8321/)を読んでおくと、コードが追いやすくなります。

### 線形計画問題の記述と実行結果

基本の流れは、`addVar` で変数を作り、`addCons` で制約を、`setObjective` で目的関数を与えてから `optimize` を呼ぶ、というものです。

```
from pyscipopt import Model

m = Model("lp")
x = m.addVar("x", lb=0)
y = m.addVar("y", lb=0)
m.addCons(x + 2 * y <= 10)
m.addCons(2 * x + y <= 10)
m.setObjective(x + y, "maximize")
m.hideOutput()
m.optimize()
print(m.getStatus(), m.getObjVal(), m.getVal(x), m.getVal(y))
# optimal 6.666666666666666 3.333333333333333 3.3333333333333335
```

連続変数なので、最適解は2本の制約の交点 x = y = 10/3 です。`hideOutput()` を呼ばないと探索ログが標準出力に流れます。

### 混合整数計画：vtypeとquicksumの指定

整数条件は、`addVar` に `vtype` を渡して指定します。`"C"` が連続、`"I"` が整数、`"B"` が0か1のバイナリです。ナップサック問題のように「入れるか入れないか」を決める問題は、バイナリ変数で書きます。

```
from pyscipopt import Model, quicksum

profit = [60, 100, 120]
weight = [10, 20, 30]
m = Model("knapsack")
x = [m.addVar(vtype="B", name=f"x{j}") for j in range(3)]
m.addCons(quicksum(weight[j] * x[j] for j in range(3)) <= 50)
m.setObjective(quicksum(profit[j] * x[j] for j in range(3)), "maximize")
m.hideOutput()
m.optimize()
print(m.getObjVal(), [m.getVal(v) for v in x])
# 220.0 [0.0, 1.0, 1.0]
```

重さ20と30の品目で容量50を使い切り、価値の合計は220です。和は組み込みの `sum` ではなく `quicksum` で取ると、変数が多いときに式の組み立てが速くなります。

### PySCIPOptの行列API（addMatrixVar）による変数配列の作成

PySCIPOptは5.4.1（2025年2月）からnumpyを必須の依存にして、変数を配列としてまとめて作れる行列APIを備えています。上のナップサックは次のようにも書けます。

```
import numpy as np
from pyscipopt import Model

m = Model("matrix")
X = m.addMatrixVar(3, vtype="B", name="x")
m.addMatrixCons(np.array([10, 20, 30]) @ X <= 50)
m.setObjective(np.array([60, 100, 120]) @ X, "maximize")
m.hideOutput()
m.optimize()
print(m.getObjVal(), m.getVal(X))
# 220.0 [0.0 1.0 1.0]
```

重みや利益がもともとnumpy配列やpandasの列で用意されているなら、内包表記で添字を回すよりこちらの方が短く書けて、読み間違いも起きにくくなります。`getVal` に行列変数を渡すと、解も配列で返ります。

### 非線形制約の書き方とx2の誤り

SCIPとPySCIPOptは非線形の式を扱えるので、二乗以上の項を含む制約もそのまま書けます（非線形の部分問題を解くIpoptも同梱されています）。よく見かける誤りは、二乗を `x2` と書いてしまうものです。`m.addCons(x2 + y2 <= 1)` を実行すると、`NameError: name 'x2' is not defined` で止まります。Pythonのべき乗は `**` です。

```
from pyscipopt import Model

m = Model("nl")
x = m.addVar("x", lb=0)
y = m.addVar("y", lb=0)
m.addCons(x ** 2 + y ** 2 <= 1)
m.setObjective(x + y, "maximize")
m.hideOutput()
m.optimize()
print(m.getStatus(), round(m.getObjVal(), 6), round(m.getVal(x), 6))
# optimal 1.414214 0.707107
```

単位円の内側で x + y を最大化しているので、目的関数値は2の平方根の1.414214です。理論値と照らせば、非線形モデルが意図どおり組めているかを確かめられます。

### 打ち切り条件：limits/time と limits/gap

整数計画では、よい解が見つかった後も、それが最適だと証明するのに長くかかることがあります。その場合は、十分よい解が見つかった時点で打ち切る設定が効きます。次のコードは、後述の速度比較と同じ変数150本の問題を作って、打ち切り条件を付けて解きます。

```
import random
from pyscipopt import Model, quicksum

def build(N, M, seed=42):
    random.seed(seed)
    profit = [random.randint(10, 100) for _ in range(N)]
    weight = [[random.randint(1, 40) for _ in range(N)] for _ in range(M)]
    cap = [int(sum(row) * 0.4) for row in weight]
    return profit, weight, cap

N, M = 150, 40
profit, weight, cap = build(N, M)
m = Model()
x = [m.addVar(vtype="B") for _ in range(N)]
for i in range(M):
    m.addCons(quicksum(weight[i][j] * x[j] for j in range(N)) <= cap[i])
m.setObjective(quicksum(profit[j] * x[j] for j in range(N)), "maximize")

m.setParam("limits/time", 10)    # 10秒で打ち切る
m.setParam("limits/gap", 0.01)   # 上界と下界の差が1%以内になったら止める
m.hideOutput()
m.optimize()
obj = m.getObjVal() if m.getNSols() > 0 else None   # 解が無いまま打ち切られた場合に備える
print(m.getStatus(), obj, round(m.getGap(), 4), round(m.getSolvingTime(), 2))
# gaplimit 4690.0 0.0071 0.83  ← 末尾の所要時間は実行ごとに変わる
```

`limits/gap` を1%で与えた結果です。最適性を証明しきった場合の目的関数値4694に対して4690で、差は0.09%です。一方、所要時間は180.1秒から0.83秒になりました（3回測って0.83〜0.86秒）。`getStatus()` が `gaplimit` を返すので、証明済みの最適解と取り違えることはありません。

## generateIISによる実行不能モデルの原因特定

結果が `infeasible` で返ってきたとき、何百本もある制約の中から矛盾している組を目で探すのは現実的ではありません。SCIP 10.0で入ったIIS（既約矛盾部分系）の抽出を使うと、制約をそれ以上取り除けない矛盾の組まで機械的に絞り込めます。既定では変数の上下限は削除候補にならずそのまま残り、上下限まで絞るには `iis/removebounds` を有効にします。要素数が最も少ない組を保証するものではありません。pipで入れたPySCIPOptのまま動きました。

```
from pyscipopt import Model

m = Model("infeas")
x = m.addVar("x", lb=0)
y = m.addVar("y", lb=0)
m.addCons(x + y <= 1, name="c1")
m.addCons(x >= 3, name="c2")
m.addCons(y >= 0.5, name="c3")
m.hideOutput()
m.optimize()
print(m.getStatus())                  # infeasible

iis = m.generateIIS()
sub = iis.getSubscip()
print([c.name for c in sub.getConss()])   # ['c2', 'c1']
print(iis.isSubscipIrreducible())         # True
```

返ってきたIISは、制約 c1・c2 と、x・y の下限0です（ログの `Num. Bounds in IIS : 2`。上下限は既定で残るため、矛盾に関係しない x の下限も含まれます）。矛盾の決め手は y の下限で、x が3以上で y が0以上なら、x + y を1以下にはできません。c3 は関係ないため入りません。このようにIISには変数の上下限も含まれますが、`getConss()` で返るのは制約だけです。`generateIIS()` は画面に `Num. Cons. in IIS : 2` などの要約を出すだけでなく、IISオブジェクトを返します。`getSubscip()` で取り出した部分問題の `getConss()` を見れば、矛盾している制約の名前をプログラムから得られます。モデルを組むときに制約へ `name` を付けておかないと、ここで `c1` のような自動名しか出ず、どの業務ルールが矛盾しているのか読み取れません。

IISの抽出にも探索の時間がかかるので、大きなモデルでは `getTime()` で所要時間を確かめておきます。

## SCIP・CBC・HiGHSの同一問題での速度比較

「SCIPはCBCより速い」という説明を見かけますが、手元で測ると成り立ちませんでした。3つのソルバーに同じ多次元ナップサック問題を、規模だけ変えて解かせた結果です。

### 3ソルバーの計測結果

探索のパラメータは既定値のままで、ログ出力を止め、求解時間の上限を600秒にしました（どの計測も上限には達していません）。同じマシン（Intel Core i9-9880H・16論理コア、macOS 26.6.2、Python 3.15.0）で測りました。SCIPはPySCIPOpt 6.3.0（SCIP 10.0.2）経由です。CBC（cbcbox 2.935）とHiGHS（highspy 1.15.1）はpython-mip 2.0.0経由で呼び、ソルバーごとに別のプロセスで実行しています。

| 規模         | SCIP 10.0.2 | CBC   | HiGHS  | 最適値  |
| ---------- | ----------- | ----- | ------ | ---- |
| 変数60・制約30  | 0.9秒        | 1.0秒  | 2.5秒   | 1803 |
| 変数100・制約30 | 7.5秒        | 4.4秒  | 6.5秒   | 3180 |
| 変数150・制約40 | 180.1秒      | 47.0秒 | 314.7秒 | 4694 |

3つのソルバーとも最適値は一致しており、解の正しさに差はありません。速度は、変数60本ではSCIPがわずかに速く、100本と150本ではCBCが最速でした。150本ではCBCがSCIPの約3.8倍、HiGHSの約6.7倍の速さです。150本の値は、初回の計測中に同じマシンで別の重い処理が動いていたため、その処理を止めて測り直した値です（初回はSCIP 284.2秒、CBC 118.4秒）。HiGHSは処理を止めた後に2回測り、321.2秒と314.7秒でした。表には2回目を載せています。2026年8月にPySCIPOpt 6.2.1（同じSCIP 10.0.2）と当時のCBCで同じ問題を測ったときも、SCIP 183.8秒、CBC 46.9秒で、順位は変わりませんでした。

ただし、1種類の問題を1つのシードで測った結果で、CBCが一般に速いことを示すものではありません。前回、2021年ビルドの古いCBCに差し替えたときは、変数100本でSCIPの方が速くなりました。ビルド時期だけで順位が入れ替わるので、自分のモデルを複数のソルバーで解いて測ってください。

### 並列求解（solveConcurrent）の効果

10.1.0で追加された `-t` オプションは、内部で `SCIPsolveConcurrent()` を呼びます。PySCIPOptでは `m.solveConcurrent()` で同じ処理を呼べるので、pip版（SCIP 10.0.2）のまま、`optimize()` の代わりに使って同じ問題を解きました。結果は、変数60本で1.7秒（通常0.9秒）、100本で9.8秒（同7.5秒）、150本で420.1秒（同180.1秒）で、すべての規模で通常の求解より遅くなりました。実行中のCPU使用率は約290%で、複数のスレッドが動いていたことは確かめています。

パラメータ一覧に `concurrent/scip-feas` や `concurrent/scip-opti` といった設定の組が並んでいることからわかるように、この並列求解は、設定や乱数シードを変えた複数のSCIPを同時に走らせ、見つけた解や変数の範囲を途中で共有する方式です。1本の探索木を分担して速く解く仕組みではありません。今回のナップサックでは並列求解のほうが所要時間が長くなりました。この計測だけでは、遅くなった原因までは切り分けられていません。並列求解は、既定の設定で探索が行き詰まるモデルで試し、効くと確かめてから使うべきです。スレッド数の上限は `parallel/maxnthreads` で、既定値は8です。

### SCIP・CBC・HiGHSの速度比較の再現手順

SCIPの計測は、前述の打ち切り例と同じモデルを、`limits/gap` の指定を外し（既定の0に戻し）、`limits/time` を600にして `optimize()` で解き、その前後を `time.perf_counter()` で計りました（並列求解は `optimize()` を `solveConcurrent()` に置き換えただけです）。CBCとHiGHSは、同じ `build()` の出力を使ってpython-mipで次のように解きました。

```
import random
import time
import mip

# 前述の打ち切り例と同じ問題生成関数
def build(N, M, seed=42):
    random.seed(seed)
    profit = [random.randint(10, 100) for _ in range(N)]
    weight = [[random.randint(1, 40) for _ in range(N)] for _ in range(M)]
    cap = [int(sum(row) * 0.4) for row in weight]
    return profit, weight, cap

N, M = 150, 40
profit, weight, cap = build(N, M)
m = mip.Model(sense=mip.MAXIMIZE, solver_name=mip.CBC)   # HiGHSは mip.HIGHS
m.verbose = 0
x = [m.add_var(var_type=mip.BINARY) for _ in range(N)]
for i in range(M):
    m += mip.xsum(weight[i][j] * x[j] for j in range(N)) <= cap[i]
m.objective = mip.xsum(profit[j] * x[j] for j in range(N))
t = time.perf_counter()
status = m.optimize(max_seconds=600)
print(status.name, m.objective_value, round(time.perf_counter() - t, 1))
# OPTIMAL 4694.0 47.0  ← 末尾の所要時間は実行ごとに変わる
```

計測では、ソルバーごとに別のプロセスで実行しました。

## SCIP・PuLP・python-mip・OR-Tools・Gurobiの選び分け

モデルを書くライブラリ（モデラー）と、実際に解くソルバーは別の層です。ライブラリ全体の比較は[ORツールの比較と選び方](/tech/details/3034/)にまとめたので、ここではSCIPとの関係だけを扱います。

### モデラーとソルバーの対応表

| 名称               | 役割           | ライセンス      | SCIPを呼べるか          |
| ---------------- | ------------ | ---------- | ------------------ |
| PySCIPOpt 6.3.0  | モデラー（SCIP同梱） | MIT        | 専用                 |
| PuLP 4.0.1       | モデラー         | MIT        | SCIP\_PY・SCIP\_CMD |
| python-mip 2.0.0 | モデラー         | EPL-2.0    | 不可                 |
| OR-Tools 9.15    | モデラー＋ソルバー    | Apache-2.0 | SCIP 10.0.0を同梱     |
| Gurobi           | ソルバー（商用）     | 有償         | －                  |

PuLPは、PySCIPOptが入っていれば `SCIP_PY` でSCIPを呼べます。対話シェルの `scip` が入っていれば `SCIP_CMD` も使えます。PuLPそのものの使い方は[PuLPで最小化問題を解く手順](/tech/details/3036/)で説明しています。OR-Toolsは[v9.15のリリースノート](https://github.com/google/or-tools/releases/tag/v9.15)のとおりSCIP 10.0.0を同梱しており、[OR-ToolsのMathOpt](/tech/details/10298/)ではGSCIPという名前で選べます。

### python-mip 2.0のmip.SCIP指定：エラーなしでCBCが実行

python-mipが使えるソルバーは、CBC、Gurobi、HiGHS（1.17から）の3つで、パッケージの中にも `cbc.py`、`gurobi.py`、`highs.py` しかありません。それなのに、2026年8月18日に公開されたmip 2.0.0にも `mip.SCIP` という定数が残っています。`Model(solver_name=mip.SCIP)` と書いてもエラーにはなりません。実行して `type(m.solver).__name__` を見ると `SolverCbc` で、`m.solver_name` も `'CBC'` でした。SCIPを指定したつもりでもCBCで解かれ、その結果をSCIPのものと思い込む事故が起こり得ます。SCIPを使うなら、PySCIPOptを直接使うか、PuLPの `SCIP_PY` を使ってください。

### SCIPを選ぶ場面と商用ソルバーへ切り替える条件

無料のソルバーの中でSCIPを選ぶ理由は、速さではなく扱える問題の幅です。二乗の制約のような一般の非線形を含む問題は、CBCやHiGHSでは解けません。HiGHSが扱えるのは、連続変数の凸二次目的関数（線形制約）までです。IISで矛盾した制約を絞り込みたい場合や、独自の制約ハンドラ・分枝ルール・列生成（プライサー）を差し込みたい場合もSCIPが向いています。逆に、線形の混合整数計画を解くだけなら、まずCBCやHiGHSで測って比べるべきです。

商用ソルバーに切り替えるのは、ギャップ設定やパラメータ調整をしても要件の時間に収まらない場合、応答時間の上限をSLAとして約束する場合、不具合時のベンダーサポートが要件になっている場合です。再実行してよい社内の試算で、自分のモデルを測って要件の時間と精度に収まるなら、SCIPで足ります。価格を含めた比較は[Gurobiの使い方と価格](/tech/details/2756/)を参照してください。

## よくある質問

### SCIPの読み方は？

最適化ソルバーのSCIPについて、ZIBが読み方を決めている資料は見つかりませんでした。Solving Constraint Integer Programsの頭字語です。一方、同じ綴りのSourcegraphのSCIPは、公式READMEに `pronunciation: "skip"` と書かれていて、「スキップ」と読みます。読み方を調べてコード索引やLSIFの話が出てきたら、それは別のSCIPです。

### SCIPは商用製品に組み込んで使えますか？

8.0.3以降なら使えます。Apache License 2.0の条件（ライセンス文の同梱など）を守れば、商用利用も再配布もできます。8.0.2まではZIB Academic Licenseなので、古い環境では `printVersion()` で版を確かめてください。

### pip install scip でインストールできますか？

コマンドは成功しますが、入るのは別物です。PyPIの `scip` は細胞画像処理ツールのScalable Cytometry Image Processing（0.1.12）で、エラーが出ないまま無関係なパッケージが入ります。最適化ソルバーのパッケージ名は `pyscipopt` です。

### SCIPとSciPyは何が違いますか？

綴りが似ているだけで、別のものです。SCIPは混合整数計画向けのソルバーで、整数条件を含む問題を分枝限定法で解き、最適性を保証できます。SciPyはPythonの科学計算ライブラリで、`scipy.optimize` は連続変数の最適化や最小二乗法が中心です。`scipy.optimize.milp` で線形の整数計画は解けますが、非線形の整数計画は扱えません。SciPyについては[SciPyの使い方とNumPyとの違い](/tech/details/3137/)で説明しています。

### SCIPとCBC・HiGHSはどれが速いですか？

問題によって変わります。多次元ナップサック問題の実測では、変数150本でCBC 47.0秒、SCIP 180.1秒、HiGHS 314.7秒でしたが、1種類の問題の結果なので一般化はできません。非線形の制約を含むならCBCとHiGHSでは解けないのでSCIP、線形だけなら自分のモデルを複数のソルバーで解いて測るのが確実です。

## 関連記事

- [ORツールとは？OR-Tools・Gurobiなど主要6ツールの比較と選び方【無償版の上限を実測】](/tech/details/3034/)
- [PuLPとは？Pythonで最小化問題を解く手順と3.3系で非推奨になったAPI](/tech/details/3036/)
- [Gurobiとは？Pythonでの使い方・インストール・価格を解説](/tech/details/2756/)
- [Google OR-Toolsとは？Pythonでの使い方とインストール、CP-SAT・配送ルートの実行例【v9.15】](/tech/details/3477/)
- [決定変数・目的関数・制約条件とは？違いと定式化の手順を例題で解説](/tech/details/8321/)

---

出典: [SCIPソルバーとは？PySCIPOptでPythonから使う手順とCBC・HiGHSとの比較【SCIP 10.1】](<https://www.issoh.co.jp/tech/details/3037/>)（株式会社一創）
