GLPK/使用 GLPSOL
此页面列出了一些使用 GLPSOL(GLPK 命令行求解器)时的技巧和提示。
请注意,默认情况下,GLPSOL 在构建 GLPK 时就已构建。因此,只要安装了 GLPK,GLPSOL 通常都应该存在。
用法
glpsol [options...] filename
例如,使用其长格式的选项
glpsol --cuts --fpump --mipgap 0.001 --model problem.mod --data problem.dat
以下信息来自用法选项--help.
一般选项
  --mps             read LP/MIP problem in fixed MPS format
  --freemps         read LP/MIP problem in free MPS format (default)
  --lp              read LP/MIP problem in CPLEX LP format
  --glp             read LP/MIP problem in GLPK format
  --math            read LP/MIP model written in GNU MathProg modeling
                    language
  -m filename, --model filename
                    read model section and optional data section from
                    filename (same as --math)
  -d filename, --data filename
                    read data section from filename (for --math only);
                    if model file also has data section, it is ignored
  -y filename, --display filename
                    send display output to filename (for --math only);
                    by default the output is sent to terminal
  --seed value      initialize pseudo-random number generator used in
                    MathProg model with specified seed (any integer);
                    if seed value is ?, some random seed will be used
  --mincost         read min-cost flow problem in DIMACS format
  --maxflow         read maximum flow problem in DIMACS format
  --simplex         use simplex method (default)
  --interior        use interior point method (LP only)
  -r filename, --read filename
                    read solution from filename rather to find it with
                    the solver
  --min             minimization
  --max             maximization
  --scale           scale problem (default)
  --noscale         do not scale problem
  -o filename, --output filename
                    write solution to filename in printable format
  -w filename, --write filename
                    write solution to filename in plain text format
  --ranges filename
                    write sensitivity analysis report to filename in
                    printable format (simplex only)
  --tmlim nnn       limit solution time to nnn seconds
  --memlim nnn      limit available memory to nnn megabytes
  --check           do not solve problem, check input data only
  --name probname   change problem name to probname
  --wmps filename   write problem to filename in fixed MPS format
  --wfreemps filename
                    write problem to filename in free MPS format
  --wlp filename    write problem to filename in CPLEX LP format
  --wglp filename   write problem to filename in GLPK format
  --log filename    write copy of terminal output to filename
  -h, --help        display this help information and exit
  -v, --version     display program version and exit
LP 基因分解选项
  --luf             LU + Forrest-Tomlin update
                    (faster, less stable; default)
  --cbg             LU + Schur complement + Bartels-Golub update
                    (slower, more stable)
  --cgr             LU + Schur complement + Givens rotation update
                    (slower, more stable)
单纯形求解器特有的选项
  --primal          use primal simplex (default)
  --dual            use dual simplex
  --std             use standard initial basis of all slacks
  --adv             use advanced initial basis (default)
  --bib             use Bixby's initial basis
  --ini filename    use as initial basis previously saved with -w
                    (disables LP presolver)
  --steep           use steepest edge technique (default)
  --nosteep         use standard "textbook" pricing
  --relax           use Harris' two-pass ratio test (default)
  --norelax         use standard "textbook" ratio test
  --presol          use presolver (default; assumes --scale and --adv)
  --nopresol        do not use presolver
  --exact           use simplex method based on exact arithmetic
  --xcheck          check final basis using exact arithmetic
内点求解器特有的选项
--nord use natural (original) ordering --qmd use quotient minimum degree ordering --amd use approximate minimum degree ordering (default) --symamd use approximate minimum degree ordering
MIP 求解器特有的选项
  --nomip           consider all integer variables as continuous
                    (allows solving MIP as pure LP)
  --first           branch on first integer variable
  --last            branch on last integer variable
  --mostf           branch on most fractional variable
  --drtom           branch using heuristic by Driebeck and Tomlin
                    (default)
  --pcost           branch using hybrid pseudocost heuristic (may be
                    useful for hard instances)
  --dfs             backtrack using depth first search
  --bfs             backtrack using breadth first search
  --bestp           backtrack using the best projection heuristic
  --bestb           backtrack using node with best local bound
                    (default)
  --intopt          use MIP presolver (default)
  --nointopt        do not use MIP presolver
  --binarize        replace general integer variables by binary ones
                    (assumes --intopt)
  --fpump           apply feasibility pump heuristic
  --gomory          generate Gomory's mixed integer cuts
  --mir             generate MIR (mixed integer rounding) cuts
  --cover           generate mixed cover cuts
  --clique          generate clique cuts
  --cuts            generate all cuts above
  --mipgap tol      set relative mip gap tolerance to tol
