...

Xpress-MP 概説書

by user

on
Category: Documents
25

views

Report

Comments

Transcript

Xpress-MP 概説書
© Copyright Dash Associates 1984 – 2002
Second Edition, February 2002.
Xpress-MP
概説書
Xpress-MPの機能と活用について一から説明します。
2007年
Dashoptimization株式会社
注:
本マニュアルに含まれるすべての商標はダッシュ社(Dash Associates)のものではありません。
本書で使用されている会社名、製品名、データは、すべて架空のものであって、単にXpress-MPの使
用方法を例示するためのものです。したがって、仮に類似の名称、データが実際に存在していても、
それは偶然であることを承知ください。
弊社への連絡方法
…
…
…
Xpress-MPの使用に関して、質問、コメント、等がありましたら、下記のダッシュ社技術
サポート部にご連絡ください。:
Xpress-MPソフトウェアの購入注文に関して、質問等がありましたら、下記のダッシュ社
各地域販売部にご連絡ください。
Xpress-MPソフトウェアと関連資料の更新に関する最新のニュースについては、下記のウ
ェブサイトをご覧ください。 http://www.msi-jp.com/doj/
2
目
次
1 始める前に 1
はじめに ·············································································7
Xpress-MP ライブラリーと構成要素 ·····················································8
Xpress-Mosel Xpress-Optimizer ························································8
Xpress-IVE ···········································································8
コンソール Xpres-MP ··································································8
Xpress-MP ライブラリー ·······························································9
どのインターフェイスを使うか? ························································9
この本の読み方 ······································································ 9
この本の構成 ········································································ 9
表記法 ·············································································· 10
2 Xpress-IVE
始める前に ·········································································· 11
Xpress-IVEを始めよう ································································ 11
簡単なモデル入門 ···································································· 11
プロジェクトの関連作業 ······························································ 12
モデルエディター ···································································· 12
コンパイルと読み込みと実行 ·························································· 13
Xpress-IVEをもっと知るために ························································ 14
Xpress-IVEについて ·································································· 15
制御オプションの設定 ································································ 15
多重モデルの実行 ···································································· 15
行列ファイルの書き方 ································································ 16
行列ファイルによる問題の入力 ························································ 17
関数のグラフ化 ······································································ 17
環境の変更 ·········································································· 18
ヘルプの利用 ··································································· 18
3 Console Xpress
始める前に ·········································································· 19
Console Xpress の構成要素 ··························································· 19
Xpress-Moselのテスト方法 ······························································· 20
Xpress-Optimizer の検査方法 ························································· 20
Xpress-Moselを用いて簡単な問題を解く ················································ 21
Mosel ファイル ······································································ 21
Moselの3つの柱 ······································································ 21
Moselからさらに情報を得る ··························································· 22
Moselをさらに用いる ································································· 23
パッチモードで実行する ······························································ 23
複数個のModelを実行する ····························································· 23
行列ファイルの書き方 ································································ 25
Xpress-Optimizerを動かす ···························································· 25
問題の解き方 ········································································ 25
解の見方 ············································································ 26
3
WRITEPRTSOLの出力 ··································································· 27
Optimizerをさらに利用するために ····················································· 28
最適化アルゴリズム ·································································· 28
整数計画法 ·········································································· 28
Optimizer の制御 ···································································· 30
ヘルプの利用 ········································································ 31
4 Xpress-MP ライブラリー
始める前に ·········································································· 32
Xpress-MPライブラリーの構成要素 ····················································· 32
Mosel ライブラリーを動かす ························································· 33
簡単なモデル入門 ···································································· 33
Mosel ライブラリーの構成要素 ························································ 33
Moselの3つの段階 ··································································· 33
解の情報の取得 ······································································ 35
Mosel ライブラリーをさらに利用するために ············································ 36
いくつかのモデルをさらに利用するために ·············································· 36
実行時間の管理 ······································································ 38
行列ファイルの書き方 ································································ 39
Xpress-BCLをさらに利用するために ···················································· 40
モデルの最初の定式化 ································································ 40
問題をBCLを用いて解く方法 ··························································· 42
行列変数を用いた問題の定式化 ························································ 44
BCLをさらに利用するために ··························································· 45
整数計画法 ·········································································· 45
行列ファイルの書き方 ································································ 46
Xpress-Optimizer ライブラリーをさらに利用するために ································· 47
Optimizer ライブラリーを用いて問題を解く方法 ········································ 48
XPRSwriteprtsolを用いて解を得る方法 ················································· 49
Optimizer ライブラリーをさらに利用するために ········································ 50
最適化アルゴリズムを変更する ························································ 50
整数計画法 ·········································································· 50
事前解法と後処理 ···································································· 51
制御と問題の特性 ···································································· 52
最適化処理の対話方式 ································································ 53
メモリーからのモデルの入力方法 ······················································ 55
Optimizerライブラリーによる問題の入力方法 ··········································· 55
問題の解を得る方法 ·································································· 57
問題の行列の変更 ···································································· 58
問題の全域要素の追加 ································································ 59
Xpress-MPライブラリーから最良解を得ること ··········································· 60
エラーの検出方法 ···································································· 60
BCLとOptimizerライブラリーの結合 ···················································· 61
Visual BasicとXpress-MPライブラリーの利用 ··········································· 63
内部ファイル ········································································ 63
主要構成 ············································································ 63
Visual Basicのコールバックスの利用 ·················································· 66
4
JavaによるXpress-MPライブラリーの使用方法 ··········································· 67
Javaを用いたBuilder Component Library (BCL) ········································· 67
Javaを用いた Optimizer ライブラリー ················································· 68
主要構成 ············································································ 70
Javaのコールバックスの利用 ·························································· 72
ヘルプの利用 ········································································ 73
5 Xpress-MPによるモデルの構築
はじめに ············································································ 74
最初のモデルの構築 ·································································· 74
盗人問題 ············································································ 74
問題の特定 ·········································································· 75
モデルのXpress-Mosel への導入 ······················································· 75
Optimizerのライブラリーモジュール ··················································· 77
行列によるモデルの構築 ······························································ 78
行列変数と添字の導入 ································································ 78
ループ化と和計算 ···································································· 79
コメント ············································································ 79
ストリング添字の使用方法 ···························································· 80
モデリングにおける汎用性 ···························································· 81
総称的モデルと例示的モデル ·························································· 81
実数の宣言 ·········································································· 81
テキストファイルからのデータの入力 ·················································· 82
強盗問題の解 ········································································ 82
Mosel によるパラメタの利用 ·························································· 85
ハイカー問題 ········································································ 85
ハイカー問題の解法 ·································································· 85
ヘルプの利用 ········································································ 86
6 Moselに関する話題
はじめに ············································································ 88
集合について ········································································ 88
動態的、固定的、最終集合 ···························································· 89
集合演算 ············································································ 89
行列の利用について ·································································· 90
動的、固定的行列 ···································································· 91
疎行列 ·············································································· 92
データの入出力 ······································································ 93
モデルデータの要素 ·································································· 93
initializations ブロックを用いたデータの転送 ········································ 93
ODBCを用いたデータの転送 ···························································· 94
readln と writeln によるデータの転送 ················································ 97
条件付き変数と制約 ·································································· 98
条件付き上下限 ······································································ 98
条件付き変数 ········································································ 99
基本的計画問題の構造 ································································ 99
if コマンド ········································································· 99
case コマンド ····································································· 101
5
forall ループ ····································································· 101
while ループ ······································································ 102
repeat ループ ····································································· 102
プロシージャと関数 ································································ 103
プロシージャ ······································································ 104
関数 ·············································································· 105
再帰性 ············································································ 106
前進型宣言 ········································································ 106
7 用語のまとめ····································································· 109
索引 ·············································································· 112
6
Xpress-MP Essentials Introduction 1
Getting
Started
1
第1章
始める前に
概要
この章では、以下の項目について説明します。
•
•
•
Xpress-Mosel と Xpress-Optimizerの概要;
Xpress-Mosel と Xpress-Optimizerの相互関連;
本書の構成と読み方.
はじめに
Xpress-MP は数理モデル構築と最適化のためのソフトウェアで、線形ならびに2次の整数計画問題
に対して、モデルの定式化、最適解、分析のための各種手法を提供します。
さらにXpress-Mosel と Xpress-Optimizerという強力な構成要素に基づいて、各種インターフェイ
スを通じて、問題解決とXpress-MP技術のソフトウェア製品への導入をはかることによって、多様な
利用者のニーズに応えるものである。
本書は、Xpress-MPへの入門書であって、初めての利用者がすぐにXpress-MPになじみ、実行できる
ように書かれている。したがって、読者が数理計画法の知識をほとんど有していないことを前提と
して、読み進めることができる構成となっている。一方、数理計画法による問題解決の経験と知識
のある読者に対しては、このソフトウェアに関する新たな知識が有効的に与えられるよう、考慮さ
れている。
Xpress-MPの多くのマニュアルでは、本書に説明されている内容に関する知識が前提とされているた
め、読者は、前もってこれらの内容に精通していることが望ましい。
Xpress-MPの構成要素とインターフェイスについて説明しよう。構成要素のうちのいずれを用いるか
について、すでに決めている読者は、それにしたがって本書の関連する章を参照することができる。
未だ決めていない読者に対しては、本書の各章の概要がわかるように工夫がなされている。
本
書は、Xpress-MP製品のインストールやセットアップ方法について詳細を述べることを目的としてい
るのではなく、そのような情報については、付属のCD-ROMにある‘readme’ 資料(readme.win,
readme.unx) を参照されたい。すべての読者が、本CD-ROMに含まれるソフトウェアをインストール
し、使用する前にオペレーティングシステム関連資料を読むことを強くすすめたい。
7
Xpress-MP の構成要素とインターフェイス
Xpress-Mosel
Xpress-MPの基本的な構成要素はXpress-MoselとXpress-Optimizerである。Moselは、Mosel モデル
言語を用いて線形計画法あるいは混合型整数計画法 (MIP)によって表されるモデルを構築し、これ
らの問題に対する解法を与える環境である。モデルが小さい場合には、機能をいろいろと増やすラ
イブラリーモジュールを含めることによってモデルの拡張が可能である。またMoselの基本的前提は、
モデリング記述と問題を解く手続きとが分離されていないということである。このために、複雑な
モデルを構築し、Moselの中で問題を解き、解を利用者が指定したように出力するライブラリーモジ
ュールとしてのOptimizerが含まれている。
ライブラリー利用者に対しては、もう一つのXpress-BCLがあるので、詳細については、4章を参照されたい。
Getting
ODBC ライブラリーモジュールを用いると、Moselによってデータを検索し、回答をスプレッドシー
トやデータベースの形で広く転送することが可能となる。ODBCは主要なデータベースとのデータ交
換を行う標準ソフトであって、Mosel mmodbcライブラリーモジュールには、ODBCをExcel, Oracle あ
るいはAccessなどのODBC関連ソフトと連結する機能がある。
利用者は、Moselをテキストファイルからデータを取り出したり、問題を表現するためのデータベー
スを作成したり、Optimizerライブラリーモジュールを呼び出して最適解を求めたり、数値結果を他
のODBC関連のソフトに転送してレポートやプレゼンテーション用資料を作成したりすることができ
る。入力データはいくつかの異なるデータソースから集められ、各種の最適解は異なるファイルに
それぞれの要求に最も良く合うように転送される。
Xpress-Optimizer
Xpress-MPの中核部分にあるXpress-Optimizerには、線形計画法(LP), 2次計画法 (QP)、そして混
合型整数計画法 (MIP)などが含まれている。連続型の計画問題に関しては、Optimizerを用いて広範
な問題の解決が可能となった。Optimizerはあらゆる問題を解くための最良の手段として広く認識を
されてきているが、各種の制御手法を用いることによって利用者がOptimizerの機能をそれぞれの問
題を各自が望むように利用することが可能となっている。このことは、特に、近似的な最適解を得
ることすら困難とされる、多くの大規模混合型整数計画問題を解く場合に有用である。最も難しい
とされるMIP問題に対して、Xpress-MPは、並列型MIP Optimizerを用いて、多様なPCネットワークや
ワークステーション、あるいはメモリー共用型マルチプロセッサーのもとで稼働し、すべてのコン
ピュータの性能を十分に発揮するように作られている。並列型Optimizerは大規模最適化手法の最先
端にある手法である。
Getting
Xpress-IVE
Xpressの対話型ビジュアル環境としてのXpress-IVEは、マイクロソフトウィンドウズの下で動くモ
デリングと最適化を進める環境である。Moselが、容易に利用可能なテキストエディターを有するグ
ラフィカルユーザーインターフェイス(GUI)として表わされるとすると、IVEは、モデルを多重的に
開発し、管理し、さらに実行する手段となる。これらは容易に使用可能であることから、Xpress-MP
利用者が精通している強力なモデリング、最適化手法を結合することによって、IVEは標準型モデル
を開発し、計算する理想型ソフトである。
Console Xpress
Console Xpress はmoselとoptimizerの2つの独自に実行可能な部分からなる。これらはMoselと
Optimizerという構成要素に対する強力なテキストベースの ‘console’ インターフェイスである。
8
これらは広範な機能とアルゴリズム上の汎用性を有し、Windows, Linux あるいは UNIXなど種々の
OS上で本質的には同様の形で利用可能となっている。Console Xpress の製品は、多くの業務用利用
者にとって各種の要求を満たすべく、作られていることが判明している。Xpress-IVEを用いてモデ
ルを構築すると、Console Xpressの要素をバッチファイルあるいはシェルスクリプトに組み込み、
大規模なモデルデータを解くように最適化アルゴリズムを利用することによって、生産システムの
モデルを容易に構築することが可能となる。
Xpress-MP ライブラリーズ
C/C++, Javaあるいは Visual Basic を用いてXpress-MP ライブラリーをMosel とOptimizerの2つ
を組み込むと、より専門的な応用を実現することが可能となります。 Xpress-MP ライブラリーの
主な長所は、Xpress-MPによって提供される各種の機能を利用者の応用例に適合させ、それぞれの応
用例の中で利用者のニーズを満たすような柔軟性を持たせていることである。Windowsの下では、
Xpress-MP ライブラリーは、Xpress-MPの構成要素をWindowsの下で統合するための標準型数理計画
問題のインターフェイスを提供するDLLとして利用可能である。
Getting
UNIX 利用者にとっては、Xpress-MP ライブラリーを共用のオブジェクトライブラリーとして利用す
ることが可能である。またXpress-MP ライブラリーのもう一つの利用方法として、すべての
Xpress-MP製品の中で基本的なモデルの構築手法と最適化機能を利用した単独の応用例を作成する
ことも可能である。データを入力し、問題を作成し、最適解を求め、解を出力するという応用例に
ついては、膨大なマニュアルに頼ることなく、容易に処理することが可能である。特殊な応用例を
実行し、特別なヒューリスティック手法を用いたい利用者にとっては、Xpress-MP ライブラリーは
より高度の機能を提供することが可能である。すなわち、行列を入力し、操作し、出力し、問題を
解き、解を検索し、多重的に問題を処理し、コントロールすることが可能である。さらに、最適化
アルゴリズムと分枝カット法(‘Branch and Cut’)の管理機能を駆使することによって、より高度の最
適化手法の応用が可能となる。
どのようなインターフェイスを使うか?
初心者が新たなモデルを構築する場合には、Xpress-IVEによってXpress-MPソフトウェアに対する最
も簡単なインターフェイスを利用することができる。統合的な開発環境を用いると、モデル構築が
容易となり、他のインターフェイスの可能性を処理するすべての解が得られる。モデルの構築と最
適化手法を利用する生産システムを作動させるには、Console Xpressが用いられ、バッチ処理の応
用例が構築される。これは最大の問題例にふさわしい最適化手法を提供する柔軟性のある製品であ
る。仮に利用者がウィンドウズのようなソフトウェアを開発している場合には、Xpress-MPライブラ
リーが最良のインターフェイスを提供する。また問題が難しく、良い解を得るために特別なヒュー
リスティック手法を開発したいような場合には、Xpress-MPライブラリーが非常に有用となることも
ある。
Getting
Started
1
この本の読み方
この本の構成
本書は、読者がXpress-MPソフトウェアをすでにインストールしていることを前提としているので、
インストールの詳細については記述されていない。Xpress-MPソフトウェアのインストールと主要な
9
各種コンパイラー環境のライブラリー構成要素のセットアップに関する情報については、インスト
ールのためのCD-ROMに付属している‘readme’ ファイル (readme.win, readme.unx および
lib\readme.txt) を参照されたい。
以下の3つの章 (2 – 4)は、初めての利用者にとって興味あるものであって、Xpress-IVE,
Console Xpressあるいは the Xpress-MP ライブラリーなどの各種Xpress-MPインターフェイスにつ
いて論じている。本書を利用する読者の大部分は、本書を利用する特定の目的のみが関心事である
ため、各種Xpress-MPインターフェイスの中でも唯一の事項だけが関連することになるであろう。以
下の各章においては、まず一つの簡単な例題を取り上げ、読者自身の問題の最適化をおこなう場合
に重要となる実際的な多くの事項を紹介する。以下の2つの章では、Moselとそのモデル言語につい
て述べている。まず5章は“Xpress-MPによるモデリング”であって、モデリング言語についての主要
な特性を紹介し、さらに簡単なモデルを構築し、いろいろなモデリングの機能の特典についても述
べている。6章では、”Mosel についてのさらなる話題”として、いくつかの概念を拡張することによ
って得られる関連の話題を紹介する。しかしながら、ここでの扱い方は概略のみであるので、詳細
については、Xpress-Moselレファレンスマニュアルを参照されたい。本書の最後は、すべてのマニ
ュアルで用いられる共通の用語集となっている。
表記法
本書の大部分を理解するには、いくつかの形式、規則について共通理解をしておく必要がある。
一般に、問題を表現するには標準的な印刷スタイルが用いられ、方程式や変数はイタリック形式の
固定幅フォントを用いた出力として得られる。問題の出力が混乱を招くような場合には、利用者の
入力をボールドタイプ(bold type face)で表し、いくつかの問題の間の相異を表すのにも、この方
式が用いられる。さらに追加的に、本書では以下のような表示形式とアイコンが用いられている。
Getting
注: 読者に知っておいて欲しいと思われる一般的事項を表す。関連のテキストの中で用いられてい
る場合に必要とされる事項である。
注意: 読者自身が問題あるいは解を正しく把握するために必要とされることが多い注意点を表す。
概念: 経験することは重要である。概念とは、われわれが過去において成功したようなアプローチ、
あるいはわれわれ利用者にとって価値があったとされる特定の知識を表す。
デバッギング: 特に本書の前半部分に関連する事項で、利用者がソフトウェアをセットアップする
のが困難な場合に必要とされる共通のエラーの扱い方、ヘルプの用い方などを表す。
演習問題: 本書を通して、いくつかの短い演習問題を掲載した。これらは本製品についての演習と
いうだけでなく、他の章にある概念についても理解を深めるために有用なものである。
標記: 本書の利用に際しては、いろいろな読み方が可能であって、各自の興味と知識に合わせて、
ある部分を読み飛ばすことも可能である。この標記は、論理的な章とその内容とが終了することを
意味し、次の章の内容を表している。
補注:
本項目は、本文中に入れられないような細かな事項を欄外に注あるいは引用の形で記載し、読者の
注意を引くことを目的としている。
Getting
まとめ
この章では、Xpress-MPソフトウェア、Mosel、Optimizerという3つの構成要素、そしてまた
Xpress-IVE, Console Xpress、Xpress-MP ライブラリーという主要な3つの構成要素に対するイン
ターフェイスについて学んだ。
Xpress-IVE
2
10
第2章
Xpress-IVE
概要
本章では、以下の項目について述べる。
•
•
•
•
プロジェクトの実施とXpress-IVEインターフェイスの中のプログラムファイルのモデル化;
単純なモデルの入力とその解法;
出力と問題の行列ファイルとしての入力;
Xpress-IVE環境の概観をカストマイズする方法を学ぶ
はじめる前に
Xpress-IVEは、Xpress-Moselに対するグラフィックユーザーインターフェイスであって、またマイ
クロソフトウィンドウズの利用者にとってはXpress-Optimizerであるため、Xpress-MPの最適化ツー
ルを利用し、学ぶ際の簡単な開発環境を提供するものである。本章の読者は、すでにXpress-IVEを
インストールしているものとする。本章を読むと、対話型のビジュアル環境が説明され、解と出力
がいろいろな形式で表現されているので、簡単なモデルをどのようにして入力し、解くかが分かる
であろう。Xpress-IVEのインターフェイスは、利用方法を容易にするために、MoselとOptimizerと
いう2つのXpress-MPの主要な構成要素を一つのグラフィック環境に組み込んでいる。強力なMosel
モデルプログラミング言語を実行するために、複雑なモデルが開発され、最小の手間で解かれるた
め、Xpress-IVEはXpress-MPソフトウェアの新たな利用者にとって理想的な出発点となっている。
2
Xpress-IVE
Xpress-IVEを始めよう
インストールをすると、スタートメニューにアイコンフォルダーが追加され、Startボタンを押し、
Programs, Xpress-MP とXpress-IVEを選択するとIVEが開始される。そうでない場合には、
xpressmp\binディレクトリーにあるive.exeアイコンをクリックすることによってWindows
Explorerからスタートすることになる。
演習問題:
IVEを開始し、インストールが正しく行われたことを確認せよ。
すべてのXpress-MP製品には、ソフトウェアにとって必須の安全システムが付けられており、インス
トールによって安全対策としてのすべての特性が実施可能となる。インストールが正しく行われな
い場合には、あるいはまたライセンスなしで実行するような場合には、Xpress-MPは‘試行モード
(trial mode)’で開始され、‘試行バージョン(Trial Version) — 業務利用禁止(commercial use
prohibited)’というメッセージがウィンドウ上枠に提示される。ソフトウェアはこのモードで実行
可能ではあるが、問題の大きさや複雑さに関しては制限が加えられている。Xpress-MPのソフトウェ
アライセンスがあるにもかかわらず、このような状況が生じた場合には、‘readme’ファイルに安全シ
ステムのセットアップの詳細が記されているので、参照されたい。
簡単なモデル入門
11
プロジェクトの関連作業
IVEを用いることによってモデルが作成され、projectとして構築される。IVEプロジェクトには一
つのモデルに対してファイルを何個でも含むことができるので、計算すべき対象を次々と設定する
ことができる。画面の左端にあるProject Files枠には
利用をさらに容易にするために、デスクトップにIVEへのショートカットを追加することができる。You may wish to add a
という表示があり、開発中のプロジェクトと関連する
ファイルが示される。新しいモデルに入る場合に最初になすべきことは、そのモデルを含むプロジ
ェクトを作ることである。
shortcut to IVE to your desktop for easier access.”
新しいXpress-IVE 2
演習問題
本章で用いる、‘essentials’ というプロジェクトを作成せよ。プロジェクトにはどのような種類の
ファイルを含む必要があるか?
Project Files枠は新しいプロジェクトを示すために更新される。プロジェクトは作成された入力フ
ァイルとモデルをコンパイル、実行して得られた出力ファイルの両方を含むことができる。モデル
プログラムファイルとモデルに関連した外部データを含む任意の個数のファイルがプロジェクトに
追加されるが、出力ファイルにはバイナリーモデルと行列ファイルを含むことも可能である。ここ
では単にプロジェクトにモデルプログラムファイルを追加してみる。
演習問題
‘simple.mos’という名前の新しいファイルMosel fileを作成し、現在のプロジェクトである
‘essentials’と結合させよ。
Project Files枠は、新しいファイルの‘simple.mos’がプロジェクトの一部であって、新しいウィン
ドウでブランクファイルが開き、モデルに入ることを示している。
新しいプロジェクトの作成
IVEメニューバーからProjectとNew Projectを選ぶ。‘Browse’ボタンを用いてプロジェクトの親ディ
レクトリーを選び、プロジェクトディレクトリーに名前を入れる。このオプションが選ばれている
場合には、プロジェクトに対するすべてのファイルを含むような新しいディレクトリーが作成され
る。‘OK’をクリックして進む。
新しいモデルプログラムファイルの追加
IVEメニューバーからFile, New と Blank Fileを選ぶ。ダイアログボックスが現れ、ファイル名と
型を特定した後、ファイルを現在のプロジェクトに加える。
中央のエディターウィンドウが現れない場合は、Output/Input 枠の端をドラッグする。
モデルエディター
IVEはモデルファイルを作成し、変更するためのエディター機能を備えている。ASCIIファイルを見
たり、編集したり、保存したりすることができるが、モデルの構造を認識し、いろいろな構成要素
を区別したりすることが可能であるという点が有用である。この特性によってデバッグに要する時
間をかなり節約することができ、さらにほとんどのタイプミス的なエラーを発見し、修正すること
ができる。
演習問題 リスト 2.1にあるモデルを1行づつモデルエディターに入力せよ。
リスト 2.1の簡単なモデルには2個の決定変数(decision variables)と2本の制約条件
(constraints)がある。問題は利益を表す目的関数(objective function)を最大化することである。
ここではIVEを利用することに主眼を置いているので、当面、モデルの意味や構成要素について論じ
ることは控えよう。5章において、Mosel言語について述べることにする。
12
リスト 2.1 簡単なモデル
model simple
uses "mmxprs"
declarations
a: mpvar
b: mpvar
end-declarations
first:= 3*a + 2*b <= 400
second:= a + 3*b <= 200
profit:= a + 2*b
maximize(profit)
writeln("Profit is ", getobjval)
end-model
Xpress-MP Essentials Entering a Simple Model 13
Xpress-IVE
2
モデルが入力されると、model, uses, declarationsなどのキーワードが認識され、青色に変わる。
キーワードはモデルプログラムのいろいろな構成要素に対する指標となるので、正確に入力しなけ
ればならない。キーワードは、Ctrlキーとスペースキーを同時に押すと、エディターによって選択
され、メニューを用いてモデルの中に直接入力されるので、非常に便利である。
演習問題 モデルの中のdeclarationsブロックを削除し、カーソルを元の位置に置き、Ctrl-Space
キーを押して、リストから‘declarations@@end-declarations’を選べ。モデルがリスト2.1のように
なることを確認せよ。
IVEモデルはテキスト探索機能を備えているが、これは長いファイルを編集する際に特に有用である。
双眼鏡のアイコンの隣のテキストボックスにある単語やフレーズを入力してリターンキーを押すと、
その単語やフレーズの最初の例が表示される。リターンキーを再度押すと、ファイルに例がなくな
るまで次へ進むことができ、最終的には最初の提示に戻る。
演習問題 IVEモデルエディターのテキスト探索機能を用いて、ファイル‘simple.mos’の中にある単
語‘profit’のすべての例を示せ。
コンパイルと読み込みと実行
ここで作成したファイルは、model programとして表示される。これはモデル様式についての記述を
含むだけでなく、実行のための指令についての記述も含んでいる。IVEはコンパイルによってこのよ
うなファイルを処理し、コンパイルファイルを読み込み、最終的にそれを実行する。モデルプログ
ラムファイルが変更されるたびに新たなモデルを解くためのプロセスを処理しなければならない。
これらのステップについて順次考えてみよう。
モデルプログラムファイルをコンパイルする
IVE メニューバーからBuild とCompile を選ぶ。現在モデルエディターで動いているファイルがコ
ンパイルされる。
"Keywords…"
"Text
searches…"
2
Xpress-IVE
13
モデルプログラムファイルがコンパイルされると、コンパイルのプロセスについての情報が作業ス
ペースの最下部にあるBuild枠の中に示される。この枠は、コンパイルが開始されると自動的に表示
される。モデルの中に文法エラーが見つかると、エラーが見つかった行と文字の位置についての詳
細と、可能な場合には問題についての記述もここに表示される。
警告のメッセージも表示され、
Eばかりでなく、Wの文字が頭に付けられている。エラーが存在しない場合には、Build枠の中に
‘Compilation successful’が示され、コンパイル済みのバイナリーファイル、すなわちBIMファイル
が作成され、プロジェクトに付加される。
演習問題 リスト 2.1にあるモデルプログラムをコンパイルせよ。エラーが見つかった場合には、
リストを注意深くチェックし、問題を修正せよ。バイナリーモデルファイルがプロジェクトに付加
されるのをチェックせよ。
問題の解を求めるために、コンパイル済みのBIMファイルが読み込まれ、実行される。
演習問題 ‘simple.bim’ファイルを読み込み、問題を解け。このモデルで得られる利益の最大値を求
めよ。
モデルプログラムが実行されると、作業スペースウィンドウの右側のOutput/Input枠が選ばれ、プ
ログラムの出力が示される。モデルの出力はすべてこのウィンドウに送られ目的関数値が示される。
BIM ファイルを読み込んで実行する
メニューバーからBuildとRunを選ぶ。現在のモデルに対するBIMファイルが自動的に読み込まれ、実
行される。
Xpress-IVE
2
Xpress-IVEをもっと知るために
モデルの中で得られる最大利益を知るということは確かに有用であるが、それを達成するためには、
決定変数はどのような値をとるべきであろうか。IVEは左側ウィンドウにあるEntities枠を通して解
に関するすべての情報を得ることができる。この枠にある決定変数のリストを拡げ、マウスポイン
ターを操作すると、解とリデューストコストが提示される。制約条件に対する双対値とスラック値
も得られる。さらにEntitiesにある変数あるいは制約条件をクリックすると、モデルの中のあらゆ
る状況を説明するすべての行がマーカーで示され、作業スペースの最下部にあるLocations枠の中に
記述されている。マーカーはIVEツールバー上の‘Clear bookmarks’アイコンを用いて次々と除去する
ことができる。
演習問題 タブをクリックしてEntities枠を提示せよ。最大利益を達成するために決定変数(aとb)
はどのような値をとらなければならないか。変数aをクリックして、最終的にマーカーを除去する前
にこの変数を含むモデルのすべての行を示せ。
IVEは、解がどのようにして得られるかをグラフ的に表示するが、これは問題が最適化されるたびに
標準的に行われる。右側ウィンドウには、解くべき問題の型と使用される特定のアルゴリズムによ
って、これらについて説明するいくつかの枠が含まれている。考察対象の問題については、
Sim:Obj(iter)枠の中に単体法が用いられる場合の反復途中段階のいくつかの目的関数値が示され
る。
演習問題 Sim:Obj(iter)枠を示し、その上にあるグラフの全貌と情報を見るために、必要な場合に
ははウィンドウの大きさを変更せよ。マウスポインターをグラフの別の領域に移動させ、各反復に
おける反復回数と目的関数値がグラフの上に提示されていることを確認せよ。
この場合には、グラフの上に初期点と最終反復値のみが提示され、それ以外の情報は存在しない。
14
現在、これを制御するパラメタを変更することによって、反復途中の状態を見ることができる。
解の詳細は、単に"Solution graphs…"というモデルファイルの要素を操作することによっても見ることができ
る。
2
Xpress-IVE
Xpress-IVEをさらに利用するために
制御オプションの設定
Mosel モデルプログラミング言語を用いると、Xpress-Optimizerのコントロールパラメタの値を設
定することによって、解のプロセスに影響を与えるようないくつかの可能性を探ることができる。
このような可能性はプログラミング言語によって直接提供されるものであるが、オプションがIVE
によって得られる出力に影響を与えることを除けば、IVEは他との重複機能を有していない。Options
の後にBuildを選択すると、これらの可能性の全リストが見られる。おそらく最も興味があるのは、
最適化の途中で解の反復についてどれだけ詳細な情報が必要かということについての指令を与える
LPLOGコントロールであろう。特に、Optimizerでは初期値、最終値、そしてあらゆるLPLOG反復につ
いての情報が出力される。標準的にLPLOG反復回数を100に設定すると、Moselの設定は最初のオプシ
ョンに対する単体法によって書き換えられる。 Sim:Obj(iter)枠の中に作られたグラフ上に反復回
数をプロットするのはこのオプションである。
演習問題 ‘Ignore Mosel settings’の箱をチェックし、LPLOG反復回数を1に設定し、‘Apply’をクリ
ックし、問題‘simple’を再最適化せよ。グラフから、アルゴリズムの最初の反復に対する目的関数値
を求めよ。
ここで紹介するような小規模の問題について考慮することは興味あることであるが、大規模な問題
に対して、出力を各反復回数示す場合、Optimizerの性能はかなり落ちる。このような場合は、LPLOG
を高い値に設定しておくのが望ましい。解のグラフ表示に関心がない場合には、グラフオプション
を不可にして、無駄な手順を費やすことなく最適化操作を実行することが望ましい。これを実現す
るには、同様のコントロールオプションメニューを利用すればよい。
多重モデルの実行
IVE には一度に一つのプロジェクトしか入力できないが、プロジェクトはいくつかのモデルファイ
ルを有しており、これらのファイルはメモリーの中に保存され、同時に実行される。エディターウ
ィンドウの中に示されているモデルは現問題active problemと呼ばれるが、開いているモデルの中
からいずれかを選ぶことによっていずれかがコンパイルされ、必要に応じて実行される。これを提
示するためには、リスト2.2に示すような他のモデルが必要となる。
演習問題 プロジェクト‘essentials’に2番目のモデルファイル‘altered.mos’を追加し、リスト2.2
のモデルに入力せよ。
モデルがIVE の中で編集されると、現問題となる。Buildメニューからコンパイル(Compile) あるい
は 実行(Run)のオプションが呼ばれると、変換される現問題となる。
リスト2.2 変換モデル
model altered
uses "mmxprs"
declarations
a: mpvar
b: mpvar
end-declarations
15
first:= 3*a + 2*b <= 400
second:= a + 3*b <= 200
third:= 6*a + 5*b <= 800
profit:= a + 2*b
maximize(profit)
writeln("Profit is ", getobjval)
writeln(" a = ", getsol(a), "; b = ", getsol(b))
end-model
これとリスト2.1のモデル上の唯一の変化は、新しい制約を追加した点である。この制約条件が等号で成立する場合には、目
的関数値が減少することが期待される。
2 Xpress-IVE
演習問題 新しいモデル ‘altered’をコンパイルせよ。現在得られる最大利益はどれだけか。これを
プロジェクト‘simple’の利益と比較せよ。
左側ウィンドウにあるProject Files枠が現在のプロジェクトのすべてのファイルのリストを示し
ていることはすでに見た。すべてのオープンファイルのリストはこのウィンドウのすぐ上にボタン
の形で示されており、ファイル名のラベルが付けられている。これらのボタンをクリックすると、
関連のファイルがエディターウィンドウに示され、問題が操作可能となる。
問題の変更はこのようにして可能となるが、Entities枠にある情報はモデルのコンパイルが実行さ
れたときに更新されるということに注意されたい。このため、Entities枠にある解の情報が必ずし
も現在の問題の状況を表しているとは限らないので、いくつかのモデルを同時に動かす場合には、
このことに注意されたい。
演習問題 エディターウィンドウにあるモデル‘simple’を再提示するためにボタンをクリックせよ。
Entities枠にあるすべての情報は問題‘altered’に関連があることを確認せよ。
プロジェクトの中の他のファイルを開くためには、Project Files枠内のファイルを右マウスボタン
をクリックし、下に示されたメニューからOpen/Show fileを選べばよい。開いたファイルを閉じる
には、同じメニューからClose fileを選べばよい。ファイルをプロジェクトから削除するには、
Remove from projectを用いればよい。
演習問題 エディターウィンドウにあるファイル‘altered.mos’を閉じ、現在のプロジェクトからこ
のファイルと‘altered.bim’を削除せよ。Entities枠にある情報を更新するために、‘simple’を再実行
せよ。
Xpress-IVE
2
行列ファイルの書き方
最適化プロセスにおいて、IVEによって提供されている以上に制御可能なモデルを構築したくなるこ
とがあるかもしれない。あるいはまたモデルを他人に利用して欲しい場合もあるかもしれない。こ
のような場合には、出力は最終段階で利用されるソルバープログラムにおいて解読可能なように共
通の形式で記録されることが必要である。IVEによって、2種類の主要な業界標準形式である LPフ
ァイルとMPSファイルという行列ファイルを作ることが可能となる。
演習問題 モデルプログラム‘simple.mos’からMPS行列ファイル‘simple.mat’を作成し、モデルファイ
ル‘simple.mos’を閉じよ。
MPS形式と異なって、LPファイルにはモデルが最大化問題あるいは最小化問題のいずれを扱う場合に
対しても追加的な情報が含まれている。ファイルをこの形式で出力する場合には、最適化の意味を
特定化することが重要である。
16
演習問題 File, Openを用いて、IVEモデルエディターによる新たな行列ファイルを観察せよ。指示
がある場合には、これを自身のプロジェクトに追加せよ。
問題行列の出力方法
メニューバーからExport matrixにしたがってBuildを選択し、MPS行列ファイルか最大化LPあるいは
最小化LPのいずれかを選べ。行列ファイルを作成する前に、どの制約が目的関数を表すか設定せよ。
この操作の前に、モデルがコンパイルされ、実行されていることを確かめよ。
2
Xpress-IVE
行列ファイルによる問題の入力
行列ファイルとして利用可能な問題を入力し、解くにはXpress-IVEを利用することができる。
Xpress-IVEはIVEの中からXpress-Optimizerに対する直接のインターフェイスを与える。IVEはMosel
を用いてモデルを構築する場合のグラフ的なインターフェイスとして有力なものであるが、たとえ
ば利用者が解のグラフ表示能力に関心を持っている場合のように、IVEをこのように利用することが
望ましいこともある。
演習問題 上記のようにして作成した行列ファイル‘simple.mat’を入力し、整数制御パラメタLPLOG
の値を1に設定し、LP問題を最大化せよ。
問題に対する解が求まると、Output/Input枠に問題の統計量が示される。これらの統計量は見過ご
されることもあるが、実際に入力された行列がわれわれが解こうとしている問題に対応しているか
否かをチェックする場合に有用である。この場合、問題の行列は3つの行(2本の制約条件と目的
関数に対応する)と2つの(構造的)列、換言すると決定変数、を有する。また行列は、a と bが
すべての行に非零係数を有しているので、6つの非零要素を持つ。これは(混合型)整数計画問題
ではないので、問題の中にはグローバル要素も集合も集合要素も存在しない。このようにして初期、
最終段階、そして各反復回数LPLOGに対する目的関数値が解の状況とともに示される。
問題の統計量が問題‘simple’に対応することを確認せよ。このことから、あるいは
Sim:Obj(iter)枠から最適な目的関数値が得られていることを確認せよ。
演習問題
行列問題による問題の入力
IVEメニューバーからOptimize matrix fileにしたがってBuildを用いて、行列ファイルが利用でき
るようにせよ。エディターウィンドウがすでに開いていれば、ファイルは自動的に選択される。ア
ルゴリズムと内容と問題の型を設定し、解き始めるために‘Start’をクリックせよ。LPLOGのような最
適化制御変数も問題の統計量の中で設定される。
Xpress-IVE
2
関数のグラフ化
最適化過程におけるすべての反復回数に対して、LPLOGの値による制御によって、IVEが目的関数値
をグラフ的に表示できることをすでに示した。しかしながらIVEにおいてもMoselプログラムの中で
コマンドIVEinitgraph と IVEaddtographを用いることによって利用者自身の関数をグラフ表示す
ることが可能となっている。この場合に出力は右側ウィンドウのUser Graph枠から見ることができ
る。リスト2.3に例を示す。
演習問題
‘decay.mos’と呼ばれる新しいファイルを作成し、リスト2.3を入れよ。User Graph枠を選
17
択してモデルを実行し、関数を観察せよ。
IVEinitgraph
IVEのグラフ化機能を初期化する。2つの引数はx y軸のそれぞれに対する名称である。
IVEaddtograph
利用者のグラフにプロットする。2つの引数はカルテシアン座標軸に対応する点の値である。
リスト 2.3 指数的崩壊状況のグラフ化
model decay
uses "mmive";
IVEinitgraph("Decaying oscillator","x","y")
forall(i in 1..400) do
IVEaddtograph(i,exp(-0.01*i)*cos(i*0.1))
end-do
end-model
2 Xpress-IVE
環境の変更
IVE環境の多くの側面はカスタム化可能で、利用者が必要としない場合には容易に変更することがで
きる。作業領域の中にあるウィンドウの配置や視度ばかりでなく、フォントや色彩や大きさといっ
た特性もすべて特定のプロジェクトに対して変更可能なように設定される。標準的な設定は新たな
プロジェクトが作られ、呼び出されるたびに適用される。
IVE作業領域の中にウィンドウを配置するのは、ウィンドウの境界を新しい位置にドラッグするのと
同じくらいに容易である。視度はViewメニューからProject Bar, Info Bar or Run Barのいずれか
を選択したり解除したりすることによって変更可能である。
演習問題 Viewメニューにあるいろいろなオプションに対してoff とonのを繰り返してそれぞれ実
験を試みよ。作業が容易になるようにウィンドウの大きさを変えよ。
プロジェクトに対する他の設定はModel Editorウィンドウにある右マウスボタンをクリックし、
Propertiesを選ぶことによってアクセス可能となる。提示される対話ボックスには、Color/Font,
Language/Tabs, Keyboard、あるいはその他のいろいろな設定を変更するためのタブが装備されてい
る。変更を指示し、‘Apply’ あるいは ‘OK’ ボタンをクリックすると、ウィンドウあるいはフォント
の情報が更新される。そしてプロジェクトあるいはアプリケーションを閉じると、これらは保存さ
れる。
演習問題 現在の設定を見た上で、エディターで用いられる色を変更してキーワードを示せ。‘Apply’
ボタンをクリックして変更を有効にせよ。
IVEモデルのエディターは、Language/Tabs枠にある言語を適切に設定することによって他の型のフ
ァイルを編集するのに利用可能となる。C/C++, Basic, Javaあるいは多くの他の型のファイルを編
集するにはオプションも存在する。長いモデルを編集するには、十進表示の行番号がMisc枠からフ
ァイルに対して適用される。
Xpress-IVE
2
ヘルプの利用
これまではXpress-IVEにあるプロジェクトをどのようにして作成し、管理するか、そしてModel
18
Editorを用いて単純なモデルをどのようにして入力し、変更し、保存するか、さらには解を得るた
めにこれらのモデルをどのようにしてコンパイルし、読み込み、実行するかを学んだ。またいくつ
かのモデルを同時に動かし、問題を行列ファイルとして転送し、最適化するにはどうすればよいか、
あるいはIVE作業領域をどのようにしてカストマイズするかについても学んだ。これまでは単にIVE
環境をどのように利用するかについてのみ集中的に述べてきた。しかしながら5章においては、
Mosel計画言語の基本について説明し、利用者の問題をどのようにしてモデル化し、解くかについて
述べる。次の項目に注目したいかもしれない。そこで以下の2章は、Console XpressとXpress-MP
ライブラリーを用いる場合の情報を説明する。IVEだけを利用したい場合には、以下の2章は飛ばし
てもよい。Mosel か Optimizerのいずれかを利用する場合のヘルプが必要な場合は、それぞれMosel
かOptimizer Reference Manualsのいずれかから入手可能である。
まとめ
本章では、IVEにあるプロジェクトをどのようにして作成し、管理するか、そして内蔵のModel Editor
を用いてモデルをどのようにして作成するか、あるいはモデルプログラムをどのようにしてコンパ
イルし、読み込み、実行するか、あるいは問題を行列ファイルとしてどのようにして転送したり、
入力したり、解いたりするか、あるいはまたIVE環境をプロジェクトとしてどのようにカストマイズ
するかについても学んだ。
2
Xpress-IVE
Console
第3章
Console Xpress
概要
この章では、以下の項目について説明する。
•
•
•
•
Xpress-Moselを用いてモデルプログラムファイルをコンパイルし、読み込み、実行する;
線形あるいは整数計画問題を解き、解を得る;
Xpress-Optimizerを用いて問題を解く;
最適化操作をするために、制御を設定し解法を選択する.
始める前に
Console XpressはXpress-MPソフトウェアに対して強力なテキストベースのインターフェイスを提
供するため、すべてのプラットフォームの利用者はモデルを対話型式あるいはバッチモードで利用
できる。読者がこの章を読む場合には、すでにConsole Xpressがインストールされていることが前
提となっている。この章を読んでいくと、単純なモデルの入力方法と解法が分かるであろうし、ま
たConsoleインターフェイスの主要な特性についても説明がなされている。Xpress-MP ライブラリー
の利用者はこれらの情報が有用であることに気づくであろう。
3
Console
Xpress
Console Xpress−の構成要素
Console XpressインターフェイスはXpress-Mosel と Xpress-Optimizerという2つの主要な構成要
素からなる。最初のXpress-Mosel は、Moselモデルプログラミング言語で書かれたモデル様式プロ
19
グラムがコンパイルされ、実行されるように高度に柔軟性のある環境を構成している。行列出力フ
ァイルはいろいろな業界標準形式で作成され、解を求めて出力するためにOptimizerの中に次々と読
み込まれることになる。他方、通常はOptimizerの機能はMoselの中にライブラリーモジュールとし
て組み込まれ、利用者がMosel自体の中で問題を解くことが可能となっている。これらの要素はいず
れも自動的に問題を解くようバッチモードで利用できるのが非常に有用である。
これらの要素の一つを実行するのはコマンドとして moselあるいは optimizerと入力するのと同じ
くらい簡単である。まず最初にこれらの要素が正しくインストールされているかをチェックするた
めにテストをしてみよう。
Xpress-Moselの検査方法
Moselが正しくインストールされているか否かをチェックするために、シェルコマンドでmoselと入
力してリターンキーを押す。プログラムは短い標示を出し、続いてMosel記号>が示され、利用者の
入力を待つことになる。
演習問題 上に示したMoselを開始せよ。Mosel記号でquitと入力すると、シェルコマンド記号に戻
るはずである。
リスト3.1は上記の手順を示しており、利用者からの入力がボールド文字で点滅する。上記の手順を
実行してもヘッダー情報が現れない場合は、mosel とoptimizerの2つの要素は現在のパスに存在し
ていないことになる。2つの要素を含むディレクトリーに変更して、そこから再度実行せよ。うま
くいった場合には、それに従ってパスを更新せよ。
Console
すべてのXpress-MP製品には、ソフトウェアの重要部分として安全保護システムが装備されている。
これはインストール時にすべての機能が立ち上がるように設定されなければならない。安全保護シ
ステムが正しく設定されないと、Xpress-MPの構成要素は‘trial mode’で開始されるため、取り扱う
ことのできる問題の大きさや複雑さについて制約を受けることになる。この場合、利用者がConsole
Xpressのライセンスを与えられているならば、安全保護システムを正しく設定するための詳細につ
いては‘readme’ファイルを参照されたい。
Xpress-Optimizerの検査方法
Optimizerの操作がうまくいっているか否かは、Moselと同様にコマンド記号optimizerを実行するこ
とによってチェックできる。プログラムは、インストールされているOptimizerのバージョンを与え
るヘッダーに対応して問題名problem nameを入力する。問題名が空白でリターンキーを押すと、
Optimizerでは作成するファイル名として問題名‘$$$$$$$$’が現れる。最後に、Optimizerのコマンド
記号>が現れ、利用者の入力待ちとなる。
演習問題 インストールがうまくいっているか否かをチェックするためにOptimizerを実行せよ。問
題名を聞かれたら、単にReturnを入力せよ。Optimizerにおいてプログラムを終了するには、QUIT
を入力せよ。
リスト3.2はOptimizerに対するリスト3.1と同一であって、利用者の入力部分はボールドタイプで示
されている。
リスト 3.1 Console Xpress-Moselをテストする
C:\> mosel
** Xpress-Mosel **
(c) Copyright Dash Associates 1998-zzzz
> quit
20
Exiting.
C:\>
問題名problem nameはOptimizer あるいは Moselによって作成された任意のファイルの基本となる。
3
Console
Xpress
Xpress-Moselを用いて簡単な問題を解く
Mosel ファイル
Mosel と Optimizerが正しく動いているならば、モデルを入力して解くのためにConsole Xpressを
用いることができる。この章の大半はリスト3.3に示した簡単なモデルについて述べている。モデル
は2つの決定変数decision variables (aとb)、そして2本の制約条件constraints (first と
second)を有し、目的は目的関数objective functionである profitを最大化することである。
当面の間、われわれはMosel と Optimizerを 用いる ことに焦点を絞っているので、モデルやそ
の構成要素については論じない。5章では、Mosel モデルプログラミング言語に焦点を絞ることに
する。
このような問題は、リスト3.3に示したような形式のモデル入力ファイルとしてMoselに提示される。
これらはASCIIテキストファイルであって、Moselが実行しようとしている処理情報に加えてモデル
の構文についても説明している。標準的には、Moselファイルは拡張子.mosを有しているので、ここ
ではこれを採用する。
リスト 3.2 Console Xpress-Optimizerをテストする
C:\> optimizer
XPRESS-MP Integer Barrier Optimizer Release xx.yy
(c) Copyright Dash Associates 1984-zzzz
Enter problem name >
Default problem name of $$$$$$$$ assumed
> QUIT
C:\>
Console
Xpress
演習問題
存せよ。
テキストエディターを用いて、リスト3.3のモデルプログラムをファイルsimple.mosに保
Moselの3つの柱
Mosel で問題を解く場合、以下に示す3つの段階がある。まず第一にモデルプログラムがコンパイ
ルされ、次にコンパイルされたプログラムはMoselに読み込まれ、最後に実行されるということであ
る。Moselがこの手続きを実行するのに必要なコマンドは、以下の通りである。
リスト 3.3 簡単なモデル
model simple
uses "mmxprs"
declarations
a: mpvar
b: mpvar
end-declarations
first:= 3*a + 2*b <= 400
21
second:= a + 3*b <= 200
profit:= a + 2*b
maximize(profit)
writeln("Profit is ", getobjval)
end-model
compile
この手続きによってモデルプログラムがコンパイルされるが、必要なのはファイル名だけである。
拡張子がない場合は.mosが付けられる。
モデルを入力するのにワードプロセッサーを用いる場合は、ファイルを"text only"形式で保存せよ。-g フラッグを用いる
と、エラーがあった場合に追加情報が得られる。
Xpress
演習問題 Moselを立ち上げ、モデルプログラムsimple.mosをコンパイルし、読み込み、実行せよ。
Moselを止めないと、どうなるかを確かめよ。
上述の手順を説明する部分はリスト 3.4に与えられている。利用者の入力部分はボールドタイプで
示されている。この手順の第一段階において、ファイルsimple.mosに保存されているモデルプログ
ラムはバイナリーモデルのBIMファイルとしてコンパイルされる。モデルの中に文法エラーが見つか
った場合には、エラー情報がコンソールに示され、エラーが見つかった行と文字の位置についての
詳細が提示される。警告メッセージもこのようにして示されるが、前にEでなくWが付けられる。コ
ンパイル中に-g フラッグを用いると、範囲エラーのような発見の難しい問題を見つけるのに役立つ、
追加的な情報が得られる。エラーが見つからない場合は、コンパイルされたモデルのファイルは次々
とMoselに読み込まれる。
load
コンパイルされたモデルのファイルはコマンドloadを用いてMoselに読み込まれる。
run
これによって現在のプログラムが実行される。引数はすべてパラメタの初期値となる。
リスト 3.4 モデルプログラムのコンパイルと読み込みと実行
C:\Mosel Files>mosel
** Xpress-Mosel **
(c) Copyright Dash Associates 1998-zzzz
>compile simple
Compiling `simple'...
>load simple
>run
Profit is 171.429
Returned value: 0
>
このようにしてパラメタを設定する例は5章に示される。
"Compilation errors…"
Console
コンパイルと読み込みという手順は非常に頻繁に行われるので、Moselではこれらを一緒にした短縮
コマンドが用いられる。最終段階では、コンパイルされたプログラムは実行され、目的関数は最大
化される。この最適値はコンソールに出力される。
Moselからさらに情報を得る
最大利益の値をモデルから得ることは確かに有用であるが、それはどのようにして達成されるので
あろうか?あるいは決定変数がどのような値をとれば、最大利益の値が得られるのだろうか?この
22
ような情報は、モデルをa と bの値を画面に表示するように変更することによって得られるが、問
題の規模が大きく、解くのに時間がかかる場合には、問題を再度コンパイルして解くということは
賢明ではない。幸いなことに、Moselではdisplayコマンドを利用することによって、変数の値や制
約条件を知ることが可能である。
Xpress
演習問題 displayコマンドを利用して、決定変数の最適値を求めよ。これらがa = 114.286; b =
28.571となることを確かめよ。
cload (cl)
これはモデルプログラムをコンパイルし、コンパイルされたバイナリーモデルのファイルを読み込
む。短縮すると、clと書くことができるが、唯一の引数はモデルプログラムのファイル名である。
display
これによってMoselは引数の値を示す。
Moselのコマンドは、他のコマンドと重ならない限り、通常2文字に短縮される。詳細については、Mosel Referenceのマニ
ュアルを参照されたい。
3
Console
Xpress
Moselをさらに用いる
バッチモードで実行する
Console Xpressの主要な利用方法の一つは、バッチ生産システムにおいて多くの問題を日常的に解
くことにある。これまではMoselを対話型で利用することについてのみ詳細を記述したが、その利用
方法は-sフラッグを用いることに限定されることなく、Moselはコマンドラインから非対話型で実行
されることである。この例はリスト3.5に与えられているが、そこでは前のモデルファイルがコンパ
イルされ、読み込まれ、実行される。
Moselでは、-cフラッグに続いて、引用符に囲まれ、セミコロン(;)で区切られたコマンドが記述さ
れる。-sフラッグを追加すると、Moselは静かに実行され、モデルファイルで要求された情報だけを
出力する。
演習問題 Moselをバッチモードで-sフラッグを用いたり、用いなかったりして実行せよ。これらの
各場合に対する出力の違いを確かめよ。
リスト 3.5 Moselをバッチモードで実行する
C:\Mosel Files>mosel -c "cload simple; run"
** Xpress-Mosel **
(c) Copyright Dash Associates 1998-zzzz
>cload simple
Compiling `simple'...
> run
Profit is 171.429
Returned value: 0
>
Exiting.
C:\Mosel Files>
Moselフラッグの全リストは、mosel –hとコマンド入力することによって得られる。
多重 Modelの実行
Moselのもう一つの特徴は、いくつかの異なるモデルをメモリーに入れ、同時に実行することである。
23
これらの一つが現問題active problemとして指定され、それぞれが必要に応じて実行されることに
なる。これを示すために、リスト3.6に示したような別のモデルを紹介する。
Xpress
演習問題 テンプレートとしてsimple.mosを用いて、リスト3.6のテキストを含む新たなファイル
altered.mosを作成せよ。
モデルがMoselに読み込まれると、現問題となる。runコマンドが呼ばれると、それが実行対象とな
る現問題となり、displayコマンドが呼ばれると、現問題に対する情報が出力される。
リスト 3.6 モデルの変更
model altered
uses "mmxprs"
declarations
a: mpvar
b: mpvar
end-declarations
first:= 3*a + 2*b <= 400
second:= a + 3*b <= 200
third:= 6*a + 5*b <= 800
profit:= a + 2*b
maximize(profit)
writeln("Profit is ", getobjval)
writeln(" a = ", getsol(a), "; b = ", getsol(b))
end-model
このモデルとリスト3.3の間の唯一の変更点は、新たな制約条件を追加したことである。この制約条件が有効になると、目的
関数値は減少する。
演習問題 Moselを立ち上げ、まずsimple.bimを読み込み(すでにコンパイルされてなければならな
い)、コンパイルし、新しい問題‘altered’として読み込め。runを用いて、変更された問題に対する
解を求めよ。
読み込まれた問題の全リストは、Moselにおけるコマンドlistを入力することによって得られる。こ
こでは2つの問題‘simple’ と ‘altered’についての詳細が示される。この場合、現問題‘altered’のフ
ァイル名の左側に星印が示される。現問題はコマンドselectを入力することによって変更されるが、
これはリスト3.7に示される。
演習問題 Moselに現在読み込まれている問題のリストをとり、現問題を‘simple’とせよ。runを入力
すると、解かれるのはこの問題である。
load あるいは cloadを用いると、Moselにさらにモデルを読み込むことができる。モデルをMosel
から削除するには、deleteを用いる。
リスト 3.7 Moselにある現問題を観察し、設定する
>list
* name: altered number: 2 size: 3832
Sys. com.: `altered.mos'
User com.:
- name: simple number: 1 size: 3176
Sys. com.: `simple.mos'
User com.:
>select simple
24
Model 1 selected.
>list
- name: altered number: 2 size: 3832
Sys. com.: `altered.mos'
User com.:
* name: simple number: 1 size: 3176
Sys. com.: `simple.mos'
User com.:
>
Console
deleteコマンドはモデルをMosel から除くだけで、モデルファイルを削除するものではない。
演習問題 delete alteredコマンドを用いて新しい問題をMoselから削除せよ。listコマンドを用い
て、‘simple’のみが残っているのを確かめよ。
行列ファイルの書き方
Moselでは、モデルを解いたり、行列を次々に変更したり、利用者との対話が必要になったりするこ
とがよくある。他方、同じ問題を他人が利用することもあるであろう。このような場合、問題が別
のプログラムに対する入力となるように、モデルの行列ファイルがMoselから要求される。Moselで
はexportprobコマンドを用いてMPS とLPの両方の形式で行列ファイルを書くことをサポートしてい
る。
list
現在Moselに読み込まれている問題のリストを与える。現問題には星印が付けられている。
select
新しい問題が現問題として選択される。引数は現問題として設定するための名前と個数である。
delete
問題をMoselから削除する。
exportprob
単独で用いられ、行列をLP形式でコンソールにプリントする。-mフラッグを用いると、MPS形式の出
力となる。ファイル名を引数にすると、行列がそのファイルに転送される。
exportprob はモデル内部からも利用できる。例として、リスト3.11を参照されたい。
演習問題 exportprob -m simple.matを用いて、MPS形式の問題‘simple’ の行列ファイルを作成せよ。
ファイルをテキストエディターを用いて観察せよ。
MPS形式と異なって、LP形式もまたモデルが最大化問題か最小化問題かについての情報を含んでいる。
標準的には、特に断らなければ、目的関数は最小化される。この問題をLP形式で転送するには、-p
フラッグを用いて目的関数が最大化であることを表示しなければならない。
演習問題 問題‘simple’ に対する行列ファイルをLP形式でコンソールに出力せよ。行列が正しく作
成され、最大化問題となっていることを確かめよ。
Xpress-Optimizer
Xpress-MP
問題の解き方
上の演習問題に対しては、モデルプログラムをMoselに入れ、問題を解くためにOptimizerをライブ
25
ラリーモジュールと呼んだ。Optimizerもまた単独のアプリケーションとして利用されるが、このよ
うな利用方法について本章の残りの部分で説明する。
Optimizerは問題の行列ファイルを主要な業界標準形式であるMPS形式あるいはLP形式で受け入れる。
この章の演習問題を試みるためには、上に示したMPSファイルであるsimple.matのような行列ファイ
ルが必要となる。このファイルを用いると、問題を解くために必要なことは、完成した行列を
Optimizerに読み込み、目的関数を最大化することである。
Console
Optimizerを用いた例はリスト3.8に与えられているが、ここでも利用者の入力はボールド表示され
ている。問題名を入力すると、Mosel で作られたMPSファイルで読むためには、コマンドREADPROB
が用いられ、その後MAXIMが呼び出され、リスト3.3に与えられている表示profitを有する目的関数
が最大化される。
演習問題 リスト3.8にしたがって、ファイルsimple.matをOptimizerに読み込み、目的関数を最大
化せよ。停止する前にコマンドWRITEPRTSOLを入力せよ。
解の見方
Optimizerの解の情報は、以下に述べるように、いくつかの異なる出力で表される。リスト3.8にあ
るコマンドMAXIMを用いて出力を画面に出すと、コマンドWRITEPRTSOLの上の行に、問題の最適解が
見つかり、目的関数値が171.428571となることが示される。これは、行列が読み込まれた場合の出
力の中で、問題に関する統計量と共に得られる最初の出力情報となる。
問題に関する統計量は解を解釈する場合に有用なチェック要素となる。読み込まれた行列がわれわ
れが解きたい問題に正しく対応しているか否かをチェックするのにこれらの統計量が用いられる。
現在の例では、リスト3.8から、行列が2本の制約条件と1本の目的関数に対応する3つの行を有す
るのが分かる。さらには、2個の決定変数に対応する2つの列を有することも分かる。2つの決定
変数はすべての行に現れているので、行列の非零要素の個数が分かる。
MPS ファイルをOptimizerに読み込む
optimizerを開始し、問題名problem_nameを入れる。次にOptimizerコマンドREADPROBを入れる。リ
ターンを押すと、Optimizerはファイルproblem_name.matを読み込む。
目的関数を最大化する
MPS ファイルが読み込まれると、ただちにOptimizerコマンドMAXIMを入力する。目的関数は最大化
される。
最小化問題の場合には、MINIM と入力する。
Xpress
最終的には、グローバル統計量から、モデルがMIP問題であることが分かるので、要素(entities)
も(特別の順序付き)集合(ordered sets)も集合要素(set members)もないことが分かる。
Optimizerでは、利用者が利用可能なより詳細な出力を出している。リスト3.8では、コマンド
WRITEPRTSOLを用いると、ファイルsimple.prtに出力される。同じ出力は、コマンドPRINTSOLを用い
ると、画面にも送られる。
リスト 3.8 Optimizerを用いた第一講
C:\Optimizer Files> optimizer
XPRESS-MP Integer Barrier Optimizer Release xx.yy
(c) Copyright Dash Associates 1984-zzzz
Enter problem name >simple
>READPROB
Reading Problem simple
26
Problem Statistics
3 ( 0 spare) rows
2 ( 0 spare) structural columns
6 ( 0 spare) non-zero elements
Global Statistics
0 entities 0 sets 0 set members
>MAXIM
Presolved problem has: 2 rows 2 cols 4 non-zeros
Crash basis containing 0 structural columns created
Its Obj Value S Ninf Nneg Sum Inf Time
0 .000000 p 0 0 .000000 1
2 171.428571 P 0 0 .000000 1
Uncrunching
2 171.428571 P 0 0 .000000 1
Optimal solution found
>WRITEPRTSOL
>QUIT
C:\Optimizer Files>
Optimizerは大小文字にはよらないが、コマンドには小文字を用いる。ここではreferenceマニュアルの記述に従うため、大
文字を用いる。
‘Global entities’ は、非連続型変数と特別の順序付き集合を記述するためにXpress-Mpでは傘付きで表示される。
Console
WRITEPRTSOLの出力
WRITEPRTSOLからの出力は、プリンターへの転送が容易なように ASCII テキストファイルとなって
いる。このファイルは、リスト3.9に示すように、構造を理解しやすくするために3つの部分に分け
られている。
すべての解の出力
目的関数を最適化した後は、コマンドPRINTSOL を用いて出力を画面に送るか、あるいは後で解を見
るためにWRITEPRTSOLを用いて出力をASCII 解のプリントファイルproblem_name.prtに送るかのい
ずれかである。
リスト 3.9コマンド WRITEPRTSOLからの出力
Problem Statistics
Matrix simple (1部)
Objective *OBJ*
RHS *RHS*
Problem has 3 rows and 2 structural columns
Solution Statistics
Maximization performed
Optimal solution found after 2 iterations
Objective function value is 171.428571
Rows Section (2部)
Number Row At Value Slack Value Dual Value RHS
N 1 *OBJ* BS 171.428571 -171.428571 .000000 .000000
L 2 second UL 200.000000 .000000 .571429 200.000000
L 3 first UL 400.000000 .000000 .142857 400.000000
Columns Section (3部)
27
Number Column At Value Input Cost Reduced Cost
C 4 a BS 114.285714 1.000000 .000000
C 5 b BS 28.571429 2.000000 .000000
Xpress
部構成を考える場合、1部,3部,2部の順番が最も有用であろう。1部では、解法に関するまと
めの統計量が与えられる。そこでは、用いられた行列(問題)名(simple)と目的関数と右辺名が与
えられる。続いて行(目的関数を含む制約条件)と列(変数)の個数、最大化問題かどうか、解く
のに2回の反復が必要であったこと、最良値が171.428571であることが示されている。
決定変数の最適値は3部のColumns Sectionに与えられている。列の値Value は各変数の最適値を与
える。各変数に対する入力コストやリデューストコストなどの解に関する追加的な情報もここに与
えられる。さらに詳細については、7章の“用語のまとめ”を参照されたい。
最終節は2部の行に関するRows Sectionである。ここでは問題の各種制約条件や目的関数のリスト
が"左辺値"と共に与えられる。特に目的関数値はここに再度与えられる。制約条件に対するスラッ
ク値や双対値もここに示される。さらに詳細については、7章の“用語のまとめ”を参照されたい。
演習問題 上で作成した出力ファイルsimple.prtを観察し、行、列等のいろいろな部分を確認せよ。
リスト中で決定変数と目的関数に関する結果をチェックせよ。
Optimizerをさらに利用するために
最適化アルゴリズム
Optimizerは、標準的には双対単体法であるが、LP問題を解くためのいろいろなアルゴリズムをサポ
ートしている。しかしながら、ある種の問題に対しては、アルゴリズムを変更したために問題を解
くのに要する時間が大きく変化することもある。また主単体法かニュートンバリア法かのいずれか
が短時間で解を見つけるかも知れない。ある種の状態下で最良のアルゴリズムを選択することは、
それ自体何か技術に近いようなものであるため、最良の選択は自身の問題に対していろいろなアル
ゴリズムを用いて実験することによって得られるものである。
"Section 1…"
"Section 3…"
"Section 2…"
Console
問題に対して用いられるアルゴリズムを変更するための最も簡単な方法は、MAXIMに通じるフラッグ
を立てることである。これらの方法は上に述べた3つのアルゴリズムのそれぞれに対応する。リス
ト3.10は、問題を解くためにニュートンバリア法を用いるためにリスト3.8からの変更を示している。
利用者の入力を含む行がここに示されている。
演習問題
3つのアルゴリズムのそれぞれを用いて問題を解き、それぞれの出力の違いを確認せよ。
整数計画法
上に考慮した問題に対して、目的関数の最大値は決定変数が小数1位まででa = 114.3、b = 28.6
のときに得られる。しかしながら、問題によっては、このような小数解は受け入れがたいものかも
知れないし、またある変数は整数値のみをとるように限定されているかも知れない。このような整
数型あるいは混合型整数計画問題に対しては
-b ニュートンバリア法を用いる;
-d 双対単体法を用いる;
-p 主単体法を用いる.
28
リスト 3.10 ニュートンバリア法を用いる
C:\Optimizer Files> optimizer
Enter problem name >simple
>READPROB
>MAXIM -b
>WRITEPRTSOL
>QUIT
C:\Optimizer Files>
"Choosing an algorithm…"
Console Xpressを用いて、このような問題を解いてみよう。
リスト3.11では、aとbが整数値をとらねばならないことを指示するために、2行が追加されている。
他の変更は、Moselではプログラムが実行されるときにMPS 行列ファイルを ‘自動的に’転送するとい
うことである。
演習問題 リスト3.11の内容を含むモデルファイルintegral.mosを作成した後、実行し、MoselでMPS
行列ファイルを作成せよ。Optimizerを用いて、LP問題を解け。目的関数の最適値を求めよ。
上で解いた問題ではaとbが整数値をとらねばならないとした。さらに、目的関数はこれらの変数の
整数倍のみを含む線形表現である。しかしながら、ここで得られた目的関数の最適値が整数値でな
いことに注意されたい。
Optimizerを用いて整数解を見つけるには、2段階操作が必要である。第一段階として、最適解を求
めるためには、LP緩和問題が解かれねばならない。
リスト3.11 問題に整数制約を追加する
model integral
declarations
a: mpvar
b: mpvar
end-declarations
first:= 3*a + 2*b <= 400
second:= a + 3*b <= 200
profit:= a + 2*b
a is_integer
b is_integer
exportprob(EP_MPS,"integral",profit)
end-model
LP緩和とは、変数に関する整数条件を無視したものである。
Console
第2に、最良整数解が存在する場合に、それを見つけるためにはグローバル探索が実行されなけれ
ばならない。グローバル探索は、g フラッグを MAXIMに入れるLP緩和問題の解に自動的にしたがう
ことから呼ばれているが、例がリスト3.12に示されている。グローバル探索が完了すると、得られ
た整数解は、PRINTSOLあるいは WRITEPRTSOLを前もって用いることによって見ることができる。
演習問題 リスト3.11の整数計画問題を解け。最適解に対するaとbの値を求めよ。(これらは整数値
でされなければならない。)
29
Optimizer の制御
Optimizerにはいくつかのパラメタが含まれているが、それらの値は利用者によりいろいろな制御設
定によって変更される。パラメタの値は、特に難しいとされる問題に対するOptimizerの性能に合わ
せて、考慮の上で細かな調整がなされるため、解法に要する時間の大幅な節約になることもある。
はじめての利用者がこれらの大部分を標準値から変更することは勧めないが、実験が有用となるよ
うな場合もかなりある。このような例について述べよう。すべての完全なリストは、Optimizerの
Referenceマニュアルに見ることができる。
リスト 3.12 整数計画問題を解くためのコマンド
READPROB
MAXIM -g
WRITEPRTSOL
QUIT
整数解を求めるグローバル探索を開始する
optimizerでコマンドMAXIM –gを入力する。問題に対する整数解を求めるために分枝限定法が用いら
れる。
MAXIM -g はコマンドGLOBALに続いてただちにMAXIMを呼ぶことと同じである。
Xpress
最適化に用いられるアルゴリズムがMAXIMに対するフラッグを用いる、という標準形から変更する方
法については、前に見た。
標準的アルゴリズムは制御DEFAULTALGによって設定されるが、DEFAULTALGはどのアルゴリズムが適
用されるべきかを表す整数値である。標準的アルゴリズムはDEFAULTALGを用いて変更されるため、
p, d と b のフラッグを MAXIM (MINIM)に入れる必要はない。
演習問題 リスト3.13にあるように現在値を求めるためにoptimizerコマンドで制御DEFAULTALGを
入力せよ。
演習問題 ニュートンバリア法を用いるために、制御DEFAULTALGの値を4に設定せよ。これは変数の
値によって影響を受けるMAXIMを呼ぶ前に実行されなければならない。再度プログラムを実行し、出
力を観察せよ。
制御値を得る
Optimizerに対する制御値は、optimizerにおいて名前を入力することによって得られる。
¾ CONTROL
制御値を変更する
Optimizerに対する制御は、標準的なプログラミング変数として扱われ、変更は値の割当によってな
される。
¾ CONTROL = value
標準的最適化アルゴリズムの変更
制御変数DEFAULTALG の変更:
1 アルゴリズムは自動的に決定される;
2 双対単体法を用いる;
30
3 主単体法を用いる;
4 ニュートンバリア法を用いる.
"Changing the algorithm used by default…"
Console
ヘルプの利用
本章におけるここまでの説明から、Moselを用いてモデルプログラムをコンパイルし、読み込み、実
行する方法、ライブラリーモジュールとしてのOptimizerを用いて問題に対する解を求める方法、そ
して問題を行列ファイルに転送する方法について学んだ。さらには、これらのファイルをOptimizer
に読み込む方法、それらを最適化する方法、解を見る方法、最適化手法に影響を与える制御を変更
する方法、等についても学んだ。これまでのところでは、特定の既存のモデルを入力し、最適化す
る方法に集中してきた。しかしながら5章では、Moselモデルプログラミング言語の基本について説
明し、利用者がモデルを作って問題を解けるようにする。次の章では、Xpress-MP ライブラリーを
利用する場合の情報を与えるので、Xpress-IVE あるいはConsole Xpressだけを使いたい読者は読み
飛ばしてもよい。Mosel かまたは Optimizerを利用する場合に追加的にヘルプを必要とするならば、
それぞれMosel かまたはOptimizer Reference Manualsを参照されたい。
リスト 3.13 制御値を得る
C:\Optimizer Files> optimizer
XPRESS-MP Integer Barrier Optimizer Release xx.yy
(c) Copyright Dash Associates 1984-zzzz
Enter problem name >simple
>READPROB
>DEFAULTALG
1
>
Xpress
まとめ
この章では、Moselを用いてモデルをコンパイルし、読み込み、実行する方法、問題の行列ファイル
を転送する方法、線形問題の解き方、解へのアクセスの仕方、整数計画問題の解法、解法アルゴリ
ズムの変更方法、Optimizer制御値のアクセスと変更、等について学んだ。
The Xpress-MP
31
第4章
Xpress-MP ライブラリー
概要
この章では以下について述べる。
•
•
いろいろなXpress-MP ライブラリーを示す;
•
•
•
Xpress-BCLを用いてモデルを構築し、解く方法を学ぶ;
Mosel ライブラリーを用いてMosel 言語で書かれた問題をコンパイルし、読み込み、解く方法を
学ぶ;
Xpress-Optimizer ライブラリーを用いて問題を読み込み、解く方法を学ぶ;
いろいろなプログラミング言語を用いてライブラリーを利用する方法を学ぶ
始める前に
Xpress-MP ライブラリーは、Xpress-Mosel とXpress-Optimizer エンジンに対するインターフェイ
スを与えるが、利用者は自身のプログラムからXpress-MPを呼ぶことができる。この章では利用者が
Xpress-MP ライブラリーを自身のシステムにインストールしていることを前提としている。本章の
構成は、Xpress-IVE と Console Xpressの章で示したように、いろいろな機能を使いつつサブルー
チンライブラリーを用いて簡単な問題を入力して解くことを基本としている。前提とはしていない
が、本章を読む前にConsole Xpressの章を調べておくのが有用であろう。
Libraries
Xpress-MP ライブラリーの構成要素
Xpress-MPには3つの主要な構成要素としてMosel, BCL, Optimizerがある。Xpress-MP ライブラリ
ーはこれらに対するインターフェイスを与え、いろいろな方法でこれらにアクセスが可能となる。
利用者にとって利用可能なこのようなライブラリーはいくつか存在するが、本章ではこれらのうち
の3つについてのみ詳細を述べることにする。
• Mosel ライブラリーによってモデルファイルをコンパイルし、読み込み、実行し、さらにいくつ
かの問題を解くモジュールとしてOptimizerにアクセスすることが可能となる。さらには、自身のア
プリケーションの中でMoselモデルプログラミング言語を柔軟に利用することが可能となる。
• Xpress-MP Builder Component Library (Xpress-BCL) は少し異なっており、Moselに対する別の
モデリング環境を与え、モデルが利用者のプログラムの中に構築され、出力ファイルを作成するか、
行列を直接Optimizerに送る、といったことが可能となる。
• Optimizer ライブラリーによって行列ファイルの入力、操作、最適化が可能となり、そしていろ
いろな方法で解に対するアクセスが可能となる。以下の各節では、ライブラリー利用者にとって一
般的に興味ある情報を与える前に、これらのライブラリーのそれぞれについて説明する。
本章における大部分の例は、Xpress-MPライブラリーを呼ぶ場合に広く用いられ、Reference Manuals
の基本となっているC プログラミング言語で書かれている。しかしながらサポートされている他の
言語としては、C++, Visual Basic, Javaなどがあり、本章の最後には、Visual BasicとJavaによる
ライブラリーを利用する場合の概要が示される。
The Xpress-MP
32
Mosel ライブラリーの利用
簡単なモデル入門
まず最初に、以前に用いたのと同じ簡単なモデルを入力する。解くのにMosel ライブラリーがどの
ようにして用いられるかが分かるであろう。リスト4.1に与えられるモデルはMoselモデルプログラ
ミング言語で書かれており、わずか2つの決定変数(a and b)と2本の制約条件 (first and second)
を有している。目的は目的関数profitを最大化することである。このような問題はモデル入力ファ
イルとしてMosel ライブラリーに送られる。これらはMoselが実行しようとしている情報を処理する
だけでなく、モデルを表現するアスキーテキストファイルでもある。標準的には、Moselファイルは
拡張子.mosを有することが前提であって、本章でもこれを採用する。
リスト 4.1 簡単なモデル
model simple
uses "mmxprs"
declarations
a: mpvar
b: mpvar
end-declarations
first:= 3*a + 2*b <= 400
second:= a + 3*b <= 200
profit:= a + 2*b
maximize(profit)
writeln("Profit is ", getobjval)
end-model
Libraries
演習問題 リスト4.1にあるモデルをファイルsimple.mosにテキストエディターを用いて入力せよ。
これは前にConsole Xpressの章にある演習問題ですでに試みたものである。
Mosel ライブラリーの構成要素
Mosel ライブラリーはランタイムライブラリーxprm_rt、コンパイラーライブラリーxprm_mcからな
る。これらのうちでランタイムライブラリーは主要なもので、利用の前後でMoselの開始と終了に対
するルーティンを含むものである。それに対してコンパイラーライブラリーは、Moselモデルプログ
ラムファイルのコンパイルに用いられる単一のルーティンを含むものである。一般にはランタイム
ライブラリーは単独で用いられることが多い。コンパイラーライブラリーが用いられる場合は、両
方のヘッダーファイルが利用者のコードに含まれなければならず、コンパイラールーティンを用い
る場合は、前もってランタイムライブラリーから開始ルーティンが呼ばれていなければならない。
この節では、以下のMoselライブラリープログラムを用いて、これらのライブラリーの両者の利用方
法を示す。
Moselの3つの柱
Moselライブラリーを用いて問題を解くには、以下のページで明らかになる3つの段階の操作が必要
である。
リスト 4.2 Moselライブラリープログラムの構造
#include "xprm_rt.h"
#include "xprm_mc.h"
33
int main(void)
{
XPRMinit();
program statements
XPRMfree();
return 0;
}
The Xpress-MP
モデルプログラムは一度書かれるとまずコンパイルされ、コンパイルされたプログラムはMoselに読
み込まれ、最終的に実行される。これらの目的のために、Mosel ライブラリーでは3つのルーティ
ンが提供される。
リスト4.3は以前に保存したモデルをコンパイルし、読み込み、実行する方法を示している。
演習問題 モデルsimple.mosをコンパイルし、読み込み、実行するためのプログラムを書き、実行
せよ。モデルから得られる最大利益を求めよ。
XPRMcompmod
これによってMoselを呼び出してモデルファイルをコンパイルし、BInaryModel (or BIM)ファイルに
入れることができる。以下の4つの引数がある。
• コンパイル操作のためのオプション;
• モデルソースファイルの名前;
• 目的地ファイルの名前、NULLでよい。;
• 出力ファイルの最初に保存されるコメントテキスト
これはモデルのコンパイラーライブラリーにおける唯一のコマンドである。
XPRMloadmod
Moselがバイナリーファイルを読み込むのを助けるもので、2つの引数を持つ。
• ファイル名;
• モデルの内部名、NULLでもよい。
XPRMloadmod では問題ポインター、型XPRMmodelの変数を返す。
XPRMrunmod
Mosel内でモデルを実行する。3つの引数がある。
• 問題ポインター;
• 結果の値が戻される領域へのポインター;
• 一連のパラメタ初期値
NULL.
Using a
‘g’ flag とXPRMcompmodを用いると、エラーがある場合にはデバッグに関する追加情報が得られる。これは発見困難な領域エ
ラーなどの場合に有用である。このようにしてパラメタを設定する例は5章に示される。
Libraries
この演習問題が難しい場合は、Mosel ライブラリーは必要とされる重要な安全保護システムファイ
ルを見つけることができないし、また他のライブラリー / DLLsを配置することができない。
Xpress-MP安全保護システムをどのようにして立ち上げるかについての詳細は、CD-ROMにある
‘readme’ファイルを参照されたい。そこには、最も共通に利用可能なコンパイラーを有するライブラ
リーを立ち上げる場合の詳細が示されている。
34
解の情報の取得
リスト4.1にあるモデルでは、Moselによって目的関数の最大値を出力することを試みた。同様にし
て、モデルでは決定変数の最適値や他の情報を出力するように書くことも可能であった。このよう
な例をあとで示そう。しかしながら、Moselの実行時間ライブラリーでは解の詳細な情報を得るため
にいくつかの関数を提供し、解の情報を他のアプリケーションで直接使えるようにしている。この
ような2つの関数を以下に示す。
リスト 4.3 モデル‘simple’をコンパイルし、読み込み、実行する
#include <stdio.h>
#include "xprm_rt.h"
#include "xprm_mc.h"
int main(void)
{
XPRMmodel simple;
int nReturn;
XPRMinit();
XPRMcompmod("","simple.mos",NULL,"Simple Example");
simple = XPRMloadmod("simple.bim",NULL);
XPRMrunmod(simple,&nReturn,NULL);
XPRMfree();
return 0;
}
The Xpress-MP
目的関数値を返すのはこれらの2つの中でも容易な方である。決定変数の値を得ることはもう少し
煩雑であるが、特定の変数名に対応する辞書要素は、ライブラリー関数XPRMfindidentを用いて最初
にMoselによって返されなければならない。ここでは値を返すべく最終的にXPRMgetvsol として用い
られる前に、XPRMmpvar変数として指定されなければならないような一般的な型を返している。リス
ト4.4ではこれらの関数とその利用方法を示し、さらにリスト4.3との違いをボールドタイプの文字
で示している。
XPRMgetobjval
目的関数値を倍精度で返す。一つの引数は問題ポインターである。
XPRMgetvsol
決定変数の値を倍精度で返す。2つの引数がある。:
• 問題ポインター;
• 決定変数の指定.
リスト 4.4 解の情報を得る
#include <stdio.h>
#include "xprm_rt.h"
#include "xprm_mc.h"
int main(void)
{
XPRMmodel simple;
XPRMalltypes atvar;
35
XPRMmpvar a, b;
int nReturn;
XPRMinit();
XPRMcompmod("","simple.mos",NULL,"Simple Example");
simple = XPRMloadmod("simple.bim",NULL);
XPRMrunmod(simple,&nReturn,NULL);
Libraries
演習問題 決定変数a とbの最適値を得るように前の問題を変更せよ。
Moselの実行時間ライブラリーには本質的にはXPRMgetvsolと同様の多くの関数が含まれている。た
とえばリデューストコスト(XPRMgetrcost), スラック値 (XPRMgetslack) 、双対値(XPRMgetdual)
などであるが、詳細についてはMosel Reference Manualを参照されたい。
Mosel ライブラリーをさらに利用するために
いくつかのモデルをさらに利用するために
Xpress-MPの利用者にとっては、いくつかの異なるモデルを並行して構築したり、アプリケーション
の中で交互に利用したりすることがよくある。Mosel ライブラリーでは、システム資源あるいはラ
イセンスの詳細に関する制約の下で、任意の数のモデルをメモリーに入れて同時に動かすことが可
能である。
すべてのXpress-MP製品の場合と同様に、Mosel ライブラリーのモデル管理は、現在読み込まれてい
るモデルを識別する問題ポインターの概念に基づいており、いかなる状況においてもどのモデルが
稼働中かを分かるようにしている。
XPRMfindident(simple,"a",&atvar);
a = atvar.mpvar;
XPRMfindident(simple,"b",&atvar);
b = atvar.mpvar;
printf("The maximal profit is %g\n",
XPRMgetobjval(simple));
printf("a = %g\nb = %g\n",
XPRMgetvsol(simple,a), XPRMgetvsol(simple,b));
XPRMfree();
return 0;
}
リスト 4.4 解の情報を得る
問題ポインターあるいは表示は、前の演習問題あるいはリストのところですでに見たように、
XPRMloadmodルーティンによって戻される。これはモデルのほとんどのルーティンの中で最初の引数
として用いられているので、Console Moselと違ってこの場合は現モデルactive modelという概念は
存在しない。
演習問題 リスト4.5のモデルをファイルaltered.mosに入れて、前のプログラムが‘simple’と
‘altered’ の両者を連続してコンパイルし、読み込み、実行するようにせよ。
使用している間、Moselは現在メモリーにあるモデルのリストを保管し、新しいモデルを読み込んだ
リストの最初に置く。モデルは次々にこのリストから関数XPRMgetnextmodを用いて選択され、非常
に多くのモデルを交互に利用するのに便利なようになっている。与えられたモデルについての情報
は、XPRMgetmodinfoを用いて検索される。
リスト 4.5 モデルの変更
36
model altered
uses "mmxprs"
declarations
a, b: mpvar
end-declarations
first:= 3*a + 2*b <= 400
second:= a + 3*b <= 200
third:= 6*a + 5*b <= 800
profit:= a + 2*b
maximize(profit)
writeln("Profit is ", getobjval)
end-model
これとリスト4.1との間の唯一の変化は、新しい制約条件が課されている点である。制約条件が有効な場合は、目的関数値は
減少する。
Libraries
モデルが不要になると、XPRMunloadmodを用いて読み出される。これらの関数は通常はわずか2つの
モデルだけでは用いられないので、リスト4.6に多くのモデルに対して容易に拡張されるような使用
例を示す。
XPRMgetmodinfo
与えられた問題ポインターによって指定されたモデルについての情報を返す。問題ポインターに続
いて以下の5つの引数がある。
• モデル名;
• モデル番号;
• システムコメント;
• 利用者コメント;
• 使用メモリーの量.
これらの5つは、不要ならば NULL でよい。
XPRMgetnextmod
引数として与えられたモデルの次のモデルに対するポインターを返す。引数がNULLの場合は、リス
ト中の最初のモデルが返される。引数がリスト中の最後のモデルの場合は、XPRMgetnextmodはNULL
を返す。
XPRMunloadmod
Instructs
Moselに指示してモデルを読み出し、それに付随するすべてのメモリーやリソースを解除する。唯一
の引数は問題ポインターである。
The Xpress-MP
演習問題 リスト4.6のプログラムを入力し、実行せよ。前の演習問題で‘simple’と ‘altered’ の両
者をすでにコンパイルしているので、ここではコンパイラーxprm_mcは不要であって、XPRMcompmod
を用いた2行を省略できる。
リスト 4.6 複数モデルを動かす
#include <stdio.h>
#include "xprm_rt.h"
37
#include "xprm_mc.h" /* if needed */
int main(void)
{
XPRMmodel mod;
int nReturn;
const char *name;
XPRMinit();
/* uncomment the following two lines if needed */
/* XPRMcompmod("","simple.mos",NULL,"");
XPRMcompmod("","altered.mos",NULL,""); */
XPRMloadmod("simple.bim",NULL);
XPRMloadmod("altered.bim",NULL); /*first in list*/
/* return a pointer to the first item in list */
mod = XPRMgetnextmod(NULL);
while(mod != NULL)
{
XPRMgetmodinfo(mod,&name,NULL,NULL,NULL,NULL);
printf("\nCurrent problem is ‘%s’\n", name);
XPRMrunmod(mod,&nReturn,NULL);
mod = XPRMgetnextmod(mod);
}
/* unload first item in list, i.e. ’altered’ */
XPRMunloadmod(XPRMgetnextmod(NULL));
XPRMfree();
return 0;
}
Libraries
実行時間の管理
モデルが読み込まれると、XPRMrunmodルーティンを用いて実行される。利用者は与えられたモデル
がXPRMisrunmodを用いて任意の時刻に実行中であるか、XPRMstoprunmodを用いて終了させられたか
を見ることができる。これらの2つのルーティンは、アプリケーションの中で、解くのに長い時間
を要すると思われる大きなモデリング問題と共に用いられることが多い。リスト4.7にはこのような
例が与えられているが、その中では‘Ctrl-C’キーを組み合わせることによって実行中にモデルを中断
することができる。
XPRMisrunmod
これによってモデルが実行中であるか否かをチェックできる。唯一の引数は問題ポインターであっ
て、モデルが実行中である場合に1,そうでないときに0となる。
XPRMstoprunmod
これによってモデルを中断することができる。唯一の引数は問題ポインターである。
リスト 4.7 モデルの実行を正しく終了する
#include <stdio.h>
#include <signal.h>
#include "xprm_rt.h"
38
XPRMmodel mod;
void end_run(int sig)
{
if(XPRMisrunmod(mod)) XPRMstoprunmod(mod);
}
行列ファイルの書き方
モデルは解かねばならないし、行列は次々に変更しなければならないし、またMoselによって与えら
れている以上に利用者との対話が必要になるということがよくある。他方、同じ問題を他人が利用
する必要がある場合もある。このような場合、問題が他のプログラムに対する入力となるように、
行列ファイルがMoselによって要求される場合がある。
Mosel ライブラリーはMPS形式とLP形式の両方の行列ファイルをXPRMexportprobルーティンを用い
て書くのをサポートしている。
int main(void)
{
int nReturn;
XPRMinit();
mod = XPRMloadmod("bigmodel.bim",NULL);
signal(SIGINT,end_run); /* Redirect Ctrl-C */
XPRMrunmod(mod,&nReturn,NULL);
XPRMfree();
return 0;
}
XPRMexportprob
これはMosel に指示してMPS形式とLP形式の両方の行列ファイルを書かせるものである。4つの引数
がある。
• 問題ポインター;
• 出力形式、MPS形式に対しては"m"、LP形式(minimization)に対しては""、 LP形式(maximization)
に対しては"p"、混合型名称に対しては"s";
• 出力に対するファイル名 — NULLの場合、出力はコンソールにプリントされる。
• 利用目的、NULLでもよい
リスト 4.7 モデルの実行を正しく終了する
Libraries
演習問題 モデルを問題に対するMPS行列ファイルsimple.matを書くように変更せよ。適当なLP形式
の行列ファイルsimple.lpを作成せよ。
MPSファイルを作成するためにXPRMexportprobを利用する例はリスト4.8に示されている。これを前
の例と比較せよ。これまでの説明から、Mosel ライブラリーを用いてモデルプログラムをコンパイ
ルし、読み込み、実行すること、アプリケーションから解の値にアクセスすること、複数の問題を
処理すること、行列ファイルを標準形式で転送すること、などが可能となった。次の章では、この
ようにして解くべきモデルを作成できるように、Moselモデルプログラミング言語についてより多く
を学ぶであろう。以下の節においては、上と同じ作業がBCLを用いてどのようにして達成されるかが
分かるであろう。BCLを用いない場合は、Optimizer ライブラリーについて紹介されている74ページ
に飛び、95ページにある節 “Xpress-MP ライブラリーを最大限利用する”に含まれる内容を見たり、
5章のMosel言語についてより多くを学んでもよい。
39
リスト 4.8 MPS行列ファイルを作成する
#include <stdio.h>
#include "xprm_rt.h"
int main(void)
{
XPRMmodel simple;
int nReturn;
XPRMinit();
simple = XPRMloadmod("simple.bim",NULL);
XPRMrunmod(simple,&nReturn,NULL);
XPRMexportprob(simple,"m","simple",NULL);
XPRMfree();
return 0;
}
ファイル名の拡張子がない場合は、MPS ファイルには.mat が付加され、LPファイルには.lp が付加されるであろう。
The Xpress-MP
Xpress-BCLをさらに利用するために
これまで、どのようにしてMosel ライブラリーを用いてモデルプログラムファイルをコンパイルし、
読み込み、実行するか、そしてOptimizerを用いて解を求めるかを見てきた。ほとんどの場合はこれ
で十分かも知れないが、時にはより多くの柔軟性、自身のプログラムの中から直接モデルを作成す
る、などが必要になるかも知れない。このためには、以下に示す3つの本質的な方法がある。
• モデルファイルを作成するためにプログラムを用い、Mosel ライブラリーを利用してそれをコン
パイルし、読み込み、実行する
• BCLを用いてモデルを動的に構築する
• モデルを局部的に構築するためにプログラムを用い、Optimizerライブラリーを利用してそれを
Optimizerに直接読み込む
最初の項目は以前見た内容に関連しているので、ここでは考慮しない。2番目の項目はこの節の問
題で、3番目は次のOptimizerライブラリーに関する内容である。
Xpress-MP Builder Component Library (Xpress-BCL) は、モデルが作成されるための別なライブラ
リー環境を与える。BCLプログラムは割に単純であって、以下のページで示すように、特定の型のモ
デルを構築するのに利用される。しかしながらもっと一般的なことは、BCLは数理計画モデルと最適
化を含む完全なソフトウェアシステムの開発に利用されるということである。
完全なモデルとは、いくつかのファイル形式のBCLによる出力である。選択的には、Optimizerに直
接読み込まれた場合に、BCLを用いて直接解くか、あるいはOptimizerライブラリーコマンドを用い
てさらに操作を加えるかのいずれかである。それぞれの可能性について論じよう。
前節あるいは前章に述べたように、ここのアプローチは49ページにあるリスト4.1に述べられた単純
なモデルを構築するために再度BCLを用いることである。したがって必要に応じてモデルのところを
参照できるようにページに印を付けておくのが有用であろう。
Libraries
モデルの最初の定式化
BCLを用いて簡単なモデルを構築するには、モデルの記述をBuilder言語に翻訳する必要がある。リ
スト4.9から始めよう。
ここに5つの単純な記述がある。すなわち決定変数、制約条件、問題ポインターを宣言する、そし
てライブラリーを初期化して問題を作成することである。
40
リスト4.1から明らかなことであるが、より多くの情報が必要とされており、宣言に続いて変数を加
えるということは比較的単純な作業である。リスト4.10に示すように型と限界を追加的に設定しな
ければならない。
リスト 4.9 構造の宣言と初期化
XPRBvar a, b;
XPRBctr first, second, profit;
XPRBprob prob;
XPRBinit("");
prob = XPRBnewprob("simple");
XPRBinit
BCL環境を初期化する。唯一の引数は、Xpress-MPの安全保護ファイルを探索するためのパスを特定
するのに用いられる。nullの場合は、標準的な探索パスが用いられる。リターンコードは常にチェ
ックされる:非零値は失敗を表すので、プログラムは終了しなければならない。
XPRBnewprob
新しい問題を作成し、名前を付ける。問題が引数であって、作成された問題に対するポインター、
型XPRBprobの変数を返す。
これまでの例ではリターンコードをチェックすることを示したが、このようなチェックは常に実行される。詳細については、
95ページの“エラーチェック”を参照されたい。
The Xpress-MP
定義された決定変数とともに制約条件が追加されるが、増加的な場合はリスト4.11に示される。
リスト 4.10 決定変数の追加
a = XPRBnewvar(prob,XPRB_PL,"a",0,200);
b = XPRBnewvar(prob,XPRB_PL,"b",0,200);
XPRBnewvar
単一の変数を追加する。5つの引数がある。
• 問題ポインター;
• 型 — XPRB_PLは連続型、非負変数を意味する;
• 出力ファイルにある名前で、後にOptimizerに送られる名前である;
• 変数に対する下限と上限で、上限がない場合は無限大とする。型XPRBvarの変数を返す。
リスト 4.11 増加的な制約条件の追加
first = XPRBnewctr(prob,"First",XPRB_L);
XPRBaddterm(prob,first,a,3);
XPRBaddterm(prob,first,b,2);
XPRBaddterm(prob,first,NULL,400);
XPRBnewctr
新しい制約を作成する。問題ポインターに続いて、制約名と制約の型の2つの引数があり、XPRB_L は
制約であることを意味し、型XPRBctrの変数を返す。
ここでの限界値は、下限値は容易に得られるが、上限は制約Secondから得られる。
Libraries
目的関数は、右辺値を設定しない制約条件と同様にして追加される。XPRBsetobjコマンドを用いた
41
目的関数として特定される。リスト 4.12に例を示す。
問題をBCLを用いて解く方法
モデルを構築すると、次の作業は解を見つけることである。Moselの場合と共通に、BCLは問題を
Optimizerに読み込み、それらを解き、結果にアクセスするという機能を有する。関数XPRBmaxim は、
解を求めるためにOptimizerを呼び出す。これに続いて、XPRBgetobjval とXPRBgetsolの2つの関数
が目的関数の最適値と決定変数の値をそれぞれ返す。最後に、これらの値を画面に示すために、標
準的なプリント関数が用いられる。
XPRBaddterm
制約条件に新たな項を加える。問題ポインターに続いて、3つの引数がある。
• XPRBnewctrから得られる制約条件を表す;
• 右辺に定数を追加するための変数あるいはNULLである。
• 2番目の引数がNULL の場合に係数あるいは右辺の値を表す。
したがってリスト4.11の2行目には、3*a をFirstという名の制約に加える。
リスト 4.12目的関数を加える
profit = XPRBnewctr(prob,"Profit",XPRB_N);
XPRBaddterm(prob,profit,a,1);
XPRBaddterm(prob,profit,b,2);
XPRBsetobj(prob,profit);
目的関数に対する行の型式は‘unconstrained’ XPRB_Nとなる。
The Xpress-MP
これらをすべてまとめると、モデルの完全な記述はリスト4.13のようになる。
XPRBmaxim
Optimizerを呼び出して問題を解く。問題ポインターとオプションフラッグの2つの引数がある。
XPRBgetobjval
最適な目的関数値を返す。
XPRBgetsol
決定変数の最適値を返す。問題ポインターと値が要求される変数という2つの引数がある。
リスト 4.13 モデルの最初の定式化
#include <stdio.h>
#include "xprb.h"
int main(void)
{
double objval;
XPRBvar a, b;
XPRBctr first, second, profit;
XPRBprob prob;
if(XPRBinit("")) return 1;
prob = XPRBnewprob("simple");
/* adding the variables */
a = XPRBnewvar(prob,XPRB_PL,"a",0,200);
42
b = XPRBnewvar(prob,XPRB_PL,"b",0,200);
xprb.h ヘッダーファイルには、BCL関数に対するすべての定義が含まれる。
最後の2つのコマンドは、問題をメモリーから削除し、他のシステムリソースを解除するものであ
る。これらはすべての問題の最後に呼び出されることが重要である。
/* adding the constraints */
first = XPRBnewctr(prob,"First",XPRB_L);
XPRBaddterm(prob,first,a,3);
XPRBaddterm(prob,first,b,2);
XPRBaddterm(prob,first,NULL,400);
second = XPRBnewctr(prob,"Second",XPRB_L);
XPRBaddterm(prob,second,a,1);
XPRBaddterm(prob,second,b,3);
XPRBaddterm(prob,second,NULL,200);
profit = XPRBnewctr(prob,"Profit",XPRB_N);
XPRBaddterm(prob,profit,a,1);
XPRBaddterm(prob,profit,b,2);
XPRBsetobj(prob,profit);
XPRBmaxim(prob,"");
/* retrieving the solution */
objval = XPRBgetobjval(prob);
printf("The maximum profit is %f\n", objval);
printf(" a = %f, b = %f\n",XPRBgetsol(prob,a),
XPRBgetsol(prob,b));
XPRBdelprob(prob);
XPRBfree();
return 0;
}
XPRBdelprob
問題をメモリーから削除する。唯一の引数は問題ポインターである。
XPRBfree
現在使われている他のシステムリソースを解除する。
リスト 4.13 モデルの最初の定式化
The Xpress-MP
演習問題 リスト4.1の簡単な問題を解くために、リスト4.13のBCLプログラムを入力し、解の値を
画面に表示せよ。
標準的には、アプリケーションの中に明示的に書かれていない限り、いかなる問題の出力もBCLによ
って与えられることはない。これは、上述のように、われわれが決定変数と目的関数の値のみを必
要とする場合には有利なことであるが、われわれにとっては、解が戻される前に最適化がどのよう
に進行しつつあるかについてより多くを知りたい場合もある。このような場合には、message level
を0から増加させることによってlogファイルの形のコンソール出力が得られる。message levelが3
になると、BCLはOptimizerによって求解のさまざまな段階における問題の統計量と目的関数の値を
含めたすべてのメッセージを出力することになる。これが必要な場合には、問題が入力される前に
43
message levelが設定されていなければならない。
演習問題
次の行
XPRBsetmsglevel(prob,3);
をXPRBnewprobコマンドに続けて上の問題に追加し、問題を再構築せよ。これを実行し出力を見よ。
行列変数を用いた問題の定式化
上に示したように、プログラムを構築する場合には常に増加的な傾向があるため、プログラムは不
必要に長たらしいものになることが多い。しかしながら、モデルを配列変数によって構築するとい
うように別のアプローチを採用すると、プログラムはより簡潔なものとなりうる。以下にこのよう
な例を示そう。
リスト4.14に示したような新しい配列変数xを宣言した記述から始める。
リスト 4.14 配列変数
XPRBarrvar x;
...
x = XPRBnewarrvar(prob,2,XPRB_PL,"x",0,200);
2つの新しい記述というのは、変数の型に関する宣言とそれに関する情報であって、前述の
XPRBnewvar関数の場合と同様である。追加的な引数として、配列の大きさがある。この場合に宣言
が必要となるのは、最終的にXPRBsetobjとして用いられる目的関数である。他の制約条件は
XPRBnewarrsum関数を用いて定義される。リスト4.15に関連部分を示す。
特に、ここで制約条件の左辺のそれぞれに対する係数を有する3つの配列を定義し、それぞれを
FIRST, SECOND, PROFITと呼ぶ。これらに配列変数xを乗じて(スカラー積として) 制約条件の左辺が
得られる。
XPRBnewarrvar
新しい配列変数を定義する。引数は問題ポインターと配列の大きさ、そしてXPRBnewvarと同じ情報
に関する4つである。型XPRBarrvarの変数を返す。
リスト 4.15 配列の制約条件
double FIRST[] = {3,2};
double SECOND[] = {1,3};
double PROFIT[] = {1,2};
...
XPRBctr profit;
...
XPRBnewarrsum(prob,"First",x,FIRST,XPRB_L,400);
XPRBnewarrsum(prob,"Second",x,SECOND,XPRB_L,200);
profit=XPRBnewarrsum(prob,"Profit",x,PROFIT,XPRB_N,0);
XPRBsetobj(prob,profit);
通常はモデルが解けて解が出力されると、モデルは終了する。完全なリストがリスト4.16に与えら
れている。
XPRBnewarrsum
2つの1次元配列によって新しい制約条件の左辺を定義するが、1つは変数でもう一つは係数を含
44
み、それらを要素ごとに乗じることになる。数学的には、次のように表現される。問題ポインター
の後に5つの引数がある。
• 制約名;
• 変数の配列;
• 係数の配列;
• 制約の型;
• 制約の限界値
リスト 4.16 完全なモデル, ‘arraymod’
#include <stdio.h>
#include "xprb.h"
double FIRST[] = {3,2};
double SECOND[] = {1,3};
double PROFIT[] = {1,2};
int main(void)
{
double objval;
XPRBarrvar x;
XPRBctr profit;
XPRBprob prob;
if(XPRBinit("")) return 1;
prob = XPRBnewprob("arraymod");
/* adding the variables */
x = XPRBnewarrvar(prob,2,XPRB_PL,"x",0,200);
a x . aixi
i
_
=
制約の型が ‘nonbinding’XPRB_Nの時は、最後の記述は無視される。
Libraries
演習問題
新しいモデルを入力し、定式化した上で解を観察せよ。
BCLをさらに利用するために
整数計画法
リスト4.1の簡単な問題に対しては、決定変数の値がそれぞれ小数点以下1位まででa = 114.3 と b
= 28.6のときに目的関数の最大値が得られるのを見た。しかしながら問題によっては、解が整数解
の場合のみ意味があるというように、このような小数解は適切ではないかも知れない。
/* adding the constraints */
XPRBnewarrsum(prob,"First",x,FIRST,XPRB_L,400);
XPRBnewarrsum(prob,"Second",x,SECOND,XPRB_L,200);
profit=XPRBnewarrsum(prob,"Profit",x,PROFIT,
XPRB_N,0);
XPRBsetobj(prob,profit);
XPRBmaxim(prob,"");
/* retrieving the solution */
objval = XPRBgetobjval(prob);
45
printf("The maximum profit is %f\n", objval);
printf(" a = %f, b = %f\n",XPRBgetsol(prob,x[0]),
XPRBgetsol(prob,x[1]));
XPRBdelprob(prob);
XPRBfree();
return 0;
}
リスト 4.16 完全なモデル, ‘arraymod’
The Xpress-MP
BCLにおいて整数変数を扱うということは、単に変数の型をXPRBnewvarあるいはXPRBnewarrvarによ
って適切に特定することである。前に連続型変数をXPRB_PLとして扱ったが、整数変数はXPRB_UIと
表される。最後の例で、これを実行する場合に必要な変更は、次式で与えられる。
x = XPRBnewarrvar(prob,2,XPRB_UI,"x",0,200);
新しい問題は元の問題ほど簡単ではなく、解を求めるにはより複雑な方法が必要である。— すなわ
ち整数解を見つけるために、グローバル探索global search が用いられる。これは、解のルーティ
ンに加えてオプショナルなg フラッグを利用するものである。
XPRBmaxim(prob,"g");
これらの2つの変更がなされると、プログラムは実行可能となる。
演習問題 リスト4.16のモデルをa と bが整数変数であるように変更して、グローバル問題を解け。
最大利益を達成するには、決定変数の値はどうあるべきかを求めよ。
配列の中の2,3の変数だけが整数であるというような場合は、作業量はさほど多くはならない。
配列の中のすべての変数が同じ整数型であると宣言されることもあるが、異なる型を有する場合に
はXPRBsetvartypeコマンドによって次々に変更されなければならない。このような場合、一連の
XPRBnewvarを用いてこれらの変数をC配列に置きながらモデルを構築するのがずっと簡単である。
行列ファイルの書き方
モデルの出力を行列ファイルとしてソルバーの中に独自に入力したり、あるいは他人に与えたりす
ることが必要となることもよくある。BCLではコマンドXPRBexportprobによってこのような目的を達
成する。
利用可能なすべての変数の型はBCL Reference Manualに記されている。
演習問題 前の問題を、問題を解くよりもMPSファイルを書くように変更せよ。Libraries
これを達成する完全なプログラムがリスト4.17に与えられている。行列ファイルarraymod.matが作
成されるが、そうでないときはプログラムが実行されるだけである。
XPRBexportprob
これによって問題を行列ファイルとして2つの企業標準形式として転送する。問題ポインターの後
に2つの引数がある。
• 出力ファイル形式。XPRB_MPSあるいはXPRB_LP であって、MPS形式ファイルか LP形式ファイルか
のいずれかである。;
• 拡張子のない出力ファイル名
リスト 4.17 MPS行列ファイルを書く
#include <stdio.h>
#include "xprb.h"
46
double FIRST[] = {3,2};
double SECOND[] = {1,3};
double PROFIT[] = {1,2};
int main(void)
{
XPRBarrvar x;
XPRBctr profit;
XPRBprob prob;
if(XPRBinit("")) return 1;
prob = XPRBnewprob("arraymod");
x = XPRBnewarrvar(prob,2,XPRB_PL,"x",0,200);
The Xpress-MP
MPS形式と同様に LP行列ファイルも目的関数が最大化か最小化かについての情報を含んでいる。こ
れが特定されないと、問題は標準的に最小化問題を前提とする。この問題に対するLPファイルを書
くためには、行列ファイルが転送される前に次の行が追加されなければならない。:
XPRBsetsense(prob,XPRB_MAXIM);
これは問題の意図を最大化問題に変更するものである。
演習問題 上のモデルを、問題に対するLP行列ファイルを書くように変更せよ。テキストエディタ
ーか同様のものを用いて問題の意図が正しく設定されていることをチェックせよ。
BCLの簡単な紹介の中ですべての可能性について説明することは不可能であって、上ではライブラリ
ーの概要のみを紹介している。詳細については、BCL Reference ManualかまたはXpress-MP CD-ROM
に含まれる多くの例を参照されたい。以下の節では、Xpress-Optimizer ライブラリーについて述べ
るが、アプリケーションからOptimizerにアクセスすることが可能となる。行列レベルで積極的にモ
デルを構築、変更する利用者にとって追加的な機能を与えるには、BCLとの結合を有効に利用するこ
とが必要である。これらの2つがどのようにして結合されるかについての詳細は、96ページの節“BCL
とOptimizerライブラリーの結合”に示されている。それ以外の点については、95ページの節
“Xpress-MPライブラリーを最大限利用する”を参照されたい。
XPRBnewarrsum(prob,"First",x,FIRST,XPRB_L,400);
XPRBnewarrsum(prob,"Second",x,SECOND,XPRB_L,200);
profit=XPRBnewarrsum(prob,"Profit",x,PROFIT,
XPRB_N,0);
XPRBsetobj(prob,profit);
XPRBexportprob(prob,XPRB_MPS,"arraymod");
XPRBdelprob(prob);
XPRBfree();
return 0;
}
リスト 4.17 MPS行列ファイルを書く
Xpress-Optimizer ライブラリーをさらに利用するために
Xpress-Optimizer ライブラリーを用いることによって、ライブラリー利用者はアプリケーションか
らOptimizerに完全にアクセスすることが可能となる。コンソール利用者にとって喜ばしい機能を提
供するとともに、Optimizer ライブラリーでは求解過程においていくつかの高度の行列操作関数を
利用したり、あるいはまた高度の対話型操作を行ったりすることが可能である。さらにライブラリ
ーでは利用者に強力なOptimizerを提供し、システムリソースとライセンスについての詳細に関する
47
制約下ではあるが、いくつかの異なる問題を同時に扱えるようにしている。Mosel ライブラリー と
BCLの場合と同様にして、Optimizer ライブラリーでは利用するそれぞれの関数を指示する問題ポイ
ンターを用いたいくつかの問題を識別している。上に述べた他のライブラリーの場合と同様に、こ
こでも実行中の現問題active problemという概念は存在しない。
Optimizer ライブラリーを用いて問題を解く方法
OptimizerではMPS形式か LP形式かのいずれかの行列ファイルを正しい入力として受け入れる。この
節の演習問題を試みるには、前章の演習問題で作成したような、あるいはまた3章の, “Console
Xpress”で得られたような正しい行列ファイルにアクセスする必要がある。この節では、リスト4.1
のモデルで作成された行列ファイルsimple.matを参照しよう。Optimizer ライブラリーでは、利用
する前にライブラリーを初期化し、システムリソースを最後に解除するための関数を備えている。
一般には、これらの2つの関数XPRSinit と XPRSfreeは、他のすべてのライブラリーコマンドを含
み、両者はOptimizerプログラムで利用できなければならない。行列をOptimizerに読み込むために
は、問題ポインターが作成され、操作に関連するあらゆる関数を利用可能な問題に対して用いられ
なければならない。XPRScreateprobを用いて、これを試みてみよう。
XPRSinit
利用する前にOptimizerライブラリーを初期化する。パスワードファイルがあるところへのポインタ
ーが唯一の引数である。これがNULLの場合は、標準インストールディレクトリーが探索される。
The Xpress-MP
リスト4.1の問題に対する解を求めるためには、目的関数が最大化される前に行列ファイルが入力さ
れなければならない。この問題を解くための完全なプログラムは、リスト4.18に与えられる。
XPRScreateprob
これは特定の問題に対する問題ポインターを立ち上げる。問題ポインターを返すための唯一の引数
がある。これは最初の引数として、問題に対して作動するあらゆる関数につながっている。
XPRSdestroyprob
問題ポインターに指示された問題を削除する。
XPRSfree
Optimizerで現在利用されるすべてのメモリーを解放し、あらゆるファイルを閉じる。
リスト 4.18 Optimizer ライブラリーを用いて問題を解く
#include <stdio.h>
#include "xprs.h"
int main(void)
{
XPRSprob prob;
XPRSinit(NULL);
XPRScreateprob(&prob);
XPRSreadprob(prob,"simple","");
XPRSmaxim(prob,"");
XPRSwriteprtsol(prob);
XPRSdestroyprob(prob);
48
XPRSfree();
return 0;
}
演習問題 リスト4.18からOptimizerプログラムを入力し、行列ファイルsimple.matを入力し、それ
を実行することによって目的関数を最大化し、XPRSwriteprtsolを用いて解を出力せよ。
XPRSwriteprtsolを用いて解を得る方法
Optimizerライブラリーを用いて解の情報を得るいくつかの方法がある。残りについては後述するが、
最も容易な方法は、ラインプリンターに対して解のファイルを送るのに最適なコマンド
XPRSwriteprtsolを用いる方法である。このファイルはリスト4.19に示されるように、3つの部分に
分けられる。これらはおそらく1部, 3部, 2部の順に考慮するのが最も有用であろう。1部は求解プ
ロセスのまとめの統計量を含んでいる。そこでは用いられた行列(問題)名(simple)と目的関数と
右辺名が与えられる。これに続いて行と列の数、最大化問題であるという事実、解くのに2回の反
復(ステップ)が必要であったこと、最良解が値171.428571を有することが記される。決定変数の
最適値は3部の列セクションColumns Sectionに与えられる。Value列が変数の最適値を与える。各
変数に対する入力コストやリデューストコストなどの追加的な解の情報もここに与えられる。これ
らの詳細については、7章にある”用語のまとめ”を参照されたい。
XPRSreadprob
MPS形式あるいは LP形式の問題ファイルを読む。3つの引数がある。
• 問題ポインター;
• 問題のファイル名(拡張子のない)
• 可能なフラッグのリスト
XPRSmaxim
問題に対する最大解の探索を開始する。問題ポインターと可能なフラッグのリストという2つの引
数がある。
XPRSwriteprtsol
解をファイルproblem_name.prtに出力する。
"Section 1…"
"Section 3…"
The Xpress-MP
考慮すべき最後は2部の行セッションRows Sectionである。これは問題に対するいくつかの制約条
件と目的関数のリスト、そして"左辺"の値を与える。特に目的関数値はここで再び現れる。制約条
件に対するスラック値と双対値もここで得られる。これらの詳細については、7章にある”用語のま
とめ”を参照されたい。
演習問題 いま作成した出力ファイルを観察して、いろいろな部分を確認せよ。決定変数と目的関
数の結果をリストにある結果を用いてチェックせよ。
リスト 4.19 XPRSwriteprtsol コマンドからの出力
Problem Statistics
Matrix simple (1部)
Objective *OBJ*
RHS *RHS*
49
Problem has 3 rows and 2 structural columns
Solution Statistics
Maximization performed
Optimal solution found after 2 iterations
Objective function value is 171.428571
Rows Section (2部)
Number Row At Value Slack Value Dual Value RHS
N 1 *OBJ* BS 171.428571 -171.428571 .000000 .000000
L 2 second UL 200.000000 .000000 .571429 200.000000
L 3 first UL 400.000000 .000000 .142857 400.000000
Columns Section (3部)
Number Column At Value Input Cost Reduced Cost
C 4 a BS 114.285714 1.000000 .000000
C 5 b BS 28.571429 2.000000 .000000
"Section 2…"s
Optimizer ライブラリーをさらに利用するために
最適化アルゴリズムを変更する
Optimizerは標準的には双対単体法dual simplexを用いてLP問題を解く。しかしながら主単体法
primal simplexとニュートンバリア法Newton barrierもサポートされているので、問題によっては
解法を変更して問題を解くのに要する時間をかなり節約することも可能である。与えられた状況で
‘最良の’ 解法を選択することは一種の技術でもあるが、最良の選択は自身の問題と同様の問題に対
していろいろな解法を実験してみてはじめて明らかになるものである。解法を変更する最も簡単な
方法は最適化ルーティンに通じるフラッグを立てることである。これらは上述の3つの解法のそれ
ぞれに対応する。
リスト 4.20には、最適化にニュートンバリア法を用いる例である。
演習問題 3つの解法のそれぞれを用いて問題を解け。このような簡単な問題の場合には、解法に
要する時間の差は目立たない。
b ニュートンバリア法;
d 双対単体法;
p 主単体法.
リスト 4.20 最適化アルゴリズムを変更する
XPRScreateprob(&prob);
XPRSreadprob(prob,"simple","");
XPRSmaxim(prob,"b");
XPRSwriteprtsol(prob);
XPRSdestroyprob(prob);
The Xpress-MP
整数計画法
上で考慮した簡単な問題に対しては、目的関数の最大値は決定変数が小数第1位まででa = 114.3 と
b = 28.6となるときに得られる。しかしながら問題によってはこのような小数解は受け入れられず、
決定変数のうちの1個あるいはそれ以上が整数値に限定されるという場合がある。リスト 4.21には、
整数解のみを必要とし、問題をMPS行列ファイルとして転送する場合に必要な変更を与える例を示す。
演習問題
リスト 4.21の整数問題をMoselライブラリーを用いてコンパイルし、読み込み、実行し、
50
MPS行列ファイルとして転送せよ。これをライブラリーを用いてOptimizerに読み込み、前と同様に
問題を解け。目的関数の値は現在いくつか。
新しい問題ファイル上でプログラムを実行した場合、整数変数を指定したにもかかわらず、戻され
た解が不変であることに気づいたであろう。この理由は、最適整数解の探索が2段階であることに
よる。第1段階では、最適解を見つけるためにLP緩和問題relaxationを解かねばならない。第2に
は、最適整数解が存在することを前提として、グローバル探索が実行されることである。
リスト 4.21 問題に整数変数を導入する
model integral
declarations
a: mpvar
b: mpvar
end-declarations
first:= 3*a + 2*b <= 400
second:= a + 3*b <= 200
profit:= a + 2*b
a is_integer
b is_integer
exportprob(EP_MPS,"integral",profit)
end-model
LP緩和問題は前の問題において変数の整数性を無視したものである。
グローバル探索は、gフラッグによってXPRSmaximを指定されたLP緩和問題の解に自動的に従う解法
であって、例がリスト 4.22に示されている。ここではプログラムのほんの一部のみを示すが、追加
的なコマンドはボールド体で示してある。これを実行して得られた解を見れば、最終的にはいずれ
の決定変数も整数値をとる。
演習問題 問題に対して整数解が得られるようにプログラムを変更せよ。この場合の目的関数の最
大値はいくつか、またそれを達成するためには決定変数はどのような値をとるべきか。
演習問題 決定変数のうちの一つだけが整数値で他の条件は削除するようにモデルを変更せよ。目
的関数の最適値はいくつか。
事前解法と後処理
Optimizerでは、最適化の前に問題を単純化して解きやすくするための手続きをいくつか利用してい
る。この一連の解法は前処理解法presolveとして知られている。前処理解法においては、行列中の
余分な行や列が削除されるため、前処理終了後の行列は元の行列とは非常に異なるものとなる。
XPRSwriteprtsolルーティンによって元の問題に関する情報が出力されるが、行列が前処理段階にあ
る場合に行列の状態に影響されて前処理で得られた解を返す他のルーティンも存在する。元の問題
に対する解ではない、前処理終了後の解を得ることは、多くの利用者にとって混乱を招くことかも
知れない。したがって、行列あるいは解にアクセスする場合には、何を期待すべきかを知っておく
ことが重要である。
リスト 4.22 整数解の探索を開始する
XPRScreateprob(&prob);
XPRSreadprob(prob,"integral","");
51
XPRSmaxim(prob,"g");
XPRSwriteprtsol(prob);
XPRSdestroyprob(prob);
g フラッグを用いてXPRSmaximを呼び出すことはフラッグなしでXPRSmaximを呼び出して後にXPRSglobalコマンドを直接呼び
出すことと同じである。
The Xpress-MP
前処理解法はXPRSmaximとXPRSminimという解法ルーティンとして呼ばれている。線形計画問題の最
適化にしたがって、行列に対して自動的に後処理解法postsolvedがなされ、元の行列を復帰させて
解を元の問題に返す。行列が非連続変数(たとえば整数変数)あるいは特定の順序付き集合を含む
場合には、グローバル探索が呼び出されることになっているので、行列はXPRSmaxim (そして
XPRSminim)の後も前処理状態のままである。特に、解法ルーティンの一つは、前述のように、g フ
ラッグなしで呼び出され、後に行列は前処理状態にとどまる。グローバル探索の間中、整数解の後
処理解法が行われ、認定されると解ファイルに書かれ、元の問題に利用可能な解を与える。しかし
ながら全行列の後処理解法は、グローバル探索の後に実行されることは決してないし、また元の行
列は保存されない。さらに行列にアクセスすることが必要とされる場合には、解法ルーティンを呼
び出す前に行列を読み出し、コピーしなければならない。
高度のライブラリー関数の多くは前処理終了後の行列には機能せず、それらを呼び出す前に行列が
正しい形式にあるように確認をとる必要があることに注意されたい。この例は後で説明されるコマ
ンド関数XPRSaddrowsである。ここでは表面的なことのみを取り上げるが、前処理解法の詳細につい
ては、Optimizer Reference Manualに見ることができる。さらなる情報については、このマニュア
ルを参照されたい。
制御と問題の特性
Optimizerにはいくつかのパラメタがあり、それらの値は利用者がいろいろな制御値controls.を設
定することによって問題に応じて変更することができる。これらのパラメタ値は、特に解くのが難
しいとされる問題に対してOptimizerの性能を向上させるように細かな調整をするための考察を加
えることも可能である。このような工夫によって求解に要する時間をかなり節約することもまた可
能である。新しい利用者がこれらの多くを標準値から変更することは勧めないが、実験が役に立つ
場合もかなりある。どのようにしてこれを達成するかについて、簡単に述べよう。
"LP problems…"
"IP problems…"
Libraries
追加的なことであるが、最適化プロセスでは、解いている特定の問題のいくつかの特性attributes
を利用する。これらの特性は制御変数と同様に検索可能なものである。設定済みのすべての制御変
数と検索可能な問題の特性の完全なリストはOptimizer Reference Manualで見ることができる。制
御変数も問題の特性も整数integer、倍精度double、文字列character stringの中の一つの型を持っ
ていて、処理の仕方は型によってそれぞれ異なる。当面、制御変数のみを扱うことにする。制御変
数の値を与える3つのライブラリー関数XPRSgetintcontrol, XPRSgetdblcontrol,
XPRSgetstrcontrolがある。特定の問題に対する与えられた制御変数の値にアクセスするためには、
型にあった正しい関数を用いなければならない。
XPRSmaximが設定された場合、解法が開始される前に問題を単純化するために、前処理解法が自動的
に呼び出されるのを見た。この標準的な操作は制御PRESOLVEによるが、これは最適化の最中に前処
理解法が実施されるか否かを指定する整数である。
演習問題 XPRSgetintcontrol(prob,XPRS_PRESOLVE,&presolve)を用いて制御PRESOLVEの整数値
presolveを検索し、これが標準的に設定された値に対応していることを確認せよ。
Xpress-MP ライブラリーから制御変数にアクセスするとき、それらの名前が接頭辞XPRS_を前に付け
52
ているという点でConsole Xpressにあるものと異なることに注意されたい。これは通常制御変数が
接頭辞なしで記述されるということが忘れられがちであるという点で重要である。
前処理解法の実施と停止
制御変数PRESOLVEを次のように設定する:
0 前処理解法なしで解法を開始する
1 前処理解法終了後に解法を開始する;
The Xpress-MP
制御変数に新しい値を設定するには、関数XPRSsetintcontrol, XPRSsetdblcontrol,
XPRSsetstrcontrolが用いられ、新しい値をそれぞれ整数、倍精度、文字列に対応させる。
演習問題 XPRSgetintcontrol(prob,XPRS_PRESOLVE,0)を用いて制御PRESOLVEの値を
前の問題に対して制御PRESOLVEを停止するときには0とする。これは変数の値によって影響を受ける
XPRSmaximを呼び出す前になされなければならない。再びプログラムを実行して出力を観察せよ。
最後に紹介するこの型の関数の集合は、問題のいろいろな特性にアクセスすることを可能にするも
のであって、求解プロセスの間にOptimizerによって設定される。XPRSgetintattrib,
XPRSgetdblattrib、そしてXPRSgetstrattribなどの関数は制御値を得るものであって、同様にして
用いられる。この例は整数問題の特性LPSTATUSに関連して与えられるが、それらの値は解が最適か、
実行不可能か、非有界か、未終了かについての詳細を与える。リスト 4.23はこれがどのようにして
有効に用いられるかを示している。ここではこれ以上詳細については述べないが、モデリングにお
けるOptimizerライブラリーの利用に関して探究を試みるために、もう一つの例を示そう。
リスト 4.23 解の状態をチェックする
int lpstatus;
…
XPRSmaxim(prob,"");
XPRSgetintattrib(prob,XPRS_LPSTATUS,&lpstatus);
if(lpstatus == XPRS_LP_OPTIMAL)
XPRSwriteprtsol(prob);
else
printf("Solution is not optimal\n");
"Problem
attributes…"
問題の特性を用いて得られたLPSTATUSのすべての可能な値に関する完全なリストは、Optimizer
Reference Manualに見られる。
最適化処理の対話方式
解くのに長い時間を要するとされる大きな問題に対しては、最適化プロセスの間にOptimizerからよ
り多くの情報を得ることが有用であるとされている。Logファイルが準備されると、これを用いて解
がどのように進行しているかを決定することが可能となるが、これは不便で柔軟性がない。このよ
うな状況に対して、Optimizerライブラリーはコールバックスcallbacksとして知られている”高度の”
関数の集合を与え、自身の関数を実行するために最適化プロセスの間の様々の時点でプログラムに
戻ることが可能となっている。コールバックスのほとんどはグローバル探索のいろいろな側面と関
連しており、これらについてはOptimizer Reference Manualに記述されている。しかしながら、よ
り一般的な状況下において呼び出されるものも少しあり、おそらく最も単純なのは
XPRSsetcbmessageである。これはテキスト行がOptimizerの出力となるたびに呼び出される関数を設
定し、その(部分的な)利用に関する例はリスト4.24に示されている。これは特に簡単な例であっ
て、Optimizerによる標準的な出力のそれぞれの行を適当な接頭辞を付けて画面に表示するだけであ
53
る。
リスト 4.24 Optimizerライブラリーでコールバックスをを利用する
void XPRS_CC callback(XPRSprob prob, void *user,
const char *msg, int len, int msgtype)
{
char *usermsg = (char *)user;
if(msgtype>=0) printf("%s: %s\n",usermsg,msg);
}
int main(void)
{
XPRSprob prob;
char *usermsg = "simple.callback";
XPRSinit(NULL);
XPRScreateprob(&prob);
XPRSsetcbmessage(prob,callback,usermsg);
…
}
Log ファイルはXPRSsetlogfileコマンドを用いて正しく設定される。この詳細については、Optimizer Reference Manualを
参照されたい。Usermsgは他の情報がコールバックへ送られないときにはNULLでよい。
The Xpress-MP
演習問題 コールバックスをプログラムに追加して、リスト4.24のようにOptimizer 出力を画面に
プリントせよ。
メッセージの型は行の出力をOptimizerによって画面に表示するのに用いられる。メッセージの型は
出力のメッセージのレベルにしたがって、以下のように変化する。
演習問題 プログラムにあるコールバック関数を変更して、メッセージのレベルにしたがってプリ
ントするときに別々にフォーマットせよ。
Optimizer Reference Manualには、ライブラリー利用者によって設定されたすべてのコールバック
関数の完全なリストが含まれている。これらが提供する可能性になじんでおくことは有用であるこ
とに気づくであろうし、また大きな整数問題を定期的に解くような利用者にとっては、特に有用で
ある。
XPRSsetcbmessage
出力の行表示がOptimizerによって作成されるたびに実行される関数を立ち上げる。表記方法:
int XPRSsetcbmessage(XPRSprob prob,
void (*uopf)(XPRSprob this_prob,
void *this_user, const char *this_msg,
int this_len, int this_msgtype),
void *user);
ここでthis_userは、利用者が定義可能なポインターであって、自身のデータがコールバック関数に
送られるようにするものである。this_msg は文字列の出力、this_len はその長さ、そして
this_msgtypeはメッセージレベルを定義する整数である。
メッセージの型とレベル
1 通常のメッセージ(情報型)
2 通常のメッセージ(デバッグ型)
3 警告メッセージ
54
4 エラーメッセージ
Libraries
メモリーからのモデルの入力方法
Optimizerライブラリーは最大のXpress-MPライブラリーであって、大きく2種類の関数を有してい
る。一つは基本的な関数であって、ほとんどがConsole Xpressコマンドの受け皿となっている。も
う一つはライブラリー利用者にのみ利用可能な高度のコマンド群である。
高度のライブラリー関数には、問題をメモリーにある配列から直接Optimizerに読み込み、そこでそ
れらを直ちに操作するのに必要なすべてのツールが含まれている。この節では、どのようにして簡
単な問題(リスト4.1)がこれらの関数を用いて直接入力され、そこでOptimizerとライブラリー関数
が
相互に機能するかを示す。
Optimizerライブラリーによる問題の入力方法
モデリング用語では、問題について記述する場合、常に制約条件と変数という言い方をするが、
Optimizerではそれらと構造的に等価な表現として行列の行と列を用いる。このことについては、解
がXPRSwriteprtsolによって作成されるのを前に見た。モデルがMoselによって転送される際には、
問題についての記述がOptimizerで解くために読み込めるように行列形式に変換される。この節では、
どのようにしてこの行列をOptimizerライブラリーによって直接作成するかということについて調
べてみよう。これは高度のライブラリー関数XPRSloadlpによって実行される。
XPRSloadlpは多くの引数を持っているが、例によって利用方法を説明しよう。49ページにあるリス
ト4.1に注目するのがよいであろう。
XPRSloadlp
これは問題をOptimizerのデータ構造の中に読み込むためのもので、すべての引数の完全なリストは
Optimizer Reference Manualの中で見られる。
The Xpress-MP
リスト4.25ではXPRSloadlpへのいろいろな引数が宣言され、前に述べたのと同じ簡単な問題に対す
る値が割り当てられる。
• 問題に対する名前であって、ここでは”高度”を選んだ。前述のように、問題名はファイルが作成さ
れ、特定されなければならない場合の基本となるものである。
• 上記の手続きに引き続いて、行列中の列(変数)の数が2 (a と b)、行(制約条件, 目的関数を含ま
ない) の数も 2であると定義する。
次の6つの配列は、行列の行を構築する場合にモデルの制約条件についての詳細を与える。
• 最初に、目的関数を行とは見なさずに、”真の” 制約条件と考える。最初の配列qrtypeは、モデル
中の各制約条件の型を特定する。これは各行に対して‘L’を用いることによって、XPRSloadlpに送ら
れる。
•上記の手続きに引き続いて、制約条件の右辺値が一つづつ定義される。最初の値は制約条件からも
たらされるが、2番目の値は
3a 2b + 400 .
a 3b + 200 .
からもたらされる。
リスト 4.25 XPRSloadlpに対する引数を宣言する
char probname[] = "advanced";
int ncol = 2;
55
int nrow = 2;
char qrtype[] = {’L’,’L’};
double rhs[] = {400.0, 200.0};
int mstart[] = {0, 2, 4};
int mrwind[] = {0, 1, 0, 1};
double dmatval[] = {3.0, 1.0, 2.0, 3.0};
double objcoefs[] = {1.0, 2.0};
double dlb[] = {0.0, 0.0};
double dub[] = {200.0, 200.0};
.
Libraries
• 次の2つの配列は、以下で定義される行列要素に対する分岐点と出発点について記述するもので
ある。これらについては、以下のパラグラフで詳細を述べる。
• 配列dmatvalは、行列の要素になる制約条件に含まれる実際の係数を含んでいる。これは垂直方向
に並んだ1次元配列であって、一度に一つづつの変数の非零要素を入れたものである。行列を左か
ら列ごとに効率的に特定する。
• 最後に、目的関数の係数が特定される。最後の2行はモデルの変数に関する上限と下限を与える。
おそらくこのリストの中で最も興味ある要素は配列mstart と mrwindである。行列要素に対する分
岐点と出発点によって行列を定義する方法は、多くの零要素を持つ問題を記述する非常に効率的な
方法である。
これまでわれわれが考えた最も簡単な例は零要素を持たないので、これらの利用方法はそれほど明
白ではないかも知れない。そこで次のような例を考えてみよう。問題1の行列は20個の要素を持ち、
そのうち10個は零である。このモデルと同じように、大きな問題は通常疎であるので、XPRSloadlp
が用いられる。問題が疎な形式であれば、より効率的である。これを利用したリスト4.26に与えら
れている。
問題 1
Maximize: 0.1x1 + 0.2x2 + x3
Subject to: x1 + 2x2 = 0
x3 + x4 - x5 = 0
x4 - 0.27x5 >= 0
3x1 + x4 - 0.4 x5 <= 0
リスト 4.26 疎行列データを入力する
int mstart[] = {0, 2,3,4, 7, 10};
int mrwind[] = {0,3,0,1,1,2,3, 1, 2, 3};
double dmatval[] = {1,3,2,1,1,1,1,-1,-0.27,-0.4};
"Offsets and
start points…"
多くの零要素を有する行列は疎といわれる。
The Xpress-MP
行列の要素 mstart は、Optimizerに対してdmatvalにあるデータが下記にしたがって行列の列に分
けられることを知らせる。
dmatval[0], dmatval[1] 列0;
dmatval[2] 列1;
dmatval[3] 列2;
dmatval[4], dmatval[5], dmatval[6] 列3;
56
dmatval[7], dmatval[8], dmatval[9] 列4.
このようにして、mstartにある要素は、dmatvalに与えられる一連のデータの中にある列に対する出
発点(と終了点)を定める。したがってmstart配列は、列i が mstart[i]で始まり、列mstart[i+1]-1
で終わるというように、列の数より1つだけ多くの要素を含む。列が定義されると、mrwindに含ま
れる情報は、各列に対する要素を下記のように正しい行におく。
dmatval[0] 行0; dmatval[1] 行3;
dmatval[2] 行0;
dmatval[3] 行1;
dmatval[4] 行1; dmatval[5] 行2; dmatval[6] 行3;
dmatval[7] 行1; dmatval[8] 行2; dmatval[9] 行3.
一度位置が特定されると、要素自体はdmatvalにあるデータから決定される。われわれの”高度の”問
題に戻ると、リスト4.25は列0の行0と1にあるdmatvalの最初の2つの要素、そして列1の行0と1にあ
るdmatvalの3番目と4番目の要素をおく。XPRSaddnamesを用いると、定められた行列の中の変数に名
前が付けられる。リスト4.27では、XPRSloadlpを用いた行列の定義とともに、このことを示す。変
数名は文字配列colnamesに無制限リストとして保存される(したがって\0文字が2つの間にある)。
すべての行と列の添字はCでは0から始まることを覚えておいて欲しい。
"Anyway…"
Libraries
問題の解を得る方法
問題の行列が定められると、目的関数は前のように最大化される。しかしながらわれわれはこれま
では解を見たり、プリントしたりするためにファイルに出力してきたが、Optimizerライブラリーで
はもう一つの関数XPRSgetsolを有しており、それによって利用者のプログラムから解へ直接アクセ
スすることが可能となる。
リスト 4.27 問題を読み込み、変数名を付ける
XPRSprob prob;
char colnames[] = "a\0b";
...
XPRSinit(NULL);
XPRScreateprob(&prob);
XPRSloadlp(prob, probname, ncol, nrow, qrtype, rhs,
NULL, objcoefs, mstart, NULL, mrwind, dmatval,
dlb, dub);
...
XPRSaddnames(prob,2,colnames,0,ncol-1);
XPRSaddnames
行列に行や列の名前を付ける。以下の5つの引数がある。
• 問題;
• 名前が行か列かによって1か2の値をとる。
• 名前の無制限な配列
• 最後の2つの引数は行列の最初と最後の行(列)に名前を付与する。
XPRSgetsol
問題に対する解を検索する。問題に対して4つの引数があり、解に関するどのような情報が必要と
されるかによるが、いずれもNULLでもよい。
ここで2つのNULLは行の範囲と各列の非零要素の数に関連している。問題を特定した場合は、これらは必要ではない。詳細
57
については、Optimizer Reference Manualを参照されたい。
The Xpress-MP
リスト4.28ではいろいろな変数の最適値を得てそれらを画面に出力するためにはどうすればよいか
を示す。XPRSgetsolによって得られない解の一部としては、目的関数値がある。この値を戻すよう
な高度ライブラリー関数は存在しない。これはむしろLPOBJVALという問題の特性の中に保存されて
おり、前述の問題の状態に関するアクセスと同様にして得られる。これを実行するコードはリスト
4.29に示される。
演習問題 リスト4.25とリスト4.29の概念を結合して、リスト4.1の問題を直接読み込んで解き、解
を画面に出力するプログラムを書け。得られた値が前の演習問題と一致することを確かめよ。
リスト 4.28 変数の値を得て提示する
#include <stdlib.h>
double *vars;
...
vars = malloc(ncol*sizeof(double));
XPRSgetsol(prob,vars,NULL,NULL,NULL);
printf("a = %2.1f\nb = %2.1f\n", vars[0], vars[1]);
リスト 4.29 目的関数の値を得て提示する
double lpobjval;
...
XPRSgetdblattrib(prob, XPRS_LPOBJVAL, &lpobjval);
printf("The objective value is %2.1f\n", lpobjval);
Libraries
問題の行列の変更
Optimizerライブラリーでは、行列の読み込みがなされた後に、それを変更することも可能である。
例として、XPRSaddrowsを用いて、追加制約がどのようにして問題に付加されるかについて述べよう。
いま、追加制約を問題に付加したいとする。これをどのようにして実現するかについては、リスト
4.30にある追加の行が必要であることを示している。XPRSloadlpは線形制約条件式の変数に関する
係数を特定し、aclindはamatvalの要素に関する列の添字を特定し、そしてastartは新しい行に対す
る要素最初の分岐点を特定する。この場合、新しい行が行列の中の要素0にあるamatval[0] (列0)
と要素3にあるamatval[1] (列1)に付加され、行列の列ごとに非零要素を特定する。XPRSaddrowsの
2番目と3番目の引数は新しい行の数と付加された行の非零要素の数である。
演習問題 前の問題に対して、解く前に新しい行を追加するようにプログラムを変更せよ。プログ
ラムを実行すると、新しい目的関数値が169.2に減少するはずである。これを達成するのに必要な決
定変数の値はいくつか。
XPRSaddrows
Optimizerのデータ構造にある行列に追加の制約行を加える。
リスト 4.30 行列に追加の行を加える
char atype[] = {’L’};
double arhs[] = {800.0};
int astart[] = {0,2};
int aclind[] = {0,1};
double amatval[] = {6.0,5.0};
58
...
XPRSaddrows(prob,1,2,atype,arhs,NULL,astart,aclind,
amatval);
これを前のリスト4.5にある‘変更’ モデルと比較せよ。
6a 5b + 800 .
The Xpress-MP
問題の全域要素の追加
Moselモデルプログラミング言語を用いると、決定変数が整数値になるように問題を変えるにはモデ
ルのプログラムファイルにわずか2行を追加すればよいことを前に見た。同様に、Optimizerライブ
ラリーを用いると、決定変数が整数値になるように特定することが可能であるが、この場合、問題
はもはやXPRSloadlpを用いて読み込むことはできず、代わりに関数XPRSloadglobalを用いなければ
ならない。
XPRSloadglobalの最初の14個の引数はXPRSloadlpの場合と全く同様であるので、これ以上は述べな
い。残りの引数のうちで、2,3についてここで述べる。リスト4.31でそれらの宣言を与え、設定
を行う。
• 新しい引数のうちで、ngentsは、問題中のグローバル要素の数を表し、ここでは、2つの変数が
整数であるので、2となる。
XPRSloadglobal
グローバル要素を有する問題をOptimizerデータ構造に読み込む。最初の14個の引数はXPRSloadlp
の場合と全く同様である。残りの引数については、Optimizer Reference Manualを参照されたい。
リスト4.31 ライブラリーを用いて整数問題を読み込む
int ngents = 2;
int nsets = 0;
char qgtype[] = {’I’,’I’};
int mgcols[] = {0,1};
XPRSloadglobal(prob, probname, ncol, nrow, qrtype,
rhs, NULL, objcoefs, mstart, NULL, mrwind,
dmatval, dlb, dub, ngents, nsets, qgtype, mgcols,
NULL, NULL, NULL, NULL, NULL);
‘グローバル要素’はXpress-MPの傘下で非連続変数と特定順序つき集合として用いられる。SOSを有する問題に対するその他の
引数に関する詳細は、Optimizer Reference Manualを参照されたい。
Libraries
• 整数 nsetsは問題の中の特定順序付集合Special Ordered Sets(SOSs)の数を表す。ここでは用い
ない。
• 配列 qgtype は両変数が整数値となるように設定する。
• mgcols はこのような型を設定された変数の数を表す。
最後の5つの引数はすべてSOSに関連している。ここではこれらを用いないので、NULLと設定される。
このような混合型整数問題に対しては、最適な目的関数値を得るために問題の特性であるLPOBJVAL
を用いるべきではない。代わりに特性MIPOBJVALが用いられなければならない。グローバル(MIP)探
索をしている間は、いくつかのLP問題が解かれ、それぞれはいろいろなグローバル変数に関する追
加的な限界を与えることによって可能な解に絞り込んでいくという操作をすることになる。グロー
バル探索が終わると、特性値LPOBJVALに最後のLP問題に対する最適な目的関数値が得られる。しか
しながら、これがMIPOBJVALに保存されているグローバルな最大値(解かねばならなかったすべての
LP問題の中で)である必要はない。さらに興味のある利用者はOptimizer Reference Manualを参照
59
されたい。
演習問題 元の問題(わずか2本の制約を有する問題)を変更して整数問題を読み込め。これを解
いて、解が前に解いた最後の整数問題と一致することを確かめよ。
演習問題 これを変更して、追加制約を有する新しいグローバル問題を読み込め。これはa が 107
でb が 31のときに最適値を有する。これを解いて確認せよ。
このライブラリーを用いたモデリングに関するより詳細な情報はOptimizer Reference Manualの中
にある。そこでは、読み込まれた問題を変更したり、解いたりするのに必要なすべての関数が示さ
れている。
すべての処理方法について述べたわけではないが、少なくともモデリングに関してこの方法の利点
については紹介することができたはずである。この章を終えるにあたっては、Xpress-MP ライブラ
リーの利用方法を他の言語を用いて説明する前に、利用者にとって有用なXpress-MP ライブラリー
についてのいくつかの一般的なコメントを与えることにする。
変数の添字は0から始まる変数配列の位置を表す。
6a 5b + 800 .
The Xpress-MP
Libraries
4
Xpress-MP ライブラリーから最良解を得ること
エラーの検出方法
ほとんどすべてのライブラリー関数は、関数の呼び出しがうまくいった場合には整数値0を返し、
そうでないときは非零値を返すようになっている。このような関数の返却値を利用すると、プログ
ラムは起こりうるエラーに対処することができ、前もってこれらの値をチェックすることによって
問題の診断が可能となる。この章のこれまでのリストではいずれにおいてもエラーチェック機能を
利用していないが、これは純粋に明白にするためになされることであるので、ライブラリー関数が
利用されるか否かに関わらず、あらゆるプログラムの中で利用者がエラーチェック機能を用いるこ
とを奨めたい。
Optimizerライブラリーを用いた基本的なエラーチェック機能の例は、リスト4.32に与えられている。
この例は特に単純であって、単にメッセージをプリントし、エラーがある場合に終了するというも
のである。実際、当然のことであるが、プログラムの中でエラーを扱う手続きとしては、もっと複
雑なものが可能であるが、これらについては、読者に任せることにする。
リスト 4.32 基本的なエラーチェック
#include <stdio.h>
#include <stdlib.h>
#include "xprs.h"
void error(XPRSprob my_prob, const char *function)
{
char errmsg[256];
XPRSgetlasterror(my_prob,errmsg);
printf("%s did not execute correctly:\n\t%s\n",
function, errmsg);
if(my_prob != NULL) XPRSdestroyprob(my_prob);
XPRSfree();
exit(1);
60
}
int main(void)
{
XPRSprob prob=NULL;
Libraries
演習問題
この章で用いたプログラムの一つをエラーチェック機能を持つように書き換えよ。
BCL とOptimizer ライブラリーの結合
利用者が必要とするすべての作業を、基本的なBCL関数だけでOptimizerの中で実行するには十分で
ない場合がある。解決策は、問題を構築して、それをBCLを用いてOptimizerの中に読み込み、あと
でOptimizer関数を呼び出すことである。こうすることによって、Optimizerライブラリーのすべて
の機能を問題に対して利用することが可能となるが、これ以降はBCLを用いて問題にアクセスするこ
とはできないという欠点がある。あらゆる求解段階においてBCLを用いて問題にアクセスしたい場合
は、上述のように、BCL関数を用いて最適化作業を実行する必要がある。BCL とOptimizer ライブラ
リーを結合するには、2つの段階が必要である。最も単純な場合は、ライブラリー関数を用いて
Optimizer に読み込めるように、MPS ファイル (リスト4.16にあるように)を書くためにBCLを用い
るということである。しかしながらASCIIファイルを作成し、読むためには、かなりの時間を要する
ディスクアクセスが必要である。このため、問題を直接Optimizerに転送するためにBCLが用いられ
る。
if(XPRSinit(NULL))
error(prob,"XPRSinit");
if(XPRScreateprob(&prob))
error(prob,"XPRScreateprob");
if(XPRSreadprob(prob,"simple",""))
error(prob,"XPRSreadprob");
if(XPRSmaxim(prob,""))
error(prob,"XPRSmaxim");
if(XPRSwriteprtsol(prob))
error(prob,"XPRSwriteprtsol");
if(XPRSdestroyprob(prob))
error(prob,"XPRSdestroyprob");
XPRSfree();
return 0;
}
リスト 4.32 基本的なエラーチェック
BCLとOptimizer ライブラリーによって用いられる問題ポインターが異なるために、このようにして
ライブラリーを結合することはかなり複雑なものとなる。その結果、どのような問題が用いられる
としても、最初にBCL、そして次にOptimizer ライブラリーに送られなければならない。リスト4.33
にこれがどのようにしてなされるかを示す。
リスト 4.33 BCLとOptimizer ライブラリーを結合する
#include <stdio.h>
#include "xprb.h"
#include "xprs.h"
double FIRST[] = {3,2};
61
double SECOND[] = {1,3};
double PROFIT[] = {1,2};
int main(void)
{
XPRSprob opt; /* Optimizer problem pointer */
XPRBprob bcl; /* BCL problem pointer */
XPRBarrvar x;
XPRBctr profit;
bcl = XPRBnewprob("combined");
x = XPRBnewarrvar(bcl,2,XPRB_PL,"x",0,200);
XPRBnewarrsum(bcl,"First",x,FIRST,XPRB_L,400);
XPRBnewarrsum(bcl,"Second",x,SECOND,XPRB_L,200);
profit=XPRBnewarrsum(bcl,"Profit",x,PROFIT,
XPRB_N,0);
XPRBsetobj(bcl,profit);
/* load the matrix into the Optimizer */
XPRBloadmat(bcl);
/* obtain the problem pointer for the Optimizer */
opt = (XPRSprob)XPRBgetXPRSprob(bcl);
Libraries
この例では、BCLの関数 XPRBnewprobはBCLとOptimizerを同時に初期化するので、関数XPRSinitを別
に呼び出す必要はない。この関数からの出力はBCLの問題ポインターであって、それが問題に対して
機能するすべてのBCL関数によって利用される。行列がXPRBloadmatを用いてOptimizerの中に読み込
まれ、その後にOptimizerの問題ポインターが必要となる。これは関数XPRBgetXPRSprobを用いてBCL
によって得られるが、その後Optimizer関数が前と全く同様にして用いられる。
演習問題 リスト4.33の例を構築し、実行を試みよ。MPSファイルが作られ、ライブラリーが機能し
て完成した行列がBCLからOptimizerに直接送られるのを確認せよ。
Optimizer関数が呼び出された後は、BCLから問題にアクセスすることはもはや不可能となることに
注意して欲しいことを再度述べておこう。これが必要な場合は、BCL解のルーティンがOptimizerル
ーティンに先だって用いられなければならない。
XPRSmaxim(opt,"");
XPRSwriteprtsol(opt);
/* tidy up using the BCL function */
XPRBdelprob(bcl);
XPRBfree();
return 0;
}
XPRBloadmat
Optimizer関数をOptimizerで動かすために行列を読み込む。
XPRBgetXPRSprob
BCL によってOptimizerに読み込まれた問題に対するOptimizer問題ポインターを返す。
リスト 4.33 BCLとOptimizer ライブラリーを結合する
The Xpress-MP
62
Visual BasicとXpress-MPライブラリーの利用
Xpress-Optimizerライブラリーは単独で、あるいはExcel, Access の中で用いられるVisual Basic
for Applications (VBA) としてVisual Basicとともに用いられる。ここでは単に‘VB’として両者を
表すことにする。読者がVBを用いない場合は、ここを飛ばしてもよい。
Xpress-MPライブラリーは、VBモジュールの中で定義される外部関数宣言xpress.basを用いたVBプロ
ジェクトに組み込まれ、Xpress-MP ライブラリーの一部として配布されている。Xpress-MPライブラ
リー関数自体は、C関数と同じ名前を有するが、これによって利用者はReference Manualsにあるプ
ロトタイプと対応するVBとの間で容易に翻訳ができるようになっている。Xpress-MPライブラリー関
数は長い値を返すが、この例はリスト4.34に与えられ、これが前の問題であるリスト4.18のVB版と
なっている。この節の残りの部分では、C と VBのインターフェイスの間の相異について述べ、この
環境におけるライブラリー利用者の陥りやすい落とし穴について紹介する。ここで用いるアプロー
チは本質的にはまとめであるので、利用者はOptimizer Reference Manualをも参照するのが有用で
あろう。
リスト 4.34 VBの中でXpress-MP ライブラリーを用いる
Public Sub main()
Dim nReturn As Long
nReturn = XPRSinit("")
nReturn = XPRScreateprob(prob);
nReturn = XPRSreadprob(prob,"simple","")
nReturn = XPRSmaxim(prob,"")
nReturn = XPRSwriteprtsol(prob)
nReturn = XPRSdestroyprob(prob)
nReturn = XPRSfree()
End Sub
このモジュールのコピーは、NULL引数を用いる関数プロトタイプを定義するときに結局はカストマイズすることになるので、
利用者のプロジェクトに加えられなければならない。ここでは明白にはしていないが、すべてのライブラリー関数が返す値
をチェックすることを奨める。詳細については、95ページにある“エラーチェック”を参照されたい。
Libraries
内部ファイル
Xpress-MP分布の一部分であるファイルmodbyte.basには、この章で用いられるいくつかの有用な関
数の定義が含まれており、このファイルはリストに述べられているプログラムのソースの中に含ま
れていることを前提としている。特に、関数ByteConversionがここで定義され、その結果、以下の
いくつかのリストはこれらの関数なしでは機能しない。この関数はCD-ROMにあるディレクトリー
\examples\optimizer\vbに見られる。
主要構成
引数の型: ルーティンに渡されるVB パラメタは、Cパラメタと以下に示すような関連がある。
定数: C定数は同じ名前を有するVBグローバル定数となる。例を示す。
Global Const XPRS_PLUSINFINITY = 1E+20
Global Const XPRS_LPLOG = 9
数値配列: Optimizer libraryにあるいくつかのルーティンでは数値配列が一つの引数に渡されるこ
とが必要である。例はルーティンXPRSgetobjによって与えられるが、その2番目の引数は倍精度配
列である。これをVBからOptimizerに渡す例はリスト4.35に与えられる。注目すべき重要な点は、配
列の最初の要素だけが渡され、配列全体ではないということである。これはすべての数値配列が
Xpress-MPとVBの間を行き来する場合である。
63
C 引数の型
int x
int *x
double x
double *x
char *x
VB 引数の型
ByVal x As Long
x As Long
ByVal x As Double
x As Double
ByVal x As String
or x As Byte
The Xpress-MP
文字配列: 文字配列をいろいろなライブラリーサブルーティンに渡すことがときどき必要となる。
VBでは、文字配列はByte変数型で渡されるが、たとえばXPRSchgboundsの定義の中では、次のように
なる。:
Declare Function XPRSchgbounds Lib "XPRS.DLL" _
(…, qbtype As Byte,…) As Long
これを用いるには、バイト配列がリスト4.36にあるAsc関数を用いてVBコードで初期化されなければ
ならない。これは"LU" に対するqbtype配列を初期化して、XPRSchgboundsルーティンにすぐに渡さ
れるようにするものである。Optimizerライブラリールーティンでは、利用者が多重列を含む文字配
列を渡すことが必要とされる。これもByteデータ型を用いてなされなければならない。各系列を分
離するには、C 系列終了記号 (バイト値 0)を用いることが必要であって、これにはVB内で何らかの
変換がなされなければならない。この変換をXpress-MP利用者が容易に行うために、Xpress-MP ライ
ブラリーによって提供されるVBの例の中にファイルmodbyte.basが含まれたことがある。このモジュ
ールは一連のVB 配列を有するByteConversion関数を含み、Xpress-MPルーティンに渡されるバイト
配列を返す。リスト4.37にこれがどのようにしてなされるかを示す。Optimizerライブラリーの中の
ルーティンには、バイト配列形式でVBへの文字配列を返すものもある。これらのバイト配列はVBの
操作をより容易にするために記号列に翻訳される。たとえば3つの要素のバイト配列を3つの要素
の文字配列に変換するためにリスト4.38にあるコードが用いられる。
リスト 4.35 数値配列を渡す
Dim gpObjCoef(2) As Double
Dim nReturn As Long
nReturn = XPRSgetobj(prob,gpObjCoef(0),0,2)
リスト 4.36 VBのバイト配列を初期化する
Dim qbtype(1) As Byte
qbtype(0) = Asc("L")
qbtype(1) = Asc("U")
"Passing
character
arrays…"
"Returning
64
character
arrays…"
Libraries
Optimizerライブラリーの中の他のルーティンは記号配列をVBに戻すが、そこではByte から String
への変換が有効になされなければならない。たとえば、XPRSgetnamesルーティンは2番目の引数と
してバイト配列を持っているが、そこでOptimizerから行あるいは列の名前を受け取る。これはリス
ト4.39のコードを用いて容易に記号配列に翻訳される。
リスト 4.37 ByteConversion 関数を用いる
Dim sRowName(3) As String
Dim bRowName() As Byte
sRowName(0) = "c1": sRowName(1) = "c2"
sRowName(2) = "c3": sRowName(3) = "c4"
’ Transform the row names in bytes
bRowName = ByteConversion(sRowName,4)
リスト 4.38 バイト配列を文字配列に変換する
For i = 0 To 2
sRowType = sRowType + Chr(qrtype(i))
Next I
リスト 4.39 バイト配列をVBの記号列に翻訳する
Dim nReturn As Long
Dim nmLen As Long
Dim i, j As Long
Dim nRow As Long
Dim bV() As Byte
Dim sV() As String
nReturn = XPRSgetintcontrol(prob, _
XPRS_MPSNAMELENGTH, nmLen)
nReturn = XPRSgetintattrib(prob, XPRS_ROWS, nRow)
"Converting
arrays from Byte
to String…"
NULL 引数: ルーティンによってはnull引数を用いてCから呼ばれるものもあるが、これは引数が無
視されることを意味する。null引数をVBに渡すのと同じことを実行するために用いられるデータ構
造は、String型のvbNullString定数である。これを利用するためには、xpress.basの関数プロトタ
イプは変更されなければならないことが多く、別のプロトタイプが関数引数リストにあるnull引数
のそれぞれの構成要素に対して宣言される。例として、Cコードと同じことを実行したい場合を仮定
しよう。
nReturn = XPRSgetsol(prob,x,NULL,NULL,NULL);
ここで後半の3つの引数リストの値は不要である。VBにおいて、xpress.bas ファイルにある
XPRSgetsol関数のプロトタイプは、以下のように宣言される。
Declare Function XPRSgetsol Lib "XPRS.DLL" _
(ByVal XPRSprob As Long,x As Double, _
65
slack As Double,dual As Double,dj As Double) _
As Long
最後の3つの引数とともにvbNullStringの利用を可能にする、カストマイズされたXPRSgetsolの定
義は、以下のようになる。
Declare Function XPRSgetsolx Lib "XPRS.DLL" _
Alias "XPRSgetsol" (ByVal XPRSprob As Long, _
x As Double, ByVal slack As String, _
ByVal dual As String, ByVal dj As String) _
As Long
ReDim bV(nmLen * nRow + nRow - 1)
ReDim sV(nRow - 1)
nReturn = XPRSgetnames(prob, 2, bV(0), 0, nRow - 1)
For i = 0 To nRow - 1
For j = 0 To nmLen - 1
sV(i) = sV(i) + Chr(bV(i * (nmLen + 1) + j))
Next j
Next I
リスト 4.39 バイト配列をVBの記号列に翻訳する
修正された引数形式を有する新しい関数は、リスト4.40にあるように、次々に用いられる。
プロトタイプXPRSgetsolxとXPRSgetsolルーティンに関する他の有用なプロトタイプはxpress.bas
の中で定義されることに注意されたい。カストマイズされたプロトタイプを必要に応じて中央の
xpress.bas ファイルに追加することはもっと容易であることに気づくであろう。
Visual Basicのコールバックスの利用
Optimizer コールバックスを利用するには、Visual Basicの中で正しいパラメタを有する関数ある
いはサブルーティンを宣言し、そのアドレスを適切なXPRSsetcbルーティンに渡すことが必要である。
これはAddressOfオペレーターを用いて得られる。しかしながら、コールバックスでは利用者によっ
て定義されたオブジェクトがコールバックス関数に最終引数として渡されるので、コールバックス
に対する新しいプロトタイプが定義されなければならない。
この例は上に示したもので、XPRSgetsol関数のプロトタイプがvbNullStringを引数として受け入れ
るように変更されなければならなかった。この例はリスト4.41に与えられる。ここでは2つの記号
列と2つの整数がコールバックスに渡され、そこでオブジェクトMyInfoがこのようなデータを含む
ように定義される。続いて、コールバックス関数XPRSsetcblplogは、2番目の引数として型MyInfo
のデータを受け取るように定義された新しいプロトタイプを持つことになる。コールバックスが立
ち上がると、オブジェクトmilへの指示が関数に渡される。
リスト 4.40 null 引数をVBの中で用いる
Dim x() As Double
Dim cols As Long
nReturn = XPRSgetintattrib(prob,XPRS_COLS,cols)
ReDim x(cols-1)
Call XPRSgetsol(prob, x(0), vbNullString, _
vbNullString, vbNullString)
66
リスト 4.41 Visual Basicの中でコールバックスを用いる
Public Type MyInfo
int1 As Long
int2 As Long
var1 As Variant
var2 As Variant
End Type
…
Declare Function XPRSsetcblplog Lib "XPRS.DLL" _
(ByVal XPRSprob As Long, _
ByVal Address As Long, _
ByRef p As MyInfo) As Long
…
Public Function lplog(ByVal prob As Long, _
ByRef mi As MyInfo) As Long
…
End Function
…
mi1.var1 = "The first string"
mi1.var2 = "The second string"
mi1.int1 = 1234
mi1.int2 = 5678
nReturn = XPRSsetcblplog(prob, AddressOf lplog, mi1)
Java によるXpress-MP ライブラリーの使用方法
BCL と Optimizer ライブラリーはJavaとともに用いられるが、標準的なJava Native Interfaceを
サポートする最近のJava Virtual Machine (JVM)が必要である。Microsoft JVMは標準的ではなく、
通常はサポートしていない。Java ライブラリーのクラスはパッケージcom.dashoptimization.*に含
まれている。このパッケージはXpress-MP ライブラリーを用いるJavaソースファイルに入っている
ことを奨める。BCLへの入口はこのパッケージに見られるクラスXPRBprobである。Optimizerでは、
クラスXPRSprobである。
Java を用いたBuilder Component Library (BCL)
BCLのJava インターフェイスは、データの入力、出力、エラー処理以外のすべてのCの機能を提供す
るため、そこでは標準的なJava関数が用いられなければならない。変数、制約条件などのモデリン
グ要素と問題はすべてクラスに変換され、関連する関数はJavaの中の対応するクラスの手法に変換
される。このようなすべてのクラス (たとえば XPRBprob, XPRBvar, XPRBctr, XPRBsos,
XPRBindexSet, XPRBbasis) はXPRBindexSetを例外として同じ名前を有し、そこではJavaの大文字使
用形式が採用されている。Java インターフェイスのすべての詳細については、CD-ROMにあるBCL
Reference Manual と JavaDoc資料を参照されたい。使用例はリスト4.42に与えられるが、これは章
全体で用いられる例のJava版である。この例のいくつかの特徴は注目に値する。Java インターフェ
イスでは、初期化と一般的なソフトウェアの状態(init と freeを含めて)とすべてのパラメタの定
義に関連する方法を含むXPRBクラスを利用する。実際、これは、標準BCLにおける接頭辞XPRB_を有
するすべてのパラメタはJavaのクラスXPRBの定数として指定されなければならないことを意味する。
たとえば標準BCLにおけるXPRB_BVはここではXPRB.BVとなる。
67
The Xpress-MP
Javaでは、制約条件の定義のために代数的オペレーターを上書きすることは、C++の場合のように可
能ではない。代わりに、いくつかのクラスがこの操作を補うために追加されている。たとえば線形
表現(クラスXPRBlinExp)は制約条件や特定順序付き集合Special Ordered Setsを定義するために必
要となる。また2次表現expressions (クラスXPRBquadExp)は2次の目的関数を用いるのに用いられ、
線形関係(クラス XPRBlinRel)は制約条件を定義するときの媒介として用いられる。さらにadd ある
いは eqlのような簡単な方法の集合が与えられ、いろいろな型やパラメタの数を受け入れるように
上書きされる。
リスト 4.42 Javaの中でBCLを用いる
import com.dashoptimization.*;
public class simple
{
static XPRBprob p;
public static void main(String[] args)
{
XPRBvar a;
XPRBvar b;
XPRB.init();
p = new XPRBprob("simple");
a = p.newVar("a",XPRB.PL,0,200);
b = p.newVar("b",XPRB.PL,0,200);
p.newCtr("First",a.mul(3).add(b.mul(2)).lEql(400));
p.newCtr("Second",a.add(b.mul(3)).lEql(200));
p.setObj("Profit",a.add(b.mul(2)));
p.maxim("");
System.out.println("Profit: "+p.getObjVal());
System.out.println(" a = "+a.getSol());
System.out.println(" b = "+b.getSol());
XPRB.free();
}
}
方法 isValid はBCLに対する有用な追加機能であるが、getVarByName, getCtrByNameなどの方法と
ともに用いられなければならないし、また説明を要する。これらの方法は常に標準BCLにおける対応
する関数ではなく、希望する型のオブジェクトを返すが、それが見つからない場合はNULLポインタ
ーを返す。方法isValidによってのみ、オブジェクトが妥当であるか否か、それが問題の定義に含ま
れているか否かをテストすることが可能となる。すべてのオブジェクトの状態は、このようにして
使用前にチェックされなければならない。
この節の残りの部分では、C とJavaのインターフェイスの間の違いがOptimizerライブラリーで論じ
られる。しかしながら、後に“主要構造”の節で論じられる大部分の事柄は、ライブラリー と BCL利
用者の両方に関連するもので、これらを適用するのは難しくはないはずである。
Java を用いたOptimizer ライブラリー
Optimizer Reference Manualに述べられているルーティン(方法)のほとんどは、XPRSprobクラスの
メンバー関数である。XPRSprobメンバー関数は、XPRS接頭辞を省略したりJavaの大文字形式を採用
68
したりするにもかかわらず、利用者がC プロトタイプと対応する Java用語の間の翻訳作業を容易に
行えるように、実質的にはCから名前を持ってくる。しかしながら、これらのページに論じられる重
要事項が2,3ある。Javaインターフェイスのより詳細については、CD-ROMにあるJavaDoc資料を参
照されたい。
使用例はリスト4.43に与えられているが、これも章全体で用いられる例のJava版である。
リスト 4.43 JavaでOptimizer ライブラリーを用いる
import com.dashoptimization.*;
import java.io.*;
public class simple
{
public static void main(String[] args)
{
この例で注目すべきは、Javaインターフェイスが静的なメンバーだけを含むXPRSクラスを利用して
いるということである。これらには2つの方法 init とfreeだけでなく、定数、制御、そして特性
の名前が含まれている。関数initは上書きされるので、標準的なパスがライセンスの詳細について
チェックされる場合でも、null も null 記号も引数としては不要である。
freeは例外は許さないものの、initはXPRSprobExceptionよりもむしろ標準的な例外を有している。
制御、そして問題の特性の名前の使用方法の例については、111ページの“制御と問題の特性”
の節を参照されたい。
JavaインターフェイスはC Optimizer 関数XPRScreateprob と XPRSdestroyprobに相当するものを
含まない。問題のオブジェクトの作成と削除はXPRSprobの構築部分とfinalize法の中で処理される。
try
{
XPRS.init();
}
catch (Exception e)
{
System.out.println("Cannot initialize");
}
try
{
XPRSprob prob = new XPRSprob();
prob.readProb("simple","");
prob.maxim("");
prob.writePrtSol();
}
catch(XPRSprobException xpe)
{
xpe.printStackTrace();
}
XPRS.free();
}
}
69
リスト 4.43 JavaでOptimizer ライブラリーを用いる
4The Xpress-MP
主要構成
データの型: ルーティンに渡されるJavaのパラメタは、以下のようにC型式と関連している。型
IntHolder, DoubleHolder, StringHolderはすべてcom.dashoptimization パッケージの中にあるこ
とに注意されたい。
数値配列: Java配列を用いて整数と倍精度の配列を渡すということはただちに可能である。配列は
常に関数を呼ぶ前に割り当てられていなければならない。例を示そう。
double sol[] = new double[
prob.getIntAttrib(XPRS.COLS)];
prob.minim("");
prob.getSol(sol, null, null, null);
失敗すると、JVMを壊すことになる。
数値参照: Cのポインターを用いて整数と倍精度の数値を関数から得るには、IntHolder と
DoubleHolderの2つのラッパーwrapperクラスのうちの一つが用いられる。これらのクラスのそれぞ
れはvalueという名の各型の単一共有変数を含んでいる。たとえば
IntHolder ni=new IntHolder();
prob.getIndex(1,"rowname",ni);
C 引数の型
int* (array of int)
int* (reference to an int)
double* (array of double)
double* (reference to a double)
char* (array of char)
char* (pointer to a ‘\0’ terminated
string passed to a routine)
char* (pointer to a ‘\0’ terminated
string received from a routine)
Java 引数の型
int []
IntHolder
double []
DoubleHolder
byte []
java.lang.String
StringHolder
System.out.println("Index of ’rowname’ is:
"+ni.value);
整数(あるいは倍精度)の両者を必要な場合には、それを関数に送る前に適切な値で値域を初期化す
るということを知っておいて欲しい。
文字配列と記号列: Optimizerルーティンには、記号列を修正前にパラメタとして送っておくことが
必要である。この場合、java.lang.String が用いられ、たとえば
prob.readProb(args[0],"");
ここで args[0] は java.lang.Stringである。もし送られた記号列が呼ばれた関数によって修正さ
70
れる必要がある場合には、クラスStringHolderが用いられる。たとえば
StringHolder p_name=new StringHolder();
prob.getProbName(p_name);
System.out.println("The problem name is: "
+p_name.value);
最後に、文字配列がルーティンによって必要とされた場合には、前もって割り当てられていたbyte[]
のJava配列を用いよ。
制御と問題の特性: Optimizerで用いられるすべての制御と問題の特性は、XPRSクラスの静的な最終
メンバーである。ここにそれらがどのようにして用いられるかを示す2つの例がある。
// get a problem attribute
double sol[] = new double[
prob.getIntAttrib(XPRS.COLS)];
// set a control
prob.setIntControl(XPRS.LPLOG,10);
エラーをチェックする: 場合によっては、すべてのXPRSprobメンバー関数は把握されなければなら
ない例外を作成する。例外クラスXPRSprobException はjava.lang.Exceptionから得られるが、それ
に対して2つのメンバー関数を追加する。これらは、例外と関連するOptimizerエラーコードを返す
public int getCode();と例外がもたらされる原因となった問題のオブジェクトの参照箇所を返す
public XPRSprob getXPRSprob();の2つである。
場合によっては、XPRSprobオブジェクトは例外がもたらされた場合でも正当とし、このチェックは
getCode (9章のOptimizer Reference Manualにある “エラーメッセージと返却コード” を見よ。)の
値を調べてはじめて決定される。XPRSprobが正当として、利用者のアプリケーションの中で例外を
用いている限りは、プログラムが停止しないので、例外は回復可能である。この例は、プログラム
がファイルからワームスタートをする場合である。ファイルが存在しない(したがって例外を起こ
す)ためにこれが失敗すると、標準の初期状態が代わりに用いられる。コードの特定の部分の周辺に
try-catchブロックを付加することによって、このような回復可能な例外の処理がなされる。例がリ
スト4.44に与えられる。
リスト 4.44回復可能な例外を処理する
try
{
XPRSprob prob = new XPRSprob();
...
}
catch(XPRSprobException xpe)
{
xpe.printStackTrace();
System.out.println("Exit code: "+xpe.getCode());
System.out.println("Message: "+xpe.getMessage());
if(xpe.getXPRSprob()!=null)
{
...
}
}
71
The Xpress-MP
Javaのコールバックスの利用
Optimizerからのコールバックスを利用するために、柔軟性のあるイベント構造がJava Optimizer
ライブラリー APIによって用いられる。それぞれのコールバックスはリスナーListenerインターフ
ェイスのイベントとして定義される。オブジェクトがコールバックスの対象である場合、クラスは
対応するリスナー(たとえば XPRSmessageListener, XPRSlpLogListener, など)を実行しなければ
ならない。その後にオブジェクトがXPRSprobオブジェクトとして登録されしなければならない。オ
ブジェクトがイベント(コールバックス)を受け取るのに関心を持っていない場合、明示的に登録解
除をしなければならない。リスナーを登録したり解除をしたりするのに用いられる方法を示す。
public void add<listener name>Listener(Listener listener, Object data)
throws XPRSprobException;
および
public void remove<listener name>Listener()
throws XPRSprobException;
コーディングを便利にするために、いかなるObject表記もリスナーを登録するときには可能となっ
ている。同じObject表記が、対応するEvent法に対するパラメタとして戻されるであろう。リスト4.45
にはMessageコールバックスがどのようにして用いられるかを示す最も簡単な例を与える。(リスト
4.43とのコーディングの違いはボールド文字で示されている。)
リスト 4.45 Javaでコールバックスを用いる
import com.dashoptimization.*;
import java.io.*;
public class CbTest implements XPRSmessageListener
{
public static void main(String[] args)
{
Optimizerが呼ぶ場合があるので、リスナーオブジェクトを壊さないように注意されたい。
Libraries
それぞれのリスナーインターフェイスに対してOptimizerは、イベントをせいぜい一つのリスナーオ
ブジェクトに送るであろうということに注意されたい。コールバックスの完全なリストと関連する
リスナーとイベントは、Optimizer Reference Manualから得られる。詳細については、オンライン
資料かOptimizer Reference Manualを参照せよ。
try
{
XPRS.init();
}
catch (Exception e)
{
System.out.println("Cannot initialize");
}
CbTest ML = new CbTest();
try
{
XPRSprob prob = new XPRSprob();
prob.addMessageListener(ML,null);
prob.readProb("simple","");
72
prob.maxim("");
prob.writePrtSol();
prob.removeMessageListener();
}
catch(XPRSprobException xpe)
{
xpe.printStackTrace();
}
XPRS.free();
}
public void XPRSmessageEvent(XPRSprob prob,
Object data, String msg, int len, int type)
{
System.out.println(msg);
}
}
リスト 4.45 Javaでコールバックスを用いる
ヘルプの利用
本章においては、これまでMosel ライブラリーを用いてプログラムをどのようにしてコンパイルし、
読み込み、実行するか、さらには多重モデルを同時に処理するか、行列ファイルを出力として作成
するかを学んだ。またBCLを用いてどのようにして問題を構築し、解くか、そしてこのライブラリー
から書き出すかをも学んだ。
さらに、どのようにしてこれらのファイルをOptimizerライブラリーを用いてOptimizerに読み込ん
で最適化し、解を見て、最適化機能に影響を与える制御変数を変更するかをも学んだ。
最後に、どのようにしてモデルが‘高度な’関数を用いてOptimizerの中で直接に構築されるかを見た。
他の言語についても論じた。5章では、強力なMoselモデルプログラミング言語に焦点を絞って、自
身のモデルを構築する仕方について紹介しよう。
ライブラリーを用いる際の追加的なヘルプ機能は、Xpress-MP CD-Romの中に例の形で見られるし、
またMosel, BCL、 そしてOptimizer Reference Manualsにも示されている。
まとめ
この章では、モデルをコンパイルし、読み込み、実行するのにMosel ライブラリーをどのように用
いるか、そしてBCLを用いてどのようにして問題を構築し、解くか、そしてOptimizerライブラリー
を用いて線形問題を解き、解にアクセスするか、さらには整数問題を解き、Optimizerライブラリー
を用いて問題を入力するか、あるいは他の言語を用いてXpress-MP ライブラリーを利用する方法、
等を学んだ。
73
Xpress-Mosel
5
第 5章
Xpress-MPによるモデルの構築
概要
この章では以下について紹介する。
•
•
•
•
Moselモデルプログラミング言語を用いて簡単なモデルを構築する。
添字付きの変数と定数を用いて多種のモデルを開発する。
モデルのデータをモデルの構造から分離することを学ぶ。
データファイルとパラメタの使用について学ぶ。
はじめに
最後の2,3章を通じてXpress-MPのそれぞれのインターフェイスがどのようにして簡単なモデルを
読み込み、解き、そして線形問題に対する最適解を得るかを見てきた。しかしながら、この章では、
Moselモデルプログラミング言語をより詳細に探求し、どのようにして新しいモデルを構築し、得ら
れた解を解釈するかについて述べる。同時に、モデルの特別な例を構成するデータとモデルの構造
を分離することによって、柔軟性のあるモデリングが望ましい形となることについても探求しよう。
Xpress-Mosel
Xpress-moselモデルプログラミング言語は、同じ問題をいろいろな方法でモデル化するのによく用
いられる。ここに与えられた例は、このようなアプローチの一つである。これらを通して、われわ
れは言語について大部分のことを紹介することを目指しているが、もっとも大事なことは、良いモ
デリングの実践方法を発展させることであるとわれわれは常に考えている。
最初のモデルの構築
盗人問題
盗人のビルがある晩、自分の欲しいものを盗むための大きな袋を持って、ある家に侵入したとする。
彼は以下のような重さと推定価値をもった多くの品物を見つけている。しかしながら、ビルは合計
で重さ102ポンドまでしか運び出すことができない。これを条件として、彼の目的は彼の運び出す品
物の推定価値を最大化することである。
重さと価値
カメラCamera2 15
ネックレスNecklace 20 100
花びんVase20 90
絵Picture30 60
TV 40 40
ビデオVideo30 15
金庫Chest60 10
積み木Brick10 1
74
Modeling with
問題の特定
盗人問題を数学的に定式化することは比較的簡単である。決定変数をcameraとして、ビルがそれを
運び出すときには値1、そうでないときは値0としよう。また同様に、他の品物に対しても決定変数
を同じ様に定義しよう。このとき、盗人問題は以下のように表されるであろう。
この問題には、読者にとってすでになじみのある部分が多くある。変数camera, necklace、などは
決定変数decision variablesとしてよく知られているが、解を求める操作の中で決定されるもので
ある。標準型線形計画問題の中では、決定変数は任意の非負実数値を取りうるし、またそれらはこ
れまでの3つの章で解いてきた種類の問題であった。しかしながら、盗人問題の場合には、ビデオを
半分運び出すとか、ただ1個しかないネックレスを5個運び出すということはほとんど意味をなさな
い。 これは決定変数が0か1かのどちらかに限定されるという混合型整数計画MIP問題と呼ばれて
いる。事実、これらはバイナリーbinary変数である。運び出されるすべての品物の総重量は、次の
ように与えられる。
2*camera + 20*necklace + 20*vase + 30*picture + 40*tv
+ 30*video + 60*chest + 10*brick
上の表現の値は、ビルが運ぶことのできる品物の重さの合計値によって制約される。換言すると、
これは102に等しいか、それ以下にならなければならないということである。LPあるいは MIP問題は
このような制約条件をいくつか有しているが、このモデルの目的としては、ただひとつの条件だけ
が要求される。
問題 1
Maximize: 15*camera + 100*necklace + 90*vase +
60*picture + 40*tv + 15*video +10*chest +
1*brick
Subject to: 2*camera + 20*necklace + 20*vase +
30*picture + 40*tv + 30*video + 60*chest +
10*brick
camera, necklace, vase, picture, tv, video,
chest, brick
102 .
0 1 ,{}(
"The decision variables…"
"The constraint"
目的関数objective functionは運び出す品物の価値である。モデリング操作を実施する目的は、い
ろいろな制約条件の下で、この関数を最大化することである。
モデルのXpress-Moselへの導入
Moselモデルプログラミング言語を用いて特定されたモデルは、いくつかのブロックblocksに分けら
れる。その中で最も外部にあるのはmodelブロックである。ここで問題に対して名前が与えられるが、
演習問題で用いるために、ここでは問題名をburglarとする。問題の中に含まれる指示がすべて終了
したときには、すべてのブロックはend-<blockname>というキーワードを使用して明示的に終了され
なければならない。われわれが最初に用いる2番目の主要ブロックは、変数が型とともに宣言される
declarationsというブロックであって、その中では決定変数は型mpvarを有する。これをリスト5.1
75
で説明しよう。
リスト 5.1 決定変数を宣言する
model burglar
declarations
camera, necklace, vase, picture: mpvar
tv, video, chest, brick: mpvar
end-declarations
end-model
モデル
モデルブロックは問題の名前を定義し、モデルの一部と考えられるすべての記述を含む。end-model
の後に現れるテキストはコメントとして扱われ、無視される。
宣言
declarationsブロックの中では、変数と型と集合とスカラー量が定義される。
"The objective function…"
問題の名前はOptimizer とMosel で作成されたいくつかのファイルの基本となっている。
決定変数はバイナリー変数と特定されなければならない。これはある意味では問題に対するもう1
つの制約であるので、他の制約があるdeclarationsブロックの外で与えられる。この構文は単に次
のようになる。
variable is_binary
最後に制約条件と目的関数が加えられなければならない。これらは名前を割り当てられ、次のよう
になる。
name := linear_expression
線形表現が特に長い場合には、必要に応じていくつかの行に分割してもよい。
Moselには分割された行を表示する文字やコマンドはないが、さらに入力があると期待される場合に
は、その行は継続するとみなされる。例として、行の最後に‘+’のようなバイナリーオペレーターが
ある場合、次に他の用語が来ることが期待される。これはリスト5.2で示され、ここで完全なモデル
が与えられる。
リスト 5.2 モデルに制約条件を加える
model burglar
declarations
camera, necklace, vase, picture: mpvar
tv, video, chest, brick: mpvar
end-declarations
camera is_binary
necklace is_binary
vase is_binary
picture is_binary
tv is_binary
video is_binary
chest is_binary
brick is_binary
TotalWeight := 2*camera + 20*necklace + 20*vase +
76
30*picture + 40*tv + 30*video +
60*chest + 10*brick <= 102
Similarly, variables
can be described as
integral using
is_integer.
"Continuation lines…"
The Optimizer Library Module
モデルが構築されると、あとは単に問題を解き、ビルが運び出すことのできるものの価値の最大値
を見つけることである。これはMoselの内部からも実行できる。標準的なMoselの構文に加えて、外
部のアプリケーションとのやりとりによって、追加的な機能がライブラリーモジュールの形でその
中に読み込まれる。Optimizer ライブラリーモジュールであるmmxprsを用いると、MoselがOptimizer
を呼び出し、問題を解き、解をディスプレイに戻すことが可能となる。これを実行するには、uses
というキーワードを用いる。目的関数はmaximizeコマンドを用いて最大化される。モデリングと解
の構成部分を用いると、これは正確にはモデルプログラムmodel programとして説明される。問題に
対する完全なモデルプログラムは、リスト 5.3に追加部分をボールド体で強調して示されている。
TotalValue := 15*camera + 100*necklace + 90*vase +
60*picture + 40*tv + 15*video +
10*chest + 1*brick
end-model
リスト 5.3 完全な盗人問題モデルプログラム
model burglar1
uses "mmxprs"
declarations
camera, necklace, vase, picture: mpvar
tv, video, chest, brick: mpvar
end-declarations
camera is_binary
necklace is_binary
vase is_binary
picture is_binary
tv is_binary
video is_binary
chest is_binary
brick is_binary
リスト 5.2 モデルに制約条件を加える
ライブラリーモジュールの名前には、‘Mosel Module’を表すために、接頭辞mmを付ける。このモデルはXpress-MP CD上にファ
イルburglar1.mosとして入っている。
このモデルプログラムの最後の部分には、得られた解をどのように扱うかが述べられている。
writelnコマンドを用いると、Mosel内でgetobjvalを使用することによって、目的関数値のような解
の情報を出力する指示が可能となる。
演習問題 リスト5.3のモデルプログラムを入力し、コンパイルし、読み込み、選択したインターフ
ェイスを使用してMoselの中でそれを実行せよ。ビルが運び出せる盗品の最大値はいくらか。これを
77
達成するためには、彼はどの品物を持っていくべきか。
TotalWeight := 2*camera + 20*necklace + 20*vase +
30*picture + 40*tv + 30*video +
60*chest + 10*brick <= 102
TotalValue := 15*camera + 100*necklace + 90*vase +
60*picture + 40*tv + 15*video +
10*chest + 1*brick
maximize(TotalValue)
writeln("Objective value is ", getobjval)
end-model
uses
ライブラリーモジュールをMoselに読み込む。
maximize / minimize
Moselを呼び出して、引数として宣言された目的関数を最適化するためのコマンド。
writeln
Moselに対して、情報を標準出力に送るように指示する。引数をいくつ入れてもよい。それぞれは指
示された順番に返される。
getobjval
解に従って目的関数値を返す
リスト 5.3 完全な盗人問題モデルプログラム
行列によるモデルの構築
行列変数と添字の導入
上で述べた形式でモデルを作成するのは、決定変数が少数の場合には便利であるが、問題のサイズ
が増加するにつれて、扱うのがすぐにやっかいになる。すでにわれわれの最初のモデルの仕様の中
で、各変数がバイナリーであると明示的に言わねばならないのは面倒であったし、またわれわれが
Moselを用いて決定変数の値を出力しなければならないとしたら、やはりそうであろう。このような
小さな問題ですら、配列変数array variablesあるいは添字付き変数subscripted variablesと呼ば
れるような変数を利用するのが普通である。
リスト5.4では盗人問題の宣言部分を変更したものを示し、使用されるいろいろな配列を紹介する。
ここで最初に定義されるのは、Itemsという配列要素のための添字集合である。Itemsは8つの整数
値を持つように割り当てられ、効果的に配列の要素に番号を付ける。これに続いて、さらにWEIGHT と
VALUE という2つの配列が定義され、それぞれ選ばれる品物の重さと価値を表している。それらは
Itemsによって配列として指標化され、それぞれの数値要素は実数型realを有している。Moselの実
数型realは、Cの倍精度浮動小数点に対応する。他のプログラミング言語の場合と同様に、Moselも
整数型integer と文字型stringをサポートしている。declarationsブロックの外にあるこれら2つの
配列は、データをコンマで分けられたリストとして入力する。
リスト 5.4 データを宣言して配列に入力する
declarations
Items = 1..8
WEIGHT: array(Items) of real
VALUE: array(Items) of real
x: array(Items) of mpvar
end-declarations
78
WEIGHT := [ 2, 20, 20, 30, 40, 30, 60, 10]
VALUE := [ 15,100, 90, 60, 40, 15, 10, 1]
declarationsブロックで定義される最後の配列は、決定変数として機能するxである。それは配列
であって、同時にItemsによって指標化され、型mpvarを有する要素である。
ループ化と和計算
配列を用いるのは、ただ単に変数宣言をより整然とするためだけではない。決定変数の配列をルー
プ化することによって、変数がバイナリーであることをわずか1行で宣言することもできる。Mosel
では、forallというコマンドを用いることによって、簡単なルーピングをサポートしている。Mosel
はまた、sumコマンドによって総和計算の表記をサポートしているが、これは制約条件の線形表現や
目的関数を構築するのに広範に用いられる。これらを用いて決定変数がバイナリーであると定義し
たり、制約条件と目的関数を設定したりする例がリスト5.5に示されている。
forall
添字集合によってルーピングを実行する。
forall(var in set) statement
ここで var はダミー変数で、set は添字集合である。
statement はそれぞれの指令によって実行される。
sum
添字集合上で総和計算を行う。構文は以下の通りである。
sum(var in set) expression
ここで varはダミー変数で、set は添字集合である。
expression isは総和をとる総称である。
do / end-doブロックの中でforallループを用いると、多重計算が可能となる。forall構造についての詳細を含めて、より詳
細については、165ページを参照されたい。
コメント
配列と添字化操作を用いることによって、盗人問題のより良いモデルはほぼ完成する。しかしなが
ら、いかなるプログラミングに関しても、自分自身と他の人が解読するには、モデルについて適切
なコメントを付けておくことは良いことである。end-modelという記述の後にはどれだけのコメント
でも付け足すことが出来るということはすでに述べた。しかしながら、モデルそれ自体の中にコメ
ントを入れたいときはどうなるであろうか。まさにこの目的のために、Moselモデルプログラミング
言語では2種類のコメントをサポートしている。単一行のコメントは、!という文字によって導入
される。この文字に続くテキストはすべて、行の終わりまでコメントとして無視される。多くの行
にわたるコメントには、!と!をペアにして使わなければならない。盗人問題のためのモデルプロ
グラムでコメントが加えられたものはリスト5.6に与えられている。
リスト 5.5 盗人問題におけるルーピングと総和計算
forall(i in Items) x(i) is_binary
TotalValue := sum(i in Items) x(i)*VALUE(i)
TotalWeight:= sum(i in Items) x(i)*WEIGHT(i)<=102
リスト 5.6 盗人問題に対するもう一つの試み
model burglar2 (! Modeling with arrays, subscripts,
summations, looping and comments !)
uses "mmxprs"
declarations
79
Items = 1..8 ! 8 items
WEIGHT: array(Items) of real
VALUE: array(Items) of real
x: array(Items) of mpvar
end-declarations
! Item: 1, 2, 3, 4, 5, 6, 7, 8
WEIGHT := [ 2, 20, 20, 30, 40, 30, 60, 10]
VALUE := [ 15,100, 90, 60, 40, 15, 10, 1]
このモデルはファイルburglar2.mos としてXpress-MP CD に載せられている。
モデルの最後に付け足された行は、Moselに目的関数値と決定変数の解を出力するように指示するも
のである。これによって別のforallループが用いられ、getsolによってそれぞれの要素の解を戻す
変数配列が調べられる。
演習問題 モデルプログラムを配列変数を用いてリスト5.6のように変更せよ。それをコンパイルし、
読み込み、実行せよ。ビルはどの品物を持ち出すであろうか。
ストリング添字の使用方法
上に開発したモデルプログラムは、最初に示したものよりはるかに簡単なものである。しかしなが
ら、解を解釈することは、それが示す品物の変数の添字にわれわれが人的に合わせなければならな
いので、より難しくなっている。
! All x are binary
forall(i in Items) x(i) is_binary
! Objective: maximize the haul
TotalValue := sum(i in Items) x(i)*VALUE(i)
! Constraint: weight restriction
TotalWeight:= sum(i in Items) x(i)*WEIGHT(i)<=102
maximize(TotalValue)
writeln("Objective value is ", getobjval)
forall(i in Items) writeln(" x(",i,") = ",
getsol(x(i)))
writeln
end-model
getsol
問題の解にしたがって、決定変数の最適値を返す。単一の引数は、値が返されることになっている
変数である。
リスト 5.6 盗人問題に対するもう一つの試み
Moselでは数字の添字よりも文字の添字の方がよく用いられている。Moselモデルプログラミングの
中で添字集合を使用するのは、おそらく数値を用いるよりも容易で、しかも自然であろう。Items
を文字集合として定義することが必要とされる唯一の変化であって、これはリスト5.7に示される。
リスト 5.7盗人問題で文字添字を用いる
model burglar3
uses "mmxprs"
80
declarations
Items = {"camera", "necklace", "vase",
"picture", "tv", "video",
"chest", "brick"}
WEIGHT: array(Items) of real
VALUE: array(Items) of real
x: array(Items) of mpvar
end-declarations
! Item: ca, ne, va, pi, tv, vi, ch, br
WEIGHT := [ 2, 20, 20, 30, 40, 30, 60, 10]
VALUE := [ 15,100, 90, 60, 40, 15, 10, 1]
! All x are binary
forall(i in Items) x(i) is_binary
! Objective: maximize the haul
TotalValue := sum(i in Items) x(i)*VALUE(i)
! Constraint: weight restriction
TotalWeight:= sum(i in Items) x(i)*WEIGHT(i)<=102
maximize(TotalValue)
writeln("Objective value is ", getobjval)
forall(i in Items) writeln(" x(",i,") = ",
getsol(x(i)))
writeln
end-model
このモデルはファイルburglar3.mosとしてXpress-MP CD に載せられている。
演習問題 モデルプログラムを文字添字集合を用いるように変更せよ。それをコンパイルし、読み込
み、実行して、その結果を前と比較せよ。
モデリングにおける汎用性
総称的モデルと例示的モデル
盗人問題は、ナップザック問題のようなよく知られている、たくさんの似たモデリング問題の中の
単なる1例にすぎない。上のモデルは盗人問題をモデル化するための第1歩としては適切なものであ
るが、品物の個数が増やされたり、あるいは問題が別のナップザック問題に変えられたりした場合
には、一般化することによってより簡単になるであろう。問題はすでに配列変数によって明確にさ
れているので、残っている課題は、データが現在のところ未だモデルに’硬く連結’されているーすな
わちモデルとデータ構造の間が分離していないーという事実によるものである。本節では、これら
の限界を克服する方法について述べよう。モデルは、一般的には、様々な決定変数を表す記号を用
いて、一連の等式と不等式によって表されるこれらの変数の間の関係―すなわち制約条件が定式化
される。これらの制約条件を体系的に記述すると、一般的genericモデルが得られる。これを与えら
れたデータ集合と結合すると、特定の数値numericalモデル、すなわちモデルの例示model instance
が得られ、それが最適化される。モデル構造を数値データから分離すると、より柔軟性のあるモデ
ルになるため、管理するのが容易になる。こういうわけで、次の2,3ページでは、このようなモデ
ルの違いを明らかにすることを目的としている。
実数の宣言
81
リスト5.7のモデルを見ると、制約条件はすでにほぼ適切で柔軟性のある形になっている。しかしな
がら、ビルが運び出すことのできる最大の重さについては、特定の情報は未だにモデルの中に組み
込まれている。ここで一つのスカラー量、MAXWTを定義し、102という値を割り当て、モデルを通し
てそれを使うことにする。
分離することによって、モデルをBIM ファイルとして頒布し、知的財産権を保護することが可能となる。
このような追加的な量は、モデルファイルの先頭にあるdeclarationsブロックから値を指定される。
値を指定された量はすべて一定であると仮定されている。
テキストファイルからのデータの入力
この段階でモデルプログラムに対してわれわれがなすべきもう一つの変更点は、モデルの配列デー
タを分離して、それを外部のデータファイルから入力することである。Moselでは、initializations
ブロックを用いてこれを実行する。
Data サブディレクトリーの中にあるファイルburglar4.datが次のような情報をもっていると仮定
する。すなわち、配列のWEIGHT と VALUE をinitializationsブロックに入れた後に、Moselはデー
タを読み取り、実行時に配列を満たすことになる。これを実行するモデルプログラムの完全なリス
トは、変更部分をボールド体で強調した上でリスト5.9に与えられている。
リスト5.8のデータをData サブディレクトリーの中にあるファイルburglar4.datに入れ、このファ
イルからデータを入力するようにモデルを変更せよ。これをコンパイルし、読み込み、実行してス
ムーズに動いてくるかをチェックせよ。
初期化
テキストファイルからデータを入力できるようにする。配列と定数は任意の順番で特定され、実行
時に読み取られる。
リスト 5.8 外部データファイルの構造
! Data file for burglar4.mos
WEIGHT: [ 2 20 20 30 40 30 60 10]
VALUE: [15 100 90 60 40 15 10 1]
配列の値はもはやコンマで分離されていないことに注意せよ。
盗人問題の解
最後の演習問題を終えたとしたら、明らかに次の質問は、 あとどれくらいデータファイルから入
力できるか? ということであろう。確かに、スカラー量MAXWTは、モデルプログラムの中で特定化
される必要はなく、データファイルに保存される。選択すべき品物の個数と名称は、事実モデルの
構造の一部というよりもモデルのデータであるので、添字集合に関しても同様のことがいえる。
リスト 5.9 ソースファイルからデータを入力する
model burglar4
uses "mmxprs"
declarations
Items = {"camera","necklace","vase","picture",
"tv","video","chest","brick"}
WEIGHT: array(Items) of real
VALUE: array(Items) of real
82
MAXWT = 102
x: array(Items) of mpvar
end-declarations
! Read in data from external file
initializations from 'Data/burglar4.dat'
WEIGHT
VALUE
end-initializations
! All x are binary
forall(i in Items) x(i) is_binary
! Objective: maximize the haul
TotalValue :=sum(i in Items) x(i)*VALUE(i)
! Constraint: weight restriction
TotalWeight:=sum(i in Items) x(i)*WEIGHT(i)<=MAXWT
maximize(TotalValue)
writeln("Objective value is ", getobjval)
forall(i in Items) writeln(" x(",i,") = ",
getsol(x(i)))
writeln
end-model
このモデルはファイルburglar4.mos としてXpress-MP CD上にある。
データファイルが以下の情報を含むように修正されたと仮定しよう。モデルプログラムがこのすべ
ての情報を実行時に入力できるとしたら、最終的にはすべてのモデルデータとモデルの構造とを分
離したことになる。リスト5.11は、これを処理すべくモデルプログラムを変更したものである。
リスト 5.10 盗人問題に対するデータファイルの修正
! Data file for burglar5.mos
Items:["camera" "necklace" "vase" "picture" "tv"
"video" "chest" "brick"]
MAXWT:102
WEIGHT:[ 2 20 20 30 40 30 60 10]
VALUE:[15 100 90 60 40 15 10 1]
リスト 5.11 盗人問題のモデルプログラムを完成する
model burglar5
uses "mmxprs"
parameters
WeightFile = 'Data/burglar5.dat'
end-parameters
declarations
Items: set of string
MAXWT: real
WEIGHT: array(Items) of real
VALUE: array(Items) of real
x: array(Items) of mpvar
83
end-declarations
! Read in data from external file
initializations from WeightFile
Items MAXWT WEIGHT VALUE
end-initializations
forall(i in Items) create(x(i))
集合は文字配列として定義され、ファイルburglar5.mos としてXpress-MP CD上に載せられている。
declarationsブロックにジャンプした後、最初に注意すべきことは、データが引き続き読み込まれ
る場合に、Items と MAXWTの型を宣言しなければならないということである。まずItemsは文字列で
ある要素からなる(添字)集合であって、またMAXWTは配列のVALUE、 WEIGHTと同じ型を有すると定
義した。
これらの変更を適用した上でモデルが実行されると、実行時にモデルが空であるということで失敗
するであろう。この場合、問題となるのは決定変数xの添字集合の大きさが宣言の中でまだ決定され
ていないという事実である。添字集合は後になるまで入力されないので、決定変数の配列は絶えず
変化し、要素がない状態で初期化される。この場合、配列は明示的に作成されなければならず、そ
のためにここではcreateコマンドを用いる。事実、これはこの問題を解く唯一の方法ではない。2
番目のdeclarationsブロックは、initializationsブロックに続いてただちに読み込まれ、変数xが
ここで宣言される。モデルの関連部分の例はリスト5.12に与えられる。
! All x are binary
forall(i in Items) x(i) is_binary
! Objective: maximize the haul
TotalValue :=sum(i in Items) x(i)*VALUE(i)
! Constraint: weight restriction
TotalWeight:=sum(i in Items) x(i)*WEIGHT(i)<=MAXWT
maximize(TotalValue)
writeln("Objective value is ", getobjval)
forall(i in Items) writeln(" x(",i,") = ",
getsol(x(i)))
writeln
end-model
create
前に宣言された動的配列の一部である変数を明示的に作成する。
リスト 5.11 盗人問題のモデルプログラムを完成する
"Understanding
Listing 5.11…"
initializationsブロックに引き続いてItemsの大きさと要素がただちに判明するので、それに関す
る線形の性質がモデルファイルからMoselの記述として読み込まれ、解釈されると、Itemsが2番目の
宣言に関する記述の集合の中で正しく定義されることになる。現在のモデルでは、これら2つの方法
のどちらかは完全にうまくいくであろうが、明確さを重視するために、ここでは前者を用いて両ブ
ロックを結合する。
演習問題 モデルプログラムをリスト5.11のように書き換えよ。前と同様にそれをコンパイルし、
読み込み、実行して問題を解け。
84
リスト 5.12 2種類の宣言を利用する
declarations
Items: set of string
MAXWT: real
WEIGHT: array(Items) of real
VALUE: array(Items) of real
end-declarations
! Read in data from external file
initializations from WeightFile
Items MAXWT WEIGHT VALUE
end-initializations
declarations
x: array(Items) of mpvar
end-declarations
Moselによるパラメタの利用
まだ議論されていないが、リスト5.11にある最後の変更点はモデルプログラムの先頭にあって、
parametersブロックを利用するものである。これを用いると、パラメタが定義され、それらの値は
モデルプログラミングを通して入力されたことになる。それらの値は数値または文字列のいずれか
の型を有するであろう。仮に異なる最大重量を選択した上で問題を実行したかった場合には、MAXWT
はスカラー量ではなく、パラメタとしてここに定義できたであろう。この例では、どのようにして
データファイルの名前が最初に定義され、後にinitializationsブロックの中でモデルの例を作成す
るためにどのようにしてデータ入力されるかを示そう。
ここで2番目の例を示す。
ハイカー問題
ヘンリーは休日にハイキングに行くことに決め、必要な品物すべてをリュックサックに詰める。彼
は5つの品物の中から何を持っていくかを選択する。それぞれの品物はある一定の量の節約額を有す
る。たとえば、テントと寝袋を持っていくことによって宿泊代が節約できる。品物とそれに伴う節
約額は以下のとおりである。
parameters
このブロックには、実行時に選択すべき値が前もって定められない場合のデフォルト値とともに、
パラメタの記号のリストが含まれる。
重量 節約額
テントTent 60 100
寝袋Sbag 28 50
カメラCamera 20 35
時計Clock 8 10
食料Food 40 50
しかしながら、彼は品物を最大100ポンドの重量までしか運ぶことが出来ない。ヘンリーはどの品物
を持っていけば節約額が最大になるだろうか?
ハイカー問題の解法
この問題はナップザック問題のもう一つの例であって、モデルの構造はこの章で作成したものと同
一である。したがって、問題を解くために唯一必要なのは、異なるモデルデータセットで同じモデ
85
ルプログラムを再び実行すればよい。これはリスト5.13に示されていて、そこでは節約額は配列
VALUEに読み込まれるであろう。
演習問題
リスト5.13のデータをDataサブディレクトリーの中のファイルhiker.datに入力せよ。コンパイルさ
れたファイルburglar5.bimはMoselの中に読み込まれ、実行される。ここでパラメタ
WeightFile=’Data/hiker.dat’をrunへの引数として用いる。このとき、ヘンリーはどの品物を持っ
ていくべきか、そしてそのときの最大の節約額はどうなるか?
Mosel を Consoleアプリケーションとして用いる例の完全な記述はリスト5.14に示される。
リスト 5.13 ハイカー問題のためのデータファイル
! hiker.dat - Data file for Hiker Problem
Items:["Tent" "Sbag" "Camera" "Clock" "Food"]
MAXWT: 100
WEIGHT: [ 60 28 20 8 40]
VALUE: [100 50 35 10 50]
Xpress-MP Essentials Getting Help 137
ヘルプの利用
この章を通して、Moselプログラミング言語の基礎的な要素をいくつか紹介するため、比較的簡単な
ナップザック問題について述べた。このような手続きを継続的に繰り返すことによって、われわれ
はモデリングの汎用性の観点から、モデル構造とデータを分離することが便益となることを見た。
しかしながらこのような説明は、単に表面をなでているに過ぎず、Mosel言語には未だ紹介されてい
ない多くの特徴がある。次の章では、これらについて2, 3簡単に述べ、他にどのようなことが可能
であるかを伝えるることにする。より完全な詳細に関しては、Mosel Reference Manualを参照され
たい。これは、ソフトウェアに付随する標準的なライブラリーモジュールのいくつかの機能につい
て記述しているだけでなく、この言語のあらゆる可能性に関しても詳細に記述している。この章に
書かれている様々なモデルについては、Mosel言語を用いた他のたくさんの例とともにすべてインス
トールしたCD-ROM上で見ることが出来る。
リスト 5.14 ハイカー問題を解く
C:\Mosel Files>mosel
** Xpress-Mosel **
(c) Copyright Dash Associates 1998-zzzz
>load burglar5
>run WeightFile='Data/hiker.dat'
Objective value is 160
x(Tent) = 1
x(Sbag) = 1
x(Camera) = 0
x(Clock) = 1
x(Food) = 0
Returned value: 0
>
86
まとめ
•
•
•
•
•
•
この章では以下のようなことを学んだ。
変数、配列、定数、添字集合の宣言の仕方
制約条件と目的関数の入力の仕方
Optimizer ライブラリーモジュールを用いて問題をき、writelnを用いて解の情報を返す
仕方
添字付き変数、総和計算、単純なルーピング構造の利用の仕方
外部ファイルからデータを入力し、モデルデータと構造を分離する仕方
•
Furt
87
6章
Mosel に関する話題
概要
この章では、以下について述べる。
・ 集合と配列の使用について学ぶ
・ データファイルとスプレッドシートを用いてデータを読み込み、転送する方法を学ぶ
・ 条件付変数と制約条件について学ぶ
・ Mosel 言語の基本的なプログラミング構造について述べる
・ 自身のモデルにサブルーチンを書くことについて学ぶ
はじめに
これまで2−4章では、インターフェイスを学ぶための基本として用いられてきた単純な例を示し、前章では、モデルがMosel
プログラミング言語を用いていくつかの異なる方法でどのようにして表現されるかを見てきた。そこで扱われた概念は多様
性に富むものではあったが、Mosel 言語に関係するいくつかの話題については、簡潔に議論する価値がある。ここで述べら
れる話題はそれぞれが完結しているので、モデリングに特別の関心がある場合には、独立して読むことも可能である。
ここで述べる内容は、以下のとおりである。
・ 一定集合、動的集合、及び集合演算
・ 多次元で動的な疎配列
・ ファイルからのデータの読み込みと、ODBCで得られた成果
・ 変数と制約の条件付作成法
・ 選択とループ構成
・ 自身の手順と関数の書き方
さらに詳細については、Mosel Reference Manualを参照されたい。
集合について
集合は同じ種類の対象物を集めたもので、そこでは順序付けは問題とはならない。Mosel の集合はす
べて初歩的な型で定義される:すなわち基本型(integer, real, string, boolean) とXpress-MP 型
(mpvar, linctr)の2種類である。それらは3つの異なった方法で初期化できる。それらの方法につ
いて簡単に述べよう。
一定集合:要素がモデルの中のdeclarations によって宣言された集合が一定集合である。─それら
の内容は後で変えることはできない。例を示そう:
declarations
SnowGear = {’hat’,’coat’,scarf’,’gloves’,’boots’}
end-declarations
ファイルの初期化:集合の要素はデータファイルに保存され、initializationsブロックを用いてモ
デルの中に読み込まれる:
declarations
FIB: set of integer
end-declarations
initializations from ’datafile.dat’
FIB
end-initializations
データの読み込みについては、148ページの「データの読み込みと転送」で詳しく述べる。
88
ここでファイルdatafile.datは、以下のようなデータを含む。
FIB: [1 1 2 3 5 8 13 21]
暗示的なファイルの初期化:配列の初期化と同時に、配列の添字を表すのに用いられる集合も間接
的に初期化される。モデルとしての例を示す。
declarations
REGION: set of string
DEMAND: array(REGION) of real
end-declarations
initializations from ’transport.dat’
DEMAND
end-initializations
where the file transport.dat might contain data such as:
DEMAND: [(North) 240 (South) 159 (East) 52 (West) 67]
the set REGION will be initialized as:
{’North’,’South’,’East’,’West’}
動態的、固定的、最終集合
Moselでは、一定でない集合は動的であると見なされる。つまり、要素は任意の時点で集合に加えら
れたり、集合から削除されたりすることが可能である。一度、集合が配列の添字を示すために用い
られると、それは固定的となり、それ以上要素を追加することは可能であるが、削除することは不
可能となる。しかしながら、多くの場合、一度初期化された集合の中身は変化しないし、またその
ような状況では、一定集合より動的集合の方がよいとする理由はほとんどない。むしろ以下のよう
な理由で、逆の方が真実となるであろう:すなわち、添字が動的集合によって指定された配列は、
Moselにおいてはそれ自身動的に作成される。Moselでは動的配列よりも静的配列(一定集合によっ
て示されるもの)の方が可能な限りより効率的に扱われるので、できるだけモデルには静的配列を
用いる方が望ましい。このようなわけで、Moselには動的集合を一定集合に変換させる機能として
finalize がある。
前の例に引き続いて、次のように使用されることもある。
finalize(FIB)
declarations
x: array(FIB) of mpvar
end-declarations
集合演算
このマニュアルでは、これまでのすべての例において、集合は単に他のモデリングの対象となるも
のを指定するためだけに用いられてきた。しかしながら、実際はこのためだけではなく、他にも利
用可能性が存在するので、それらのいくつかについて詳細を述べよう。これらについてはリスト6.1
に示されている。ここでは3つの集合演算の使用方法について説明する。
• 集合和 (‘+’);
• 集合積 (‘*’);
• 集合差 (‘-’).
リスト 6.1 集合演算を利用する
model Sets
declarations
Cits = {"Rome","Bristol","London","Paris",
"Liverpool"}
Ports = {"Plymouth","Bristol","Glasgow",
"London","Calais","Liverpool"}
Caps = {"Rome","London","Paris","Madrid"}
end-declarations
writeln("Union of all places: ", Cits+Ports+Caps)
89
writeln("Intersection of all three: ",
Cits*Ports*Caps)
writeln("Cities that are not capitals: ",Cits-Caps)
end-model
最初と最後では、数字の場合と同じように集合に対して実行される演算として‘+=’ と ‘-=’を定義し、
他の集合の要素に従って集合を修正している。
演習問題 リスト6.1の例を入力し、それらの和、積、差を求めよ。演算‘+=’ と ‘-=’を用いるように
例を変更せよ。
Mosel supports a number of other operators for use with sets. The in
operator has already been seen in several examples of the forall
structure, allowing us to loop over all elements of a set. Comparison
operators may also be used and include: subset (‘<=’), superset (‘>=’),
difference (‘<>’) and equality (‘=’), returning boolean expressions.
Their use is illustrated in Listing 6.2.
Moselでは、他にもいくつかの集合演算をサポートしている。in演算についてはforall構造のいくつ
かの例ですでに見たが、この演算によって集合のすべての要素に対してループ操作をすることが可
能となった。比較演算も使用されるが、たとえば部分集合subset (‘<=’), 包含集合superset (‘>=’),
差集合difference (‘<>’)、そして等号 (‘=’)などによってブールboolean 表現が許されている。この
利用については、リスト6.2.で説明する。
演習問題 リスト6.2のモデルを入力し、出力の中に他の比較演算を含むように変更せよ。出力はど
うなるか。
リスト6.2
集合比較演算を利用する
model "Set Comparisons"
declarations
RAINBOW = {"red","yellow","orange","green",
"blue","indigo","violet"}
BRIGHT = {"orange","yellow"}
DARK = {"blue","brown","black"}
end-declarations
writeln("BRIGHT is included in RAINBOW: ",
BRIGHT<=RAINBOW)
writeln("BRIGHT is not the same as DARK: ",
BRIGHT<>DARK)
writeln("RAINBOW contains DARK: ", RAINBOW>=DARK)
end-model
行列の利用について
集合とは対照的であるが、配列は同じ種類のものの順序付き集合であって、基本型 (integer, real,
string, boolean) とXpress-MP型 (mpvar, linctr)という2つの基本的分類がなされている。配列
は集合によって指標化され、その例については前項で見たが、より単純には、集合を定義すること
なく、自然数のみを用いることもある。
データを初期化して一次元配列に入力するには、次のようにすればよい。
declarations
OneDim: array(1..10) of real
end-declarations
OneDim:= [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
一次元的配列をセットアップする多くの例については、第5章ですでに見た。多次元的配列を初期
化する場合もほぼ同様にできるが、この場合には、結果をよりわかりやすくするためにフォーマッ
ト操作が有効に用いられる。2次元の場合は、以下のようにして行う。
declarations
90
TwoDim: array(1..2,1..3) of real
end-declarations
TwoDim:= [11, 12, 13,
21, 22, 23]
これはもちろん構文的には以下の表現と同じである。
TwoDim:= [11, 12, 13, 21, 22, 23]
これらの指示は、Moselでは、数値を配列TwoDim に行形式に並べるものと解釈される — 最初に変
化するのは最後の添字である。このようにして、配列の中の数値は次のようになる。
Further Mosel
TwoDim[1][1] = 11
TwoDim[1][2] = 12
TwoDim[1][3] = 13
TwoDim[2][1] = 21
TwoDim[2][2] = 22
TwoDim[2][3] = 23
In higher dimensions, the same principle may be applied. Listing 6.3
describes a small model which enters data into a three-dimensional
array and then prints out the array elements along with their values.
より高次元の場合でも同様の原則が適用可能である。リスト6.3では、データを3次元配列に入力し、
それらの数値と共に配列要素をプリントする小さなモデルについて説明する。
演習問題 リスト6.3のモデルを入力し、コンパイルし、読み込み、実行するせよ。配列要素の添字
が要素の数値に対応することを確認せよ。
リスト6.3
3次元配列を初期化する
model ThreeDimEx
declarations
ThreeDim: array(1..2,1..3,1..4) of integer
end-declarations
ThreeDim:= [111, 112, 113, 114,
121, 122, 123, 124,
131, 132, 133, 134,
211, 212, 213, 214,
221, 222, 223, 224,
231, 232, 233, 234]
forall(i in 1..2, j in 1..3, k in 1..4) do
writeln("ThreeDim(",i,",",j,",",k,") = ",
ThreeDim(i,j,k) )
end-do
end-model
See page 165 for
details of the
‘forall’ structure.
動的、固定的行列
Mosel言語における配列は固定されたサイズを持つか,あるいはモデルプログラムが実行されるのに
したがって動的に変動する。標準的には、すべての添字集合が固定サイズのものならば、つまりそ
れらが一定であるか、またはそのサイズを最終決定しているならば、配列は固定されたサイズで作
成される。固定的配列は、配列のタイプによって数値0 かまたは’’ (空の記号列)を与えられた未
初期化セルと宣言時に作成されたすべてのセルに対するスペースを有している。
これとは対照的に、配列のサイズが宣言時に知られていない場合は、それは動的に作成される。外
部ファイルから添字集合が読み込まれることになっているために、添字集合の一つが固定サイズを
持たない場合にも、このことは起こりうる。動的配列は最初は空の状態で作成されるが、数値を割
り当てられるに従ってセルを加え、配列は必要に応じて大きくなる。 配列は、dynamic指定を受け
91
ることによって、動的配列となりうる。
型mpvarを有する配列は、動的と宣言されるか、あるいはまた、添字集合の少なくとも一つのサイズ
が宣言時に知られていないために暗にそうなる場合には、対応する変数は作成されない。このよう
な場合には、個々の要素はすべてcreateコマンドを用いて作成されなければならない。これがなさ
れなければ、配列のサイズは零で、決定変数は存在せず、問題は空集合となる。この例は前章のリ
スト5.11で見られるが、159ページの”条件付き変数と制約”の項でも再度提示する。
疎行列
ほとんどすべての大規模LPあるいはMIP問題は、疎性として知られている特性を有している。すなわ
ち、それぞれの変数は制約条件の全体集合の中の非常に小さな部分のみで非零係数を有している。
この特性は、モデルの中で使用されるデータ配列においては、多量の零係数として考慮される。
この場合には、全ての数値のリストを作成するよりもむしろ、非零数値だけを与える方がより便利
である。これはまた、データを2次元以上のデータ配列に入力する場合でも最も簡単な方法である。
さらなる利点は、使用されるメモリーがより少なくてすむということである。リスト6.4の情報を含
むデータファイルSparseEx.datを持っていると仮定しよう。
集合の型についての詳細は、前の “集合についての作業”を参照されたい。
この例では、配列COSTの要素は、Depot1 から Customer1へ、Depot2 からCustomer1へ、等に対して
製品を送るのに割り当てられた非零数値を持つ。しかしながら、Depot2 からCustomer3へ製品を送
るのに必要なコストは定義されていないので、この配列は疎と見なされる。リスト6.5では、モデル
はこのファイルに含まれるデータを読み込み、すべての可能なDEPOT-CUSTOMERの組み合せについて
その関連コストを伴ったリストをプリントする。割り当てられたコストのない要素には数値0が与え
られる。
この例では、配列COSTのサイズは、宣言時にいずれの添字集合のサイズも知られていないため、動
的に扱われる。データを保存するために使われるスペースは追加された要素の個数に対応する —
それ以外の零要素の為のスペースは作られない。コンソールでコマンドdisplay COSTを用いると、
これが見られる。
リスト6.4
疎データフォーマット配列の例
! SparseEx.dat - Data for SparseEx.mos
COST: [(Depot1 Customer1) 11
(Depot2 Customer1) 21
(Depot3 Customer2) 32
(Depot2 Customer2) 22
(Depot1 Customer3) 13]
リスト6.5 疎データフォーマットにデータを入力する
model SparseEx
declarations
DEPOT, CUSTOMER: set of string
COST: array(DEPOT,CUSTOMER) of integer
end-declarations
initializations from 'SparseEx.dat'
COST
end-initializations
forall(d in DEPOT, c in CUSTOMER)
writeln(d," -> ",c,": ",COST(d,c))
end-model
このファイルフォーマットでは、括弧に入れられた語は数値が記憶される配列の中の場所を表す。
Topics
演習問題 上記のモデルを入力し、Moselの中でそれを実行せよ。配列COSTの数値を表示することに
よって、この配列が動的であることを確認せよ。
92
データの入出力
モデル実例を構成する特定のデータとモデルの一般的形式あるいは構造を分離することによって明
白な効用が得られる。Moselモデルプログラミング言語によってこのようなモデリングの原理の理解
が進み、データの読み込みと転送が非常に容易になる。
4つの主要な方法によってMoselモデルプログラム配列にデータを入力できる。
・ モデルプログラムファイルに直接
・ initializationsブロックを用いて
・ ODBCを用いて
・ readlnコマンドを用いて
最後の3つの方法によって、データにしたがって得られた解を転送する方法が与えられる。この項
では、これらについての関連する効用について述べる。
モデルデータの要素
データをMosel配列に入力する最も簡単な方法は、モデル自身の中にデータを直接埋め込むことであ
ろう。前章でこのような例をいくつか見たが、どのようにしてデータが入力されるかについてのよ
り詳しい例をリスト6.6に示す。
この例では、サイズ5の1次元配列が作成され、データが入力される: A(1)は数値1,A(2)は数値
2.5、等のように割り当てられる。最終的には、writelnを用いて配列がコンソールに表示される。
Further Mosel
利用するには速くて容易であるものの、この方法に依存すると、いかなる方法を用いてもデータと
モデル構造を切り離すことは不可能となる。したがって、このような方法の利用は、小さなテスト
例題の作成あるいはプロトタイプモデルの開発に限られるであろう。
初期化ブロックを用いたデータの転送
initializationsブロックは、スカラー、配列、外部データファイルからの集合などの基本的なもの
を初期化し、モデルプログラムの中の解データを後で転送するのに使用することができる。
ASCIIファイルからのデータの読み込み:初期化データファイルはそのフォームの複数個のレコード
を含まねばならない。
label: value
ここでlabelはテキスト記号列であって、またvalueは定数、あるいはスペースで切り離され、括弧
で囲まれた数値の集まりである。数値の集まりは、集合あるいは配列を初期化するのに用いられる。
データ入力の間、初期化しなければならないものは外部ファイルのlabelに関連付けられる。これは
一般的には対象となるものの名称と同じラベルであるが、修正子asが用いられる場合は異なること
もある。initializationsブロックが実行されると、与えられたファイルが開かれ、対応する対象を
初期化するために、要求されたラベルがこのファイルの中で探索される。
このファイルでは特別なフォーマット作業は必要ない:スペース、タブ、行の区切りはすべて通常
の分離記号となる。さらに、1行以内のコメントがファイル内でサポートされる。そのようなファ
イルの例はリスト6.7に与えられる。
リスト6.6
配列への原データの入力
model NativeEx
declarations
A: array(1..5) of real
end-declarations
A:=[1, 2.5, -6.1, 10, 77]
writeln("A is: ",A)
end-model
このファイルでは、1つの整数(Item)が2つの配列(A1とalbatross)と一緒に定義される。リスト6.8
はこれらの数値をメモリーに読み込むモデルファイルの例である。
この例にはいくつかの特筆すべき事柄がある。まず、データファイルの名前はinitializationsブロ
ックの始めと同じ行になければならず、語fromの後に引用されなければならない。initializations
ブロックはデータの転送にも使用されるので、修正子fromはデータ移動の意味を特定するものであ
る。この場合は、情報を外部の情報源から入手している。
93
リスト6.7 初期化で使用するASCIIファイルフォーマット
! InitEx.dat: Using the initialization block
Item: 25
albatross: [12.9 76 1.55 0.99]
A1: [23 15 43 29 90 180]
リスト6.8
ASCIIファイルからの入力を提示するモデルファイル
model InitEx
declarations
Item: integer
A1: array(1..6) of integer
A2: array(1..4) of real
end-declarations
initializations from ’InitEx.dat’
Item A1
A2 as "albatross"
end-initializations
writeln("Item is: ",Item)
writeln("A1 is: ",A1)
writeln("A2 is: ",A2)
end-model
第2に、initializationsブロックに含まれる項目はスペースで区切られているので、これらのうち
のいくつかは同じ行に置かれるかもしれない。この例ではItemとA1を用いてこれを実行した。ここ
で対象とするものは付随するデータファイルの中のデータと必ずしも同じ順序である必要はないこ
とに注意されたいが、明確さを重視する場合に順序を保つことは往々にして賢明なことではある。
最後に、データファイルの中のラベルalbatrossと関連する配列データは、配列A2に読み込まれるこ
とになっている。これはモデルファイルの中で修正子asを使用することによって達成される。この
構成が使用される場合にはデータファイルの中のラベルがモデルファイルに引用されなければなら
ないので、モデルファイル内のラベルは、必要に応じて複数個の語から成る場合も生じる。
演習問題 上記の例を入力するか、またはデータを読み込んで表示する自身のプログラムを作成せ
よ。自身の例は上述のすべての可能性を提示するものでなければならない。
データをASCIIファイルに転送する:initializationsブロックに対するフォーマットを利用して、
Moselからのデータを問題の解にしたがって外部のデータファイルに転送する場合、同等の方法が使
用されることもある。
initializations to filename
identifier [as label]
end-initializations
この形式が実行される場合、ファイル内のすべての与えられたラベルの数値は、対応する識別子の
現在の数値に更新される。ラベルが見つからない場合には、ファイルの最後に新しいレコードが付
加され、またラベルが存在しない場合には、ファイルが作成される。
演習問題 上記の演習問題の中の自身のモデルを変更し、フォーマットを用いて別のファイルにデ
ータを転送せよ。テキストエディターを用いて新しいファイルを作成し、どのようにしてデータが
入力されたかを調べよ。
Topics
ODBCを用いたデータの転送
テキストファイルにデータを作り、保持することは極めて単純な操作であるが、多くの人々にとっ
てより効率的で役に立つ様式としてスプレッドシートとデータベースを用いる方法がある。Mosel
言語には、構造的質問言語であるSQL(structured query language)を用いて、ODBCに基づくスプレ
ッドシートとデータベースプログラムからデータを入力したり、転送したりする機能が存在する。
それを実行するには、Xpress-MPライセンスの特別許可に加えて、ライブラリーモジュールmmodbc
を使用することが必要である。
ODBCを立ち上げる: Myss.xlsと呼ばれるスプレッドシートの中で下記のデータがセルに入力されて
94
いて、範囲B2:C5がMyRangeと呼ばれているとしよう。データがスプレッドシートからXpress-MPに入
力される時、指定範囲の第1行は常に列の見出し名を含むと仮定されているので、無視される。こ
の例では、MyRangeからのデータはサイズ3*2の配列を満たすであろうし、またODBCはこのデータを
配列A(3,2)の中に抽出するのに用いられるであろう。
演習問題 “ODBCを利用する”のボックスの中で述べられたように、Excelのユーザーデータソースを
立ち上げよ。
A B C
1
2 First Second
3 6.2 1.3
4 -1.0 16.2
5 2.0 -17.9
ODBCを使用する
ウィンドウズのコントロールパネルで、32ビット ODBCを選び、MyExcelと呼ばれるユーザーデータ
ソースを立ち上げよ。その際、Addをクリックし、Microsoft Excel Driver (*.xls)を選び、ODBC
Microsoft Excelセットアップダイアログを書き込め。続いてOptions >>をクリックし、Read Only
のチェックボックスを消せ。
ここの例を用いて作業をする場合には、Microsoft Excelにアクセスする必要がある。
スプレッドシートの範囲では、最上行に列の表題をつけなければならない。
Further Mosel
ODBCに基づく製品からのデータを入力する:リスト6.9では、このようなExcelスプレッドシートか
らMoselへどのようにしてデータを読み込むかを示す。ここで注意すべきことは、要求されたデータ
をスプレッドシートから得るためにはSQL文法が使用されねばならないことである。極めて単純なこ
とであるが、‘SELECT * FROM MyRange’によって、MyRangeの中のすべての情報が戻され、その後要求
に応じて配列Aの中に置かれる。
演習問題
よ。)
このようにしてExcelからデータを得るモデルを作成せよ(または前のモデルを変更せ
ODBCに基づく製品へデータを転送する: スプレッドシートにデータを転送して戻すことはほとんど
同じやり方でできる。この例はリスト6.10にあり、そこでは新しいシートNewが作られ、そこに配列
Aからデータが入力される。
MoselとODBCに基づくアプリケーションの間のいかなるコミュニケーションにもSQLが使われるので、
これよりもはるかに複雑な操作が可能となる。
リスト6.9 Excelスプレッドシートからのデータを読み込む
model ODBCImpEx
uses "mmodbc"
declarations
A: array(1..3,1..2) of real
CSTR: string
end-declarations
CSTR:= ’DSN=MyExcel; DBQ=Myss.xls’
SQLconnect(CSTR)
SQLexecute("SELECT * FROM MyRange",[A])
SQLdisconnect
forall(i in 1..3)do
writeln("Row(",i,"): ",A(i,1)," ",A(i,2))
end-do
end-model
その可能性の詳細については、SQLに関するどの標準的なテキストを調べてほしい。
95
演習問題 自身の前のモデルを変更して、問題の解を含むデータを出力してエクセルに戻すように
せよ。あるいは前述の例の1つを変更して、同様のことをせよ。問題がある場合には、次の項を参
照せよ。
Microsoft Excelの表を開いて使用する: MoselからMicrosoft Excelにデータを書き込む時、考慮す
べき点がいくつかある。Excelはスプレッドシートのアプリケーションであって、ODBCは本来データ
ベース用に作られたものであるので、ODBCを用いてエクセルを読み書きするには特別なルールに従
わなければならない。
・ データの表を参照するには、Excelワークシートの中では名前を有する範囲が使用されなければ
ならない。
・ 列の名前はフィールドの名前として使用されねばならない。
・ 各フィールドのデータタイプは列の見出しの下に見本データの行を用いて定義されなければな
らない。
・
リスト6.10 Excelスプレッドシートへデータを書き込む
model ODBCExpEx
uses "mmodbc"
declarations
A: array(1..3,1..2) of real
end-declarations
forall(i in 1..3,j in 1..2) A(i,j) := i*j
SQLconnect(’DSN=MyExcel; DBQ=Myss.xls’)
SQLexecute("CREATE TABLE New(Col1 integer, Col2
integer)")
SQLexecute("INSERT INTO New(Col1,Col2) VALUES
(?,?)",A)
SQLdisconnect
end-model
Further Mosel
ExcelでOBDCを使用する場合には、各々の範囲の最上行は列の見出しをを含むことが重要である。—
さもないとエラーが生じ、データのワークシートとのやりとりが正確に行われないであろう。見本
データの行はまた、各々の列のデータの型を確認するために見出しの下の行に必要とされる。この
見本の行もまた範囲に含まれなければならない。
利用者は、Excelで名前の付いた範囲として明示されたデータベースの表に書き込む場合には、新し
いデータが加えられるとすると、範囲のサイズが大きくなることを認識すべきである。いま範囲の
中にODBCを用いて、すでに書き込まれたデータの最上段にさらにデータを書き込みたいとする。こ
のとき、Excel内では、前のデータを選んでDeleteキーを打つだけでは、それらのデータを削除する
のには十分ではない。これをすると、削除されたデータがそれまであったところの空白の長方形の
後にさらなるデータが加えられるであろう。代わりに、Excel内でEdit, Delete, Shift cells up
を用いて前のデータの痕跡をすべて消去し、拡大された範囲を用いることが重要である。
MicrosoftのExcelの表は、一度に一人の利用者しか作成したり、開いたりすることができない。し
かしながら、Excelのドライバーオプションで利用される‘Read Only’オプションを用いると、多数の
利用者が同じ.xlsファイルから読み取ることが可能となる。
スプレッドシートデータに対する配列のサイズ調整: Moselは扱う対象を処理する順番に評価する
ので、表の大きさは動的に調整される。実際問題として、モデルを書き込んだ後に追加データが入
力されると、スプレッドシートの領域の大きさは実際に変化するという可能性がある。これは特に
便利なやり方なので、その使用方法について簡潔に述べておこう。
スプレッドシートMyss.xlsでの作業を続けていて、データがさらに加えられたときにMyRangeの大き
さを変えたいとしよう。これはスプレッドシートに追加の領域を作ることによって対処することが
できるが、それをSizesと称する。この中に、問題を特徴づける数を次のようにして挿入する。
Number of Rows Number of Columns
=ROWS(MyRange)-1 =COLUMNS(MyRange)
行の数を1だけ減らすと、列名を含む行を減らすことになる。
Topics
96
最初の列の2つのセルによって形成される範囲をNrowsと命名し、2番目の列の2つのセルによって
形成される範囲をNcolsと命名すると、リスト6.11のコマンドがモデルの導入部を形成することにな
る。
演習問題 前のモデルを変更して、表のサイズを動的に変えられるようにせよ。次に読み込むべき
データの行の数を変更し、Moselの中で新モデルを実行せよ。余分なデータが入力されることをチェ
ックせよ。
Readlnとwritelnによるデータの転送
ASCIIファイルからデータを読むためのより一般的な方法は、readln と readコマンドによって与え
られる。これらのコマンドは、現在の入力列に対して与えられた記号列を割り当てるか、または与
えられた表現を読み込まれるものと適合させようとするものである。
リスト6.11 スプレッドシートによって表の大きさを動的に調整する
model SizingEx
uses "mmodbc"
declarations
NRows, NCols: integer
end-declarations
SQLconnect(’DSN=MyExcel;DBQ=Myss.xls’)
NRows:=SQLreadinteger("select NRows from Sizes")
NCols:=SQLreadinteger("select NCols from Sizes")
declarations
A: array(1..NRows,1..NCols) of real
end-declarations
SQLexecute("select * from MyRange",[A])
SQLdisconnect
forall(i in 1..NRows,j in 1..NCols) do
writeln("A(",i,",",j,") = ", A(i,j))
end-do
end-model
Further Mosel
readコマンドは複数行にわたって実行されるが、readlnコマンドの場合は、すべての記号列が単一
行に含まれなければならない。
これらのコマンドの使用については、例を用いた説明が一番わかりやすいであろう。リスト6.12で
述べられるような情報を含む入力データファイルがあると仮定しよう。
ファイルReadlnEx.datは、リスト6.13で述べられるモデルプログラムによって読み込まれる。その
モデルは、プログラムに必要な変数を宣言するという、普通の方法で始まる。ファイルの中のデー
タは配列Aの中に読み込まれることになっており、その配列Aは疎であって、動的に大きさが調整さ
れることになっている。
リスト6.12 readlnによるファイル形式
! File ReadlnEx.dat
read_format( 1 and 1)= 12.5
read_format( 2 and 3)= 5.6
read_format(10 and 9)= -7.1
リスト6.13 readlnによるデータの読み込み
model ReadlnEx
declarations
A: array(range,range) of real
i, j: integer
end-declarations
fopen("ReadlnEx.dat",F_INPUT)
readln("!")
97
repeat
readln("read_format(",i,"and",j,")=",A(i,j))
until getparam("nbread") < 6
fclose(F_INPUT)
writeln("A is: ",A)
end-model
ここで動的配列Aは、動的集合rangeによって指標化されることに注意されたい。
‘repeat’構造の詳細については、巻末のページを参照せよ。
Topics
fopenコマンドを用いると、データファイルが開けられ、現在の入力列F_INPUTに割り当てられる。
その後、ファイルの1行目はコメントを含んでいるので、!文字を含む行を読む。これに続いて、反
復ループを用いて、リスト6.12で述べられるフォーマットの中で可能な限り多くの行を読み込み、=
記号の後の数値を‘and’という言葉を添付された、数値の添字を有する配列要素に割り当てる。最後
に、入力列は閉じられ、その配列はコンソールにプリントされる。
プログラムの実行中、readとreadlnコマンドによって制御パラメタnbreadを1行で実際に認識可能
な項目の個数に設定する。これを調べることによって、与えられた記号列に適合しない情報がいつ
読み込まれたかが明らかになる。われわれの例では、1行目の後、1行につき6項目がパーサー
parserによって認識されることになっている。読み込むべきデータが存在しない時、反復ループを
終了するのにこれを用いることができる。
演習問題 readlnとreadを用いるモデルを作成し、外部ソースファイルからデータを入力し、既に
読み取ったデータを表示せよ。
write とwritelnによるデータの転送
配列と解のデータは、writelnとwriteコマンドを用いるのとほとんど同じ方法でファイルに書き込
まれる。ファイルを開いて、それを現在の出力列F_OUTPUTに割り当てると、その後のコマンドとし
ては、writeとwritelnのいずれも出力はコンソールでなくてファイルとなる。この例はリスト6.14
に与えられているが、そこでは2章から4章の簡単な問題が解かれ、解の値がデータファイルに転
送される。
このやり方で情報が転送される場合、現在ファイルに書き込み中のすべての情報が失われ、ファイ
ルは新しいデータで完全に上書きされることに注意しなければならない。これを望まない場合は、
代わりに、データを追加するためにはfopen(Filename,F_APPEND)を用いてファイルをく必要がある。
演習問題 リスト6.14のモデルを入力して実行し、ファイルWritelnEx.datにデータを書き込め。次
にデータを追加するようにモデルを変更し、プログラムを再度実行せよ。出力ファイルをテキスト
エディターで読み込め。
Further Mosel
条件付変数と制約
条件付上下限
N変数の集合のすべての要素ではないが、それらの一部に上限値を適用したいとする。適用される上
限値は各々の変数によって異なり、これらは集合で与えられる。
しかしながら、データ表の要素がある量、たとえば20、より大きい場合に限って、それらは適用さ
れるべきである。もし境界値が、これまで通例であったように、数値に依存しない場合には、forall(i
in 1..N) x(i) <= U(i)
を用いて表現されたであろう。しかしながら、条件付境界の場合には、これは少々変更されなけれ
ばならない。
リスト6.14 writelnを用いて解データを出力する
model WritelnEx
uses "mmxprs"
declarations
a,b: mpvar
end-declarations
first:= 3*a + 2*b <= 400
98
second:= a + 3*b <= 200
profit:= a + 2*b
maximize(profit)
fopen("WritelnEx.dat",F_OUTPUT)
writeln("Profit = ",getobjval)
writeln("a=",getsol(a),": b=",getsol(b))
fclose(F_OUTPUT)
end-model
xi
Ui
CONDi
CONDi
Topics
すなわち、下式のようになる。
forall(i in 1..N ¦ COND(i) > 20) x(i) <= U(i)
このようにして、これらの例の2番目の行は、 COND(i)が20より大きい時はいつでも、i=1 to Nに
対して、変数x(i)はU(i)よりも小さいか等しくなければならない と読むことができる。
条件付変数
変数が動的配列であると宣言し、さらにある条件を満たす変数のみを作成するという場合、このよ
うな変数の存在もまた条件付となりうる。この例はリスト6.15に示される。ここで実際に定義され
る変数は、x(1), x(2), x(3), x(6), x(8) そして x(10)である。小さなモデルを作成してコンソー
ルにそれを出力することによって、これは明らかとなる。
¦
垂直な棒の記号(¦)は、後に続く論理的な表現とともに条件付オペレーターを表し、 以下の表現が
正確である時はいつでもなされるか、またはそのようなもの と読むことができる。
リスト6.15 条件付変数の作成方法
model ConditionalEx
declarations
Elements = 1..10
COND: array(Elements) of integer
x: dynamic array(Elements) of mpvar
end-declarations
COND:= [1, 2, 3, 0, -1, 6, -7, 8, -9, 10]
この例はすでに第5章で見てきたが、そこでは添字集合もまた外部のファイルから入力された。詳細については、132ページ
のリスト5.11を参照されたい。
Further Mosel
演習問題 リスト6.15のモデルを作り、実行せよ。作成された問題のLP形式行列を調べ、6つの変
数のみが存在することを確認せよ。
このようにしてexportprobを用いると、作成された問題を直接見ることができる。出力用のファイ
ル名を明示しなくとも、行列は画面上に表示される。
基本的計画問題の構造
Moselモデルプログラミング言語はモデルの仕様に関するコマンドや手順ばかりでなく、高度なプロ
グラミング言語の可能性をすべて有している。これはモデリング環境にとって強力な追加機能とな
っている。それらのいくつかについて、以下に論じる。
if コマンド
if 記述の一般形は以下の通りである。:
if expression_1
then commands_1
[ elif expression_2
then commands_2 ]
[ else commands_3 ]
99
end-if
forall(i in Elements ¦ (COND(i) = i)) create(x(i))
! build a little model to show what’s there
obj:= sum(i in Elements) x(i)
c:= sum(i in Elements) i*x(i) >= 10
exportprob(0,"",obj)
end-model
リスト 6.15 条件付変数の作成方法pics
ブール表示expression_1を評価することによって、選択が行われる。すなわち、これがtrueの場合
はcommands_1が実行され、end-if記述に続く制御が実施される。オプションのelif部分が含まれる
場合は、ブール表示expression_2が評価され、これがtrueの場合は、end-if記述に続く制御が実施
される前にcommands_2が実行される。if あるいは elifのいずれの接頭辞を有する表現もtrueと評
価されない場合は、オプションのelse記述に続くcommands_3が実行される。プログラムはend-if記
述に続いて実行される。この例はリスト6.16に与えられている。この例においては、モデルの実行
中の出力を制御するために、整数DEBUGが用いられている。通常はDEBUGは0に設定され、Moselの出
力に関する記述では、データを読み込む時と場所が指定される。しかしながら、DEBUGはパラメタで
あるので、値は実行中に変更され、たとえば値が1のときは、読み込まれるデータは画面に提示され、
正しく入力されているか否かの確認ができる。リスト6.17は、Moselを用いて、まずモデルプログラ
ムが正常に実行され、続いてDEBUGパラメタの値を1に設定する例を示したものである。
リスト 6.16 モデリングの中で if 記述を用いる
model IfEx
parameters
DEBUG=0
File=’InitEx.dat’
end-parameters
declarations
A: array(1..6) of integer
Item: integer
end-declarations
initializations from File
Item A as "A1"
end-initializations
if(DEBUG=1) then
writeln("Item is ",Item,"\nA is ",A)
else
writeln("Data read in from ",File,"...")
end-if
end-model
パラメタブロックには、実行時に変更されるものが標準的な値とともにリスト表示されている。コマンド列\nは、2重の引
用符で囲まれている場合には、newline文字として解釈される。
Further Mosel
この機能を用いると、長いモデルのデバッギングには特に便利である。エラーの原因を探りたい場
合には、writelnコマンドを利用して変数の値を出力するデバッギングを行うのが普通のやり方であ
る。この目的のために追加された記述がifで囲まれている場合は、これらはデバッギングが終了し
てもモデルの中にそのまま残されることになり、それらを認識した上で削除するという操作は行わ
れない。さらに詳細が続けて追加される場合には、追加的なデバッギングが必要となる。この場合
も、デバッギング記述はモデルの中に残ることになる。
演習問題 リスト6.16の例を入力し、通常の場合とDEBUG特性を用いた場合を実行せよ。モデルプロ
グラムをelif記述を用いて変更し、次のレベルのDEBUGによって、データが収集されたファイル名を
追加的にプリントするようにせよ。
リスト 6.17 モデルのデバッギング特性を用いる
100
C:\Mosel Files>mosel
** Mosel **
(c) Copyright Dash Associates 1998-zzzz
>cload IfEx
Compiling `IfEx'...
>run
Data read in from InitEx.dat...
Returned value: 0
>run DEBUG=1
Item is 25
A is [23,15,43,29,90,180]
Returned value: 0
>
もう一つの例は170ページのリスト6.22にある。
Topics
case コマンド
case 記述の一般形は、以下のようになる。:
case Expression_0 of
Expression_1: Statement_1
or
Expression_1: do Statement_list_1 end-do
[
Expression_2: Statement_2
or
Expression_2: do Statement_list_2 end-do
...]
[ else Statement_list_3]
end-case
ブール表示Expression_0を評価し、続けてそれをExpression_iと比較して合致していることを確認
することによって、選択が行われる。ここではStatement_i か Statement_list_iかのいずれかが実
行され(構築方式による)、end-case記述に続く制御が実施される。いずれの表現も合致せず、else
記述がある場合には、Statement_list_3が実行され、end-case記述に続く制御が実施される。これ
を示す簡単な例がリスト6.18に与えられている。この例においては、配列Aの要素が探索され、規則
(いくらか奇妙ではあるが)にしたがって分類される。すなわち、値が0か、1から3の間か、8か10
の場合は’興味ある’であるが、それ以外の場合は、’興味ない’とされる。配列Aの各要素が分類され、
値に関する記述が画面にプリントされる。
演習問題 case構造を利用するモデルプログラムを構築せよ。あるいは前のプログラムをcase構造を
利用していくつかのデバッギングレベルを処理するように修正せよ。
Further Mosel
forall ループ
forall 記述の一般形は、以下のようになる。:
forall (Iterator_list) Statement
or
forall (Iterator_list) do Statement_list end-do
ここでStatement あるいは Statement_listはIterator_listによって作成されたそれぞれの添字の
組にしたがって繰り返し実行される。この例はリスト6.19に与えられている。
この例においては、Moselによって配列Fの最初の 20個にフィボナッチ数列の数を入れ、それらをコ
ンソールにプリントする。この数列において、最初の2つの数字は1で、続く数字は前の2つの数字の
和とされる。添字集合Elemsでループを実施すると、簡単なif記述によって、最初の2つの項を初期
化しているか、そうでないときには、数列の次の項を決定するようにアルゴリズムを適用する、と
いう手続きを決定する。
リスト 6.18 簡単な case 例
model CaseEx
101
declarations
A: array(1..10) of integer
end-declarations
A:=[1,2,3,0,-1,1,3,8,2,10]
forall(i in 1..10) do
case A(i) of
0: writeln('A(',i,') is 0')
1..3: writeln('A(',i,') is between 1 and 3')
8,10: writeln('A(',i,') is either 8 or 10')
else writeln('A(',i,') is not interesting')
end-case
end-do
end-model
Topics
forallループを含む他の例として、リスト5.6にあるように決定変数をバイナリーに設定したり、リ
スト5.11にあるように変数を明示的に作成したりするものがある。これらはいずれも前章に示した
ものである。
演習問題 forallループを利用してモデルプログラムを作成し、入力し、ここに与えられた例を実行
せよ。
while ループ
while 記述の一般形は、以下のようになる。:
while (Expression) Statement
or
while (Expression) do Statement_list end-do
上の構成を用いると、ブール表示Expressionが評価され、Expression が trueである限りStatement
あるいは Statement_listが実行される。Expression がfalseであると評価されると、while記述は
完全に飛ばされる。例がリスト6.20に与えられている。
ここでwhile記述が用いられて‘時間表times table’が作られ、行と列の数の積がプリントされる。各
行の最後にnewline文字がプリントされ、行の数字の間にはtab文字が用いられる。
リスト 6.19 簡単な forall 例
model ForallEx
declarations
Elems=1..20
F: array(Elems) of integer
end-declarations
forall(i in Elems) do
if(i=1 or i=2) then
F(i):=1
else F(i):= F(i-1) + F(i-2)
end-if
writeln("F(",i,")\t= ",F(i))
end-do
end-model
コマンド列 \t は、2重の引用符で囲まれた場合のみtab文字と解釈される。
演習問題 リストにある例を入力し、while記述を用いて自分の例を作成せよ。それをコンパイルし、
読み込み、実行して、出力をチェックせよ。
repeat ループ
最後のループ構造はrepeat ループであって、次のような一般形を有している。
repeat Statement_1
[ Statement_2…]
102
until Expression
リスト 6.20 簡単な while 例
model WhileEx
declarations
i,j: integer
end-declarations
i:=1
j:=1
while(i <= 10) do
while(j <= 10) do
write(i*j)
if(j=10) then writeln
else write("\t")
end-if
j+=1
end-do
j:=1
i+=1
end-do
end-model
ここでブール表示 Statement_1 (他の記述も含めて)は、ブール表示Expressionがfalseと評価され
るまで繰り返し実行される。それに対してwhileループでは、Expressionが評価される前に実行され
るので、repeatループにある記述が少なくとも一度は実行されることが保証されている。リスト6.21
に例が与えられている。
この例は、与えられた数値が素数であるか否かをテストする短いプログラムである。実行すると、
利用者は数字を入力するように要求され、それらが繰り返しテストされ、除数が見つかるか、また
は素数であると判定される。
演習問題 リストにある例を入力して、実行せよ。入力数値が整数値で0より大きいかをテストする
ように、プログラムを変更せよ。1の入力をどのように処理するかを別に考える必要があるであろう。
リスト 6.21 簡単な repeat 例
model RepeatEx
declarations
i: integer
number: integer
end-declarations
i:=1
writeln("Input a positive integer:")
readln(number)
repeat i+=1
until ((number mod i =0) or i>sqrt(number))
if(i>sqrt(number)) then writeln(number," is prime!")
else writeln(number," is divisible by ",i)
end-if
end-model
Further Mosel
プロシ-ジャと関数
記述と宣言の集合をサブルーティンの形に結合し、モデルの実行中に何度もそれを呼び出すことが
可能である。Moselでは、手順と関数という2種類のサブルーティンをサポートしている。これらは
いずれもパラメタを有し、局所的データを定義し、再帰的に呼び出すことができる。
103
プロシージャ
手順はいくつかの記述からなり、数カ所で同時に実行できる。実行されると記述にしたがって実施
されるが、数値は返されない。
手順の例はリスト6.22に与えられており、モデルを実行すると最初に標識がプリントされる。パラ
メタを用いたモデルに対しては、このような例によって出力を分類する有用な方法が得られ、特に
情報が画面でなくてファイルに送られる場合には効果的となる。リスト6.23はConsole Xpressから
このプログラムを利用する例を示している。
モデルを実行すると最初に標識を出力する簡単な手順を作成せよ。モデルがパラメタや他の設定を
外部ファイルから行う場合は、これらの出力を用いてもよい。
手順procedure
手順ブロックは次のような形式を有する。:
procedure proc_name [ (param_list) ]
proc_body
end-procedure
ここで proc_name は手順名であって、param_listはコンマで分離されたパラメタのリストである。
この手順が呼ばれると、proc_bodyにある記述が実行される。
Topics
リスト 6.22 簡単な手順
model ProcEx
parameters
DEBUG=0
File='InitEx.dat'
end-parameters
procedure banner(DEBUG:integer,File:string)
writeln("This is the ProcEx model, release 1")
if(DEBUG = 1) then
writeln("\tDebugging on...")
end-if
if(File <> 'InitEx.dat') then
writeln("\tInput file ",File," in use...")
end-if
writeln
end-procedure
banner(DEBUG,File)
end-model
リスト 6.23 パラメタを入力して手順を実行する
C:\Mosel Files>mosel
** Mosel **
(c) Copyright Dash Associates 1998-zzzz
>cload ProcEx
Compiling `ProcEx'...
>run
This is the ProcEx model, release 1
Returned value: 0
>run 'DEBUG=1,File=data.dat'
This is the ProcEx model, release 1
Debugging on...
Input file data.dat in use...
Returned value: 0
>
手順は、キーワードforwardを用いて使用する前に宣言されている限りは、モデルの最後に一緒においてもよい。詳細につい
ては、以下の節を参照されたい。デバッギングに関する追加情報は、compile あるいはXPRMcompmodでgフラッグを利用すれ
104
ば入手できる。
Further Mosel
関数
関数は1ヶ所あるいは数カ所で一緒に実行される記述の集合であって、数値を返す。
リスト6.24は完全数perfect numbersを求める3つの関数を用いる例である。完全数は、除数の和が
その数自体と等しくなるような数である。最初の関数isPrimeは数が素数であるか否かをチェックす
るし、また2番目の関数は数の正のべき乗を計算する。最終的に、3番目の関数はこれらの関数を
呼び出してメルセンヌ素数Mersenne Primes数を生成し、ユークリッド公式を用いて完全数を計算す
る。
この例で注意したいことは、いずれの関数についての記述もキーワードreturnedを備えていなけれ
ばならないということである。その値は関数が存在する場所に戻され、関数の最初に宣言されてい
るように、型typeの値に設定される。この例では、if記述によって、あるいはまたべき乗計算によ
って整数値がreturnedに割り当てられる。
演習問題リスト6.24にある例を入力して実行し、最初の4個か5個の完全数を求めよ。関数がより
一般的で、不正な引数を棄却するようにプログラムを修正せよ。
関数
関数ブロックは、以下のような形式を有する。:
function func_name [ (param_list) ]: type
func_body
end-function
ここで func_name は関数名で、param_list はコンマで分離された形式的なパラメタのリストで、
typeは返却する値の基本的な型を表す。手順が呼ばれると、func_bodyにある記述が実行され、数値
が返される。
Topics
リスト 6.24 関数を用いて完全数を計算する
model PerfectEx
function isPrime(number: integer): boolean
i := 1
repeat i+= 1
until ((number mod i = 0) or i > sqrt(number))
if(i > sqrt(number)) then returned := true
else returned := false
end-if
end-function
function power(a,b: integer): integer
pow := 1
while(b > 0) do
pow := pow*a
b-=1
end-do
returned := pow
end-function
function Perfect(n: integer): integer
Mn := power(2,n)-1
if(isPrime(Mn)) then
returned := power(2,n-1)*Mn
else returned := 0
end-if
end-function
i := 1; k := 1
while(k<5) do
i+=1
if(Perfect(i) > 1) then
105
write(Perfect(i)," = ")
forall(j in 0..i-1) write(power(2,j),"+")
write(power(2,i)-1)
forall(j in 1..i-2)
write("+",(power(2,i)-1)*power(2,j))
writeln; k+=1
end-if
end-do
end-model
関数の前進型宣言も許されている。詳細については、以下の節を参照されたい。
Further Mosel
再帰性
関数も手順はいずれも直接あるいは間接にそれらを呼び出すことによって、再帰的に利用すること
ができる。これは特に便利なので、例を紹介しよう。リスト6.25において、関数hcfは再帰的に呼ば
れ、2つの数の最大公約数が決定される。
演習問題リスト6.25にある例を入力して、いくつかの例を用いて実験せよ。
リスト 6.25 関数の再帰性
model HcfEx
function hcf(a,b: integer): integer
if(a=b) then
returned:=a
elif(a>b) then
returned:=hcf(b,a-b)
else
returned:=hcf(a,b-a)
end-if
end-function
declarations
A,B: integer
end-declarations
write("Enter two integer numbers:\n A: ")
readln(A)
write(" B: ")
readln(B)
writeln("Highest common factor: ",hcf(A,B))
end-model
Topics
前進型宣言
Moselでは再帰性ばかりでなく、交差再帰性cross recursionという、2つのサブルーティンが交互
にお互いを呼ぶ性質も可能であることをすでに述べた。しかしながら、すべての関数と手順は呼ば
れる前に宣言されていなければならないので、最初に定義されたとサブルーティンは未だ定義され
ていないもう一つのサブルーティンを呼ぶ必要に迫られる。解決法としては、キーワードforward
を用いて、コマンドが定義される前にひとつか2つのサブルーティンを宣言しておけばよい。
ここで重要なことは、用いられるいろいろな用語の間の相違点を明確にしておくことである。サブ
ルーティンの宣言declarationには、名前、パラメタ(型と名前)、そして関数に対しては返却する
数値の型が記述されている。モデルプログラムの中で後に続くサブルーティンの定義definitionに
は、サブルーティンの本体である、呼ばれた場合に実行されるコマンド群が含まれる。
この違いを例示するのがよいであろう。リスト6.26では、ランダムに並べられた数値の配列を増加
順に並べるクイックソートアルゴリズムを実行する。ソーティングアルゴリズムを開始する手順
startは、プログラムの最後に定義されているが、呼ばれる前に、最初に宣言されておく必要がある。
リスト 6.26 サブルーティンの前進型宣言
model "Quick Sort"
106
parameters
LIM=50
end-parameters
forward procedure start(L:array(range) of integer)
declarations
T: array(1..LIM) of integer
end-declarations
forall(i in 1..LIM) T(i):=round(.5+random*LIM)
writeln(T)
start(T)
writeln(T)
"Declaration v. definition…"
Further Mosel
! swap the positions of two numbers in an array
procedure swap(L:array(range) of integer,
i,j:integer)
k:=L(i)
L(i):=L(j)
L(j):=k
end-procedure
! main sorting routine
procedure qsort(L:array(range) of integer,
s,e:integer)
! Determine partitioning value
V:=L((s+e) div 2)
i:=s; j:=e
repeat ! Partition into two subarrays
while(L(i)<V) i+=1
while(L(j)>V) j-=1
if(i<j) then
swap(L,i,j)
i+=1; j-=1
end-if
until i>=j
! Recursively sort the two subarrays:
if(j<e and s<j) then
qsort(L,s,j)
end-if
if(i>s and i<e) then
qsort(L,i,e)
end-if
end-procedure
! start of the sorting process
procedure start(L:array(r:range) of integer)
qsort(L,getfirst(r),getlast(r))
end-procedure
end-model
リスト 6.26 サブルーティンの前進型宣言
Topics
クイックソートアルゴリズムの概念は、ソートされる配列を2つに分割することである。これらの
一つは分割値よりも小さなすべての値を含むし、またもう一つはこの値よりも大きなすべての値を
含む。分割操作は、すべての値がソートされるまで、再帰的に2つの部分配列に対して適用される。
演習問題 リスト6.26にあるモデルを入力せよ。あるいは前の例に対して、すべてのサブルーティン
107
の定義をプログラムの最後におくように修正せよ。
をして、いくつかの例を用いて実験せよ。
forwardキーワードは、モデルファイルに何らかの構造を与え、それらをより連続的なものにする場
合に特に有用である。モデルに関する詳細をすべてサブルーティンの中におき、これらについての
詳細な記述を最後におくことによって、プログラムの主要な流れが明白になる。
ここに至って、Mosel モデルプログラミング言語の諸特性を利用することによって、より複雑なモ
デルを作成し、好きなインターフェイスを用いて解くことが可能となっていることに気づいたであ
ろう。これらの開発過程においては、Mosel言語のさらなる特性が必要となるかも知れないが、これ
らについてはMosel Reference Manualを参照されたい。次の最終章では、これまで用いた用語に関
する何らかのまとめを与える。
まとめ
本章では、以下のことを学んだ。:
いろいろな次元を有する固定サイズあるいは動的配列を初期化する;
外部ソースやアプリケーションを用いてモデルデータを入力あるいは転送する;
条件付表現あるいは変数を作成する;
選択あるいはループ構造を作成する;
関数あるいは手順を書く.
108
第7章
用語のまとめ
2値変数(binary variable)
解において、0か1のいずれかの値をとる決定変数。2値変数を含む問題は、混合型整数計画問題で
ある。
境界値(bound)
決定変数に関する単純な上界値あるいは下界値を与えたり、または決定変数をある値に固定させる
のに用いられる簡単な制約条件。
制約条件(constraint)
最適解における決定変数の値が満たすべき線形不等式(または等式)。
制約条件(constraint type)
5つの型の制約条件がある。すなわち、(より大きい、または等しい), (より小さい、または等しい),
(等しい), 領域が与えられているか無制約, たとえば目的関数。
連続変数(continuous variable)
0と無限大の間(一般には何らかの下限と上限の間)の値をとる決定変数。1次変数とも呼ばれる。
制御(control)
求解過程に影響するような中のパラメタ。
..
=
決定変数(decision variable)
最適化によって値が決定される。線形計画法 (LP)においては、すべての決定変数は線形(あるいは
連続)で、0と無限大の間(一般には何らかの下限と上限の間)の値をとる。混合型整数計画法 (MIP)
においては、変数によっては2値あるいは整数値、あるいは特定の順序付集合となる。単に‘変数’
と呼ばれることもある。
dj
リデューストコストを見よ。
双対値(dual value)
制約条件の右辺値の単位量の変化に伴う目的関数値の変化量。シャドウプライスー制約条件によっ
て割り当てられる資源の‘価格’ーと呼ばれることもある。双対値は制約条件がどれだけきついかを表
す基準である。制約条件がきつい場合は、少しだけ緩和されたとすると、目的関数値がよりよくな
ることが期待される。双対値はこれに対する数値的基準を与える。一般に、行の右辺値が1だけ増加
すると、目的関数値は行の双対値だけ増加する。より具体的には、双対値は限界的な概念であるの
で、右辺値が十分少量だけ増加すると、目的関数値は双対値だけ増加することになる。
グローバル要素(global entity)
2値あるいは整数値、あるいは部分的整数あるいは半連続変数、あるいは特定の順序付集合。
入力コスト(input cost)
The original objective coefficient of a variable.
整数計画問題(IP problem)
混合型整数計画問題 (MIP) の別名で、特に連続変数を含まない問題。
.
109
™
™ ⋅Glossary of
整数変数(integer variable)
0, 1, 2, など上限値までのいずれかの値をとる決定変数。整数変数を含む問題は混合型整数計画問
題である。
キーワードkeyword (in Mosel)
Xpress-MP model の中のキーワードは、モデルのコマンドかあるいはブロックを導入/終了するかで
ある。Mosel モデルプログラミング言語の要素か、または読み込まれたライブラリーモジュールか
らの要素かのいずれかである。典型的なキーワードはdeclarations とusesである。
線形表現(linear expression)
constant decision variableの形を有する項(あるいは項の和)。
線形不等式あるいは等式(linear inequality or equation)
定数項(右辺値)に対して‘より大きい、または等しい’, ‘より小さい、または等しい’, ‘等しい’のいず
れかが成立するという線形表現。
線形計画法 (LP) problem
線形の決定変数、制約条件、目的関数からなる決定問題。制約条件と目的関数は決定変数の1次関
数である。データ値(すなわち変数の係数と制約条件の定数項)はすべて既知である。
1次変数(linear variable)
0と無限大の間(一般には何らかの下限と上限の間)の値をとる決定変数。連続変数とも呼ばれる。
混合型整数計画問題(mixed integer programming (MIP) problem)
いくつかのグローバル要素、すなわち2値変数あるいは整数変数、あるいは特定の順序付集合を含
む線形計画問題。
モデル(model)
問題を定義する決定変数、制約条件、目的関数、そしてデータの集合。問題に対するXpress-MP表現
を意味する場合もある。
モデルの例(model instance)
明示的なデータ、すなわちデータとパラメタの値、を完備したモデル構造。
モデルプログラム(model program)
解くための指令を備えたモデル。これらはMoselによって実行され、Moselモデルプログラミング言
語で書かれている。
モデルの構造(model structure)
決定変数、データ表、制約条件に関する定義とそれらの間の代数的関係であって、データとパラメ
タの値は明示されていない。
目的関数(objective function)
決定変数の値を選択することによって最適化(最大化あるいは最小化)される線形あるいは2次表現。
最適解(optimal solution)
目的関数の値を最適(最大あるいは最小)にする解。
部分的整数変数(partial integer variable)
解において、0, 1, 2, など上限値までのいずれかの値をとり、それを超える部分が連続値である決
定変数。部分的整数変数を含む問題は混合型整数計画問題である。
問題の特性(problem attribute)
求解過程においてOptimizerによって設定される値で、ライブラリー利用者によって検索可能である。
これは解くべき問題あるいは解の重要な特性である。
110
リデューストコスト(reduced cost)
決定変数の目的関数における係数値で、当該変数が限界から動いた場合の変化量を表す。
場合によっては、‘dj’と表されることもある。
右辺値(right hand side (RHS))
制約条件における定数項。慣例として、Xpress-MPでは必要ではないが、値は制約条件の右辺に書か
れる。
半連続変数(semi-continuous variable)
解の決定変数で、0か下限値と上限値の間の連続値をとる。半連続変数を含む問題は混合型整数計画
問題である。
シャドウプライス(shadow price)
双対値を見よ。
スラック値(slack value)
制約条件と右辺値の差。
解(solution)
制約条件を満たす決定変数の値の集合。最適解を見よ。
特定順序付集合(special ordered set (SOS))
特定の条件を満たさねばならない変数の順序付集合。型1の特定順序付集合( ‘SOS1’ か ‘S1 set’)は
たかだか1個の非零変数を含む。型2の特定順序付集合( ‘SOS2’ か ‘S2 set’)はたかだか2個の非零
変数を含み、2つの変数が非零の場合は、それらの順序はお互いに隣り合っていなければならない。
Xpress-MPにおいては、順序は‘参照行reference row’として与えられ、それらは通常の制約条件であ
るか、または別の無制約条件である。変数が整数値をとらなければならないという条件はない。
変数(variable)
決定変数を見よ。
111
索引
記号Symbols
! コメントcommentsを見よ
\0 無終了null-terminatedを見よ
\n 新行文字newline characterを見よ
\t タブ文字tab characterを見よ
¦ 条件付オペレーターconditional operatorを見よ
A
現問題active problem 17, 33, 34, 55, 74
アルゴリズムalgorithm 40, 44, 78
設定setting 40, 78
配列arrays
バイト配列byte arrays 102
動的配列dynamic arrays 133, 146, 147, 157, 160
入データentering data 144, 146, 148
固定サイズ配列fixed size arrays 146
多次元配列multi-dimensional arrays 144
疎配列sparse arrays 146, 157
as 149
B
バッチモードbatch mode 26, 32
BCL 48, 61
制約条件constraints 63, 64, 68
エラーチェックerror checking 95
ヘッダーファイルheader file 65
初期化initialization 62
初期化と終了initialization and termination 62
Optimizer にモデルを読み込むloading models in the Optimizer 61, 98
ログファイルlog files 67
メモリー管理memory management 66
メッセージレベルmessage level 67
目的関数objective function 64
最適化optimization 64, 65
sense 73
問題管理problem management 62, 66, 96
問題ポインターproblem pointer 98
プログラム出力program output 67
返却値return values 95
解情報solution information 65
変数variables 62, 67
Optimizer ライブラリーを用いたwith the Optimizer library 61, 96
行列ファイルを書くwriting matrix files 71
ブロックblocks 120
112
宣言declarations 120, 130, 133
関数functions 171
初期化initializations 130, 134, 149
モデルmodel 120
パラメタparameters 135, 162
手続きprocedure 169
限界値bounds 62, 88, 177
条件付conditional 159
分枝限定法Branch and Bound 43
強盗問題Burglar Problem 118
バイト変換ByteConversion 101
C
コールバックcallbacks 84, 104, 113
ケースcase 164
cload 31
列columns 40, 76, 86, 87
変数variablesを見よ
コメントcomments 126
コンパイルcompile 29
条件付オペレーターconditional operator 160
コンソールConsole Xpress 4, 5, 25
現問題active problem 33, 34
Xpress-MP Essentials Index 184
バッチモードbatch mode 32
モデルファイルをコンパイルするcompiling model files 29
制御controls. See controls
デバッグdebugging 30
整数問題integer problems 42
読み込まれたモデルのリストlist of loaded models 34
問題を読み込むloading problems 30, 37
モデル管理model management 33, 35
Mosel. See Mosel
最適化optimization 29, 37
Optimizer. See Optimizer
モデルを実行するrunning models 30, 137, 170
解情報solution information 31, 37
行列ファイルを書くwriting matrix files 35
制約条件constraints 12, 40, 86, 119, 177
条件付conditional 159
限界値boundsをも見よ。
連続行continuation lines 121
制御controls 3, 43, 44, 81, 82, 111, 177
ライブラリー接頭辞library prefix 82
作成するcreate 133, 146
D
データベースdatabases 3, 152
113
デバッグdebugging 14, 30, 51, 95, 163, 170
決定変数decision variables. See variables
宣言declarations 120, 130, 133
DEFAULTALG 44
削除するdelete 35
提示するdisplay 31
dj. リヂューストコストreduced costを見よ。
DLLs 4, 52
実行するdo 164
DoubleHolder 110
双対値dual values 40, 54, 178
動的dynamic 146
E
elif 161
else 161, 164
要素entities. グローバル要素global entitiesを見よ。
エラーチェックerror checking 95, 111
エラーメッセージerror messages 14, 30
終了コードexit codes 95
転送データexporting data 148
スプレッドシートへto spreadsheets 153
テキストファイルへto text files 151
writelnを用いる 158
exportprob 35, 161
F
F_APPEND. ファイルfiles, データを追加するappending dataを見よ
F_INPUT. 入力列input streamを見よ
F_OUTPUT. 出力列output streamを見よ
fclose 157, 159
フィボナッチ列Fibonacci sequence 165
ファイル形式file formats
データファイルdata files 149
LP形式LP format 36, 73
疎データ形式sparse data format 147
ファイルfiles
データを追加するappending data 158
バッチファイルbatch files 4
バイナリーモデルファイルbinary model files (.bim) 14, 30
Excel (.xls) 155
ヘッダーファイルheader files (.h) 50, 65, 75
logファイルlog files (.log) 67, 84
LP行列ファイルLP matrix files (.lp) 19, 36, 59, 71
Mosel ファイルfiles (.mos) 28, 49
MPS行列ファイルmatrix files (.mat) 19, 35, 59, 71
解ファイルsolution files (.prt) 38, 39, 76
終了するfinalize 141
114
fopen 158, 159
forall 125, 165
forward 170, 174
function 171
関数functions 171
再帰recursion 173
G
getobjval 123
getparam 157
getsol 127
GLOBAL 43
グローバル要素global entities 38, 93, 178
グローバル探索global search 43, 80
グラフ化graphing 15, 21
H
ハイカー問題Hiker Problem 135
I
if 161
データを読み込むimporting data 148
テキストファイルからfrom text files 130, 149
readlnを用いて 156
添字集合index sets 140
初期化initialization 140
数値指標numerical indices 124
オペレーターoperators 142
記号列指標string indices 127, 132
初期化initialization 50, 62, 74
initializations 130, 134, 149
入力コストinput cost 40, 178
入力列input stream 156, 158
ソフトウェアをインストールするinstalling software 2, 6
整数integer 124, 145
整数計画法 41, 42, 79, 93, 119,
178
整数解integer solutions. グローバル探索global searchを見よ
IntHolder 110
is_binary 121
is_integer 42, 79, 121
反復iteration. ループloopingを見よ
IVEaddtograph 21
IVEinitgraph 21
J
Java 4, 106
コールバックスcallbacks 113
文字配列と記号列character arrays and strings 111
エラーをチェックするchecking errors 111
115
制御と問題の特性controls and problem attributes 111
数値配列と参照numerical arrays and references 110
K
キーワードkeywords 13, 179
ナップサック問題knapsack problem 129
L
ライブラリー 4, 47
結合combining 96
構成要素components 48, 50
デバッグdebugging 51
エラーチェックerror checking 95
ヘッダーファイルheader files 50, 65, 75
メモリー管理memory management 56, 66, 75
Mosel. Mosel ライブラリーを見よ
Optimizer. Optimizerライブラリーを見よ
問題ポインターproblem pointers 55, 74, 98
返却値return values 95
線形計画法 3, 179
リストlist 35
load 30
ループlooping 125, 165
LP 緩和relaxation. グローバル探索global searchを
LPLOG 16
LPOBJVAL 91, 94
LPSTATUS 83
M
行列ファイルmatrix files 19, 35, 59, 71, 74
MAXIM 37
フラッグflags 41, 43
最大化maximize 123
メモリー管理memory management 56, 66, 74, 146
メルセンヌ素数Mersenne Primes 171
MINIM 37
最小化minimize 123
MIPOBJVAL 94
混合型mixed 整数計画法 3, 179
mmive 21
mmodbc 3, 152
mmxprs 122
mod 168
モデルmodel 180
データdata 118, 148
モデルを提示するdisplaying model 161
エディターeditor. Xpress-IVEを見よ
遺伝的generic 129
例instance 118, 129, 148, 180
116
キーワードkeywords 13, 179
モデル管理model management 33, 35, 54
モデルプログラムmodel program 2, 13, 28, 122, 180
構造structure 180
モデルmodel 120
モデリングmodeling
言語language 9, 26, 48, 117, 139
汎用性versatility 129
Mosel 2, 9, 26
現問題active problem 33, 34
バッチモードbatch mode 32
バイナリーモデルファイルbinary model files 14, 30
コンパイラーライブラリーcompiler library. See Mosel ライブラリー
モデルファイルをコンパイルするcompiling model files 13, 29, 50
デバッグdebugging 12, 30
フラッグflags 32
グラフ利用者インターフェイスgraphical user interface 4, 9
ライブラリー. See Mosel ライブラリー
ライブラリーモジュールlibrary modules 2, 26
ODBC, mmodbc 3, 152
Optimizer, mmxprs 2, 122
読み込まれたモデルのリストlist of loaded models 34
モデルを読み込むloading models 14, 30
メモリー管理memory management 146
モデル管理model management 33, 35
モデルプログラムmodel program. See model
最適化optimization 12, 29
パラメタparameters 30, 51, 135, 137, 163, 170
実行時間ライブラリーrun time library. See Mosel ライブラリーを見よ
モデルを実行するrunning models 14, 30
コマンドを短くするshortening commands 31
解情報solution information 31, 123
行列ファイルを書くwriting matrix files 19, 35
Mosel 言語 language. モデリングmodelingを見よ
Mosel ライブラリー 48, 49
コンパイラーライブラリーcompiler library 50
モデルファイルをコンパイルするcompiling model files 50, 51
エラーチェックerror checking 95
ヘッダーファイルheader files 50
初期化と終了initialization and termination 50
モデルの実行を中止するinterrupting a model run 58
読み込まれたモデルのリストlist of loaded models 55
モデルを読み込むloading models 49, 51
モデル管理model management 51, 54, 56, 58
問題ポインターproblem pointer 55
返却値return values 95
117
実行時間ライブラリーrun time library 50
解情報solution information 52, 53
行列ファイルを書くwriting matrix files 59
mosel See Mosel
MPS file. See matrix files
mpvar 120, 146
マルチプロセッサー計算multiprocessor computing 3
N
新行文字newline character 162
零終了null-terminated 89
O
目的関数objective function 12, 40, 88, 120, 180
最大化maximizing 37, 65, 122
最適値optimum value 14, 31, 53, 91, 94, 180
解を得るobtaining a solution. 解solutionを見よ
ODBC 152
Optimizer 3, 9, 36, 74
アルゴリズムalgorithm. アルゴリズムalgorithmを見よ
制御controls. 制御controlsを見よ
入力ファイルinput files 36, 74
ライブラリーlibrary. Optimizerライブラリーlibraryを見よ
log ファイルfiles 84
行列ファイルmatrix files 36, 76
メモリー管理memory management 74
メッセージレベルmessage level 85
Mosel モジュールmodule. Moselを見よ
出力output 84
パラレルparallel 3
性能performance. 性能調整performance tuningを見よ
後処理postsolve 81
前処理presolve 80
問題の特性problem attributes. 問題problemを見よ
特性attributes
解solution 37, 40, 76
脈絡安全thread-safety 74
Optimizerライブラリーlibrary 48, 74, 99
行/列名を追加するadding row/column names 90
高度ライブラリー関数advanced library functions 74, 86
アルゴリズムalgorithm. アルゴリズムalgorithmを見よ
コールバックス関数callback functions 84
制御controls. 制御controlsを見よ
エラーチェックerror checking 95
初期化と終了initialization and termination 74
log ファイルfiles 84
行列matrix 86, 92
メモリー管理memory management 74
118
最適化optimization 74, 76
出力output 84
問題の特性problem attributes. See problem
特性attributes
問題の入力problem input 74, 76, 86, 98
問題ポインターproblem pointer 74, 98
返却値return values 95
解情報solution information 76, 90, 91, 94
脈絡安全thread-safety 74
解を理解するunderstanding the solution 76
with BCL 61, 96
optimizer Console Xpressを見よ
出力列output stream 158
P
パラメタparameters 30, 51, 135, 137, 170
parameters 135, 162
完全数perfect numbers 171
性能調整performance tuning 43, 81
後処理postsolve 81
PRESOLVE 82
前処理presolve 80
設定を変更するchanging settings 82
素数prime numbers 168
メルセンヌMersenne 171
PRINTSOL 38
問題の特性problem attributes 82, 111, 181
ライブラリー接頭辞library prefix 82
問題名problem name 27, 40, 120
問題の統計量problem statistics 20, 37, 38, 67
procedure 169
手続きprocedures 169
再帰性recursion 173
Q
2次計画法 3
クイックソートアルゴリズムquick sort algorithm 174
QUIT 27
停止quit 27
R
read / readln 156
READPROB 37
再帰性recursion 173
リヂューストコストreduced cost 40, 54, 181
repeat 157, 167
制限restrictions. トライアルモードtrial mode
returned 171
行rows 38, 40, 86, 87
119
制約条件constraintsを見よ
run 30, 137, 170
S
スカラーscalars 129
安全システムsecurity system 10, 27, 52
select 35
選択selections 162
スラック値slack values 40, 54, 181
ソフトウェアのインストールsoftware installation 2, 6
解solution 14, 39, 53, 65, 90, 181
グラフgraphs 15, 21
出力を理解するunderstanding output 40, 76
観察するviewing 37, 76, 123, 127
疎sparsity 88, 146
特定順序付き集合Special Ordered Sets (SOS) 38, 94, 181
スプレッドシートspreadsheets 3, 152
配列規模array sizing 155
Microsoft Excel 154
SQL 153
SQLconnect 153, 154, 156
SQLdisconnect 153, 154, 156
SQLexecute 153, 154, 156
SQLreadinteger 156
sqrt 168
string 124, 132, 134
記号列指標string indices 127
StringHolder 110
サブルーティンsubroutine ライブラリー. See ライブラリー
sum 125
総和summation 125
T
タブ文字tab character 166
テキストベースtext-based. Console Xpressを見よ
then 161
時間表times table 166
トライアルモードtrial mode 10, 27
U
until 167
uses 123
V
変数variables
配列array 67, 124
バイナリーbinary 119, 121, 177
条件付conditional 160
連続continuous 177
作成creation 133, 146
120
決定変数decision variables 12, 40, 86, 119, 178
動的配列変数dynamic array variables 133, 147, 160
整数integer 41, 79, 93, 121, 179
線形linear 179
部分的整数partial integer 180
半連続semi-continuous 181
添字付変数subscripted variables 124
vbNullString 103
Visual Basic 4, 99
引数型argument types, 100
コールバックスcallbacks 104
文字配列character arrays 101
NULL arguments 103
数値配列numerical arrays 100
W
警告メッセージwarning messages 14, 30
while 166
Windows DLLs. See DLLs
write / writeln 123, 158
WRITEPRTSOL 37, 38
X
XPRBaddterm 64
XPRBarrvar 68
XPRBctr 63
XPRBdelprob 66
XPRBexportprob 72
XPRBfree 66
XPRBgetobjval 65
XPRBgetsol 65
XPRBgetXPRSprob 98
XPRBinit 62
Xpress-MP Essentials Index 189
XPRBloadmat 98
XPRBmaxim 65
XPRBnewarrsum 69
XPRBnewarrvar 68
XPRBnewctr 63
XPRBnewprob 62, 98
XPRBnewvar 63
XPRBprob 62
XPRBsetmsglevel 67
XPRBsetobj 64
XPRBsetsense 73
XPRBsetterm 64
XPRBvar 63
Xpress-IVE 4, 9
121
ファイルを追加するadding files 11
制御オプションcontrol options 16
デバッグdebugging 12, 14
環境設定environment settings 22
キーワードメニューkeyword menu 13
モデルエディターmodel editor 10, 12
モデル管理model management 13, 14, 17
プロジェクト管理project management 10, 11
設定settings 22
解グラフsolution graphs 15, 21
ウィンドウwindows
構築枠Build pane 14
要素枠Entities pane 15
言語/タブ枠Language/Tabs pane 22
配置枠Locations pane 15
その他枠Misc pane 22
出力/入力枠Output/Input pane 14
プロジェクトファイル枠Project Files pane 10
Sim:Obj(iter) pane 15
利用者グラフ枠User Graph pane 21
writing matrix files 19
Xpress-MP 1
構成要素components 2
Console Xpress. Console Xpressを見よ
グラフ利用者インターフェイスgraphical user interface 9
インストールinstallation 2, 6, 27
インターフェイスinterfaces 4, 6
ライブラリー. See ライブラリー
ライセンスlicenses 10
Mosel. Moselを見よ
Optimizer. Optimizerを見よ
利用上の制限restrictions on use 10, 27
安全システムsecurity system 10
ライブラリーを設定する 2
Xpress-IVE. Xpress-IVEを見よ
xprm_mc 50
xprm_rt 50
XPRMalltypes 53
XPRMcompmod 51
XPRMexportprob 59
XPRMfindident 53
XPRMfree 50
XPRMgetdual 54
XPRMgetmodinfo 56
XPRMgetnextmod 56
XPRMgetobjval 53
122
XPRMgetrcost 54
XPRMgetslack 54
XPRMgetvsol 53
XPRMinit 50
XPRMisrunmod 58
XPRMloadmod 51
XPRMmodel 51
XPRMmpvar 53
XPRMrunmod 51
XPRMstoprunmod 58
XPRMunloadmod 56
XPRSaddnames 90
XPRSaddrows 81, 92
XPRSchgbounds 101
XPRScreateprob 75
XPRSdestroyprob 75
XPRSfree 75
XPRSgetdblattrib 83
XPRSgetdblcontrol 82
XPRSgetintattrib 83
XPRSgetintcontrol 82
XPRSgetnames 102
XPRSgetobj 100
XPRSgetsol 90
XPRSgetstrattrib 83
XPRSgetstrcontrol 82
XPRSinit 74
XPRSloadglobal 93
XPRSloadlp 86
XPRSmaxim 76
flags 78, 80
XPRSreadprob 76
XPRSsetcbmessage 85
XPRSsetdblcontrol 83
XPRSsetintcontrol 83
XPRSsetlogfile 84
XPRSsetstrcontrol 83
XPRSwriteprtsol 76
123
Fly UP