CNF-SAT 可满足性问题的选项
--cnf filename read CNF-SAT problem in DIMACS format from filename --wcnf filename write CNF-SAT problem in DIMACS format to filename --minisat solve CNF-SAT problem with glp_infeas1 solver --objbnd bound add inequality bounds to 0-1 feasibility problem (assumes --minisat)
通过追加后缀可以减小输出文件的大小.gz。 [1] 这表示gzip 压缩。例如
glpsol ... --wlp squash.lp.gz
类似地,GLPSOL 将自动解压缩它遇到的任何以扩展名结尾的文件.gz.
GLPSOL 支持以下三个标准流
- /dev/stdin
- /dev/stdout
- /dev/stderr
这些由 GLPK I/O 例程以平台无关的方式视为特殊文件名。因此,以下命令应该在 Windows、Mac OS X 和 Linux 上都能正常工作,将求解报告传递到终端而不是传递到普通文件
glpsol .. --output "/dev/stdout"
如果您需要通过命令行传递参数值,以下示例演示了如何使用shell 脚本 来执行此操作。
shell 脚本,要么是test.bat或者test.sh,首先创建一个动态数据文件test.dat,其中包含所需的命令行值。然后,shell 脚本调用 GLPSOL,使用一个硬编码的模型名称,在本例中,该名称只是简单地打印最初从命令行传递的值。
| 步骤 | Microsoft Windows | Linux 和 Mac OS X [2] | 
|---|---|---|
| 创建一个模型文件 | test.mod param p; printf "p = %f\n", p; end; | |
| 创建一个 shell 脚本文件 | test.bat echo data;param p := %1;end; > test.dat
glpsol.exe -m test.mod -d test.dat
 | test.sh [3] #!/bin/sh
echo data\;param p := $1\;end\; > test.dat
glpsol -m test.mod -d test.dat
 | 
| 使该文件可执行 | 什么也不做 [4] | chmod u+x test.sh | 
| 运行 shell 脚本 | test.bat 3.14159 | ./test.sh 3.14159 | 
请注意,您可以在 shell 脚本中指定多个数据文件,例如
glpsol -m test.mod -d one.dat -d two.dat -d three.dat
如果再稍微发挥点巧思,就可以将大量信息传递到 shell 脚本,脚本本身可以在进行内部调用时展现一定的智能(参见GLPK/Scripting_plus_MathProg)。
该xglpsol bash 脚本(您可以根据需要将其重命名)为 GLPSOL 命令行求解器提供了一个简化的接口。例如,命令
$ xglpsol -dkrsw short
生成并运行 GLPSOL 调用
glpsol --scale --nopresol --nointopt --ranges "/dev/stdout" --output "/dev/stdout" --glp short.glpk
然后,它将屏幕截图保存到short.grab,并将其与以前的屏幕截图文件进行diff。
此脚本使用户能够快速更改和查看不同 GLPSOL 选项的效果。其他 GLPSOL 选项可以轻松添加,例如,控制 MIP 行为的选项。来自xglpsol的帮助消息仅供参考。
             usage: xglpsol                model[.ext]     basic GLPSOL run
                    xglpsol  --            model[.ext]     basic GLPSOL run (for convenience)
                    xglpsol  -acdklmrswy   model[.ext]     extended run
                    xglpsol  --help                        display this message and exit (takes priority)
       run options:   -a                   implies -lms
                      -c                   check model            --check
                      -l                   add back LP presolve   --nopresol | --presol
                      -m                   add back MIP presolve  --nointopt | --intopt
                      -s                   add back scaling       --noscale  | --scale
    output options:   -d                   diff with the last available capture (implies -k)
                      -k                   keep console output (with existing file backed up)
                      -r                   display sensitivity analysis (simplex only)  --ranges
                      -w                   display solution (includes KKT)              --output
                      -y                   dry run, simply print the GLPSOL call
        extensions: model.glpk             GLPK problem      --glp
                    model.lp               CPLEX LP problem  --lp
                    model.mod              MathProg model    --math
                    model.mps              free MPS problem  --freemps
           purpose: simplified interface to GLPK GLPSOL command-line solver
         hardcodes: GLPSOL utility             = glpsol
                    default extension          = .glpk
                    terminal capture extension = .grab
                    diff call                  = diff --side-by-side --suppress-common-lines --width=167
可以从下面折叠的表格中复制 bash 源代码。xglpsol是根据知识共享署名-相同方式共享许可授权的。
| xglpsol.sh | 
|---|
| #! /bin/bash
#  LEGAL
#
#  Copyright: (c) 2011 Robbie Morrison. Some rights reserved.
#  License: this code is licensed under a Creative Commons BY-SA.
#  http://www.creativecommons.org/licenses/by-sa/3.0/
#  Version: $Id: xglpsol 6703 2011-05-07 07:56:57Z robbie $
#  OVERVIEW
#
#  This script provides a simplified interface to the
#  GLPK GLPSOL command-line solver.  It pumps out
#  GLPSOL command-lines, can diff recent output, and
#  generally facilitates experimentation.
#
#  The script was developed on Linux Ubuntu 10.04 using
#  Bash 4.1.5.  It should work on older versions of
#  Bash too.
# ---------------------------------
#  user modifiable
# ---------------------------------
EXTN="glpk"                             # assumed extension if no extension given
WIDTH=$(stty size | awk '{ print $2 }') # the 'diff' default is often 130 but my screen is wider
DIFF="diff --side-by-side --suppress-common-lines --width=$WIDTH"
# ---------------------------------
#  preamble
# ---------------------------------
GLPSOL="glpsol"                         # GLPSOL call
LOG="grab"                              # terminal capture extension
SCRIPT=$(basename "$0")
# script exit codes
E_SUCCESS=0
E_FAILURE=1
E_USAGE=2
E_GLPSOL_NOT_FOUND=3
E_FILE_NOT_FOUND=4
E_EXTN_NOT_SUPPORTED=5
E_OTHER=64
# ---------------------------------
#  display_help()
# ---------------------------------
function display_help
{
    cat << EOM
             usage: $SCRIPT                model[.ext]     basic GLPSOL run
                    $SCRIPT  --            model[.ext]     basic GLPSOL run (for convenience)
                    $SCRIPT  -acdklmrswy   model[.ext]     extended run
                    $SCRIPT  --help                        display this message and exit (takes priority)
       run options:   -a                   implies -lms
                      -c                   check model            --check
                      -l                   add back LP presolve   --nopresol | --presol
                      -m                   add back MIP presolve  --nointopt | --intopt
                      -s                   add back scaling       --noscale  | --scale
    output options:   -d                   diff with the last available capture (implies -k)
                      -k                   keep console output (with existing file backed up)
                      -r                   display sensitivity analysis (simplex only)  --ranges
                      -w                   display solution (includes KKT)              --output
                      -y                   dry run, simply print the GLPSOL call
        extensions: model.glpk             GLPK problem      --glp
                    model.lp               CPLEX LP problem  --lp
                    model.mod              MathProg model    --math
                    model.mps              free MPS problem  --freemps
           purpose: simplified interface to GLPK GLPSOL command-line solver
         hardcodes: GLPSOL utility             = $GLPSOL
                    default extension          = .$EXTN
                    terminal capture extension = .$LOG
                    diff call                  = $DIFF
EOM
}
# ---------------------------------
#  process long-form options
# ---------------------------------
case "$1" in
    --help|--hel|--he|--h|-help|-hel|-he|-h|"-?")
        display_help
        exit $E_SUCCESS
        ;;
esac
# ------------------------------
#  process short-form options
# ------------------------------
# capture command-line
cline=$(echo $SCRIPT $*)
# set the default flags
usageflag="0"
storeflag="0"
rangeflag="0"
writeflag="0"
sdiffflag="0"
dummyflag="0"
lppreflag="0"
mipreflag="0"
scaleflag="0"
checkflag="0"
# process options
while getopts ":-acdhklmrswy" option  # CAUTION: the leading : should be correct
do
    case "$option" in
        -)  :                          ;; # this codes for option "--" and do nothing is correct
        h)  usageflag="1"              ;;
        d)  sdiffflag="1"              ;;
        k)  storeflag="1"              ;;
        r)  rangeflag="1"              ;;
        w)  writeflag="1"              ;;
        y)  dummyflag="1"              ;;
        a)  lppreflag="1"; mipreflag="1"; scaleflag="1" ;;
        c)  checkflag="1"              ;;
        l)  lppreflag="1"              ;;
        m)  mipreflag="1"              ;;
        s)  scaleflag="1"              ;;
        *)
            echo "$SCRIPT: incorrect usage, try --help"
            exit $E_USAGE
            ;;
    esac
done
shift $(($OPTIND - 1))
#  the above decrements the argument pointer so it points to next
#  argument, hence $1 now references the first non-option supplied
#  on the command-line, in the event that substantive arguments
#  were given
# process help in multiple options
case "$usageflag" in
    1)
        display_help
        exit $E_SUCCESS
        ;;
esac
file="$1"
# rework the flags for some cases
case "$checkflag" in
    1) sdiffflag="0"                ;;
esac
case "$dummyflag" in
    1) sdiffflag="0"; storeflag="0" ;;
esac
case "$sdiffflag" in
    1) storeflag="1"                ;;
esac
# ---------------------------------
#  lead-up code
# ---------------------------------
# presume success
exitval=0
# confirm glpsol
test $(which "$GLPSOL") ||
{
    echo "$SCRIPT: GLPSOL not found: $GLPSOL"
    exit $E_GLPSOL_NOT_FOUND
}
# process filename
extn=${file##*.}                        # grab extension
test "$extn" == "$file" &&              # indicates no extension given
{
    extn="$EXTN"
    file="$file.$extn"
}
case "$extn" in
    glpk) fileopt="--glp"      ;;
    lp)   fileopt="--lp"       ;;
    mod)  fileopt="--math"     ;;
    mps)  fileopt="--freemps"  ;;
    *)
        echo "$SCRIPT: FATAL: model extension not supported: .$extn"
        exit $E_EXTN_NOT_SUPPORTED
        ;;
esac
stub=$(basename "$file" ".$extn")
# confirm model file
test -f "$file" ||
{
    echo "$SCRIPT: FATAL: input file not found: $file"
    exit $E_FILE_NOT_FOUND
}
# obtain some run-time details
lines=$(wc --lines "$file" | gawk '{ print $1 }')
tstamp=$(date "+%Z %z %a %d-%b-%Y %H:%M:%S")
# ---------------------------------
#  create GLPSOL call
# ---------------------------------
REDIRECT="/dev/stdout"                  # location of STDOUT
REDIRECT="\"$REDIRECT\""                # place in double-quotes
options=""
case "$checkflag" in
    0) :                                      ;;
    1) options="$options --check"             ;;
esac
case "$scaleflag" in
    0) options="$options --noscale"           ;;
    1) options="$options --scale"             ;;
esac
case "$lppreflag" in
    0) options="$options --nopresol"          ;;
    1) options="$options --presol"            ;;
esac
case "$mipreflag" in
    0) options="$options --nointopt"          ;;
    1) options="$options --intopt"            ;;
esac
case "$rangeflag" in
    0) :                                      ;;
    1) options="$options --ranges $REDIRECT"  ;;
esac
case "$writeflag" in
    0) :                                      ;;
    1) options="$options --output $REDIRECT"  ;;
esac
call="$GLPSOL$options $fileopt $file"
# ---------------------------------
#  call code
# ---------------------------------
test -f "$stub.$LOG" && mv --force "$stub.$LOG" "$stub.$LOG~"
{                                       # local block used to redirect output
    echo
    echo "  time    : $tstamp"
    echo "  cline   : $cline"
    echo "  model   : $file"
    echo "  lines   : $lines"
    echo "  call    : '$call'"
    echo
    case "$dummyflag" in
        0)
            eval "$call"
            exitval=$?                  # capture return
            ;;
        1)
            echo "  dry run, GLPSOL call shown above"
            ;;
    esac
    echo
    echo "  return  : $exitval"
    echo "  elapsed : $SECONDS"
    echo
} >> "$stub.$LOG"
cat "$stub.$LOG"
test "$storeflag" == "0" && rm --force "$stub.$LOG"
# ---------------------------------
#  diff code
# ---------------------------------
case "$sdiffflag" in
    1)
        test -f "$stub.$LOG" -a -f "$stub.$LOG~" &&
        {
            echo "  diff output : $stub.$LOG : $stub.$LOG~"
            echo
            $DIFF "$stub.$LOG" "$stub.$LOG~"
            echo
        }
        ;;
esac
# ---------------------------------
#  housekeeping
# ---------------------------------
exit $exitval
#  end of file
 | 
模型文件可能包含机密数据,需要通过加密进行保护。可以使用GNU Privacy Guard轻松加密模型文件。
gpg --output tsp.enc --encrypt --recipient user@example.com tsp.mod
为了避免将解密后的模型写入磁盘,可以通过管道将其传递给 glpsol。
gpg --decrypt tsp.enc | glpsol -m /dev/stdin
Set Xs;
Set Ys;
Param pcs {Ys, Xs};
Param pd {Xs};
Param ps {Ys};
Var vq{Ys, Xs} >= 0;
Minimize obj:
 Sum {I in Ys, j in Xs} pcs [i,j] * vq[i,j];
Subject to Ps {i in Ys}:
 Sum {j in Xs} Vq[i,j] <= ps [i];
Subject to Pd {j in Xs}:
 Sum {i in Ys} vq[i,j] = pd[j];
Solve;
End;