lpsolve 5.5.10.i
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Rakefile +78 -0
- data/VERSION +1 -0
- data/doc/Doxyfile +1127 -0
- data/doc/run_doxygen +107 -0
- data/doc/typos.txt +29 -0
- data/example/boilerplate.rb +8 -0
- data/example/demo.rb +223 -0
- data/example/lp.lp +9 -0
- data/example/lp.mps +25 -0
- data/example/model.lp +8 -0
- data/example/model.mps +16 -0
- data/example/rubydemo.rb +215 -0
- data/ext/Makefile +187 -0
- data/ext/extconf.rb +11 -0
- data/ext/lpconsts.c +174 -0
- data/ext/lpsolve.c +2915 -0
- data/test/Rakefile +8 -0
- data/test/lp_model.right +24 -0
- data/test/lpsolve.right +60 -0
- data/test/mps_model.right +24 -0
- data/test/test_lpsolve.rb +530 -0
- metadata +96 -0
data/ext/Makefile
ADDED
@@ -0,0 +1,187 @@
|
|
1
|
+
|
2
|
+
SHELL = /bin/sh
|
3
|
+
|
4
|
+
#### Start of system configuration section. ####
|
5
|
+
|
6
|
+
srcdir = .
|
7
|
+
topdir = /usr/local/include/ruby-1.9.1
|
8
|
+
hdrdir = /usr/local/include/ruby-1.9.1
|
9
|
+
arch_hdrdir = /usr/local/include/ruby-1.9.1/$(arch)
|
10
|
+
VPATH = $(srcdir):$(arch_hdrdir)/ruby:$(hdrdir)/ruby
|
11
|
+
prefix = $(DESTDIR)/usr/local
|
12
|
+
rubylibprefix = $(libdir)/$(RUBY_BASE_NAME)
|
13
|
+
exec_prefix = $(prefix)
|
14
|
+
vendorhdrdir = $(rubyhdrdir)/vendor_ruby
|
15
|
+
sitehdrdir = $(rubyhdrdir)/site_ruby
|
16
|
+
rubyhdrdir = $(includedir)/$(RUBY_BASE_NAME)-$(ruby_version)
|
17
|
+
vendordir = $(rubylibprefix)/vendor_ruby
|
18
|
+
sitedir = $(rubylibprefix)/site_ruby
|
19
|
+
ridir = $(datarootdir)/$(RI_BASE_NAME)
|
20
|
+
mandir = $(datarootdir)/man
|
21
|
+
localedir = $(datarootdir)/locale
|
22
|
+
libdir = $(exec_prefix)/lib
|
23
|
+
psdir = $(docdir)
|
24
|
+
pdfdir = $(docdir)
|
25
|
+
dvidir = $(docdir)
|
26
|
+
htmldir = $(docdir)
|
27
|
+
infodir = $(datarootdir)/info
|
28
|
+
docdir = $(datarootdir)/doc/$(PACKAGE)
|
29
|
+
oldincludedir = $(DESTDIR)/usr/include
|
30
|
+
includedir = $(prefix)/include
|
31
|
+
localstatedir = $(prefix)/var
|
32
|
+
sharedstatedir = $(prefix)/com
|
33
|
+
sysconfdir = $(prefix)/etc
|
34
|
+
datadir = $(datarootdir)
|
35
|
+
datarootdir = $(prefix)/share
|
36
|
+
libexecdir = $(exec_prefix)/libexec
|
37
|
+
sbindir = $(exec_prefix)/sbin
|
38
|
+
bindir = $(exec_prefix)/bin
|
39
|
+
rubylibdir = $(rubylibprefix)/$(ruby_version)
|
40
|
+
archdir = $(rubylibdir)/$(arch)
|
41
|
+
sitelibdir = $(sitedir)/$(ruby_version)
|
42
|
+
sitearchdir = $(sitelibdir)/$(sitearch)
|
43
|
+
vendorlibdir = $(vendordir)/$(ruby_version)
|
44
|
+
vendorarchdir = $(vendorlibdir)/$(sitearch)
|
45
|
+
|
46
|
+
CC = gcc
|
47
|
+
CXX = g++
|
48
|
+
LIBRUBY = $(LIBRUBY_A)
|
49
|
+
LIBRUBY_A = lib$(RUBY_SO_NAME)-static.a
|
50
|
+
LIBRUBYARG_SHARED = -Wl,-R -Wl,$(libdir) -L$(libdir) -l$(RUBY_SO_NAME)
|
51
|
+
LIBRUBYARG_STATIC = -Wl,-R -Wl,$(libdir) -L$(libdir) -l$(RUBY_SO_NAME)-static
|
52
|
+
OUTFLAG = -o
|
53
|
+
COUTFLAG = -o
|
54
|
+
|
55
|
+
RUBY_EXTCONF_H =
|
56
|
+
cflags = $(optflags) $(debugflags) $(warnflags)
|
57
|
+
optflags = -O3
|
58
|
+
debugflags = -ggdb
|
59
|
+
warnflags = -Wextra -Wno-unused-parameter -Wno-parentheses -Wpointer-arith -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long
|
60
|
+
CFLAGS = -fPIC $(cflags)
|
61
|
+
INCFLAGS = -I. -I$(arch_hdrdir) -I$(hdrdir)/ruby/backward -I$(hdrdir) -I$(srcdir)
|
62
|
+
DEFS = -D_FILE_OFFSET_BITS=64
|
63
|
+
CPPFLAGS = $(DEFS) $(cppflags)
|
64
|
+
CXXFLAGS = $(CFLAGS) $(cxxflags)
|
65
|
+
ldflags = -L. -rdynamic -Wl,-export-dynamic
|
66
|
+
dldflags =
|
67
|
+
ARCH_FLAG =
|
68
|
+
DLDFLAGS = $(ldflags) $(dldflags)
|
69
|
+
LDSHARED = $(CC) -shared
|
70
|
+
LDSHAREDXX = $(CXX) -shared
|
71
|
+
AR = ar
|
72
|
+
EXEEXT =
|
73
|
+
|
74
|
+
RUBY_BASE_NAME = ruby
|
75
|
+
RUBY_INSTALL_NAME = ruby
|
76
|
+
RUBY_SO_NAME = ruby
|
77
|
+
arch = i686-linux
|
78
|
+
sitearch = $(arch)
|
79
|
+
ruby_version = 1.9.1
|
80
|
+
ruby = /usr/local/bin/ruby
|
81
|
+
RUBY = $(ruby)
|
82
|
+
RM = rm -f
|
83
|
+
RM_RF = $(RUBY) -run -e rm -- -rf
|
84
|
+
RMDIRS = $(RUBY) -run -e rmdir -- -p
|
85
|
+
MAKEDIRS = /bin/mkdir -p
|
86
|
+
INSTALL = /usr/bin/install -c
|
87
|
+
INSTALL_PROG = $(INSTALL) -m 0755
|
88
|
+
INSTALL_DATA = $(INSTALL) -m 644
|
89
|
+
COPY = cp
|
90
|
+
|
91
|
+
#### End of system configuration section. ####
|
92
|
+
|
93
|
+
preload =
|
94
|
+
|
95
|
+
libpath = . $(libdir)
|
96
|
+
LIBPATH = -L. -L$(libdir) -Wl,-R$(libdir)
|
97
|
+
DEFFILE =
|
98
|
+
|
99
|
+
CLEANFILES = mkmf.log
|
100
|
+
DISTCLEANFILES =
|
101
|
+
DISTCLEANDIRS =
|
102
|
+
|
103
|
+
extout =
|
104
|
+
extout_prefix =
|
105
|
+
target_prefix =
|
106
|
+
LOCAL_LIBS =
|
107
|
+
LIBS = -lm -ldl -llpsolve55 -lm -lpthread -lrt -ldl -lcrypt -lm -lc
|
108
|
+
SRCS = lpsolve.c lpconsts.c
|
109
|
+
OBJS = lpsolve.o lpconsts.o
|
110
|
+
TARGET = lpsolve
|
111
|
+
DLLIB = $(TARGET).so
|
112
|
+
EXTSTATIC =
|
113
|
+
STATIC_LIB =
|
114
|
+
|
115
|
+
BINDIR = $(bindir)
|
116
|
+
RUBYCOMMONDIR = $(sitedir)$(target_prefix)
|
117
|
+
RUBYLIBDIR = $(sitelibdir)$(target_prefix)
|
118
|
+
RUBYARCHDIR = $(sitearchdir)$(target_prefix)
|
119
|
+
HDRDIR = $(rubyhdrdir)/ruby$(target_prefix)
|
120
|
+
ARCHHDRDIR = $(rubyhdrdir)/$(arch)/ruby$(target_prefix)
|
121
|
+
|
122
|
+
TARGET_SO = $(DLLIB)
|
123
|
+
CLEANLIBS = $(TARGET).so
|
124
|
+
CLEANOBJS = *.o *.bak
|
125
|
+
|
126
|
+
all: $(DLLIB)
|
127
|
+
static: $(STATIC_LIB)
|
128
|
+
.PHONY: all install static install-so install-rb
|
129
|
+
.PHONY: clean clean-so clean-rb
|
130
|
+
|
131
|
+
clean-rb-default::
|
132
|
+
clean-rb::
|
133
|
+
clean-so::
|
134
|
+
clean: clean-so clean-rb-default clean-rb
|
135
|
+
@-$(RM) $(CLEANLIBS) $(CLEANOBJS) $(CLEANFILES)
|
136
|
+
|
137
|
+
distclean-rb-default::
|
138
|
+
distclean-rb::
|
139
|
+
distclean-so::
|
140
|
+
distclean: clean distclean-so distclean-rb-default distclean-rb
|
141
|
+
@-$(RM) Makefile $(RUBY_EXTCONF_H) conftest.* mkmf.log
|
142
|
+
@-$(RM) core ruby$(EXEEXT) *~ $(DISTCLEANFILES)
|
143
|
+
@-$(RMDIRS) $(DISTCLEANDIRS)
|
144
|
+
|
145
|
+
realclean: distclean
|
146
|
+
install: install-so install-rb
|
147
|
+
|
148
|
+
install-so: $(RUBYARCHDIR)
|
149
|
+
install-so: $(RUBYARCHDIR)/$(DLLIB)
|
150
|
+
$(RUBYARCHDIR)/$(DLLIB): $(DLLIB)
|
151
|
+
@-$(MAKEDIRS) $(@D)
|
152
|
+
$(INSTALL_PROG) $(DLLIB) $(@D)
|
153
|
+
install-rb: pre-install-rb install-rb-default
|
154
|
+
install-rb-default: pre-install-rb-default
|
155
|
+
pre-install-rb: Makefile
|
156
|
+
pre-install-rb-default: Makefile
|
157
|
+
$(RUBYARCHDIR):
|
158
|
+
$(MAKEDIRS) $@
|
159
|
+
|
160
|
+
site-install: site-install-so site-install-rb
|
161
|
+
site-install-so: install-so
|
162
|
+
site-install-rb: install-rb
|
163
|
+
|
164
|
+
.SUFFIXES: .c .m .cc .cxx .cpp .C .o
|
165
|
+
|
166
|
+
.cc.o:
|
167
|
+
$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $<
|
168
|
+
|
169
|
+
.cxx.o:
|
170
|
+
$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $<
|
171
|
+
|
172
|
+
.cpp.o:
|
173
|
+
$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $<
|
174
|
+
|
175
|
+
.C.o:
|
176
|
+
$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $<
|
177
|
+
|
178
|
+
.c.o:
|
179
|
+
$(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $<
|
180
|
+
|
181
|
+
$(DLLIB): $(OBJS) Makefile
|
182
|
+
@-$(RM) $(@)
|
183
|
+
$(LDSHARED) -o $@ $(OBJS) $(LIBPATH) $(DLDFLAGS) $(LOCAL_LIBS) $(LIBS)
|
184
|
+
|
185
|
+
|
186
|
+
|
187
|
+
$(OBJS): $(hdrdir)/ruby.h $(hdrdir)/ruby/defines.h $(arch_hdrdir)/ruby/config.h
|
data/ext/extconf.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'mkmf'
|
3
|
+
dir_config('lpsolve')
|
4
|
+
$libs = append_library($libs, "m -ldl -llpsolve55 -lm")
|
5
|
+
|
6
|
+
config_file = File.join(File.dirname(__FILE__), 'config_options.rb')
|
7
|
+
load config_file if File.exist?(config_file)
|
8
|
+
|
9
|
+
# if debug:
|
10
|
+
# $CFLAGS = "-Wall -g -fno-strict-aliasing -fPIC"
|
11
|
+
create_makefile('lpsolve')
|
data/ext/lpconsts.c
ADDED
@@ -0,0 +1,174 @@
|
|
1
|
+
/* Copyright (C) 2007, 2010 Rocky Bernstein <rockyb@rubyforge.org>
|
2
|
+
|
3
|
+
This program is free software: you can redistribute it and/or modify
|
4
|
+
it under the terms of the GNU General Public License as published by
|
5
|
+
the Free Software Foundation, either version 3 of the License, or
|
6
|
+
(at your option) any later version.
|
7
|
+
|
8
|
+
This program is distributed in the hope that it will be useful,
|
9
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
GNU General Public License for more details.
|
12
|
+
|
13
|
+
You should have received a copy of the GNU General Public License
|
14
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
15
|
+
*/
|
16
|
+
#include <ruby.h>
|
17
|
+
#include <lpsolve/lp_lib.h>
|
18
|
+
|
19
|
+
extern VALUE rb_cLPSolve;
|
20
|
+
|
21
|
+
/** \file lpconsts.c
|
22
|
+
*
|
23
|
+
* \brief Provides Ruby bindings for LPSolve constants.
|
24
|
+
|
25
|
+
The constants below are all prefixed by \a LPSolve::, e.g.
|
26
|
+
\a LPSolve::EQ.
|
27
|
+
*/
|
28
|
+
|
29
|
+
/**
|
30
|
+
Routine called by Init_lpsolve() create \a LPSolve:: constants, e.g.
|
31
|
+
\a LPSolve::EQ.
|
32
|
+
*/
|
33
|
+
void
|
34
|
+
init_lpsolve_constants()
|
35
|
+
{
|
36
|
+
|
37
|
+
/* Equality/Inequality values */
|
38
|
+
|
39
|
+
rb_define_const(rb_cLPSolve,"EQ", INT2FIX(EQ));
|
40
|
+
rb_define_const(rb_cLPSolve,"FR", INT2FIX(FR));
|
41
|
+
rb_define_const(rb_cLPSolve,"GE", INT2FIX(GE));
|
42
|
+
rb_define_const(rb_cLPSolve,"LE", INT2FIX(LE));
|
43
|
+
rb_define_const(rb_cLPSolve,"OF", INT2FIX(OF));
|
44
|
+
|
45
|
+
/* Verbosity constants */
|
46
|
+
rb_define_const(rb_cLPSolve, "NEUTRAL", INT2FIX(NEUTRAL));
|
47
|
+
rb_define_const(rb_cLPSolve, "CRITICAL", INT2FIX(CRITICAL));
|
48
|
+
rb_define_const(rb_cLPSolve, "SEVERE", INT2FIX(SEVERE));
|
49
|
+
rb_define_const(rb_cLPSolve, "IMPORTANT",INT2FIX(IMPORTANT));
|
50
|
+
rb_define_const(rb_cLPSolve, "NORMAL", INT2FIX(NORMAL));
|
51
|
+
rb_define_const(rb_cLPSolve, "DETAILED", INT2FIX(DETAILED));
|
52
|
+
rb_define_const(rb_cLPSolve, "FULL", INT2FIX(FULL));
|
53
|
+
|
54
|
+
/* Branch and Bound constants */
|
55
|
+
|
56
|
+
rb_define_const(rb_cLPSolve, "NODE_FIRSTSELECT",
|
57
|
+
INT2FIX(NODE_FIRSTSELECT));
|
58
|
+
rb_define_const(rb_cLPSolve, "NODE_GAPSELECT",
|
59
|
+
INT2FIX(NODE_GAPSELECT));
|
60
|
+
rb_define_const(rb_cLPSolve, "NODE_RANGESELECT",
|
61
|
+
INT2FIX(NODE_RANGESELECT));
|
62
|
+
rb_define_const(rb_cLPSolve, "NODE_FRACTIONSELECT",
|
63
|
+
INT2FIX(NODE_FRACTIONSELECT));
|
64
|
+
rb_define_const(rb_cLPSolve, "NODE_PSEUDOCOSTSELECT",
|
65
|
+
INT2FIX(NODE_PSEUDOCOSTSELECT));
|
66
|
+
rb_define_const(rb_cLPSolve, "NODE_PSEUDONONINTSELECT",
|
67
|
+
INT2FIX(NODE_PSEUDONONINTSELECT));
|
68
|
+
rb_define_const(rb_cLPSolve, "NODE_PSEUDOFEASSELECT",
|
69
|
+
INT2FIX(NODE_PSEUDOFEASSELECT));
|
70
|
+
rb_define_const(rb_cLPSolve, "NODE_PSEUDORATIOSELECT",
|
71
|
+
INT2FIX(NODE_PSEUDORATIOSELECT));
|
72
|
+
rb_define_const(rb_cLPSolve, "NODE_USERSELECT",
|
73
|
+
INT2FIX(NODE_USERSELECT));
|
74
|
+
rb_define_const(rb_cLPSolve, "NODE_STRATEGYMASK",
|
75
|
+
INT2FIX(NODE_STRATEGYMASK));
|
76
|
+
rb_define_const(rb_cLPSolve, "NODE_WEIGHTREVERSEMODE",
|
77
|
+
INT2FIX(NODE_WEIGHTREVERSEMODE));
|
78
|
+
rb_define_const(rb_cLPSolve, "NODE_BRANCHREVERSEMODE",
|
79
|
+
INT2FIX(NODE_BRANCHREVERSEMODE));
|
80
|
+
rb_define_const(rb_cLPSolve, "NODE_GREEDYMODE",
|
81
|
+
INT2FIX(NODE_GREEDYMODE));
|
82
|
+
rb_define_const(rb_cLPSolve, "NODE_PSEUDOCOSTMODE",
|
83
|
+
INT2FIX(NODE_PSEUDOCOSTMODE));
|
84
|
+
rb_define_const(rb_cLPSolve, "NODE_DEPTHFIRSTMODE",
|
85
|
+
INT2FIX(NODE_DEPTHFIRSTMODE));
|
86
|
+
rb_define_const(rb_cLPSolve, "NODE_RANDOMIZEMODE",
|
87
|
+
INT2FIX(NODE_RANDOMIZEMODE));
|
88
|
+
rb_define_const(rb_cLPSolve, "NODE_GUBMODE",
|
89
|
+
INT2FIX(NODE_GUBMODE));
|
90
|
+
rb_define_const(rb_cLPSolve, "NODE_DYNAMICMODE",
|
91
|
+
INT2FIX(NODE_DYNAMICMODE));
|
92
|
+
rb_define_const(rb_cLPSolve, "NODE_RESTARTMODE",
|
93
|
+
INT2FIX(NODE_RESTARTMODE));
|
94
|
+
rb_define_const(rb_cLPSolve, "NODE_BREADTHFIRSTMODE",
|
95
|
+
INT2FIX(NODE_BREADTHFIRSTMODE));
|
96
|
+
rb_define_const(rb_cLPSolve, "NODE_AUTOORDER",
|
97
|
+
INT2FIX(NODE_AUTOORDER));
|
98
|
+
rb_define_const(rb_cLPSolve, "NODE_RCOSTFIXING",
|
99
|
+
INT2FIX(NODE_RCOSTFIXING));
|
100
|
+
rb_define_const(rb_cLPSolve, "NODE_STRONGINIT",
|
101
|
+
INT2FIX(NODE_STRONGINIT));
|
102
|
+
|
103
|
+
/* Presolve constants used in a bitmask */
|
104
|
+
rb_define_const(rb_cLPSolve, "PRESOLVE_NONE", INT2FIX(PRESOLVE_NONE));
|
105
|
+
rb_define_const(rb_cLPSolve, "PRESOLVE_ROWS", INT2FIX(PRESOLVE_ROWS));
|
106
|
+
rb_define_const(rb_cLPSolve, "PRESOLVE_COLS", INT2FIX(PRESOLVE_COLS));
|
107
|
+
rb_define_const(rb_cLPSolve, "PRESOLVE_LINDEP", INT2FIX(4));
|
108
|
+
rb_define_const(rb_cLPSolve, "PRESOLVE_SOS", INT2FIX(PRESOLVE_SOS));
|
109
|
+
rb_define_const(rb_cLPSolve, "PRESOLVE_REDUCEMIP", INT2FIX(64));
|
110
|
+
rb_define_const(rb_cLPSolve, "PRESOLVE_KNAPSACK", INT2FIX(128));
|
111
|
+
rb_define_const(rb_cLPSolve, "PRESOLVE_ELIMEQ2", INT2FIX(256));
|
112
|
+
rb_define_const(rb_cLPSolve, "PRESOLVE_IMPLIEDFREE", INT2FIX(512));
|
113
|
+
rb_define_const(rb_cLPSolve, "PRESOLVE_REDUCEGCD", INT2FIX(1024));
|
114
|
+
rb_define_const(rb_cLPSolve, "PRESOLVE_PROBEFIX", INT2FIX(2048));
|
115
|
+
rb_define_const(rb_cLPSolve, "PRESOLVE_PROBEREDUCE", INT2FIX(4096));
|
116
|
+
rb_define_const(rb_cLPSolve, "PRESOLVE_ROWDOMINATE", INT2FIX(8192));
|
117
|
+
rb_define_const(rb_cLPSolve, "PRESOLVE_COLDOMINATE", INT2FIX(16384));
|
118
|
+
rb_define_const(rb_cLPSolve, "PRESOLVE_MERGEROWS", INT2FIX(32768));
|
119
|
+
rb_define_const(rb_cLPSolve, "PRESOLVE_IMPLIEDSLK", INT2FIX(65536));
|
120
|
+
rb_define_const(rb_cLPSolve, "PRESOLVE_COLFIXDUAL", INT2FIX(131072));
|
121
|
+
rb_define_const(rb_cLPSolve, "PRESOLVE_BOUNDS", INT2FIX(262144));
|
122
|
+
rb_define_const(rb_cLPSolve, "PRESOLVE_LASTMASKMODE",
|
123
|
+
INT2FIX(PRESOLVE_DUALS - 1));
|
124
|
+
rb_define_const(rb_cLPSolve, "PRESOLVE_DUALS", INT2FIX(PRESOLVE_DUALS));
|
125
|
+
rb_define_const(rb_cLPSolve, "PRESOLVE_SENSDUALS", INT2FIX(1048576));
|
126
|
+
|
127
|
+
|
128
|
+
/* Scaling constants used in a bitmask */
|
129
|
+
|
130
|
+
rb_define_const(rb_cLPSolve, "SCALE_NONE", INT2FIX(SCALE_NONE));
|
131
|
+
rb_define_const(rb_cLPSolve, "SCALE_EXTREME", INT2FIX(SCALE_EXTREME));
|
132
|
+
rb_define_const(rb_cLPSolve, "SCALE_RANGE", INT2FIX(SCALE_RANGE));
|
133
|
+
rb_define_const(rb_cLPSolve, "SCALE_MEAN", INT2FIX(SCALE_MEAN));
|
134
|
+
rb_define_const(rb_cLPSolve, "SCALE_GEOMETRIC", INT2FIX(SCALE_GEOMETRIC));
|
135
|
+
rb_define_const(rb_cLPSolve, "SCALE_CURTISREID", INT2FIX(SCALE_CURTISREID));
|
136
|
+
|
137
|
+
/* Above can be Or'd with.. */
|
138
|
+
rb_define_const(rb_cLPSolve, "SCALE_QUADRATIC", INT2FIX(SCALE_QUADRATIC));
|
139
|
+
rb_define_const(rb_cLPSolve, "SCALE_LOGARITHMIC", INT2FIX(SCALE_LOGARITHMIC));
|
140
|
+
rb_define_const(rb_cLPSolve, "SCALE_USERWEIGHT", INT2FIX(SCALE_USERWEIGHT));
|
141
|
+
rb_define_const(rb_cLPSolve, "SCALE_POWER2", INT2FIX(SCALE_POWER2));
|
142
|
+
rb_define_const(rb_cLPSolve, "SCALE_EQUILIBRATE", INT2FIX(SCALE_EQUILIBRATE));
|
143
|
+
rb_define_const(rb_cLPSolve, "SCALE_INTEGERS", INT2FIX(SCALE_INTEGERS));
|
144
|
+
rb_define_const(rb_cLPSolve, "SCALE_DYNUPDATE", INT2FIX(SCALE_DYNUPDATE));
|
145
|
+
rb_define_const(rb_cLPSolve, "SCALE_ROWSONLY", INT2FIX(SCALE_ROWSONLY));
|
146
|
+
rb_define_const(rb_cLPSolve, "SCALE_COLSONLY", INT2FIX(SCALE_COLSONLY));
|
147
|
+
|
148
|
+
/* Simplex types */
|
149
|
+
rb_define_const(rb_cLPSolve, "SIMPLEX_PRIMAL_PRIMAL",
|
150
|
+
INT2FIX(SIMPLEX_PRIMAL_PRIMAL));
|
151
|
+
rb_define_const(rb_cLPSolve, "SIMPLEX_DUAL_PRIMAL",
|
152
|
+
INT2FIX(SIMPLEX_DUAL_PRIMAL));
|
153
|
+
rb_define_const(rb_cLPSolve, "SIMPLEX_PRIMAL_DUAL",
|
154
|
+
INT2FIX(SIMPLEX_PRIMAL_DUAL));
|
155
|
+
rb_define_const(rb_cLPSolve, "SIMPLEX_DUAL_DUAL",
|
156
|
+
INT2FIX(SIMPLEX_DUAL_DUAL));
|
157
|
+
|
158
|
+
/* Solve return codes. */
|
159
|
+
rb_define_const(rb_cLPSolve, "NOMEMORY", INT2FIX(NOMEMORY));
|
160
|
+
rb_define_const(rb_cLPSolve, "OPTIMAL", INT2FIX(OPTIMAL));
|
161
|
+
rb_define_const(rb_cLPSolve, "SUBOPTIMAL", INT2FIX(SUBOPTIMAL));
|
162
|
+
rb_define_const(rb_cLPSolve, "INFEASIBLE", INT2FIX(INFEASIBLE));
|
163
|
+
rb_define_const(rb_cLPSolve, "UNBOUNDED", INT2FIX(UNBOUNDED));
|
164
|
+
rb_define_const(rb_cLPSolve, "DEGENERATE", INT2FIX(DEGENERATE));
|
165
|
+
rb_define_const(rb_cLPSolve, "NUMFAILURE", INT2FIX(NUMFAILURE));
|
166
|
+
rb_define_const(rb_cLPSolve, "USERABORT", INT2FIX(USERABORT));
|
167
|
+
rb_define_const(rb_cLPSolve, "TIMEOUT", INT2FIX(TIMEOUT));
|
168
|
+
rb_define_const(rb_cLPSolve, "PRESOLVED", INT2FIX(PRESOLVED));
|
169
|
+
rb_define_const(rb_cLPSolve, "PROCFAIL", INT2FIX(PROCFAIL));
|
170
|
+
rb_define_const(rb_cLPSolve, "PROCBREAK", INT2FIX(PROCBREAK));
|
171
|
+
rb_define_const(rb_cLPSolve, "FEASFOUND", INT2FIX(FEASFOUND));
|
172
|
+
rb_define_const(rb_cLPSolve, "NOFEASFOUND", INT2FIX(NOFEASFOUND));
|
173
|
+
}
|
174
|
+
|
data/ext/lpsolve.c
ADDED
@@ -0,0 +1,2915 @@
|
|
1
|
+
/* Copyright (C) 2007, 2010 Rocky Bernstein <rockyb@rubyforge.org>
|
2
|
+
|
3
|
+
This program is free software: you can redistribute it and/or modify
|
4
|
+
it under the terms of the GNU General Public License as published by
|
5
|
+
the Free Software Foundation, either version 3 of the License, or
|
6
|
+
(at your option) any later version.
|
7
|
+
|
8
|
+
This program is distributed in the hope that it will be useful,
|
9
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
GNU General Public License for more details.
|
12
|
+
|
13
|
+
You should have received a copy of the GNU General Public License
|
14
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
15
|
+
*/
|
16
|
+
#include <ruby.h>
|
17
|
+
#include <stdio.h>
|
18
|
+
#include <lpsolve/lp_lib.h>
|
19
|
+
#include <lpsolve/lp_report.h>
|
20
|
+
|
21
|
+
/** \file lpsolve.c
|
22
|
+
*
|
23
|
+
* \brief Provides Ruby access to lpsolve.
|
24
|
+
|
25
|
+
Ruby LPSolve class is created.
|
26
|
+
|
27
|
+
In the documentation below, change "lpsolve_" to LPSolve:: to
|
28
|
+
get the corresponding Ruby method name. For example lpsolve_get_mat()
|
29
|
+
is visible in Ruby as LPSolve::get_mat().
|
30
|
+
*/
|
31
|
+
|
32
|
+
#define DEBUG_GC 0
|
33
|
+
|
34
|
+
#define SOLVE_NOT_CALLED -10
|
35
|
+
|
36
|
+
/* Not part of API (yet). Return a column number for a given column name.
|
37
|
+
-1 is returned if the column was not found.
|
38
|
+
*/
|
39
|
+
static int
|
40
|
+
get_col_num(lprec *lp, const char *psz_col_name)
|
41
|
+
{
|
42
|
+
if (lp->names_used && lp->use_col_names) {
|
43
|
+
unsigned int i;
|
44
|
+
for (i=0; i<= lp->columns; i++) {
|
45
|
+
if ((lp->col_name[i] != NULL) && (lp->col_name[i]->name != NULL)) {
|
46
|
+
#ifdef Paranoia
|
47
|
+
if(lp->col_name[i]->index != i)
|
48
|
+
report(lp, SEVERE,
|
49
|
+
"%s: Inconsistent column ordinal %d vs %d\n",
|
50
|
+
__FUNCTION__, i, lp->col_name[i]->index);
|
51
|
+
#endif
|
52
|
+
if (0 == strcmp(psz_col_name, lp->col_name[i]->name))
|
53
|
+
return i;
|
54
|
+
}
|
55
|
+
}
|
56
|
+
}
|
57
|
+
/* Not found. */
|
58
|
+
return -1;
|
59
|
+
}
|
60
|
+
|
61
|
+
/** \def INIT_LP
|
62
|
+
|
63
|
+
Boilerplate beginning of all functions: declares a pointer to the lp
|
64
|
+
structure, gets the internal object from Ruby (basically "self") and if
|
65
|
+
that's nil, fail immediately.
|
66
|
+
*/
|
67
|
+
#define INIT_LP \
|
68
|
+
lprec *lp; \
|
69
|
+
Data_Get_Struct(self, lprec, lp); \
|
70
|
+
if (NULL == lp) return Qnil; \
|
71
|
+
|
72
|
+
|
73
|
+
#define RETURN_BOOL(x) \
|
74
|
+
return (x) ? Qtrue : Qfalse
|
75
|
+
|
76
|
+
/** \def LPSOLVE_0_IN_BOOL_OUT
|
77
|
+
|
78
|
+
A macro used in defining a Ruby method which takes no arguments
|
79
|
+
other than self and calls the corresponding C function returns the
|
80
|
+
boolean static back to Ruby. That is, if lp is not \a NULL we
|
81
|
+
return Qtrue. If lp is \a NULL, we return \a Qfalse.
|
82
|
+
*/
|
83
|
+
#define LPSOLVE_0_IN_BOOL_OUT(fn) \
|
84
|
+
static VALUE \
|
85
|
+
lpsolve_ ## fn(VALUE self) \
|
86
|
+
{ \
|
87
|
+
INIT_LP; \
|
88
|
+
RETURN_BOOL(fn(lp)); \
|
89
|
+
}
|
90
|
+
|
91
|
+
/** \def LPSOLVE_0_IN_INT_OUT
|
92
|
+
|
93
|
+
A macro used in defining a Ruby method which takes no arguments
|
94
|
+
other than self and calls the corresponding C function returns the
|
95
|
+
integer return value back to Ruby. That is, if \a lp is not \a
|
96
|
+
NULL. If it's \a NULL, we return \a nil.
|
97
|
+
*/
|
98
|
+
#define LPSOLVE_0_IN_INT_OUT(fn) \
|
99
|
+
static VALUE \
|
100
|
+
lpsolve_ ## fn(VALUE self) \
|
101
|
+
{ \
|
102
|
+
INIT_LP; \
|
103
|
+
return (NULL != lp) ? INT2FIX(fn(lp)) : Qnil; \
|
104
|
+
}
|
105
|
+
|
106
|
+
/** \def LPSOLVE_0_IN_NUM_OUT
|
107
|
+
|
108
|
+
A macro used in defining a Ruby method which takes no arguments
|
109
|
+
other than self and calls the corresponding C function returns the
|
110
|
+
number return value back to Ruby. That is, if \a lp is not \a
|
111
|
+
NULL. If it's \a NULL, we return \a nil.
|
112
|
+
*/
|
113
|
+
#define LPSOLVE_0_IN_NUM_OUT(fn) \
|
114
|
+
static VALUE \
|
115
|
+
lpsolve_ ## fn(VALUE self) \
|
116
|
+
{ \
|
117
|
+
INIT_LP; \
|
118
|
+
return rb_float_new(fn(lp)); \
|
119
|
+
}
|
120
|
+
|
121
|
+
/** \def LPSOLVE_0_IN_STATUS_OUT
|
122
|
+
|
123
|
+
A macro used in defining a Ruby method which takes no arguments
|
124
|
+
other than self and calls the corresponding C function returns the
|
125
|
+
boolean statuc back to Ruby. That is, if lp is not \a NULL we
|
126
|
+
return Qtrue. If lp is \a NULL, we return \a Qfalse.
|
127
|
+
*/
|
128
|
+
#define LPSOLVE_0_IN_STATUS_OUT(fn) \
|
129
|
+
static VALUE \
|
130
|
+
lpsolve_ ## fn(VALUE self) \
|
131
|
+
{ \
|
132
|
+
INIT_LP; \
|
133
|
+
fn(lp); \
|
134
|
+
return Qtrue; \
|
135
|
+
}
|
136
|
+
|
137
|
+
/** \def LPSOLVE_0_IN_TIME_OUT
|
138
|
+
|
139
|
+
A macro used in defining a Ruby method which takes no arguments
|
140
|
+
other than self returns a floating point number which is the
|
141
|
+
difference between to floating-point fields - time values.
|
142
|
+
*/
|
143
|
+
#define LPSOLVE_0_IN_TIME_OUT(fn, field1, field2) \
|
144
|
+
static VALUE \
|
145
|
+
lpsolve_ ## fn(VALUE self) \
|
146
|
+
{ \
|
147
|
+
INIT_LP; \
|
148
|
+
int status = NUM2INT(rb_ivar_get(self, rb_intern("@status"))); \
|
149
|
+
if (SOLVE_NOT_CALLED == status) \
|
150
|
+
return rb_float_new(0); \
|
151
|
+
return rb_float_new(lp->field2 - lp->field1); \
|
152
|
+
}
|
153
|
+
|
154
|
+
/** \def LPSOLVE_1_BOOL_IN_BOOL_OUT
|
155
|
+
|
156
|
+
A macro used in defining a Ruby method which takes one boolean
|
157
|
+
argument other than self and calls the corresponding C function
|
158
|
+
returns the boolean statuc back to Ruby. That is, if lp is not \a
|
159
|
+
NULL we return Qtrue. If lp is \a NULL, we return \a Qnil.
|
160
|
+
*/
|
161
|
+
#define LPSOLVE_1_BOOL_IN_BOOL_OUT(fn) \
|
162
|
+
static VALUE \
|
163
|
+
lpsolve_ ## fn(VALUE self, VALUE param1) \
|
164
|
+
{ \
|
165
|
+
INIT_LP; \
|
166
|
+
if (param1 != Qtrue && param1 != Qfalse) { \
|
167
|
+
report(lp, IMPORTANT, \
|
168
|
+
"%s: Parameter is not a boolean.\n", \
|
169
|
+
__FUNCTION__); \
|
170
|
+
return Qnil; \
|
171
|
+
} else { \
|
172
|
+
unsigned char turnon = param1 == Qtrue ? 1 : 0; \
|
173
|
+
RETURN_BOOL(fn(lp, turnon)); \
|
174
|
+
} \
|
175
|
+
}
|
176
|
+
|
177
|
+
/** \def LPSOLVE_1_IN_BOOL_OUT
|
178
|
+
|
179
|
+
A macro used in defining a Ruby method which takes one argument
|
180
|
+
other than self and calls the corresponding C function returns the
|
181
|
+
boolean statuc back to Ruby. That is, if lp is not \a NULL we
|
182
|
+
return Qtrue. If lp is \a NULL, we return \a Qnil
|
183
|
+
|
184
|
+
\a type is a Ruby typename like \a T_FIXNUM, \a typename is a type
|
185
|
+
name string to use in an error message, e.g "an integer"; \a
|
186
|
+
convert a Ruby conversion macro like \a FIX2INT.
|
187
|
+
*/
|
188
|
+
#define LPSOLVE_1_IN_BOOL_OUT(fn, type, typename, convert) \
|
189
|
+
static VALUE \
|
190
|
+
lpsolve_ ## fn(VALUE self, VALUE param1) \
|
191
|
+
{ \
|
192
|
+
INIT_LP; \
|
193
|
+
if (TYPE(param1) != type) { \
|
194
|
+
report(lp, IMPORTANT, \
|
195
|
+
"%s: Parameter is not %s.\n", \
|
196
|
+
__FUNCTION__, typename); \
|
197
|
+
return Qnil; \
|
198
|
+
} \
|
199
|
+
RETURN_BOOL(fn(lp, convert(param1))); \
|
200
|
+
}
|
201
|
+
|
202
|
+
/** \def LPSOLVE_1_IN_NUM_OUT
|
203
|
+
|
204
|
+
A macro used in defining a Ruby method which takes one argument
|
205
|
+
along with self and calls the corresponding C function returns the
|
206
|
+
integer return value back to Ruby. That is, if \a lp is not \a
|
207
|
+
NULL. If it's \a NULL, we return \a nil.
|
208
|
+
|
209
|
+
\a type is a Ruby typename like \a T_FIXNUM, \a typename is a type
|
210
|
+
name string to use in an error message, e.g "an integer"; \a
|
211
|
+
convert a Ruby conversion macro like \a FIX2INT.
|
212
|
+
\a fn is the lpsolve function to call.
|
213
|
+
|
214
|
+
*/
|
215
|
+
#define LPSOLVE_1_IN_NUM_OUT(fn, type, typename, convert) \
|
216
|
+
static VALUE \
|
217
|
+
lpsolve_ ## fn (VALUE self, VALUE param1) \
|
218
|
+
{ \
|
219
|
+
INIT_LP \
|
220
|
+
if (TYPE(param1) != type) { \
|
221
|
+
report(lp, IMPORTANT, \
|
222
|
+
"%s: Parameter is not %s.\n", \
|
223
|
+
__FUNCTION__, typename); \
|
224
|
+
return Qnil; \
|
225
|
+
} \
|
226
|
+
return rb_float_new(fn(lp, convert(param1))); \
|
227
|
+
}
|
228
|
+
|
229
|
+
/** \def LPSOLVE_1_IN_STR_OUT
|
230
|
+
|
231
|
+
A macro used in defining a Ruby method which takes one argument
|
232
|
+
along with self and calls the corresponding C function returns a
|
233
|
+
string back to Ruby. That is, if \a lp is not \a
|
234
|
+
NULL. If it's \a NULL, we return \a nil.
|
235
|
+
|
236
|
+
\a arg1 is passed to the \a lpsolve routine. It should be
|
237
|
+
a function of \a param1 which is the parameter of the wrapper
|
238
|
+
function. For example \a arg1 could be \a FIX2INT(param1).
|
239
|
+
|
240
|
+
*/
|
241
|
+
#define LPSOLVE_1_IN_STR_OUT(fn, type, typename, convert) \
|
242
|
+
static VALUE \
|
243
|
+
lpsolve_ ## fn (VALUE self, VALUE param1) \
|
244
|
+
{ \
|
245
|
+
INIT_LP \
|
246
|
+
if (TYPE(param1) != type) { \
|
247
|
+
report(lp, IMPORTANT, \
|
248
|
+
"%s: Parameter is not %s.\n", \
|
249
|
+
__FUNCTION__, typename); \
|
250
|
+
return Qnil; \
|
251
|
+
} \
|
252
|
+
return rb_str_new2(fn(lp, convert(param1))); \
|
253
|
+
}
|
254
|
+
|
255
|
+
/** \def LPSOLVE_1_IN_BOOL_OUT
|
256
|
+
|
257
|
+
A macro used in defining a Ruby method which takes one argument
|
258
|
+
along with self and calls the corresponding C function returns the
|
259
|
+
integer return value back to Ruby. That is, if \a lp is not \a
|
260
|
+
NULL. If it's \a NULL, we return \a nil.
|
261
|
+
*/
|
262
|
+
#define LPSOLVE_1_STR_IN_BOOL_OUT(fn) \
|
263
|
+
static VALUE \
|
264
|
+
lpsolve_ ## fn (VALUE self, VALUE str) \
|
265
|
+
{ \
|
266
|
+
INIT_LP; \
|
267
|
+
if (TYPE(str) != T_STRING) { \
|
268
|
+
report(lp, IMPORTANT, \
|
269
|
+
"%s: Parameter 1 is not a string\n", \
|
270
|
+
__FUNCTION__); \
|
271
|
+
return Qfalse; \
|
272
|
+
} \
|
273
|
+
RETURN_BOOL(fn(lp, RSTRING_PTR(str))); \
|
274
|
+
}
|
275
|
+
|
276
|
+
/** \def LPSOLVE_1_IN_STATUS_OUT
|
277
|
+
|
278
|
+
A macro used in defining a Ruby method which takes one argument
|
279
|
+
along with self and calls the corresponding C function returns the
|
280
|
+
integer return value back to Ruby. That is, if \a lp is not \a
|
281
|
+
NULL. If it's \a NULL, we return \a nil.
|
282
|
+
|
283
|
+
\a arg1 is passed to the \a lpsolve routine. It should be
|
284
|
+
a function of \a param1 which is the parameter of the wrapper
|
285
|
+
function. For example \a arg1 could be \a FIX2INT(param1).
|
286
|
+
|
287
|
+
*/
|
288
|
+
#define LPSOLVE_1_IN_STATUS_OUT(fn, arg1) \
|
289
|
+
static VALUE \
|
290
|
+
lpsolve_ ## fn (VALUE self, VALUE param1) \
|
291
|
+
{ \
|
292
|
+
INIT_LP \
|
293
|
+
fn(lp, arg1); \
|
294
|
+
return Qtrue; \
|
295
|
+
}
|
296
|
+
|
297
|
+
#define LPSOLVE_SET_VARTYPE(fn) \
|
298
|
+
static VALUE \
|
299
|
+
lpsolve_ ## fn (VALUE self, VALUE column_num, VALUE new_bool) \
|
300
|
+
{ \
|
301
|
+
INIT_LP; \
|
302
|
+
if (new_bool != Qtrue && new_bool != Qfalse && new_bool != Qnil) { \
|
303
|
+
report(lp, IMPORTANT, \
|
304
|
+
"%s: Parameter is not a boolean or nil.\n", \
|
305
|
+
__FUNCTION__); \
|
306
|
+
return Qfalse; \
|
307
|
+
} else { \
|
308
|
+
RETURN_BOOL(fn(lp, FIX2INT(column_num), Qtrue == new_bool)); \
|
309
|
+
} \
|
310
|
+
}
|
311
|
+
|
312
|
+
|
313
|
+
static VALUE
|
314
|
+
lpsolve_set_binary (VALUE self, VALUE column_num, VALUE new_bool)
|
315
|
+
{
|
316
|
+
INIT_LP;
|
317
|
+
if (new_bool != Qtrue && new_bool != Qfalse && new_bool != Qnil) {
|
318
|
+
report(lp, IMPORTANT,
|
319
|
+
"%s: Parameter is not a boolean or nil.\n",
|
320
|
+
__FUNCTION__);
|
321
|
+
return Qfalse;
|
322
|
+
} else {
|
323
|
+
RETURN_BOOL(set_binary(lp, FIX2INT(column_num), Qtrue == new_bool));
|
324
|
+
}
|
325
|
+
}
|
326
|
+
|
327
|
+
|
328
|
+
/** Holder for LPSolve class object. A singleton value. */
|
329
|
+
VALUE rb_cLPSolve;
|
330
|
+
|
331
|
+
static void lpsolve_free(void *lp);
|
332
|
+
|
333
|
+
/**
|
334
|
+
A wrapper for add_constraintex.
|
335
|
+
|
336
|
+
Adds a constraint. These routines will perform much better when
|
337
|
+
lpsolve_set_add_rowmode() is called before adding constraints.
|
338
|
+
|
339
|
+
@param self self
|
340
|
+
@param name The name of the constraint or \a nil if no name.
|
341
|
+
|
342
|
+
@param row_coeffs A list of tuples. The first entry of the tuple is
|
343
|
+
the column number which should be in the range 0..columns-1; the
|
344
|
+
second entry in the tuple should be the coefficient value.
|
345
|
+
|
346
|
+
@param constr_type The constraint type. Should be one of
|
347
|
+
\a LPSolve::LE, \a LPSolve::EQ, \a LPSolve::GE.
|
348
|
+
|
349
|
+
@param rh The right-hand-side constant, a number.
|
350
|
+
|
351
|
+
@return number of rows, (the row number of the constraint added) if
|
352
|
+
successful or \a nil on error.
|
353
|
+
|
354
|
+
*/
|
355
|
+
static VALUE
|
356
|
+
lpsolve_add_constraintex(VALUE self, VALUE name, VALUE row_coeffs,
|
357
|
+
VALUE constr_type, VALUE rh)
|
358
|
+
{
|
359
|
+
int i_constr_type = FIX2INT(constr_type);
|
360
|
+
REAL r_rh = NUM2DBL(rh);
|
361
|
+
REAL *row = NULL;
|
362
|
+
int *colno = NULL;
|
363
|
+
long int i, count;
|
364
|
+
VALUE ret = Qnil;
|
365
|
+
MYBOOL b_ret;
|
366
|
+
VALUE *p_row_coeff = NULL;
|
367
|
+
|
368
|
+
INIT_LP;
|
369
|
+
|
370
|
+
if (TYPE(name) != T_STRING && name != Qnil) {
|
371
|
+
report(lp, IMPORTANT,
|
372
|
+
"%s: constraint name, parameter 1, should be nil or a string.\n",
|
373
|
+
__FUNCTION__);
|
374
|
+
return Qnil;
|
375
|
+
}
|
376
|
+
|
377
|
+
if (TYPE(row_coeffs) != T_ARRAY) {
|
378
|
+
report(lp, IMPORTANT,
|
379
|
+
"%s: row coefficients, parameter 2 is not an array.\n",
|
380
|
+
__FUNCTION__);
|
381
|
+
return Qnil;
|
382
|
+
}
|
383
|
+
|
384
|
+
if (TYPE(constr_type) != T_FIXNUM) {
|
385
|
+
report(lp, IMPORTANT,
|
386
|
+
"%s: constraint type, parameter 3, is not a number.\n",
|
387
|
+
__FUNCTION__);
|
388
|
+
return Qnil;
|
389
|
+
}
|
390
|
+
|
391
|
+
switch (i_constr_type) {
|
392
|
+
case EQ:
|
393
|
+
case GE:
|
394
|
+
case LE: break;
|
395
|
+
default:
|
396
|
+
report(lp, IMPORTANT,
|
397
|
+
"%s: constraint type, parameter 3, should be LE, EQ, or GE.\n",
|
398
|
+
__FUNCTION__);
|
399
|
+
return Qnil;
|
400
|
+
}
|
401
|
+
|
402
|
+
/***FIXME: combine common parts of this with add_constraintex ****/
|
403
|
+
count = RARRAY_LEN(row_coeffs);
|
404
|
+
|
405
|
+
if (0 == count) {
|
406
|
+
report(lp, IMPORTANT,
|
407
|
+
"%s: row coefficients array has to have at least one item.\n",
|
408
|
+
__FUNCTION__);
|
409
|
+
return Qnil;
|
410
|
+
}
|
411
|
+
|
412
|
+
colno = ALLOC_N(int, count);
|
413
|
+
row = ALLOC_N(REAL, count);
|
414
|
+
|
415
|
+
p_row_coeff = RARRAY_PTR(row_coeffs);
|
416
|
+
for (i = 0; i < count; i++) {
|
417
|
+
int i_col;
|
418
|
+
if (TYPE(*p_row_coeff) != T_ARRAY) {
|
419
|
+
report(lp, IMPORTANT,
|
420
|
+
"%s: row coeffient element %d is not an array.\n",
|
421
|
+
__FUNCTION__, i);
|
422
|
+
goto done;
|
423
|
+
}
|
424
|
+
if (RARRAY_LEN(*p_row_coeff) != 2) {
|
425
|
+
report(lp, IMPORTANT,
|
426
|
+
"%s: row coeffient element %d is not an array tuple.\n",
|
427
|
+
__FUNCTION__, i);
|
428
|
+
goto done;
|
429
|
+
} else {
|
430
|
+
VALUE *tuple = RARRAY_PTR(*p_row_coeff);
|
431
|
+
if (TYPE(tuple[0]) != T_FIXNUM) {
|
432
|
+
report(lp, IMPORTANT,
|
433
|
+
"%s: Column number, first element, of row coefficients at " \
|
434
|
+
"tuple %d is not a integer.\n", __FUNCTION__, i);
|
435
|
+
goto done;
|
436
|
+
}
|
437
|
+
switch (TYPE(tuple[1])) {
|
438
|
+
case T_FIXNUM:
|
439
|
+
case T_FLOAT: break;
|
440
|
+
default:
|
441
|
+
report(lp, IMPORTANT,
|
442
|
+
"%s: Coefficient value, second element, of row coeffients at "
|
443
|
+
"tuple %d is not an integer.\n", __FUNCTION__, i);
|
444
|
+
goto done;
|
445
|
+
}
|
446
|
+
|
447
|
+
i_col = FIX2INT(tuple[0]);
|
448
|
+
if (i_col <= 0 || i_col > lp->columns) {
|
449
|
+
report(lp, IMPORTANT,
|
450
|
+
"%s: Column number, first element, of row coeffients at " \
|
451
|
+
"tuple %d, value %d, is not in the range 1..%d\n",
|
452
|
+
__FUNCTION__, i, i_col, lp->columns);
|
453
|
+
goto done;
|
454
|
+
}
|
455
|
+
colno[i] = i_col;
|
456
|
+
row[i] = NUM2DBL(tuple[1]);
|
457
|
+
}
|
458
|
+
p_row_coeff++;
|
459
|
+
}
|
460
|
+
|
461
|
+
b_ret = add_constraintex(lp, count, row, colno, i_constr_type, r_rh);
|
462
|
+
if (b_ret) {
|
463
|
+
ret = INT2FIX(lp->rows);
|
464
|
+
if (name != Qnil)
|
465
|
+
set_row_name(lp, lp->rows, RSTRING_PTR(name));
|
466
|
+
}
|
467
|
+
|
468
|
+
done:
|
469
|
+
free(row);
|
470
|
+
free(colno);
|
471
|
+
return ret;
|
472
|
+
}
|
473
|
+
|
474
|
+
/**
|
475
|
+
A wrapper for add_SOS.
|
476
|
+
|
477
|
+
Adds an SOS constraint. A Special Ordered Set of Type n is a way of
|
478
|
+
indicating that at most n of a set of variables may be nonzero.
|
479
|
+
|
480
|
+
@param self self
|
481
|
+
@param name The name of the SOS constraint.
|
482
|
+
|
483
|
+
@param sos_type The type of the SOS constraint, 1 means "at most 1" 2
|
484
|
+
means "at most 2". Must be >= 1.
|
485
|
+
@param priority Priority of the SOS constraint in the SOS set.
|
486
|
+
@param sos_vars A list of tuples of column numbers and weights
|
487
|
+
|
488
|
+
*/
|
489
|
+
static VALUE
|
490
|
+
lpsolve_add_SOS(VALUE self, VALUE name, VALUE sos_type, VALUE priority,
|
491
|
+
VALUE sos_vars)
|
492
|
+
{
|
493
|
+
int i_sos_type = FIX2INT(sos_type);
|
494
|
+
int i_priority = FIX2INT(priority);
|
495
|
+
int *vars = NULL;
|
496
|
+
double *weights = NULL;
|
497
|
+
long int i, count;
|
498
|
+
VALUE *p_sos_var;
|
499
|
+
VALUE ret = Qnil;
|
500
|
+
int i_ret = 0;
|
501
|
+
|
502
|
+
INIT_LP;
|
503
|
+
|
504
|
+
if (TYPE(sos_type) != T_FIXNUM) {
|
505
|
+
report(lp, IMPORTANT,
|
506
|
+
"%s: SOS type, parameter 2, is not a number.\n", __FUNCTION__);
|
507
|
+
return Qnil;
|
508
|
+
}
|
509
|
+
|
510
|
+
if (TYPE(priority) != T_FIXNUM) {
|
511
|
+
report(lp, IMPORTANT,
|
512
|
+
"%s: priority, parameter 3, not a number.\n", __FUNCTION__);
|
513
|
+
return Qnil;
|
514
|
+
}
|
515
|
+
if (TYPE(name) != T_STRING) {
|
516
|
+
report(lp, IMPORTANT, "%s: name is not a string.\n", __FUNCTION__);
|
517
|
+
return Qnil;
|
518
|
+
}
|
519
|
+
if (i_sos_type < 1) {
|
520
|
+
report(lp, IMPORTANT, "%s: SOS type (%ld) is less than 1.\n",
|
521
|
+
__FUNCTION__, i_sos_type);
|
522
|
+
return Qnil;
|
523
|
+
}
|
524
|
+
|
525
|
+
if (TYPE(sos_vars) != T_ARRAY) {
|
526
|
+
report(lp, IMPORTANT, "%s: SOS vars is not an array.\n", __FUNCTION__);
|
527
|
+
return Qnil;
|
528
|
+
}
|
529
|
+
|
530
|
+
count = RARRAY_LEN(sos_vars);
|
531
|
+
|
532
|
+
if (0 == count) {
|
533
|
+
report(lp, IMPORTANT,
|
534
|
+
"%s: SOS vars array has to have at least one item.\n",
|
535
|
+
__FUNCTION__);
|
536
|
+
return Qnil;
|
537
|
+
}
|
538
|
+
|
539
|
+
vars = ALLOC_N(int, count);
|
540
|
+
weights = ALLOC_N(double, count);
|
541
|
+
|
542
|
+
p_sos_var = RARRAY_PTR(sos_vars);
|
543
|
+
for (i = 0; i < count; i++) {
|
544
|
+
if (TYPE(*p_sos_var) != T_ARRAY) {
|
545
|
+
report(lp, IMPORTANT,
|
546
|
+
"%s: SOS vars element %d is not an array.\n", __FUNCTION__, i);
|
547
|
+
goto done;
|
548
|
+
}
|
549
|
+
if (RARRAY_LEN(*p_sos_var) != 2) {
|
550
|
+
report(lp, IMPORTANT,
|
551
|
+
"%s: SOS vars element %d is not an array tuple.\n", __FUNCTION__,
|
552
|
+
i);
|
553
|
+
goto done;
|
554
|
+
} else {
|
555
|
+
VALUE *tuple = RARRAY_PTR(*p_sos_var);
|
556
|
+
if (TYPE(tuple[0]) != T_FIXNUM) {
|
557
|
+
report(lp, IMPORTANT,
|
558
|
+
"%s: First element of SOS vars at tuple %d " \
|
559
|
+
"is not a integer.\n", __FUNCTION__, i);
|
560
|
+
goto done;
|
561
|
+
}
|
562
|
+
if (TYPE(tuple[1]) != T_FIXNUM) {
|
563
|
+
report(lp, IMPORTANT,
|
564
|
+
"%s: Second element of SOS vars at tuple %d " \
|
565
|
+
"is not an integer.\n", __FUNCTION__, i);
|
566
|
+
goto done;
|
567
|
+
}
|
568
|
+
vars[i] = FIX2INT(tuple[0]);
|
569
|
+
weights[i] = FIX2INT(tuple[1]);
|
570
|
+
}
|
571
|
+
p_sos_var++;
|
572
|
+
}
|
573
|
+
i_ret = add_SOS(lp, RSTRING_PTR(name), i_sos_type, i_priority,
|
574
|
+
count, vars, weights);
|
575
|
+
if (i_ret != 0)
|
576
|
+
ret = INT2FIX(i_ret);
|
577
|
+
|
578
|
+
done:
|
579
|
+
free(vars);
|
580
|
+
free(weights);
|
581
|
+
return ret;
|
582
|
+
}
|
583
|
+
|
584
|
+
/** Allocate a Ruby container for a lprec * pointer. Ruby may call
|
585
|
+
this routine directly under various circumstances such as when
|
586
|
+
doing data marshalling. However usually the most common case is
|
587
|
+
when new() is called. Here, after the call to lpsolve_alloc(),
|
588
|
+
Ruby will call lpsolve_initialize().
|
589
|
+
*/
|
590
|
+
static VALUE
|
591
|
+
lpsolve_alloc(VALUE klass)
|
592
|
+
{
|
593
|
+
VALUE obj;
|
594
|
+
obj = Data_Wrap_Struct(klass, 0, lpsolve_free, NULL);
|
595
|
+
return obj;
|
596
|
+
}
|
597
|
+
|
598
|
+
/** A wrapper for default_basis().
|
599
|
+
|
600
|
+
Sets the starting base to an all slack basis (the default simplex
|
601
|
+
starting basis).
|
602
|
+
|
603
|
+
@param self self
|
604
|
+
@return \a true unless we have an error.
|
605
|
+
*/
|
606
|
+
static VALUE lpsolve_default_basis(VALUE self);
|
607
|
+
LPSOLVE_0_IN_STATUS_OUT(default_basis)
|
608
|
+
|
609
|
+
/** A wrapper for del_column().
|
610
|
+
|
611
|
+
@param self self
|
612
|
+
@param column_num column number
|
613
|
+
|
614
|
+
@return \a true if the operation was successful. false indicates an
|
615
|
+
error. An error occurs when column is not between 1 and the number
|
616
|
+
of columns in the lp. Note that row entry mode must be off, else
|
617
|
+
this function also fails.
|
618
|
+
|
619
|
+
@see lpsolve_set_add_rowmode()
|
620
|
+
*/
|
621
|
+
static VALUE lpsolve_del_column(VALUE self, VALUE column_num);
|
622
|
+
LPSOLVE_1_IN_BOOL_OUT(del_column, T_FIXNUM, "an integer", FIX2INT);
|
623
|
+
|
624
|
+
/** A wrapper for del_constraint()
|
625
|
+
|
626
|
+
del_constraint returns true if the operation was successful.
|
627
|
+
|
628
|
+
@param self self
|
629
|
+
@param row_num row number
|
630
|
+
|
631
|
+
@return a \a false value indicates an error. An error occurs when
|
632
|
+
row_num is not between 1 and the number of rows self. Note that row
|
633
|
+
entry mode must be off, else this function also fails. @see
|
634
|
+
lpsolve_set_add_rowmode().
|
635
|
+
*/
|
636
|
+
static VALUE lpsolve_del_constraint(VALUE self, VALUE row_num);
|
637
|
+
LPSOLVE_1_IN_BOOL_OUT(del_constraint, T_FIXNUM, "an integer", FIX2INT);
|
638
|
+
|
639
|
+
|
640
|
+
static void
|
641
|
+
lpsolve_free(void *lp)
|
642
|
+
{
|
643
|
+
#if DEBUG_GC
|
644
|
+
printf("lpsolve_free called\n");
|
645
|
+
#endif
|
646
|
+
if (NULL != lp) delete_lp((lprec *)lp);
|
647
|
+
}
|
648
|
+
|
649
|
+
/** A wrapper for get_bb_depthlimit(lprec *lp);
|
650
|
+
|
651
|
+
get_bb_depthlimit returns the maximum branch-and-bound depth.
|
652
|
+
|
653
|
+
Parameters
|
654
|
+
|
655
|
+
lp
|
656
|
+
|
657
|
+
Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI
|
658
|
+
|
659
|
+
Remarks
|
660
|
+
|
661
|
+
The get_bb_depthlimit function returns the maximum branch-and-bound
|
662
|
+
depth. This is only useful if there are integer, semi-continious
|
663
|
+
or SOS variables in the model so that the branch-and-bound
|
664
|
+
algorithm must be used to solve them. The branch-and-bound
|
665
|
+
algorithm will not go deeper than this level. When 0 then there is
|
666
|
+
no limit to the depth. Limiting the depth will speed up solving
|
667
|
+
time, but there is a chance that the found solution is not the most
|
668
|
+
optimal one. Be aware of this. It can also result in not finding a
|
669
|
+
solution at all. A positive value means that the depth is
|
670
|
+
absolute. NOTE: in the standard lpsolve an absolute depth is
|
671
|
+
*added* to the number of SOS vars and semi-continuous vars. In a
|
672
|
+
hacked version of lpsolve, absolute is, well, absolute.
|
673
|
+
|
674
|
+
A negative value means a relative B&B depth limit. The
|
675
|
+
"order" of a MIP problem is defined to be 2x the number of binary
|
676
|
+
variables plus the number of SC and SOS variables. A relative value
|
677
|
+
of -x results in a maximum depth of x times the order of the MIP
|
678
|
+
problem. The default is -50. The get_bb_rule function returns the
|
679
|
+
branch-and-bound rule for choosing which non-integer variable is to
|
680
|
+
be selected. This rule can influence solving times
|
681
|
+
considerably. Depending on the model one rule can be best and for
|
682
|
+
another model another rule. The default is NODE_PSEUDONONINTSELECT
|
683
|
+
+ NODE_GREEDYMODE + NODE_DYNAMICMODE + NODE_RCOSTFIXING (17445).
|
684
|
+
|
685
|
+
@param self self
|
686
|
+
@return Returns the branch-and-bound rule.
|
687
|
+
*/
|
688
|
+
static VALUE lpsolve_get_bb_depthlimit(VALUE self);
|
689
|
+
LPSOLVE_0_IN_NUM_OUT(get_bb_depthlimit);
|
690
|
+
|
691
|
+
/** A wrapper for get_bb_rule().
|
692
|
+
|
693
|
+
The get_bb_rule function returns the branch-and-bound rule for
|
694
|
+
choosing which non-integer variable is to be selected. This rule
|
695
|
+
can influence solving times considerably. Depending on the model
|
696
|
+
one rule can be best and for another model another rule. The
|
697
|
+
default is NODE_PSEUDONONINTSELECT + NODE_GREEDYMODE +
|
698
|
+
NODE_DYNAMICMODE + NODE_RCOSTFIXING (17445).
|
699
|
+
|
700
|
+
@param self self
|
701
|
+
@return Returns the branch-and-bound rule.
|
702
|
+
|
703
|
+
*/
|
704
|
+
static VALUE lpsolve_get_bb_rule(VALUE self);
|
705
|
+
LPSOLVE_0_IN_NUM_OUT(get_bb_rule);
|
706
|
+
|
707
|
+
/** A wrapper for get_col_name().
|
708
|
+
|
709
|
+
get_col_name() returns the name of the specified column. The
|
710
|
+
difference between get_col_name and get_origcol_name is only
|
711
|
+
visible when a presolve (set_presolve) was done. Presolve can
|
712
|
+
result in deletion of columns in the model. In get_col_name(),
|
713
|
+
column specifies the column number after presolve was done.
|
714
|
+
|
715
|
+
@return the string name. A value of \a nil indicates an error.
|
716
|
+
*/
|
717
|
+
static VALUE
|
718
|
+
lpsolve_get_col_name(VALUE self, VALUE column_num)
|
719
|
+
{
|
720
|
+
char *psz_col_name;
|
721
|
+
INIT_LP;
|
722
|
+
|
723
|
+
if (TYPE(column_num) != T_FIXNUM) {
|
724
|
+
report(lp, IMPORTANT,
|
725
|
+
"%s: column number, parameter 1, is not an integer.\n",
|
726
|
+
__FUNCTION__);
|
727
|
+
return Qnil;
|
728
|
+
}
|
729
|
+
|
730
|
+
psz_col_name = get_col_name(lp, FIX2INT(column_num));
|
731
|
+
return psz_col_name ? rb_str_new2(psz_col_name) : Qnil;
|
732
|
+
}
|
733
|
+
|
734
|
+
/** get_col_num(). - Not in API (yet)
|
735
|
+
|
736
|
+
get_col_num() returns the column number for the specified column
|
737
|
+
name.
|
738
|
+
|
739
|
+
@return the column number. A value of \a nil indicates an error.
|
740
|
+
*/
|
741
|
+
static VALUE
|
742
|
+
lpsolve_get_col_num(VALUE self, VALUE column_name)
|
743
|
+
{
|
744
|
+
INIT_LP;
|
745
|
+
|
746
|
+
if (TYPE(column_name) != T_STRING) {
|
747
|
+
report(lp, IMPORTANT,
|
748
|
+
"%s: column number, parameter 1, is not a string.\n",
|
749
|
+
__FUNCTION__);
|
750
|
+
return Qnil;
|
751
|
+
} else {
|
752
|
+
int retval = get_col_num(lp, RSTRING_PTR(column_name));
|
753
|
+
return (-1 == retval) ? Qnil : INT2FIX(retval);
|
754
|
+
}
|
755
|
+
}
|
756
|
+
|
757
|
+
/** A wrapper for get_column().
|
758
|
+
|
759
|
+
Get all column elements from the matrix for a given column number.
|
760
|
+
|
761
|
+
@param self self
|
762
|
+
|
763
|
+
@param column_num the column number that you want. The value must be
|
764
|
+
between 1 and the number of columns.
|
765
|
+
|
766
|
+
@return an array of the column values. The size of the array is
|
767
|
+
the number of rows + 1. \a Nil is returned if there was an error.
|
768
|
+
*/
|
769
|
+
static VALUE
|
770
|
+
lpsolve_get_column(VALUE self, VALUE column_num)
|
771
|
+
{
|
772
|
+
unsigned int i_column = FIX2INT(column_num);
|
773
|
+
unsigned int i_rows;
|
774
|
+
REAL *p_column;
|
775
|
+
INIT_LP;
|
776
|
+
|
777
|
+
i_rows = get_Nrows(lp); /* Yep, Nrows, not Ncolumns. */
|
778
|
+
p_column = ALLOC_N(REAL, i_rows + 1);
|
779
|
+
|
780
|
+
if (!get_column(lp, i_column, p_column)) {
|
781
|
+
free(p_column);
|
782
|
+
return Qnil;
|
783
|
+
} else {
|
784
|
+
VALUE ret_ary = rb_ary_new2(i_rows+1);
|
785
|
+
unsigned int i;
|
786
|
+
for (i=0; i<=i_rows; i++) {
|
787
|
+
rb_ary_push(ret_ary, rb_float_new(p_column[i]));
|
788
|
+
}
|
789
|
+
free(p_column);
|
790
|
+
return ret_ary;
|
791
|
+
}
|
792
|
+
|
793
|
+
}
|
794
|
+
|
795
|
+
/** A wrapper for get_infinite().
|
796
|
+
|
797
|
+
@param self self
|
798
|
+
@return Returns the value of "infinite".
|
799
|
+
*/
|
800
|
+
static VALUE lpsolve_get_infinite(VALUE self);
|
801
|
+
LPSOLVE_0_IN_NUM_OUT(get_infinite);
|
802
|
+
|
803
|
+
/** A wrapper for get_lowbo().
|
804
|
+
|
805
|
+
Returns the upper bound on the variable identified by column.
|
806
|
+
Setting a bound on a variable is the way to go instead of adding an
|
807
|
+
extra constraint (row) to the model. Setting a bound doesn't
|
808
|
+
increase the model size that means that the model stays smaller and
|
809
|
+
will be solved faster. The default upper bound of a variable is
|
810
|
+
infinity (well not quite. It is a very big number. The value of
|
811
|
+
lpsolve_get_infinite().
|
812
|
+
|
813
|
+
@param self self
|
814
|
+
|
815
|
+
@param column_num the column number of the variable. It must be
|
816
|
+
between 1 and the number of columns in the lp.
|
817
|
+
|
818
|
+
*/
|
819
|
+
|
820
|
+
static VALUE lpsolve_get_lowbo(VALUE self, VALUE column_num);
|
821
|
+
LPSOLVE_1_IN_NUM_OUT(get_lowbo, T_FIXNUM, "an integer", FIX2INT);
|
822
|
+
|
823
|
+
/** A wrapper for get_lp_name().
|
824
|
+
|
825
|
+
@return the name of the lp. The doc says the default name is
|
826
|
+
"Unnamed", but in fact we seem to return "".
|
827
|
+
*/
|
828
|
+
static VALUE
|
829
|
+
lpsolve_get_lp_name(VALUE self)
|
830
|
+
{
|
831
|
+
char *psz_lp_name;
|
832
|
+
INIT_LP;
|
833
|
+
psz_lp_name = get_lp_name(lp);
|
834
|
+
return psz_lp_name ? rb_str_new2(psz_lp_name) : rb_str_new2("Unnamed");
|
835
|
+
}
|
836
|
+
|
837
|
+
/**
|
838
|
+
A wrapper for get_Ncolumns().
|
839
|
+
|
840
|
+
Return the number of columns (variables) in the lp object. Note
|
841
|
+
that the number of columns can change when a presolve is done or
|
842
|
+
when negative variables are split in a positive and a negative
|
843
|
+
part. Therefore it is advisable to use this function to determine
|
844
|
+
how many columns there are in the lp instead of relying one's own
|
845
|
+
count.
|
846
|
+
|
847
|
+
@param self self
|
848
|
+
@return the number of columns (variables) in the lp.
|
849
|
+
*/
|
850
|
+
static VALUE lpsolve_get_Ncolumns(VALUE self);
|
851
|
+
LPSOLVE_0_IN_INT_OUT(get_Ncolumns)
|
852
|
+
|
853
|
+
/** A wrapper for get_nonzeros().
|
854
|
+
|
855
|
+
Return the number of non-zero elements in matrix of the the lp object.
|
856
|
+
|
857
|
+
@param self self
|
858
|
+
@return the number of non-zero elements in the matrix of the lp.
|
859
|
+
*/
|
860
|
+
static VALUE lpsolve_get_nonzeros(VALUE self);
|
861
|
+
LPSOLVE_0_IN_INT_OUT(get_nonzeros)
|
862
|
+
|
863
|
+
/**
|
864
|
+
A wrapper for get_Norig_columns().
|
865
|
+
|
866
|
+
Return the number of original columns (variables) in the lp
|
867
|
+
object. Note that the number of row does not change, but the
|
868
|
+
number of original columns does not.
|
869
|
+
|
870
|
+
@param self self
|
871
|
+
@return the number of columns (variables) in the lp.
|
872
|
+
*/
|
873
|
+
static VALUE lpsolve_get_Norig_columns(VALUE self);
|
874
|
+
LPSOLVE_0_IN_INT_OUT(get_Norig_columns)
|
875
|
+
|
876
|
+
/** A wrapper for get_Norig_rows().
|
877
|
+
|
878
|
+
Return the number of original rows (constraints) in the lp
|
879
|
+
object. Note that the number of row does not change, but the
|
880
|
+
number of original rows does not.
|
881
|
+
|
882
|
+
@param self self
|
883
|
+
@return the number of original rows (constraints) in the lp.
|
884
|
+
*/
|
885
|
+
static VALUE lpsolve_get_Norig_rows(VALUE self);
|
886
|
+
LPSOLVE_0_IN_INT_OUT(get_Norig_rows)
|
887
|
+
|
888
|
+
/** A wrapper for get_Nrows().
|
889
|
+
|
890
|
+
Return the number of rows (variables) in the lp object. Note that
|
891
|
+
the number of columns can change when a presolve is done or when
|
892
|
+
negative variables are split in a positive and a negative part.
|
893
|
+
Therefore it is advisable to use this function to determine how
|
894
|
+
many columns there are in the lp instead of relying one's own
|
895
|
+
count.
|
896
|
+
|
897
|
+
@param self self
|
898
|
+
@return the number of rows (constraints) in the lp.
|
899
|
+
*/
|
900
|
+
static VALUE lpsolve_get_Nrows(VALUE self);
|
901
|
+
LPSOLVE_0_IN_INT_OUT(get_Nrows)
|
902
|
+
|
903
|
+
/** A wrapper for get_mat().
|
904
|
+
|
905
|
+
Get a single element from the matrix.
|
906
|
+
|
907
|
+
@param self self
|
908
|
+
@param row_num row number
|
909
|
+
@param col_num column number
|
910
|
+
|
911
|
+
@return the value of the element on row \a row, column \a column. If no
|
912
|
+
value was set for this element, the function returns 0. Note that
|
913
|
+
row entry mode must be off, else this function also fails. @see
|
914
|
+
lpsolve_set_add_rowmode().
|
915
|
+
|
916
|
+
*/
|
917
|
+
static VALUE
|
918
|
+
lpsolve_get_mat(VALUE self, VALUE row_num, VALUE col_num)
|
919
|
+
{
|
920
|
+
INIT_LP;
|
921
|
+
if (TYPE(row_num) != T_FIXNUM) {
|
922
|
+
report(lp, IMPORTANT,
|
923
|
+
"%s: row number, parameter 1, is not a number.\n", __FUNCTION__);
|
924
|
+
return Qnil;
|
925
|
+
}
|
926
|
+
if (TYPE(col_num) != T_FIXNUM) {
|
927
|
+
report(lp, IMPORTANT,
|
928
|
+
"%s: column number, parameter 2, is not a number.\n", __FUNCTION__);
|
929
|
+
return Qnil;
|
930
|
+
}
|
931
|
+
return rb_float_new(get_mat(lp, FIX2INT(row_num), FIX2INT(col_num)));
|
932
|
+
}
|
933
|
+
|
934
|
+
/** A wrapper for get_mip_gap().
|
935
|
+
|
936
|
+
Sets the MIP gap that specifies a tolerance for the branch and bound
|
937
|
+
algorithm. This tolerance is the difference between the best-found
|
938
|
+
solution yet and the current solution. If the difference is smaller
|
939
|
+
than this tolerance then the solution (and all the sub-solutions) is
|
940
|
+
rejected. This can result in faster solving times, but results in a
|
941
|
+
solution which is not the perfect solution. So be careful with this
|
942
|
+
tolerance. The default mip_gap value is 1e-9
|
943
|
+
|
944
|
+
|
945
|
+
@param self self
|
946
|
+
@param abs_rel: set to true if the gap is absolute, or false for relative.
|
947
|
+
@param val: gap value. The default mip_gap is 1e-9.
|
948
|
+
@return \a gap value or nil if there was an error.
|
949
|
+
*/
|
950
|
+
static VALUE
|
951
|
+
lpsolve_get_mip_gap(VALUE self, VALUE abs_rel)
|
952
|
+
{
|
953
|
+
INIT_LP;
|
954
|
+
if (abs_rel != Qtrue && abs_rel != Qfalse && abs_rel != Qnil) {
|
955
|
+
report(lp, IMPORTANT,
|
956
|
+
"%s: Parameter is not a boolean or nil.\n",
|
957
|
+
__FUNCTION__);
|
958
|
+
return Qnil;
|
959
|
+
} else {
|
960
|
+
return rb_float_new(get_mip_gap(lp, Qtrue == abs_rel));
|
961
|
+
}
|
962
|
+
}
|
963
|
+
|
964
|
+
/** A wrapper for get_objective().
|
965
|
+
|
966
|
+
returns the value of the objective of the last solve().
|
967
|
+
This value is only valid after a successful lpsolve_solve() or
|
968
|
+
lag_solve.
|
969
|
+
|
970
|
+
In Ruby, you can also use accessor function objective.
|
971
|
+
|
972
|
+
@param self self
|
973
|
+
@return the objective value. It is a real value.
|
974
|
+
*/
|
975
|
+
static VALUE lpsolve_get_objective(VALUE self);
|
976
|
+
LPSOLVE_0_IN_NUM_OUT(get_objective);
|
977
|
+
|
978
|
+
/** A wrapper for get_origcol_name().
|
979
|
+
|
980
|
+
Returns the name of the specified column.
|
981
|
+
|
982
|
+
The difference between lpsolve_get_col_name() and
|
983
|
+
lpsolve_get_origcol_name() is only visible when a presolve
|
984
|
+
(lpsolve_set_presolve()) was done. Presolve can result in deletion
|
985
|
+
of columns in the model. In lpsolve_get_col_name(), column
|
986
|
+
specifies the column number after presolve was done.
|
987
|
+
|
988
|
+
@param self self
|
989
|
+
@param column_num column number
|
990
|
+
|
991
|
+
@return nil indicates an error.
|
992
|
+
*/
|
993
|
+
static VALUE
|
994
|
+
lpsolve_get_origcol_name(VALUE self, VALUE column_num)
|
995
|
+
{
|
996
|
+
lprec *lp;
|
997
|
+
char *psz_col_name;
|
998
|
+
Data_Get_Struct(self, lprec, lp);
|
999
|
+
if (TYPE(column_num) != T_FIXNUM) {
|
1000
|
+
report(lp, IMPORTANT,
|
1001
|
+
"%s: column number, parameter 1, is not an integer.\n",
|
1002
|
+
__FUNCTION__);
|
1003
|
+
return Qnil;
|
1004
|
+
}
|
1005
|
+
psz_col_name = get_origcol_name(lp, FIX2INT(column_num));
|
1006
|
+
return psz_col_name ? rb_str_new2(psz_col_name) : Qnil;
|
1007
|
+
}
|
1008
|
+
|
1009
|
+
/** A wrapper for get_origrow_name()
|
1010
|
+
|
1011
|
+
@param self self
|
1012
|
+
@param row_num row number
|
1013
|
+
|
1014
|
+
get_row_name and get_origrow_name return the name of the specified
|
1015
|
+
row. A return value of NULL indicates an error. The difference
|
1016
|
+
between lpsolve_get_row_name() and lpsolve_get_origrow_name() is
|
1017
|
+
only visible when a presolve (lpsovle_set_presolve()) was
|
1018
|
+
done. Presolve can result in deletion of rows in the model. In
|
1019
|
+
get_row_name, row specifies the row number after presolve was
|
1020
|
+
done. In lpsolve_get_origrow_name(), row specifies the row number
|
1021
|
+
before presolve was done, ie the original row number. If presolve
|
1022
|
+
is not active then both functions are equal.
|
1023
|
+
|
1024
|
+
@return a Ruby string row name.
|
1025
|
+
*/
|
1026
|
+
static VALUE
|
1027
|
+
lpsolve_get_origrow_name(VALUE self, VALUE row_num)
|
1028
|
+
{
|
1029
|
+
char *psz_col_name;
|
1030
|
+
INIT_LP;
|
1031
|
+
if (TYPE(row_num) != T_FIXNUM) {
|
1032
|
+
report(lp, IMPORTANT,
|
1033
|
+
"%s: row number, parameter 1, is not a number.\n", __FUNCTION__);
|
1034
|
+
return Qnil;
|
1035
|
+
}
|
1036
|
+
psz_col_name = get_origrow_name(lp, FIX2INT(row_num));
|
1037
|
+
return psz_col_name ? rb_str_new2(psz_col_name) : Qnil;
|
1038
|
+
}
|
1039
|
+
|
1040
|
+
/**
|
1041
|
+
A wrapper for get_presolve().
|
1042
|
+
|
1043
|
+
@param self self
|
1044
|
+
@return the number of columns (variables) in the lp.
|
1045
|
+
*/
|
1046
|
+
static VALUE lpsolve_get_presolve(VALUE self);
|
1047
|
+
LPSOLVE_0_IN_INT_OUT(get_presolve);
|
1048
|
+
|
1049
|
+
/**
|
1050
|
+
A wrapper for get_presolveloops().
|
1051
|
+
|
1052
|
+
Returns the number of times presolve is may be iterated. After a
|
1053
|
+
presolve is performed, another presolve may result in elimination
|
1054
|
+
of more rows and columns. This number specifies the maximum
|
1055
|
+
number of times this process may be repeated.
|
1056
|
+
|
1057
|
+
By default presolve repetition is performed until no simplification
|
1058
|
+
is done.
|
1059
|
+
|
1060
|
+
@param self self
|
1061
|
+
@return maximum number of presolve loops. A value of -1 means we
|
1062
|
+
loop for as many times as there is improvement.
|
1063
|
+
*/
|
1064
|
+
static VALUE lpsolve_get_presolveloops(VALUE self);
|
1065
|
+
LPSOLVE_0_IN_INT_OUT(get_presolveloops);
|
1066
|
+
|
1067
|
+
/** A wrapper for get_row().
|
1068
|
+
|
1069
|
+
Get all row elements from the matrix for a given row number.
|
1070
|
+
|
1071
|
+
@param self self
|
1072
|
+
|
1073
|
+
@param row_num the row number that you want. The value must be
|
1074
|
+
between 1 and the number of rows.
|
1075
|
+
|
1076
|
+
@return an array of the row values. The size of the array is
|
1077
|
+
the number of columns + 1. Nil is returned if there was an error.
|
1078
|
+
*/
|
1079
|
+
static VALUE
|
1080
|
+
lpsolve_get_row(VALUE self, VALUE row_num)
|
1081
|
+
{
|
1082
|
+
unsigned int i_row = FIX2INT(row_num);
|
1083
|
+
unsigned int i_columns;
|
1084
|
+
REAL *p_row;
|
1085
|
+
|
1086
|
+
INIT_LP;
|
1087
|
+
|
1088
|
+
if (TYPE(row_num) != T_FIXNUM) {
|
1089
|
+
report(lp, IMPORTANT,
|
1090
|
+
"%s: row number, parameter 1, is not a number.\n", __FUNCTION__);
|
1091
|
+
return Qnil;
|
1092
|
+
}
|
1093
|
+
i_columns = get_Ncolumns(lp); /* Yep, Ncolumns, not Nrows. */
|
1094
|
+
p_row = ALLOC_N(REAL, i_columns + 1);
|
1095
|
+
|
1096
|
+
if (!get_row(lp, i_row, p_row)) {
|
1097
|
+
free(p_row);
|
1098
|
+
return Qnil;
|
1099
|
+
} else {
|
1100
|
+
VALUE ret_ary = rb_ary_new2(i_columns+1);
|
1101
|
+
unsigned int i;
|
1102
|
+
for (i=0; i<=i_columns; i++) {
|
1103
|
+
rb_ary_push(ret_ary, rb_float_new(p_row[i]));
|
1104
|
+
}
|
1105
|
+
free(p_row);
|
1106
|
+
return ret_ary;
|
1107
|
+
}
|
1108
|
+
|
1109
|
+
}
|
1110
|
+
|
1111
|
+
/** A wrapper for get_row_name()
|
1112
|
+
|
1113
|
+
@param self self
|
1114
|
+
@param row_num row number
|
1115
|
+
|
1116
|
+
@return the name of the specified row. A return value of NULL
|
1117
|
+
indicates an error. The difference between lpsolve_get_row_name()
|
1118
|
+
and lpsolve_get_origrow_name() is only visible when a presolve
|
1119
|
+
(set_presolve) was done. Presolve can result in deletion of rows
|
1120
|
+
in the model. In lpsolve_get_row_name(), row specifies the row
|
1121
|
+
number after presolve was done. In lpsolve_aget_origrow_name(),
|
1122
|
+
row specifies the row number before presolve was done, ie the
|
1123
|
+
original row number. If presolve is not active then both functions
|
1124
|
+
are equal. Returns a Ruby string row name.
|
1125
|
+
*/
|
1126
|
+
static VALUE
|
1127
|
+
lpsolve_get_row_name(VALUE self, VALUE row_num)
|
1128
|
+
{
|
1129
|
+
char *psz_col_name;
|
1130
|
+
INIT_LP;
|
1131
|
+
if (TYPE(row_num) != T_FIXNUM) {
|
1132
|
+
report(lp, IMPORTANT,
|
1133
|
+
"%s: row number, parameter 1, is not a number.\n", __FUNCTION__);
|
1134
|
+
return Qnil;
|
1135
|
+
}
|
1136
|
+
psz_col_name = get_row_name(lp, FIX2INT(row_num));
|
1137
|
+
return psz_col_name ? rb_str_new2(psz_col_name) : Qnil;
|
1138
|
+
}
|
1139
|
+
|
1140
|
+
/** A wrapper for get_scaling().
|
1141
|
+
|
1142
|
+
@param self self
|
1143
|
+
@return A Ruby integer indicating scaling algorithm is used.
|
1144
|
+
|
1145
|
+
In Ruby, you can also use accessor function scaling.
|
1146
|
+
*/
|
1147
|
+
static VALUE lpsolve_get_scaling(VALUE self);
|
1148
|
+
LPSOLVE_0_IN_INT_OUT(get_scaling)
|
1149
|
+
|
1150
|
+
/**
|
1151
|
+
A wrapper for get_simplextype()
|
1152
|
+
|
1153
|
+
get_simplextype returns the desired combination of primal and dual
|
1154
|
+
simplex algorithms.
|
1155
|
+
|
1156
|
+
The default is SIMPLEX_DUAL_PRIMAL.
|
1157
|
+
|
1158
|
+
In Ruby, you can also use accessor function simplextype.
|
1159
|
+
|
1160
|
+
@param self self
|
1161
|
+
|
1162
|
+
@return a Ruby integer simplex type which is one of the following
|
1163
|
+
values:
|
1164
|
+
\a LPSolve::SIMPLEX_PRIMAL_PRIMAL,
|
1165
|
+
\a LPSolve::DUAL_PRIMAL,
|
1166
|
+
\a LPSolve::PRIMAL_DUAL,
|
1167
|
+
\a LPSolve::DUAL_DUAL
|
1168
|
+
|
1169
|
+
*/
|
1170
|
+
static VALUE lpsolve_get_simplextype(VALUE self);
|
1171
|
+
LPSOLVE_0_IN_INT_OUT(get_simplextype)
|
1172
|
+
|
1173
|
+
/**
|
1174
|
+
A wrapper for get_solutioncount().
|
1175
|
+
|
1176
|
+
Returns the number of equal solutions. This is only valid if there
|
1177
|
+
are integer, semi-continious or SOS variables in the model so that
|
1178
|
+
the branch-and-bound algoritm is used. This count gives the number
|
1179
|
+
of solutions with the same optimal objective value. If there is
|
1180
|
+
only one optimal solution, this value is 1.
|
1181
|
+
|
1182
|
+
@param self self
|
1183
|
+
|
1184
|
+
@return the number of equal solutions to to
|
1185
|
+
lpsolve_get_solutionlimit.
|
1186
|
+
|
1187
|
+
*/
|
1188
|
+
static VALUE lpsolve_get_solutioncount(VALUE self);
|
1189
|
+
LPSOLVE_0_IN_INT_OUT(get_solutioncount)
|
1190
|
+
|
1191
|
+
/**
|
1192
|
+
A wrapper for get_solutionlimit().
|
1193
|
+
|
1194
|
+
returns the number of solutions that must be returned.
|
1195
|
+
|
1196
|
+
@param self self
|
1197
|
+
|
1198
|
+
@return the number of solutions that must be returned.
|
1199
|
+
|
1200
|
+
This is only valid if there are integer, semi-continious or SOS
|
1201
|
+
variables in the model so that the branch-and-bound algoritm is
|
1202
|
+
used. If there are more solutions with the same objective value,
|
1203
|
+
then this number specifies which solution must be returned. This
|
1204
|
+
can be used to retrieve all possible solutions. Start with 1 till
|
1205
|
+
get_solutioncount
|
1206
|
+
|
1207
|
+
*/
|
1208
|
+
static VALUE lpsolve_get_solutionlimit(VALUE self);
|
1209
|
+
LPSOLVE_0_IN_INT_OUT(get_solutionlimit)
|
1210
|
+
|
1211
|
+
/**
|
1212
|
+
return the status of the last solve.
|
1213
|
+
@param self self
|
1214
|
+
@return A return status number of the last solve.
|
1215
|
+
*/
|
1216
|
+
static VALUE lpsolve_get_status(VALUE self)
|
1217
|
+
{
|
1218
|
+
return rb_ivar_get(self, rb_intern("@status"));
|
1219
|
+
}
|
1220
|
+
|
1221
|
+
|
1222
|
+
/**
|
1223
|
+
A wrapper for get_statustext(statuscode).
|
1224
|
+
However statuscode need not be supplied. If it isn't we use
|
1225
|
+
the status code from the last solve.
|
1226
|
+
|
1227
|
+
@param self self
|
1228
|
+
@param statuscode can be omitted or nil or an integer
|
1229
|
+
@return string description of statuscode
|
1230
|
+
|
1231
|
+
In Ruby, you can also use accessor function statustext.
|
1232
|
+
*/
|
1233
|
+
static VALUE lpsolve_get_statustext(int argc, VALUE *argv, VALUE self)
|
1234
|
+
{
|
1235
|
+
VALUE statuscode;
|
1236
|
+
unsigned int i_scanned;
|
1237
|
+
int i_statuscode;
|
1238
|
+
INIT_LP;
|
1239
|
+
if ((argc > 1) || (argc < 0))
|
1240
|
+
rb_raise(rb_eArgError, "wrong number of arguments (%d for 0 or 1)", argc);
|
1241
|
+
i_scanned = rb_scan_args(argc, argv, "01", &statuscode);
|
1242
|
+
switch (i_scanned) {
|
1243
|
+
case 0:
|
1244
|
+
statuscode = rb_ivar_get(self, rb_intern("@status"));
|
1245
|
+
break;
|
1246
|
+
case 1:
|
1247
|
+
if (statuscode != Qnil)
|
1248
|
+
statuscode = rb_ivar_get(self, rb_intern("@status"));
|
1249
|
+
else if (TYPE(statuscode) != T_FIXNUM) {
|
1250
|
+
report(lp, IMPORTANT, "%s: Parameter is not nil or an integer.\n",
|
1251
|
+
__FUNCTION__);
|
1252
|
+
return Qnil;
|
1253
|
+
}
|
1254
|
+
break;
|
1255
|
+
default:
|
1256
|
+
rb_raise(rb_eArgError, "wrong number of arguments (%d for 0 or 1)",
|
1257
|
+
i_scanned);
|
1258
|
+
}
|
1259
|
+
|
1260
|
+
i_statuscode = FIX2INT(statuscode);
|
1261
|
+
if (i_statuscode == SOLVE_NOT_CALLED)
|
1262
|
+
return rb_str_new2("LPSolve method solve() not performed yet.");
|
1263
|
+
else
|
1264
|
+
return rb_str_new2(get_statustext(lp, FIX2INT(statuscode)));
|
1265
|
+
}
|
1266
|
+
|
1267
|
+
/** A wrapper for get_timeout().
|
1268
|
+
|
1269
|
+
@param self self
|
1270
|
+
@return the number of seconds after which a timeout occurs.
|
1271
|
+
*/
|
1272
|
+
static VALUE lpsolve_get_timeout(VALUE self);
|
1273
|
+
LPSOLVE_0_IN_NUM_OUT(get_timeout);
|
1274
|
+
|
1275
|
+
/** A wrapper for get_timeout().
|
1276
|
+
|
1277
|
+
Returns the total number of iterations with Branch-and-bound of
|
1278
|
+
the last solution.
|
1279
|
+
|
1280
|
+
@param self self
|
1281
|
+
|
1282
|
+
@return the total number of iterations with Branch-and-bound of
|
1283
|
+
the last solution.
|
1284
|
+
*/
|
1285
|
+
static VALUE lpsolve_get_total_iter(VALUE self);
|
1286
|
+
LPSOLVE_0_IN_NUM_OUT(get_total_iter);
|
1287
|
+
|
1288
|
+
/** A wrapper for get_upbo().
|
1289
|
+
|
1290
|
+
Returns the upper bound on the variable identified by column.
|
1291
|
+
Setting a bound on a variable is the way to go instead of adding an
|
1292
|
+
extra constraint (row) to the model. Setting a bound doesn't
|
1293
|
+
increase the model size that means that the model stays smaller and
|
1294
|
+
will be solved faster. The default upper bound of a variable is
|
1295
|
+
infinity (well not quite. It is a very big number. The value of
|
1296
|
+
lpsolve_get_infinite().
|
1297
|
+
|
1298
|
+
@param self self
|
1299
|
+
|
1300
|
+
@param column_num the column number of the variable. It must be
|
1301
|
+
between 1 and the number of columns in the lp.
|
1302
|
+
|
1303
|
+
*/
|
1304
|
+
|
1305
|
+
static VALUE lpsolve_get_upbo(VALUE self, VALUE column_num);
|
1306
|
+
LPSOLVE_1_IN_NUM_OUT(get_upbo, T_FIXNUM, "an integer", FIX2INT);
|
1307
|
+
|
1308
|
+
/** A wrapper for get_var_dualresult()
|
1309
|
+
|
1310
|
+
|
1311
|
+
|
1312
|
+
@param self self
|
1313
|
+
@param index index
|
1314
|
+
|
1315
|
+
@return returns the reduced cost.
|
1316
|
+
|
1317
|
+
In contrast to get_dual_solution, the original index number is
|
1318
|
+
preserved.
|
1319
|
+
*/
|
1320
|
+
static VALUE lpsolve_get_var_dualresult(VALUE self, VALUE index);
|
1321
|
+
LPSOLVE_1_IN_NUM_OUT(get_var_dualresult, T_FIXNUM, "an integer", FIX2INT);
|
1322
|
+
|
1323
|
+
/** A wrapper for get_var_primalresult()
|
1324
|
+
|
1325
|
+
@param self self
|
1326
|
+
@param index index
|
1327
|
+
|
1328
|
+
@return the name of the specified row. A return value of NULL
|
1329
|
+
indicates an error. The difference between lpsolve_get_row_name()
|
1330
|
+
and lpsovle_get_origrow_name() is only visible when a presolve
|
1331
|
+
(set_presolve) was done. Presolve can result in deletion of rows
|
1332
|
+
in the model. In lpsolve_get_row_name(), row specifies the row
|
1333
|
+
number after presolve was done. In lpsovle_aget_origrow_name(),
|
1334
|
+
row specifies the row number before presolve was done, ie the
|
1335
|
+
original row number. If presolve is not active then both functions
|
1336
|
+
are equal. Returns a Ruby string row name.
|
1337
|
+
|
1338
|
+
Retrieve the a value of the objective function, constraints and variables.
|
1339
|
+
These values are only valid after a successful solve or lag_solve.
|
1340
|
+
|
1341
|
+
In contrast to get_primal_solution, the original index number is
|
1342
|
+
preserved.
|
1343
|
+
*/
|
1344
|
+
static VALUE lpsolve_get_var_primalresult(VALUE self, VALUE index);
|
1345
|
+
LPSOLVE_1_IN_NUM_OUT(get_var_primalresult, T_FIXNUM, "an integer", FIX2INT);
|
1346
|
+
|
1347
|
+
/** A wrapper for get_variables().
|
1348
|
+
|
1349
|
+
Get the values of the variables.
|
1350
|
+
@param self self
|
1351
|
+
|
1352
|
+
@return an array of the variable values. The size of the array is
|
1353
|
+
the number of columns + 1. Nil is returned if there was an error.
|
1354
|
+
*/
|
1355
|
+
static VALUE
|
1356
|
+
lpsolve_get_variables(VALUE self)
|
1357
|
+
{
|
1358
|
+
unsigned int i_columns;
|
1359
|
+
REAL *p_variables;
|
1360
|
+
|
1361
|
+
INIT_LP;
|
1362
|
+
i_columns = get_Ncolumns(lp);
|
1363
|
+
|
1364
|
+
if (!get_ptr_variables(lp, &p_variables)) {
|
1365
|
+
return Qnil;
|
1366
|
+
} else {
|
1367
|
+
VALUE ret_ary = rb_ary_new2(i_columns);
|
1368
|
+
unsigned int i;
|
1369
|
+
for (i=0; i<i_columns; i++) {
|
1370
|
+
rb_ary_push(ret_ary, rb_float_new(p_variables[i]));
|
1371
|
+
}
|
1372
|
+
return ret_ary;
|
1373
|
+
}
|
1374
|
+
|
1375
|
+
}
|
1376
|
+
|
1377
|
+
/** A wrapper for get_verbose()
|
1378
|
+
|
1379
|
+
get_verbose returns the current verbose level. Can be one of the
|
1380
|
+
following values:
|
1381
|
+
\a LPSolve::NEUTRAL, \a LPSolve::CRITICAL, \a LPSolve::SEVERE,
|
1382
|
+
\a LPSolve::IMPORTANT, \a LPSolve::NORMAL, \a LPSolve::DETAILED, or
|
1383
|
+
\a LPSolve::FULL
|
1384
|
+
|
1385
|
+
How much information is reported depends on the verbose level. The
|
1386
|
+
default verbose level is \a LPSOLVE::NORMAL. lp_solve determines
|
1387
|
+
how verbose a given message is. For example specifying a wrong
|
1388
|
+
row/column index values is considered as a \a LPSOLVE::SEVERE
|
1389
|
+
error. All messages equal to and below the set level are reported.
|
1390
|
+
The default reporting device is the console screen. It is possible
|
1391
|
+
to set a used defined reporting routine via lpsolve_put_logfunc().
|
1392
|
+
|
1393
|
+
In Ruby, you can also use accessor function verbose.
|
1394
|
+
|
1395
|
+
@param self self
|
1396
|
+
@return a Ruby integer verbosity level.
|
1397
|
+
|
1398
|
+
*/
|
1399
|
+
static VALUE lpsolve_get_verbose(VALUE self);
|
1400
|
+
LPSOLVE_0_IN_INT_OUT(get_verbose)
|
1401
|
+
|
1402
|
+
static VALUE
|
1403
|
+
lpsolve_initialize(VALUE self, VALUE num_vars, VALUE num_constraints)
|
1404
|
+
{
|
1405
|
+
int i_vars = NUM2INT(num_vars);
|
1406
|
+
int i_constraints = NUM2INT(num_constraints);
|
1407
|
+
lprec *lp = make_lp(i_vars, i_constraints);
|
1408
|
+
DATA_PTR(self) = lp;
|
1409
|
+
rb_ivar_set(self, rb_intern("@status"), INT2FIX(SOLVE_NOT_CALLED));
|
1410
|
+
return self;
|
1411
|
+
}
|
1412
|
+
|
1413
|
+
/** A wrapper for is_debug().
|
1414
|
+
|
1415
|
+
Returns a flag if all intermediate results and the
|
1416
|
+
branch-and-bound decisions must be printed while solving. This
|
1417
|
+
function is meant for debugging purposes. The default is not to
|
1418
|
+
debug.
|
1419
|
+
|
1420
|
+
Returns a flag if
|
1421
|
+
@param self self
|
1422
|
+
|
1423
|
+
@return true, false, or nil on error. If true is returned, all
|
1424
|
+
intermediate results and the branch-and-bound decisions will be
|
1425
|
+
printed while solving.
|
1426
|
+
*/
|
1427
|
+
static VALUE lpsolve_is_debug(VALUE self);
|
1428
|
+
LPSOLVE_0_IN_BOOL_OUT(is_debug);
|
1429
|
+
|
1430
|
+
/** A wrapper for is_maxim().
|
1431
|
+
|
1432
|
+
@param self self
|
1433
|
+
@return boolean or nil on error.
|
1434
|
+
*/
|
1435
|
+
static VALUE lpsolve_is_maxim(VALUE self);
|
1436
|
+
LPSOLVE_0_IN_BOOL_OUT(is_maxim);
|
1437
|
+
|
1438
|
+
/** A wrapper for is_SOS_var().
|
1439
|
+
|
1440
|
+
Returns if a variable is a SOS variable or not. By default a variable
|
1441
|
+
is not SOS. A variable becomes a SOS variable via lpsolve_add_SOS().
|
1442
|
+
|
1443
|
+
@param column the column number of the variable to be checked. It
|
1444
|
+
should be between 1 and the number of columns in the lp.
|
1445
|
+
@param self self
|
1446
|
+
@return boolean or nil on error.
|
1447
|
+
*/
|
1448
|
+
static VALUE lpsolve_is_SOS_var(VALUE self, VALUE column);
|
1449
|
+
LPSOLVE_1_IN_BOOL_OUT(is_SOS_var, T_FIXNUM, "an integer", FIX2INT)
|
1450
|
+
|
1451
|
+
static void __WINAPI
|
1452
|
+
lpsolve_logfunction(lprec *lp, void *userhandle, char *buf)
|
1453
|
+
{
|
1454
|
+
printf("***%s\n", buf);
|
1455
|
+
}
|
1456
|
+
|
1457
|
+
/**
|
1458
|
+
Constructs a new LP. Sets all variables to initial values. The LP
|
1459
|
+
has rows rows and columns columns. The matrix contains no values,
|
1460
|
+
but space for one value. All arrays that depend on rows and columns
|
1461
|
+
are allocated.
|
1462
|
+
|
1463
|
+
@param class_or_model_name either the class or module name which this
|
1464
|
+
is to belong to (it will be equal to LPSolve or LPsolve). If you are
|
1465
|
+
calling from Ruby, this parameter will be taken care of automatically.
|
1466
|
+
@param num_vars number of variables or columns
|
1467
|
+
@param num_constraints number of constraints or rows
|
1468
|
+
|
1469
|
+
@return nil is returned if there was an error.
|
1470
|
+
*/
|
1471
|
+
|
1472
|
+
static VALUE
|
1473
|
+
lpsolve_make_lp(VALUE class_or_model_name, VALUE num_constraints,
|
1474
|
+
VALUE num_vars)
|
1475
|
+
{
|
1476
|
+
int i_constraints = NUM2INT(num_constraints);
|
1477
|
+
int i_vars = NUM2INT(num_vars);
|
1478
|
+
lprec *lp = make_lp(i_constraints, i_vars);
|
1479
|
+
if (NULL == lp) {
|
1480
|
+
return Qnil;
|
1481
|
+
} else {
|
1482
|
+
VALUE obj = lpsolve_alloc(rb_cLPSolve);
|
1483
|
+
DATA_PTR(obj) = lp;
|
1484
|
+
return obj;
|
1485
|
+
}
|
1486
|
+
}
|
1487
|
+
|
1488
|
+
/** A wrapper for print_duals().
|
1489
|
+
|
1490
|
+
@param self self
|
1491
|
+
@return \a true unless we have an error.
|
1492
|
+
*/
|
1493
|
+
LPSOLVE_0_IN_STATUS_OUT(print_duals)
|
1494
|
+
|
1495
|
+
/** A wrapper for print_debugdump().
|
1496
|
+
|
1497
|
+
The print_debugdump function creates a generic readable data dump
|
1498
|
+
of key lp_solve model variables; principally for run difference and
|
1499
|
+
debugging purposes This function is meant for debugging purposes.
|
1500
|
+
|
1501
|
+
@return \a true if we could write the output file.
|
1502
|
+
*/
|
1503
|
+
static VALUE lpsolve_print_debugdump(VALUE self, VALUE filename);
|
1504
|
+
LPSOLVE_1_STR_IN_BOOL_OUT(print_debugdump)
|
1505
|
+
|
1506
|
+
/** A wrapper for print_lp.
|
1507
|
+
|
1508
|
+
@param self self
|
1509
|
+
@return \a true unless we have an error.
|
1510
|
+
*/
|
1511
|
+
static VALUE lpsolve_print_lp(VALUE self);
|
1512
|
+
LPSOLVE_0_IN_STATUS_OUT(print_lp)
|
1513
|
+
|
1514
|
+
static VALUE lpsolve_print(VALUE self);
|
1515
|
+
void print(lprec *lp);
|
1516
|
+
LPSOLVE_0_IN_STATUS_OUT(print)
|
1517
|
+
|
1518
|
+
/** A wrapper for print_constraints.
|
1519
|
+
@param self self
|
1520
|
+
@param num constraint number.
|
1521
|
+
@return \a true unless we have an error.
|
1522
|
+
*/
|
1523
|
+
static VALUE lpsolve_print_constraints(VALUE self, VALUE num);
|
1524
|
+
LPSOLVE_1_IN_STATUS_OUT(print_constraints, FIX2INT(param1));
|
1525
|
+
|
1526
|
+
/** A wrapper for print_logfunc
|
1527
|
+
@return nil.
|
1528
|
+
*/
|
1529
|
+
static VALUE
|
1530
|
+
lpsolve_put_logfunc(VALUE self, VALUE logfunc_name)
|
1531
|
+
{
|
1532
|
+
lprec *lp;
|
1533
|
+
rb_define_readonly_variable("@logfunc_name", &logfunc_name);
|
1534
|
+
Data_Get_Struct(self, lprec, lp);
|
1535
|
+
put_logfunc(lp, lpsolve_logfunction, NULL);
|
1536
|
+
return Qnil;
|
1537
|
+
}
|
1538
|
+
|
1539
|
+
/** A wrapper for print_objective.
|
1540
|
+
@return nil.
|
1541
|
+
*/
|
1542
|
+
LPSOLVE_0_IN_STATUS_OUT(print_objective)
|
1543
|
+
|
1544
|
+
/** A wrapper for print_tableau().
|
1545
|
+
|
1546
|
+
The print_tableau function prints the tableau. This function only
|
1547
|
+
works after a successful solve This function is meant for
|
1548
|
+
debugging purposes. By default, the output is stdout. However this
|
1549
|
+
can be changed via a call to set_outputstream, set_outputfile.
|
1550
|
+
|
1551
|
+
@param self self
|
1552
|
+
@return \a true unless we have an error.
|
1553
|
+
*/
|
1554
|
+
LPSOLVE_0_IN_STATUS_OUT(print_tableau)
|
1555
|
+
|
1556
|
+
/** A wrapper for read_LP.
|
1557
|
+
|
1558
|
+
Create a LPSolve object and read an lp model from file.
|
1559
|
+
|
1560
|
+
Returns anew LPSolve object. A Nil return value indicates an
|
1561
|
+
error. Specifically file could not be opened or file has wrong
|
1562
|
+
structure or not enough memory available to setup an lprec
|
1563
|
+
structure.
|
1564
|
+
|
1565
|
+
*/
|
1566
|
+
static VALUE
|
1567
|
+
lpsolve_read_LP(VALUE model, VALUE filename, VALUE verbosity,
|
1568
|
+
VALUE model_name)
|
1569
|
+
{
|
1570
|
+
lprec *lp;
|
1571
|
+
|
1572
|
+
if (TYPE(filename) != T_STRING) {
|
1573
|
+
return Qnil;
|
1574
|
+
}
|
1575
|
+
|
1576
|
+
if (TYPE(verbosity) != T_FIXNUM) {
|
1577
|
+
return Qnil;
|
1578
|
+
}
|
1579
|
+
|
1580
|
+
if (TYPE(model_name) != T_STRING) {
|
1581
|
+
return Qnil;
|
1582
|
+
}
|
1583
|
+
|
1584
|
+
lp = read_LP(RSTRING_PTR(filename), verbosity, RSTRING_PTR(model_name));
|
1585
|
+
if (NULL == lp) {
|
1586
|
+
return Qnil;
|
1587
|
+
} else {
|
1588
|
+
VALUE obj = lpsolve_alloc(rb_cLPSolve);
|
1589
|
+
DATA_PTR(obj) = lp;
|
1590
|
+
return obj;
|
1591
|
+
}
|
1592
|
+
}
|
1593
|
+
|
1594
|
+
/** A wrapper for read_MPS.
|
1595
|
+
|
1596
|
+
Create a LPSolve object and read an MPS model from a file.
|
1597
|
+
|
1598
|
+
Returns a new LPSolve Object. A Nil return value indicates an
|
1599
|
+
error. Specifically file could not be opened or file has wrong
|
1600
|
+
structure or not enough memory available to setup an lprec
|
1601
|
+
structure.
|
1602
|
+
|
1603
|
+
*/
|
1604
|
+
static VALUE
|
1605
|
+
lpsolve_read_MPS(VALUE module, VALUE filename, VALUE verbosity)
|
1606
|
+
{
|
1607
|
+
lprec *lp;
|
1608
|
+
|
1609
|
+
if (TYPE(filename) != T_STRING) {
|
1610
|
+
return Qnil;
|
1611
|
+
}
|
1612
|
+
|
1613
|
+
if (TYPE(verbosity) != T_FIXNUM) {
|
1614
|
+
return Qnil;
|
1615
|
+
}
|
1616
|
+
|
1617
|
+
lp = read_MPS(RSTRING_PTR(filename), verbosity);
|
1618
|
+
if (NULL == lp) {
|
1619
|
+
return Qnil;
|
1620
|
+
} else {
|
1621
|
+
VALUE obj = lpsolve_alloc(rb_cLPSolve);
|
1622
|
+
DATA_PTR(obj) = lp;
|
1623
|
+
return obj;
|
1624
|
+
}
|
1625
|
+
}
|
1626
|
+
|
1627
|
+
/** A wrapper for print_str
|
1628
|
+
|
1629
|
+
Prints a string. By default, the output is stdout. However this
|
1630
|
+
can be changed via a call to lpsolve_set_outputfile(). Possibly
|
1631
|
+
useful for debugging/demo purposes.
|
1632
|
+
|
1633
|
+
@param self self
|
1634
|
+
@param str the string to print
|
1635
|
+
|
1636
|
+
@return \a true if string was printed; false on error such as the
|
1637
|
+
str parameter is not a string type.
|
1638
|
+
*/
|
1639
|
+
static VALUE
|
1640
|
+
lpsolve_print_str(VALUE self, VALUE str)
|
1641
|
+
{
|
1642
|
+
lprec *lp;
|
1643
|
+
Data_Get_Struct(self, lprec, lp);
|
1644
|
+
|
1645
|
+
if (TYPE(str) != T_STRING) {
|
1646
|
+
report(lp, IMPORTANT,
|
1647
|
+
"%s: parameter 2 is not a string.\n",
|
1648
|
+
__FUNCTION__);
|
1649
|
+
return Qfalse;
|
1650
|
+
}
|
1651
|
+
|
1652
|
+
print_str(lp, RSTRING_PTR(str));
|
1653
|
+
return Qtrue;
|
1654
|
+
}
|
1655
|
+
|
1656
|
+
/** A wrapper for print_solution.
|
1657
|
+
|
1658
|
+
Prints the solution (variables) of the lp. This can only be done
|
1659
|
+
after a successful solve. This function is meant for debugging
|
1660
|
+
purposes. By default, the output is stdout. However this can be
|
1661
|
+
changed via a call to lpsolve_set_outputfile().
|
1662
|
+
|
1663
|
+
@param self self
|
1664
|
+
@param columns Number of columns to use in printing the solution.
|
1665
|
+
if columns is negative we will only print those variables which are
|
1666
|
+
nonzero.
|
1667
|
+
|
1668
|
+
@return \a true unless we have an error.
|
1669
|
+
*/
|
1670
|
+
static VALUE lpsolve_print_solution(VALUE self, VALUE columns);
|
1671
|
+
static VALUE
|
1672
|
+
lpsolve_print_solution(VALUE self, VALUE columns)
|
1673
|
+
{
|
1674
|
+
lprec *lp;
|
1675
|
+
int i_columns = FIX2INT(columns);
|
1676
|
+
Data_Get_Struct(self, lprec, lp);
|
1677
|
+
if (NULL == lp) return Qfalse;
|
1678
|
+
if (i_columns < 0) {
|
1679
|
+
int print_sol_save = lp->print_sol;
|
1680
|
+
lp->print_sol = lp->print_sol | AUTOMATIC;
|
1681
|
+
print_solution(lp, -i_columns);
|
1682
|
+
lp->print_sol = print_sol_save;
|
1683
|
+
} else {
|
1684
|
+
print_solution(lp, i_columns);
|
1685
|
+
}
|
1686
|
+
return Qtrue;
|
1687
|
+
}
|
1688
|
+
|
1689
|
+
/** wrapper for set_bb_depthlimit
|
1690
|
+
|
1691
|
+
Sets the maximum branch-and-bound depth.
|
1692
|
+
|
1693
|
+
Parameters
|
1694
|
+
|
1695
|
+
lp
|
1696
|
+
|
1697
|
+
Pointer to previously created lp model. See return value of make_lp, copy_lp, read_lp, read_LP, read_mps, read_freemps, read_MPS, read_freeMPS, read_XLI
|
1698
|
+
|
1699
|
+
bb_maxlevel
|
1700
|
+
|
1701
|
+
Specifies the maximum branch-and-bound depth. A positive value means
|
1702
|
+
that the depth is absoluut. A negative value means a relative B&B
|
1703
|
+
depth limit. The "order" of a MIP problem is defined to be 2x the
|
1704
|
+
number of binary variables plus the number of SC and SOS variables. A
|
1705
|
+
relative value of -x results in a maximum depth of x times the order
|
1706
|
+
of the MIP problem.
|
1707
|
+
|
1708
|
+
Remarks
|
1709
|
+
|
1710
|
+
The set_bb_depthlimit function sets the maximum branch-and-bound
|
1711
|
+
depth. This is only useful if there are integer, semi-continious or
|
1712
|
+
SOS variables in the model so that the branch-and-bound algorithm must
|
1713
|
+
be used to solve them. The branch-and-bound algorithm will not go
|
1714
|
+
deeper than this level. When 0 then there is no limit to the
|
1715
|
+
depth. Limiting the depth will speed up solving time, but there is a
|
1716
|
+
chance that the found solution is not the most optimal one. Be aware
|
1717
|
+
of this. It can also result in not finding a solution at all. The
|
1718
|
+
default is -50.
|
1719
|
+
*/
|
1720
|
+
static VALUE lpsolve_set_bb_depthlimit(VALUE self, VALUE limit);
|
1721
|
+
LPSOLVE_1_IN_STATUS_OUT(set_bb_depthlimit, FIX2INT(param1));
|
1722
|
+
|
1723
|
+
/** wrapper for set_bb_bb_rule
|
1724
|
+
|
1725
|
+
The set_bb_rule function specifies the branch-and-bound rule for
|
1726
|
+
choosing which non-integer variable is to be selected. This rule can
|
1727
|
+
influence solving times considerably. Depending on the model one rule
|
1728
|
+
can be best and for another model another rule. The default is
|
1729
|
+
NODE_FIRSTSELECT (0).
|
1730
|
+
|
1731
|
+
*/
|
1732
|
+
static VALUE lpsolve_set_bb_rule(VALUE self, VALUE bb_rule);
|
1733
|
+
LPSOLVE_1_IN_STATUS_OUT(set_bb_rule, FIX2INT(param1));
|
1734
|
+
|
1735
|
+
/** A wrapper for set_add_rowmode().
|
1736
|
+
|
1737
|
+
Normally a model is built either column by column or row by row.
|
1738
|
+
|
1739
|
+
The default \a on_off setting is \a false, which assumes model
|
1740
|
+
building column by column. So lpsolve_add_column(),
|
1741
|
+
lpsolve_add_columnex(), and lpsolve_str_add_column() perform best
|
1742
|
+
here.
|
1743
|
+
|
1744
|
+
If the model is built row by row via lpsolve_add_constraint(),
|
1745
|
+
lpsolve_add_constraintex(), or lpsolve_str_add_constraint() calls,
|
1746
|
+
then these routines will be much faster if this routine is called
|
1747
|
+
with \a on_off set \a true. The speed improvement is spectacular,
|
1748
|
+
especially for bigger models, so it is advisable to call this
|
1749
|
+
routine to set the mode.
|
1750
|
+
|
1751
|
+
There are several restrictions with this mode. Only use this
|
1752
|
+
function after lpsolve_make_lp() is called, not when the model is
|
1753
|
+
read from a file. Also, if this function is used, first add the
|
1754
|
+
objective function via set_obj_fn, set_obj_fnex, str_set_obj_fn
|
1755
|
+
and after that add the constraints via add_constraint,
|
1756
|
+
add_constraintex, str_add_constraint. Don't call other API
|
1757
|
+
functions while in row entry mode. No other data matrix access is
|
1758
|
+
allowed while in row entry mode. After adding the contraints, turn
|
1759
|
+
row entry mode back off. Once turned off, you cannot switch back to
|
1760
|
+
row entry mode. So in short: - turn row entry mode on - set the
|
1761
|
+
objective function - create the constraints - turn row entry mode
|
1762
|
+
off
|
1763
|
+
|
1764
|
+
@param self self
|
1765
|
+
@param on_off \a true if are going to add by rows, \a false if not
|
1766
|
+
or addign by columns.
|
1767
|
+
|
1768
|
+
@return \a true if changed from mode and \a false if this mode was
|
1769
|
+
already set; \a nil if there was an error
|
1770
|
+
*/
|
1771
|
+
static VALUE lpsolve_set_add_rowmode(VALUE self, VALUE on_off);
|
1772
|
+
LPSOLVE_1_BOOL_IN_BOOL_OUT(set_add_rowmode);
|
1773
|
+
|
1774
|
+
/** A wrapper for set_binary().
|
1775
|
+
|
1776
|
+
Set the type of the variable to be binary or floating point.
|
1777
|
+
The default type of a variable is floating point.
|
1778
|
+
|
1779
|
+
@param self self
|
1780
|
+
|
1781
|
+
@param column_num column number.
|
1782
|
+
|
1783
|
+
@param new_bool \a true if you want the column (variable) to take
|
1784
|
+
on a binary value, \a false or \a nil if you want the column to
|
1785
|
+
take on a floating-point value. If no value is given we assume \a
|
1786
|
+
true (set to binary).
|
1787
|
+
|
1788
|
+
@return \a true if the operation was successful, \a false if there
|
1789
|
+
was an error.
|
1790
|
+
*/
|
1791
|
+
#if 0
|
1792
|
+
LPSOLVE_SET_VARTYPE(set_binary)
|
1793
|
+
#endif
|
1794
|
+
|
1795
|
+
/** A wrapper for set_bounds().
|
1796
|
+
|
1797
|
+
The set_bounds function sets a lower and upper bound on the
|
1798
|
+
variable identified by column. Setting a bound on a variable is
|
1799
|
+
the way to go instead of adding an extra constraint (row) to the
|
1800
|
+
model. Setting a bound doesn't increase the model size that means
|
1801
|
+
that the model stays smaller and will be solved faster. Note that
|
1802
|
+
the default lower bound of each variable is 0. So variables will
|
1803
|
+
never take negative values if no negative lower bound is set. The
|
1804
|
+
default upper bound of a variable is infinity (well not quite. It
|
1805
|
+
is a very big number. The value of get_infinite).
|
1806
|
+
|
1807
|
+
@return \a true if no errors.
|
1808
|
+
*/
|
1809
|
+
static VALUE
|
1810
|
+
lpsolve_set_bounds(VALUE self, VALUE column_num, VALUE lower_bound,
|
1811
|
+
VALUE upper_bound)
|
1812
|
+
{
|
1813
|
+
INIT_LP;
|
1814
|
+
if (TYPE(column_num) != T_FIXNUM) {
|
1815
|
+
report(lp, IMPORTANT,
|
1816
|
+
"%s: column number, parameter 1, is not an integer.\n",
|
1817
|
+
__FUNCTION__);
|
1818
|
+
return Qfalse;
|
1819
|
+
}
|
1820
|
+
|
1821
|
+
RETURN_BOOL(set_bounds(lp, FIX2INT(column_num),
|
1822
|
+
NUM2DBL(lower_bound), NUM2DBL(upper_bound)));
|
1823
|
+
}
|
1824
|
+
|
1825
|
+
/** A wrapper for set_col_name
|
1826
|
+
Returns a Ruby string column name.
|
1827
|
+
*/
|
1828
|
+
static VALUE
|
1829
|
+
lpsolve_set_col_name(VALUE self, VALUE column_num, VALUE new_name)
|
1830
|
+
{
|
1831
|
+
INIT_LP;
|
1832
|
+
|
1833
|
+
if (TYPE(column_num) != T_FIXNUM) {
|
1834
|
+
report(lp, IMPORTANT,
|
1835
|
+
"%s: column number, parameter 1, is not an integer.\n",
|
1836
|
+
__FUNCTION__);
|
1837
|
+
return Qnil;
|
1838
|
+
}
|
1839
|
+
|
1840
|
+
if (TYPE(new_name) != T_STRING) {
|
1841
|
+
report(lp, IMPORTANT,
|
1842
|
+
"%s: new name, parameter 2, is not a string.\n",
|
1843
|
+
__FUNCTION__);
|
1844
|
+
return Qnil;
|
1845
|
+
}
|
1846
|
+
|
1847
|
+
return set_col_name(lp, FIX2INT(column_num), RSTRING_PTR(new_name)) ?
|
1848
|
+
Qtrue: Qfalse;
|
1849
|
+
}
|
1850
|
+
|
1851
|
+
/** A wrapper for set_debug
|
1852
|
+
|
1853
|
+
Sets a flag if all intermediate results and the branch-and-bound
|
1854
|
+
decisions must be printed while solving.
|
1855
|
+
|
1856
|
+
@return \a true if no errors, false if an error (e.g. you didn't
|
1857
|
+
pass true or false).
|
1858
|
+
*/
|
1859
|
+
static VALUE
|
1860
|
+
lpsolve_set_debug(VALUE self, VALUE new_bool)
|
1861
|
+
{
|
1862
|
+
if (new_bool != Qtrue && new_bool != Qfalse) {
|
1863
|
+
return Qfalse;
|
1864
|
+
} else {
|
1865
|
+
INIT_LP;
|
1866
|
+
set_debug(lp, Qtrue == new_bool);
|
1867
|
+
return Qtrue;
|
1868
|
+
}
|
1869
|
+
}
|
1870
|
+
|
1871
|
+
/** A wrapper for set_int
|
1872
|
+
|
1873
|
+
Set the type of the variable to be integer or floating point.
|
1874
|
+
The default type of a variable is floating point.
|
1875
|
+
|
1876
|
+
The argument \a new_bool specifies what the status of the variable
|
1877
|
+
becomes. From the moment there is at least one integer variable in
|
1878
|
+
the model, the Branch and Bound algorithm is used to make these
|
1879
|
+
variables integer. Note that solving times can be considerably
|
1880
|
+
larger when there are integer variables.
|
1881
|
+
|
1882
|
+
@param self self
|
1883
|
+
|
1884
|
+
@param column_num column number of variable
|
1885
|
+
|
1886
|
+
@param new_bool \a true if you want the column (variable) to be an
|
1887
|
+
integer, \a false or \a nil if you want the column not to take on
|
1888
|
+
a floating-point value. If no parameter is given, we assumed it
|
1889
|
+
to be true (set to integer).
|
1890
|
+
|
1891
|
+
@param new_bool
|
1892
|
+
|
1893
|
+
@return \a true if the operation was successful, \a false if there
|
1894
|
+
was an error.
|
1895
|
+
*/
|
1896
|
+
LPSOLVE_SET_VARTYPE(set_int)
|
1897
|
+
|
1898
|
+
/** A wrapper for set_lp_name
|
1899
|
+
|
1900
|
+
Set the name of the lp. Returns true if the operation was
|
1901
|
+
successful. A return value of false indicates an error.
|
1902
|
+
*/
|
1903
|
+
static VALUE lpsolve_set_lp_name(VALUE self, VALUE model_name);
|
1904
|
+
LPSOLVE_1_STR_IN_BOOL_OUT(set_lp_name)
|
1905
|
+
|
1906
|
+
/** A wrapper for set_lowbo().
|
1907
|
+
@return \a true if no errors.
|
1908
|
+
*/
|
1909
|
+
static VALUE
|
1910
|
+
lpsolve_set_lowbo(VALUE self, VALUE column, VALUE val)
|
1911
|
+
{
|
1912
|
+
INIT_LP;
|
1913
|
+
if (TYPE(column) != T_FIXNUM) {
|
1914
|
+
report(lp, IMPORTANT,
|
1915
|
+
"%s: column number, parameter 1, is not an integer.\n",
|
1916
|
+
__FUNCTION__);
|
1917
|
+
return Qnil;
|
1918
|
+
}
|
1919
|
+
RETURN_BOOL(set_lowbo(lp, FIX2INT(column), NUM2DBL(val)));
|
1920
|
+
}
|
1921
|
+
|
1922
|
+
/** A wrapper for set_mat().
|
1923
|
+
@return \a true if no errors.
|
1924
|
+
*/
|
1925
|
+
static VALUE
|
1926
|
+
lpsolve_set_mat(VALUE self, VALUE row, VALUE column, VALUE val)
|
1927
|
+
{
|
1928
|
+
INIT_LP;
|
1929
|
+
RETURN_BOOL(set_mat(lp, FIX2INT(row), FIX2INT(column), NUM2DBL(val)));
|
1930
|
+
}
|
1931
|
+
|
1932
|
+
/** A wrapper for set_maxim().
|
1933
|
+
|
1934
|
+
Sets the objective direction to maximize. The default is to
|
1935
|
+
minimize, except when reading a model in via lpsolve_read_LP.
|
1936
|
+
|
1937
|
+
@return \a true unless we have an error.
|
1938
|
+
*/
|
1939
|
+
static VALUE lpsolve_set_maxim(VALUE self);
|
1940
|
+
LPSOLVE_0_IN_STATUS_OUT(set_maxim)
|
1941
|
+
|
1942
|
+
/** A wrapper for set_minim().
|
1943
|
+
|
1944
|
+
Sets the objective direction to minimize. The default is to
|
1945
|
+
minimize, except when reading a model in via lpsolve_read_LP.
|
1946
|
+
|
1947
|
+
@return \a true unless we have an error.
|
1948
|
+
*/
|
1949
|
+
static VALUE lpsolve_set_minim(VALUE self);
|
1950
|
+
LPSOLVE_0_IN_STATUS_OUT(set_minim)
|
1951
|
+
|
1952
|
+
/** A wrapper for set_mip_gap().
|
1953
|
+
|
1954
|
+
Sets the MIP gap that specifies a tolerance for the branch and bound
|
1955
|
+
algorithm. This tolerance is the difference between the best-found
|
1956
|
+
solution yet and the current solution. If the difference is smaller
|
1957
|
+
than this tolerance then the solution (and all the sub-solutions) is
|
1958
|
+
rejected. This can result in faster solving times, but results in a
|
1959
|
+
solution which is not the perfect solution. So be careful with this
|
1960
|
+
tolerance. The default mip_gap value is 1e-9
|
1961
|
+
|
1962
|
+
|
1963
|
+
@param self self
|
1964
|
+
@param abs_rel: set to true if the gap is absolute, or false for relative.
|
1965
|
+
@param val: gap value. The default mip_gap is 1e-9.
|
1966
|
+
@return \a true if no errors.
|
1967
|
+
*/
|
1968
|
+
static VALUE
|
1969
|
+
lpsolve_set_mip_gap(VALUE self, VALUE abs_rel, VALUE val)
|
1970
|
+
{
|
1971
|
+
INIT_LP;
|
1972
|
+
if (abs_rel != Qtrue && abs_rel != Qfalse && abs_rel != Qnil) {
|
1973
|
+
report(lp, IMPORTANT,
|
1974
|
+
"%s: Parameter is not a boolean or nil.\n",
|
1975
|
+
__FUNCTION__);
|
1976
|
+
return Qfalse;
|
1977
|
+
} else {
|
1978
|
+
set_mip_gap(lp, Qtrue == abs_rel, NUM2DBL(val));
|
1979
|
+
return Qtrue;
|
1980
|
+
}
|
1981
|
+
}
|
1982
|
+
|
1983
|
+
/** A wrapper for str_set_obj_fn().
|
1984
|
+
|
1985
|
+
Set the objective function (row 0) of the matrix.
|
1986
|
+
|
1987
|
+
@return \a true unless we have an error, then \a nil or \a false.
|
1988
|
+
*/
|
1989
|
+
static VALUE
|
1990
|
+
lpsolve_set_obj_fnex(VALUE self, VALUE row_coeffs)
|
1991
|
+
{
|
1992
|
+
REAL *row = NULL;
|
1993
|
+
int *colno = NULL;
|
1994
|
+
long int i, count;
|
1995
|
+
VALUE ret = Qnil;
|
1996
|
+
VALUE *p_row_coeff = NULL;
|
1997
|
+
|
1998
|
+
INIT_LP;
|
1999
|
+
|
2000
|
+
/***FIXME: combine common parts of this with add_constraintex ****/
|
2001
|
+
if (TYPE(row_coeffs) != T_ARRAY) {
|
2002
|
+
report(lp, IMPORTANT,
|
2003
|
+
"%s: row coefficients parameter is not an array.\n",
|
2004
|
+
__FUNCTION__);
|
2005
|
+
return Qnil;
|
2006
|
+
}
|
2007
|
+
|
2008
|
+
count = RARRAY_LEN(row_coeffs);
|
2009
|
+
colno = ALLOC_N(int, count);
|
2010
|
+
row = ALLOC_N(REAL, count);
|
2011
|
+
|
2012
|
+
p_row_coeff = RARRAY_PTR(row_coeffs);
|
2013
|
+
for (i = 0; i < count; i++) {
|
2014
|
+
int i_col;
|
2015
|
+
if (TYPE(*p_row_coeff) != T_ARRAY) {
|
2016
|
+
report(lp, IMPORTANT,
|
2017
|
+
"%s: row coeffient element %d is not an array.\n",
|
2018
|
+
__FUNCTION__, i);
|
2019
|
+
goto done;
|
2020
|
+
}
|
2021
|
+
if (RARRAY_LEN(*p_row_coeff) != 2) {
|
2022
|
+
report(lp, IMPORTANT,
|
2023
|
+
"%s: row coeffient element %d is not an array tuple.\n",
|
2024
|
+
__FUNCTION__, i);
|
2025
|
+
goto done;
|
2026
|
+
} else {
|
2027
|
+
VALUE *tuple = RARRAY_PTR(*p_row_coeff);
|
2028
|
+
if (TYPE(tuple[0]) != T_FIXNUM) {
|
2029
|
+
report(lp, IMPORTANT,
|
2030
|
+
"%s: Column number, first element, of row coefficients at " \
|
2031
|
+
"tuple %d is not a integer.\n", __FUNCTION__, i);
|
2032
|
+
goto done;
|
2033
|
+
}
|
2034
|
+
switch (TYPE(tuple[1])) {
|
2035
|
+
case T_FIXNUM:
|
2036
|
+
case T_FLOAT: break;
|
2037
|
+
default:
|
2038
|
+
report(lp, IMPORTANT,
|
2039
|
+
"%s: Coefficient value, second element, of row coeffients at "
|
2040
|
+
"tuple %d is not an integer.\n", __FUNCTION__, i);
|
2041
|
+
goto done;
|
2042
|
+
}
|
2043
|
+
|
2044
|
+
i_col = FIX2INT(tuple[0]);
|
2045
|
+
if (i_col <= 0 || i_col > lp->columns) {
|
2046
|
+
report(lp, IMPORTANT,
|
2047
|
+
"%s: Column number, first element, of row coeffients at " \
|
2048
|
+
"tuple %d is in the range 1..%d\n",
|
2049
|
+
__FUNCTION__, i, lp->columns);
|
2050
|
+
goto done;
|
2051
|
+
}
|
2052
|
+
colno[i] = i_col;
|
2053
|
+
row[i] = NUM2DBL(tuple[1]);
|
2054
|
+
}
|
2055
|
+
p_row_coeff++;
|
2056
|
+
}
|
2057
|
+
|
2058
|
+
ret = set_obj_fnex(lp, count, row, colno) ? Qtrue : Qfalse ;
|
2059
|
+
|
2060
|
+
done:
|
2061
|
+
free(row);
|
2062
|
+
free(colno);
|
2063
|
+
return ret;
|
2064
|
+
|
2065
|
+
}
|
2066
|
+
|
2067
|
+
/** A wrapper for set_outputfile().
|
2068
|
+
|
2069
|
+
@return \a true if we could set the output file.
|
2070
|
+
*/
|
2071
|
+
static VALUE lpsolve_set_outputfile(VALUE self, VALUE filename);
|
2072
|
+
LPSOLVE_1_STR_IN_BOOL_OUT(set_outputfile)
|
2073
|
+
|
2074
|
+
/** A wrapper for set_presolve().
|
2075
|
+
|
2076
|
+
@return \a true if no errors.
|
2077
|
+
*/
|
2078
|
+
static VALUE lpsolve_set_presolve(VALUE self, VALUE do_presolve,
|
2079
|
+
VALUE maxloops)
|
2080
|
+
{
|
2081
|
+
INIT_LP;
|
2082
|
+
if (TYPE(do_presolve) != T_FIXNUM) {
|
2083
|
+
report(lp, IMPORTANT, "%s: Presolve parameter is not a number (bitmask).\n",
|
2084
|
+
__FUNCTION__);
|
2085
|
+
return Qnil;
|
2086
|
+
}
|
2087
|
+
if (TYPE(maxloops) != T_FIXNUM ) {
|
2088
|
+
report(lp, IMPORTANT,
|
2089
|
+
"%s: maxloops parameter should be a number (bitmask).\n",
|
2090
|
+
__FUNCTION__);
|
2091
|
+
return Qnil;
|
2092
|
+
}
|
2093
|
+
set_presolve(lp, FIX2INT(do_presolve), FIX2INT(maxloops));
|
2094
|
+
return Qtrue;
|
2095
|
+
}
|
2096
|
+
|
2097
|
+
|
2098
|
+
/** A wrapper for set_presolve().
|
2099
|
+
|
2100
|
+
@return \a true if no errors.
|
2101
|
+
*/
|
2102
|
+
static VALUE lpsolve_set_presolve1(VALUE self, VALUE do_presolve)
|
2103
|
+
{
|
2104
|
+
int i_maxloops;
|
2105
|
+
INIT_LP;
|
2106
|
+
if (TYPE(do_presolve) != T_FIXNUM) {
|
2107
|
+
report(lp, IMPORTANT, "%s: Presolve parameter is not a number (bitmask).\n",
|
2108
|
+
__FUNCTION__);
|
2109
|
+
return Qnil;
|
2110
|
+
}
|
2111
|
+
i_maxloops = get_presolveloops(lp);
|
2112
|
+
set_presolve(lp, FIX2INT(do_presolve), i_maxloops);
|
2113
|
+
return Qtrue;
|
2114
|
+
}
|
2115
|
+
|
2116
|
+
|
2117
|
+
/** A wrapper for set_rh().
|
2118
|
+
|
2119
|
+
(Re)Set the value of the right hand side (RHS) vector (column 0) for
|
2120
|
+
the specified row.
|
2121
|
+
|
2122
|
+
@param self self
|
2123
|
+
@param row_num the row number for which the RHS is to be must be set.
|
2124
|
+
Must be between 0 and number of rows in the lp.
|
2125
|
+
|
2126
|
+
@param value The value to set the RHS to.
|
2127
|
+
|
2128
|
+
@return \a true of no error, or \a nil if there was an error.
|
2129
|
+
*/
|
2130
|
+
static VALUE
|
2131
|
+
lpsolve_set_rh(VALUE self, VALUE row_num, VALUE value)
|
2132
|
+
{
|
2133
|
+
INIT_LP;
|
2134
|
+
set_rh(lp, FIX2INT(row_num), NUM2DBL(value));
|
2135
|
+
return Qnil;
|
2136
|
+
}
|
2137
|
+
|
2138
|
+
/** A wrapper for set_rh_range().
|
2139
|
+
|
2140
|
+
Set a range on the constraint (row) identified by row. Setting a
|
2141
|
+
range on a row is the way to go instead of another constraint (row) to
|
2142
|
+
the model. (Note that in either case, there are two API calls
|
2143
|
+
to set the lower and upper bound.
|
2144
|
+
|
2145
|
+
Setting a range doesn't increase the model size, and that means
|
2146
|
+
that the model stays smaller and will be solved faster. If the row
|
2147
|
+
previously had a less-than constraint, then the range means setting
|
2148
|
+
a minimum on the constraint that is equal to the RHS value minus
|
2149
|
+
the range. If the row has a greater-than constraint then the range
|
2150
|
+
means setting a maximum on the constraint that is equal to the RHS
|
2151
|
+
value plus the range. Note that the range value is the difference
|
2152
|
+
value and not the absolute value. Set the value of the right hand
|
2153
|
+
side (RHS) vector (column 0) for the specified row.
|
2154
|
+
|
2155
|
+
@param self self
|
2156
|
+
@param row_num the row number for which the RHS is to be must be set.
|
2157
|
+
Must be between 0 and number of rows in the lp.
|
2158
|
+
|
2159
|
+
@param value The value to set the RHS to.
|
2160
|
+
|
2161
|
+
@return \a true of no error, or \a nil if there was an error.
|
2162
|
+
*/
|
2163
|
+
static VALUE
|
2164
|
+
lpsolve_set_rh_range(VALUE self, VALUE row_num, VALUE deltavalue)
|
2165
|
+
{
|
2166
|
+
INIT_LP;
|
2167
|
+
RETURN_BOOL(set_rh_range(lp, FIX2INT(row_num), NUM2DBL(deltavalue)));
|
2168
|
+
}
|
2169
|
+
|
2170
|
+
/** A wrapper for set_row_name.
|
2171
|
+
|
2172
|
+
Set the name of a constraint (row) in the lp.
|
2173
|
+
|
2174
|
+
@return \a true if the operation was successful, false if not.
|
2175
|
+
*/
|
2176
|
+
static VALUE
|
2177
|
+
lpsolve_set_row_name(VALUE self, VALUE row_num, VALUE new_name)
|
2178
|
+
{
|
2179
|
+
INIT_LP;
|
2180
|
+
|
2181
|
+
if (TYPE(new_name) != T_STRING) {
|
2182
|
+
return Qfalse;
|
2183
|
+
}
|
2184
|
+
|
2185
|
+
RETURN_BOOL(set_row_name(lp, FIX2INT(row_num), RSTRING_PTR(new_name)));
|
2186
|
+
}
|
2187
|
+
|
2188
|
+
/** A wrapper for set_semicont().
|
2189
|
+
|
2190
|
+
Set the type of the variable (column) to be semi-continuous or not. By
|
2191
|
+
default, a variables are not semi-continuous. Note that a
|
2192
|
+
semi-continuous variable should have a nonzero lower bound to for this
|
2193
|
+
to have different effect. Recall that the default lower bound on
|
2194
|
+
variables is zero. The lower bound may be set before or after setting
|
2195
|
+
the semi-continuous status.
|
2196
|
+
|
2197
|
+
@param self self
|
2198
|
+
|
2199
|
+
@param column_num column number of the variable
|
2200
|
+
|
2201
|
+
@param new_bool true if you want the column (variable) to be a
|
2202
|
+
semi-continuous value, \a false or \a nil if you want the column
|
2203
|
+
not to take on a floating-point value. If no parameter specified,
|
2204
|
+
\a true is assumed
|
2205
|
+
|
2206
|
+
@return \a true if the operation was successful, \a false if there
|
2207
|
+
was an error.
|
2208
|
+
*/
|
2209
|
+
LPSOLVE_SET_VARTYPE(set_semicont)
|
2210
|
+
|
2211
|
+
/**
|
2212
|
+
return the status status code of the last solve.
|
2213
|
+
@param self self
|
2214
|
+
@return A return status number of the last solve.
|
2215
|
+
*/
|
2216
|
+
static VALUE lpsolve_set_status(VALUE self, VALUE newstatus)
|
2217
|
+
{
|
2218
|
+
INIT_LP;
|
2219
|
+
if (FIXNUM_P(newstatus))
|
2220
|
+
return rb_ivar_set(self, rb_intern("@status"), newstatus);
|
2221
|
+
else
|
2222
|
+
report(lp, IMPORTANT,
|
2223
|
+
"%s: status should be a Fixnum.\n", __FUNCTION__);
|
2224
|
+
return Qnil;
|
2225
|
+
}
|
2226
|
+
|
2227
|
+
|
2228
|
+
/** A wrapper for set_timeout().
|
2229
|
+
|
2230
|
+
In Ruby, you can also use accessor function timeout=.
|
2231
|
+
|
2232
|
+
The solve() and lag_solve() methods may not last longer than this
|
2233
|
+
time or the routines return with a timeout. The default timeout is
|
2234
|
+
0, resulting in no timeout. If a timout occurs, but there was
|
2235
|
+
already an integer solution found (that is possibly not the best),
|
2236
|
+
then solve will return LPSolve::SUBOPTIMAL. If there was no integer
|
2237
|
+
solution found yet or there are no integers or the solvers is
|
2238
|
+
still in the first phase where a REAL optimal solution is searched
|
2239
|
+
for, then solve will return TIMEOUT.
|
2240
|
+
|
2241
|
+
Set a timeout for solving .
|
2242
|
+
@param self self
|
2243
|
+
@param sec_timeout floating-point timeout value in seconds.
|
2244
|
+
@return nil.
|
2245
|
+
*/
|
2246
|
+
static VALUE
|
2247
|
+
lpsolve_set_timeout(VALUE self, VALUE sec_timeout)
|
2248
|
+
{
|
2249
|
+
INIT_LP;
|
2250
|
+
set_timeout(lp, NUM2DBL(sec_timeout));
|
2251
|
+
return Qnil;
|
2252
|
+
}
|
2253
|
+
|
2254
|
+
/** A wrapper for set_scaling().
|
2255
|
+
|
2256
|
+
Specifies which scaling algorithm must be used.
|
2257
|
+
|
2258
|
+
@return nil.
|
2259
|
+
*/
|
2260
|
+
static VALUE
|
2261
|
+
lpsolve_set_scaling(VALUE self, VALUE new_scalemode)
|
2262
|
+
{
|
2263
|
+
INIT_LP;
|
2264
|
+
set_scaling(lp, FIX2INT(new_scalemode));
|
2265
|
+
return Qnil;
|
2266
|
+
}
|
2267
|
+
|
2268
|
+
/** A wrapper for set_simplextype().
|
2269
|
+
|
2270
|
+
In Ruby, you can also use accessor function simplextype=.
|
2271
|
+
|
2272
|
+
@param self
|
2273
|
+
@param new_simplextype desired level of verbosity, an integer. @see
|
2274
|
+
lpsolve_get_simplextype() for simplex types.
|
2275
|
+
@return nil on error.
|
2276
|
+
*/
|
2277
|
+
static VALUE lpsolve_set_simplextype(VALUE self, VALUE new_simplextype);
|
2278
|
+
LPSOLVE_1_IN_STATUS_OUT(set_simplextype, FIX2INT(param1))
|
2279
|
+
|
2280
|
+
/** A wrapper for set_solutionlimit().
|
2281
|
+
|
2282
|
+
Sets the solution number that must be returned.
|
2283
|
+
|
2284
|
+
This function is only valid if there are integer, semi-continious
|
2285
|
+
or SOS variables in the model so that the branch-and-bound
|
2286
|
+
algoritm is used. If there are more solutions with the same
|
2287
|
+
objective value, then this number specifies which solution must be
|
2288
|
+
returned. This can be used to retrieve all possible
|
2289
|
+
solutions. Start with 1 till get_solutioncount
|
2290
|
+
|
2291
|
+
@param self
|
2292
|
+
@param limit number of solutions needed
|
2293
|
+
@return nil on error.
|
2294
|
+
|
2295
|
+
@return nil.
|
2296
|
+
*/
|
2297
|
+
static VALUE lpsolve_set_solutionlimit(VALUE self, VALUE limit);
|
2298
|
+
LPSOLVE_1_IN_STATUS_OUT(set_solutionlimit, FIX2INT(param1))
|
2299
|
+
|
2300
|
+
/** A wrapper for set_trace
|
2301
|
+
|
2302
|
+
Sets a flag if pivot selection must be printed while solving.
|
2303
|
+
|
2304
|
+
@param self self
|
2305
|
+
@param print_bool print if true; don't print if false.
|
2306
|
+
@return \a true if the operation was successful, FALSE if there was an error.
|
2307
|
+
*/
|
2308
|
+
static VALUE
|
2309
|
+
lpsolve_set_trace(VALUE self, VALUE print_bool)
|
2310
|
+
{
|
2311
|
+
if (print_bool != Qtrue && print_bool != Qfalse) {
|
2312
|
+
return Qfalse;
|
2313
|
+
} else {
|
2314
|
+
INIT_LP;
|
2315
|
+
set_trace(lp, Qtrue == print_bool);
|
2316
|
+
return Qtrue;
|
2317
|
+
}
|
2318
|
+
}
|
2319
|
+
|
2320
|
+
/** A wrapper for set_upbo().
|
2321
|
+
|
2322
|
+
@return \a true if no errors.
|
2323
|
+
*/
|
2324
|
+
static VALUE
|
2325
|
+
lpsolve_set_upbo(VALUE self, VALUE column, VALUE val)
|
2326
|
+
{
|
2327
|
+
INIT_LP;
|
2328
|
+
RETURN_BOOL(set_upbo(lp, FIX2INT(column), NUM2DBL(val)));
|
2329
|
+
}
|
2330
|
+
|
2331
|
+
/** A wrapper for set_verbose().
|
2332
|
+
|
2333
|
+
In Ruby, you can also use accessor function verbose=.
|
2334
|
+
|
2335
|
+
@param self
|
2336
|
+
@param new_verbosity desired level of verbosity, an integer. @see
|
2337
|
+
lpsolve_get_verbose() for verbosity levels.
|
2338
|
+
@return \a true unless we have an error.
|
2339
|
+
*/
|
2340
|
+
static VALUE lpsolve_set_verbose(VALUE self, VALUE new_verbosity);
|
2341
|
+
LPSOLVE_1_IN_STATUS_OUT(set_verbose, FIX2INT(param1))
|
2342
|
+
|
2343
|
+
/** A wrapper for solve().
|
2344
|
+
@returns 0 if no error.
|
2345
|
+
*/
|
2346
|
+
|
2347
|
+
static VALUE lpsolve_solve(VALUE self)
|
2348
|
+
{
|
2349
|
+
INIT_LP;
|
2350
|
+
if (NULL != lp) {
|
2351
|
+
VALUE status = INT2FIX(solve(lp));
|
2352
|
+
rb_ivar_set(self, rb_intern("@status"), status);
|
2353
|
+
return status;
|
2354
|
+
} else {
|
2355
|
+
return Qnil;
|
2356
|
+
}
|
2357
|
+
}
|
2358
|
+
|
2359
|
+
/** A wrapper for str_add_column().
|
2360
|
+
|
2361
|
+
@return \a true if the operation was successful. A false value
|
2362
|
+
indicates an error.
|
2363
|
+
*/
|
2364
|
+
static VALUE lpsolve_str_add_column(VALUE self, VALUE col_str);
|
2365
|
+
LPSOLVE_1_STR_IN_BOOL_OUT(str_add_column)
|
2366
|
+
|
2367
|
+
/** A wrapper for str_add_constraint().
|
2368
|
+
@return boolean
|
2369
|
+
*/
|
2370
|
+
static VALUE
|
2371
|
+
lpsolve_str_add_constraint(VALUE self, VALUE constraint,
|
2372
|
+
VALUE compare, VALUE num_constraints)
|
2373
|
+
{
|
2374
|
+
char *psz_constraint = RSTRING_PTR(constraint);
|
2375
|
+
int i_compare = NUM2INT(compare);
|
2376
|
+
int i_constraints = NUM2INT(num_constraints);
|
2377
|
+
lprec *lp;
|
2378
|
+
Data_Get_Struct(self, lprec, lp);
|
2379
|
+
RETURN_BOOL(str_add_constraint(lp, psz_constraint, i_compare, i_constraints));
|
2380
|
+
}
|
2381
|
+
|
2382
|
+
/** A wrapper for str_set_obj_fn().
|
2383
|
+
|
2384
|
+
Set the objective function (row 0) of the matrix via a string.
|
2385
|
+
|
2386
|
+
@return \a true unless we have an error.
|
2387
|
+
*/
|
2388
|
+
static VALUE
|
2389
|
+
lpsolve_str_set_obj_fn(VALUE self, VALUE obj_fn)
|
2390
|
+
{
|
2391
|
+
char *psz_obj_fn = RSTRING_PTR(obj_fn);
|
2392
|
+
lprec *lp;
|
2393
|
+
Data_Get_Struct(self, lprec, lp);
|
2394
|
+
RETURN_BOOL(str_set_obj_fn(lp, psz_obj_fn));
|
2395
|
+
}
|
2396
|
+
|
2397
|
+
/** A wrapper for time_elapsed().
|
2398
|
+
|
2399
|
+
The time_elapsed function returns the time in seconds since solve
|
2400
|
+
and lag_solve has started. In contrast to totaltime, the time does
|
2401
|
+
not include the load time. If solving has not completed he value
|
2402
|
+
will be the number of seconds of until the time of the call
|
2403
|
+
rather than the time the solve completed.
|
2404
|
+
|
2405
|
+
@param self self.
|
2406
|
+
|
2407
|
+
@return \a Floating-point number for time since solve and
|
2408
|
+
lag_solve has started
|
2409
|
+
*/
|
2410
|
+
static VALUE lpsolve_time_elapsed(VALUE self);
|
2411
|
+
LPSOLVE_0_IN_NUM_OUT(time_elapsed);
|
2412
|
+
|
2413
|
+
/** \fn time_load Return the amount of time used to load in data
|
2414
|
+
|
2415
|
+
@param self self
|
2416
|
+
|
2417
|
+
@return A Ruby floating-point number indicating how long the
|
2418
|
+
presolver solver took.
|
2419
|
+
|
2420
|
+
*/
|
2421
|
+
static VALUE lpsolve_time_load(VALUE self) ;
|
2422
|
+
LPSOLVE_0_IN_TIME_OUT(time_load, timecreate, timestart);
|
2423
|
+
|
2424
|
+
/** Return the amount of time used in the simplex solver
|
2425
|
+
|
2426
|
+
@param self self
|
2427
|
+
|
2428
|
+
@return A Ruby floating-point number indicating how long the
|
2429
|
+
simplex solver took.
|
2430
|
+
|
2431
|
+
This only makes sense if a problem was solved. See also
|
2432
|
+
the status instance variable.
|
2433
|
+
|
2434
|
+
In Ruby, you can also use accessor function simplextime
|
2435
|
+
*/
|
2436
|
+
static VALUE lpsolve_time_simplex(VALUE self) ;
|
2437
|
+
LPSOLVE_0_IN_TIME_OUT(time_simplex, timepresolved, timeend);
|
2438
|
+
|
2439
|
+
/** \fn time_presolve
|
2440
|
+
Return the amount of time used in the presolver
|
2441
|
+
|
2442
|
+
@param self self
|
2443
|
+
|
2444
|
+
@return A Ruby floating-point number indicating how long the
|
2445
|
+
presolver solver took.
|
2446
|
+
|
2447
|
+
This only makes sense if a problem was solved. See also
|
2448
|
+
the status instance variable.
|
2449
|
+
|
2450
|
+
In Ruby, you can also use accessor function simplextime
|
2451
|
+
*/
|
2452
|
+
static VALUE lpsolve_time_presolve(VALUE self) ;
|
2453
|
+
LPSOLVE_0_IN_TIME_OUT(time_presolve, timestart, timepresolved);
|
2454
|
+
|
2455
|
+
/** Return the total amount elapsed time from start to finish.
|
2456
|
+
|
2457
|
+
@param self self
|
2458
|
+
|
2459
|
+
@return A Ruby floating-point number indicating how long the
|
2460
|
+
simplex solver took.
|
2461
|
+
|
2462
|
+
This only makes sense if a problem was solved. See also
|
2463
|
+
the status instance variable.
|
2464
|
+
*/
|
2465
|
+
static VALUE lpsolve_time_total(VALUE self) ;
|
2466
|
+
LPSOLVE_0_IN_TIME_OUT(time_total, timecreate, timeend);
|
2467
|
+
|
2468
|
+
/** A wrapper for solve_unscale().
|
2469
|
+
|
2470
|
+
The get_bb_rule function returns the branch-and-bound rule for
|
2471
|
+
choosing which non-integer variable is to be selected. This rule
|
2472
|
+
can influence solving times considerably. Depending on the model
|
2473
|
+
one rule can be best and for another model another rule. The
|
2474
|
+
default is NODE_PSEUDONONINTSELECT + NODE_GREEDYMODE +
|
2475
|
+
NODE_DYNAMICMODE + NODE_RCOSTFIXING (17445).
|
2476
|
+
|
2477
|
+
@param self self
|
2478
|
+
@return Returns the branch-and-bound rule.
|
2479
|
+
|
2480
|
+
*/
|
2481
|
+
static VALUE lpsolve_unscale(VALUE self);
|
2482
|
+
LPSOLVE_0_IN_STATUS_OUT(unscale)
|
2483
|
+
|
2484
|
+
/** A wrapper for lp_solve_version().
|
2485
|
+
@return 4-tuple: [major_version, minor_version, release, build]
|
2486
|
+
*/
|
2487
|
+
static VALUE
|
2488
|
+
lpsolve_version(VALUE module_or_class)
|
2489
|
+
{
|
2490
|
+
int major_version;
|
2491
|
+
int minor_version;
|
2492
|
+
int release;
|
2493
|
+
int build;
|
2494
|
+
lp_solve_version(&major_version, &minor_version, &release, &build);
|
2495
|
+
return rb_ary_new3(4,
|
2496
|
+
INT2FIX(major_version), INT2FIX(minor_version),
|
2497
|
+
INT2FIX(release), INT2FIX(build));
|
2498
|
+
}
|
2499
|
+
|
2500
|
+
/** A wrapper for write_basis().
|
2501
|
+
|
2502
|
+
The write_basis function writes the current basis to filename.
|
2503
|
+
This basis can later be reused by read_basis to reset a basis. Setting
|
2504
|
+
an initial basis can speed up the solver considerably. It is the
|
2505
|
+
starting point from where the algorithm continues to find an optimal
|
2506
|
+
solution. When a restart is done, lp_solve continues at the last
|
2507
|
+
basis, except if set_basis, default_basis, guess_basis or read_basis
|
2508
|
+
is called.
|
2509
|
+
|
2510
|
+
The basis in the file is written in MPS bas file format.
|
2511
|
+
|
2512
|
+
@return \a true if we could write the output file.
|
2513
|
+
*/
|
2514
|
+
static VALUE lpsolve_write_basis(VALUE self, VALUE filename);
|
2515
|
+
LPSOLVE_1_STR_IN_BOOL_OUT(write_basis)
|
2516
|
+
|
2517
|
+
/** A wrapper for write_lp().
|
2518
|
+
|
2519
|
+
The model in the file will be written in LP-format unless there
|
2520
|
+
is an error.
|
2521
|
+
Note that row entry mode must be off, else this
|
2522
|
+
function also fails. @see lpsolve_set_add_rowmode()
|
2523
|
+
|
2524
|
+
@param self self
|
2525
|
+
|
2526
|
+
@param filename place to write LP file. If this is nil, then
|
2527
|
+
output is written the location specified by set_outputstream, or
|
2528
|
+
of that has not been set stdout.
|
2529
|
+
|
2530
|
+
@return \a true if we could write the output file.
|
2531
|
+
*/
|
2532
|
+
static VALUE lpsolve_write_lp(int argc, VALUE *argv, VALUE self)
|
2533
|
+
{
|
2534
|
+
VALUE filename;
|
2535
|
+
unsigned int i_scanned;
|
2536
|
+
INIT_LP;
|
2537
|
+
if ((argc > 1) || (argc < 0))
|
2538
|
+
rb_raise(rb_eArgError, "wrong number of arguments (%d for 0 or 1)", argc);
|
2539
|
+
i_scanned = rb_scan_args(argc, argv, "01", &filename);
|
2540
|
+
switch (i_scanned) {
|
2541
|
+
case 0:
|
2542
|
+
RETURN_BOOL(write_lp(lp, NULL));
|
2543
|
+
break;
|
2544
|
+
case 1:
|
2545
|
+
if (filename == Qnil)
|
2546
|
+
RETURN_BOOL(write_lp(lp, NULL));
|
2547
|
+
else if (TYPE(filename) != T_STRING) {
|
2548
|
+
report(lp, IMPORTANT, "%s: Parameter is not nil or a string filename.\n",
|
2549
|
+
__FUNCTION__);
|
2550
|
+
return Qnil;
|
2551
|
+
} else
|
2552
|
+
RETURN_BOOL(write_lp(lp, RSTRING_PTR(filename)));
|
2553
|
+
default:
|
2554
|
+
rb_raise(rb_eArgError, "wrong number of arguments (%d for 0 or 1)",
|
2555
|
+
i_scanned);
|
2556
|
+
}
|
2557
|
+
return Qfalse;
|
2558
|
+
}
|
2559
|
+
|
2560
|
+
/** A wrapper for write_mps().
|
2561
|
+
|
2562
|
+
The model in the file will be written in MPS-format unless there is an
|
2563
|
+
error.
|
2564
|
+
Note that row entry mode must be off, else this function also fails.
|
2565
|
+
@see lpsolve_set_add_rowmode()
|
2566
|
+
|
2567
|
+
@param self self
|
2568
|
+
|
2569
|
+
@param filename place to write MPS file. If this is nil, then
|
2570
|
+
output is written the location specified by set_outputstream, or
|
2571
|
+
of that has not been set stdout.
|
2572
|
+
|
2573
|
+
@return \a true if we could write the output file.
|
2574
|
+
*/
|
2575
|
+
static VALUE lpsolve_write_mps(int argc, VALUE *argv, VALUE self)
|
2576
|
+
{
|
2577
|
+
VALUE filename;
|
2578
|
+
unsigned int i_scanned;
|
2579
|
+
INIT_LP;
|
2580
|
+
if ((argc > 1) || (argc < 0))
|
2581
|
+
rb_raise(rb_eArgError, "wrong number of arguments (%d for 0 or 1)", argc);
|
2582
|
+
i_scanned = rb_scan_args(argc, argv, "01", &filename);
|
2583
|
+
switch (i_scanned) {
|
2584
|
+
case 0:
|
2585
|
+
RETURN_BOOL(write_mps(lp, NULL));
|
2586
|
+
|
2587
|
+
break;
|
2588
|
+
case 1:
|
2589
|
+
if (filename == Qnil)
|
2590
|
+
RETURN_BOOL(write_mps(lp, NULL));
|
2591
|
+
else if (TYPE(filename) != T_STRING) {
|
2592
|
+
report(lp, IMPORTANT, "%s: Parameter is not nil or a string filename.\n",
|
2593
|
+
__FUNCTION__);
|
2594
|
+
return Qnil;
|
2595
|
+
} else
|
2596
|
+
RETURN_BOOL(write_mps(lp, RSTRING_PTR(filename)));
|
2597
|
+
default:
|
2598
|
+
rb_raise(rb_eArgError, "wrong number of arguments (%d for 0 or 1)",
|
2599
|
+
i_scanned);
|
2600
|
+
}
|
2601
|
+
return Qfalse;
|
2602
|
+
}
|
2603
|
+
|
2604
|
+
extern void init_lpsolve_constants();
|
2605
|
+
/*#include "lpconsts.h" */
|
2606
|
+
|
2607
|
+
/** Called when we issue from Ruby:
|
2608
|
+
\verbatim
|
2609
|
+
require "lpsolve"
|
2610
|
+
\endverbatim
|
2611
|
+
*/
|
2612
|
+
void Init_lpsolve()
|
2613
|
+
{
|
2614
|
+
rb_cLPSolve = rb_define_class("LPSolve", rb_cObject);
|
2615
|
+
rb_define_alloc_func(rb_cLPSolve, lpsolve_alloc);
|
2616
|
+
|
2617
|
+
init_lpsolve_constants();
|
2618
|
+
|
2619
|
+
/* Class functions */
|
2620
|
+
rb_define_module_function(rb_cLPSolve, "make_lp", lpsolve_make_lp, 2);
|
2621
|
+
rb_define_module_function(rb_cLPSolve, "read_LP", lpsolve_read_LP, 3);
|
2622
|
+
rb_define_module_function(rb_cLPSolve, "read_MPS", lpsolve_read_MPS, 2);
|
2623
|
+
rb_define_module_function(rb_cLPSolve, "version", lpsolve_version, 0);
|
2624
|
+
|
2625
|
+
/* Class Methods */
|
2626
|
+
rb_define_method(rb_cLPSolve, "add_constraintex",
|
2627
|
+
lpsolve_add_constraintex, 4);
|
2628
|
+
rb_define_method(rb_cLPSolve, "add_SOS", lpsolve_add_SOS, 4);
|
2629
|
+
rb_define_method(rb_cLPSolve, "default_basis", lpsolve_default_basis, 0);
|
2630
|
+
rb_define_method(rb_cLPSolve, "del_column", lpsolve_del_column, 1);
|
2631
|
+
rb_define_method(rb_cLPSolve, "del_constraint", lpsolve_del_constraint, 1);
|
2632
|
+
rb_define_method(rb_cLPSolve, "get_bb_depthlimit",
|
2633
|
+
lpsolve_get_bb_depthlimit, 0);
|
2634
|
+
rb_define_method(rb_cLPSolve, "get_bb_rule", lpsolve_get_bb_rule, 0);
|
2635
|
+
rb_define_method(rb_cLPSolve, "get_col_name", lpsolve_get_col_name, 1);
|
2636
|
+
rb_define_method(rb_cLPSolve, "get_col_num", lpsolve_get_col_num, 1);
|
2637
|
+
rb_define_method(rb_cLPSolve, "get_column", lpsolve_get_column, 1);
|
2638
|
+
rb_define_method(rb_cLPSolve, "get_infinite", lpsolve_get_infinite, 0);
|
2639
|
+
rb_define_method(rb_cLPSolve, "get_lowbo", lpsolve_get_lowbo, 1);
|
2640
|
+
rb_define_method(rb_cLPSolve, "get_lp_name", lpsolve_get_lp_name, 0);
|
2641
|
+
rb_define_method(rb_cLPSolve, "get_mip_gap", lpsolve_get_mip_gap, 1);
|
2642
|
+
rb_define_method(rb_cLPSolve, "get_Ncolumns", lpsolve_get_Ncolumns, 0);
|
2643
|
+
rb_define_method(rb_cLPSolve, "get_Norig_columns",
|
2644
|
+
lpsolve_get_Norig_columns, 0);
|
2645
|
+
rb_define_method(rb_cLPSolve, "get_Norig_rows", lpsolve_get_Norig_rows, 0);
|
2646
|
+
rb_define_method(rb_cLPSolve, "get_Nrows", lpsolve_get_Nrows, 0);
|
2647
|
+
rb_define_method(rb_cLPSolve, "get_nonzeros", lpsolve_get_nonzeros, 0);
|
2648
|
+
rb_define_method(rb_cLPSolve, "get_mat", lpsolve_get_mat, 2);
|
2649
|
+
rb_define_method(rb_cLPSolve, "get_objective", lpsolve_get_objective, 0);
|
2650
|
+
rb_define_method(rb_cLPSolve, "get_origcol_name",
|
2651
|
+
lpsolve_get_origcol_name, 1);
|
2652
|
+
rb_define_method(rb_cLPSolve, "get_origrow_name",
|
2653
|
+
lpsolve_get_origrow_name, 1);
|
2654
|
+
rb_define_method(rb_cLPSolve, "get_presolve", lpsolve_get_presolve, 0);
|
2655
|
+
rb_define_method(rb_cLPSolve, "get_presolveloops",
|
2656
|
+
lpsolve_get_presolveloops, 0);
|
2657
|
+
rb_define_method(rb_cLPSolve, "get_row", lpsolve_get_row, 1);
|
2658
|
+
rb_define_method(rb_cLPSolve, "get_row_name", lpsolve_get_row_name, 1);
|
2659
|
+
rb_define_method(rb_cLPSolve, "get_scaling", lpsolve_get_scaling, 0);
|
2660
|
+
rb_define_method(rb_cLPSolve, "get_simplextype", lpsolve_get_simplextype, 0);
|
2661
|
+
rb_define_method(rb_cLPSolve, "get_solutioncount",
|
2662
|
+
lpsolve_get_solutioncount, 0);
|
2663
|
+
rb_define_method(rb_cLPSolve, "get_solutionlimit",
|
2664
|
+
lpsolve_get_solutionlimit, 0);
|
2665
|
+
rb_define_method(rb_cLPSolve, "get_status", lpsolve_get_status, 0);
|
2666
|
+
rb_define_method(rb_cLPSolve, "get_statustext", lpsolve_get_statustext, -1);
|
2667
|
+
rb_define_method(rb_cLPSolve, "get_timeout", lpsolve_get_timeout, 0);
|
2668
|
+
rb_define_method(rb_cLPSolve, "get_total_iter", lpsolve_get_total_iter, 0);
|
2669
|
+
rb_define_method(rb_cLPSolve, "get_upbo", lpsolve_get_upbo, 1);
|
2670
|
+
rb_define_method(rb_cLPSolve, "get_var_dualresult",
|
2671
|
+
lpsolve_get_var_dualresult, 1);
|
2672
|
+
rb_define_method(rb_cLPSolve, "get_var_primalresult",
|
2673
|
+
lpsolve_get_var_primalresult, 1);
|
2674
|
+
rb_define_method(rb_cLPSolve, "get_variables", lpsolve_get_variables, 0);
|
2675
|
+
rb_define_method(rb_cLPSolve, "get_verbose", lpsolve_get_verbose, 0);
|
2676
|
+
rb_define_method(rb_cLPSolve, "initialize", lpsolve_initialize, 2);
|
2677
|
+
rb_define_method(rb_cLPSolve, "is_debug", lpsolve_is_debug, 0);
|
2678
|
+
rb_define_method(rb_cLPSolve, "is_maxim", lpsolve_is_maxim, 0);
|
2679
|
+
rb_define_method(rb_cLPSolve, "is_SOS_var", lpsolve_is_SOS_var, 1);
|
2680
|
+
rb_define_method(rb_cLPSolve, "presolve=", lpsolve_set_presolve1, 1);
|
2681
|
+
rb_define_method(rb_cLPSolve, "print", lpsolve_print, 0);
|
2682
|
+
rb_define_method(rb_cLPSolve, "print_debugdump",
|
2683
|
+
lpsolve_print_debugdump, 1);
|
2684
|
+
rb_define_method(rb_cLPSolve, "print_constraints",
|
2685
|
+
lpsolve_print_constraints, 1);
|
2686
|
+
rb_define_method(rb_cLPSolve, "print_duals", lpsolve_print_duals, 0);
|
2687
|
+
rb_define_method(rb_cLPSolve, "print_lp", lpsolve_print_lp, 0);
|
2688
|
+
rb_define_method(rb_cLPSolve, "print_objective", lpsolve_print_objective, 0);
|
2689
|
+
rb_define_method(rb_cLPSolve, "print_str", lpsolve_print_str, 1);
|
2690
|
+
rb_define_method(rb_cLPSolve, "print_solution", lpsolve_print_solution, 1);
|
2691
|
+
rb_define_method(rb_cLPSolve, "print_tableau", lpsolve_print_tableau, 0);
|
2692
|
+
rb_define_method(rb_cLPSolve, "put_logfunc", lpsolve_put_logfunc, 1);
|
2693
|
+
rb_define_method(rb_cLPSolve, "set_add_rowmode", lpsolve_set_add_rowmode, 1);
|
2694
|
+
rb_define_method(rb_cLPSolve, "set_bb_depthlimit",
|
2695
|
+
lpsolve_set_bb_depthlimit, 1);
|
2696
|
+
rb_define_method(rb_cLPSolve, "set_bb_rule", lpsolve_set_bb_rule, 1);
|
2697
|
+
rb_define_method(rb_cLPSolve, "set_binary", lpsolve_set_binary, 2);
|
2698
|
+
rb_define_method(rb_cLPSolve, "set_bounds", lpsolve_set_bounds, 3);
|
2699
|
+
rb_define_method(rb_cLPSolve, "set_debug", lpsolve_set_debug, 1);
|
2700
|
+
rb_define_method(rb_cLPSolve, "set_col_name", lpsolve_set_col_name, 2);
|
2701
|
+
rb_define_method(rb_cLPSolve, "set_int", lpsolve_set_int, 2);
|
2702
|
+
rb_define_method(rb_cLPSolve, "set_mat", lpsolve_set_mat, 3);
|
2703
|
+
rb_define_method(rb_cLPSolve, "set_maxim", lpsolve_set_maxim, 0);
|
2704
|
+
rb_define_method(rb_cLPSolve, "set_minim", lpsolve_set_minim, 0);
|
2705
|
+
rb_define_method(rb_cLPSolve, "set_mip_gap", lpsolve_set_mip_gap, 2);
|
2706
|
+
rb_define_method(rb_cLPSolve, "set_lowbo", lpsolve_set_lowbo, 2);
|
2707
|
+
rb_define_method(rb_cLPSolve, "set_lp_name", lpsolve_set_lp_name, 1);
|
2708
|
+
rb_define_method(rb_cLPSolve, "set_obj_fnex", lpsolve_set_obj_fnex, 1);
|
2709
|
+
rb_define_method(rb_cLPSolve, "set_outputfile", lpsolve_set_outputfile, 1);
|
2710
|
+
rb_define_method(rb_cLPSolve, "set_presolve", lpsolve_set_presolve, 2);
|
2711
|
+
rb_define_method(rb_cLPSolve, "set_rh", lpsolve_set_rh, 2);
|
2712
|
+
rb_define_method(rb_cLPSolve, "set_rh_range", lpsolve_set_rh_range, 2);
|
2713
|
+
rb_define_method(rb_cLPSolve, "set_row_name", lpsolve_set_row_name, 2);
|
2714
|
+
rb_define_method(rb_cLPSolve, "set_semicont", lpsolve_set_semicont, 2);
|
2715
|
+
rb_define_method(rb_cLPSolve, "set_scaling", lpsolve_set_scaling, 1);
|
2716
|
+
rb_define_method(rb_cLPSolve, "set_simplextype", lpsolve_set_simplextype, 1);
|
2717
|
+
rb_define_method(rb_cLPSolve, "set_solutionlimit",
|
2718
|
+
lpsolve_set_solutionlimit, 1);
|
2719
|
+
rb_define_method(rb_cLPSolve, "set_status", lpsolve_set_status, 1);
|
2720
|
+
rb_define_method(rb_cLPSolve, "set_timeout", lpsolve_set_timeout, 1);
|
2721
|
+
rb_define_method(rb_cLPSolve, "set_trace", lpsolve_set_trace, 1);
|
2722
|
+
rb_define_method(rb_cLPSolve, "set_upbo", lpsolve_set_upbo, 2);
|
2723
|
+
rb_define_method(rb_cLPSolve, "set_verbose", lpsolve_set_verbose, 1);
|
2724
|
+
rb_define_method(rb_cLPSolve, "solve", lpsolve_solve, 0);
|
2725
|
+
rb_define_method(rb_cLPSolve, "str_add_column", lpsolve_str_add_column,
|
2726
|
+
1);
|
2727
|
+
rb_define_method(rb_cLPSolve, "str_add_constraint",
|
2728
|
+
lpsolve_str_add_constraint, 3);
|
2729
|
+
rb_define_method(rb_cLPSolve, "str_set_obj_fn",
|
2730
|
+
lpsolve_str_set_obj_fn, 1);
|
2731
|
+
rb_define_method(rb_cLPSolve, "time_elapsed", lpsolve_time_elapsed, 0);
|
2732
|
+
rb_define_method(rb_cLPSolve, "time_load", lpsolve_time_load, 0);
|
2733
|
+
rb_define_method(rb_cLPSolve, "time_presolve", lpsolve_time_presolve, 0);
|
2734
|
+
rb_define_method(rb_cLPSolve, "time_simplex", lpsolve_time_simplex, 0);
|
2735
|
+
rb_define_method(rb_cLPSolve, "time_total", lpsolve_time_total, 0);
|
2736
|
+
rb_define_method(rb_cLPSolve, "unscale", lpsolve_unscale, 0);
|
2737
|
+
rb_define_method(rb_cLPSolve, "version", lpsolve_version, 0);
|
2738
|
+
rb_define_method(rb_cLPSolve, "write_basis", lpsolve_write_basis, 1);
|
2739
|
+
rb_define_method(rb_cLPSolve, "write_lp", lpsolve_write_lp, -1);
|
2740
|
+
rb_define_method(rb_cLPSolve, "write_mps", lpsolve_write_mps, -1);
|
2741
|
+
|
2742
|
+
/* Aliases accessors. */
|
2743
|
+
rb_define_alias(rb_cLPSolve, "bb_rule", "get_bb_rule");
|
2744
|
+
rb_define_alias(rb_cLPSolve, "bb_rule=", "set_bb_rule");
|
2745
|
+
rb_define_alias(rb_cLPSolve, "bb_depthlimit", "get_bb_depthlimit");
|
2746
|
+
rb_define_alias(rb_cLPSolve, "bb_depthlimit=", "set_bb_depthlimit");
|
2747
|
+
rb_define_alias(rb_cLPSolve, "debug?", "is_debug");
|
2748
|
+
rb_define_alias(rb_cLPSolve, "debug=", "set_debug");
|
2749
|
+
rb_define_alias(rb_cLPSolve, "infinite", "get_infinite");
|
2750
|
+
rb_define_alias(rb_cLPSolve, "maxim?", "is_maxim");
|
2751
|
+
rb_define_alias(rb_cLPSolve, "lp_name", "get_lp_name");
|
2752
|
+
rb_define_alias(rb_cLPSolve, "lp_name=", "set_lp_name");
|
2753
|
+
rb_define_alias(rb_cLPSolve, "Ncolumns", "get_Ncolumns");
|
2754
|
+
rb_define_alias(rb_cLPSolve, "Norig_columns", "get_Norig_columns");
|
2755
|
+
rb_define_alias(rb_cLPSolve, "nonzeros", "get_nonzeros");
|
2756
|
+
rb_define_alias(rb_cLPSolve, "Norig_rows", "get_Norig_rows");
|
2757
|
+
rb_define_alias(rb_cLPSolve, "Nrows", "get_Nrows");
|
2758
|
+
rb_define_alias(rb_cLPSolve, "objective", "get_objective");
|
2759
|
+
rb_define_alias(rb_cLPSolve, "presolve", "get_presolve");
|
2760
|
+
rb_define_alias(rb_cLPSolve, "presolveloops", "get_presolveloops");
|
2761
|
+
/* rb_define_alias(rb_cLPSolve, "print", "print_lp"); */
|
2762
|
+
rb_define_alias(rb_cLPSolve, "scaling", "get_scaling");
|
2763
|
+
rb_define_alias(rb_cLPSolve, "scaling=", "set_scaling");
|
2764
|
+
rb_define_alias(rb_cLPSolve, "status", "get_status");
|
2765
|
+
rb_define_alias(rb_cLPSolve, "status=", "set_status");
|
2766
|
+
rb_define_alias(rb_cLPSolve, "statustext", "get_statustext");
|
2767
|
+
rb_define_alias(rb_cLPSolve, "simplextype", "get_simplextype");
|
2768
|
+
rb_define_alias(rb_cLPSolve, "simplextype=", "set_simplextype");
|
2769
|
+
rb_define_alias(rb_cLPSolve, "solutioncount", "get_solutioncount");
|
2770
|
+
rb_define_alias(rb_cLPSolve, "solutionlimit", "get_solutionlimit");
|
2771
|
+
rb_define_alias(rb_cLPSolve, "solutionlimit=", "set_solutionlimit");
|
2772
|
+
rb_define_alias(rb_cLPSolve, "sos_var?", "is_SOS_var");
|
2773
|
+
rb_define_alias(rb_cLPSolve, "timeout", "get_timeout");
|
2774
|
+
rb_define_alias(rb_cLPSolve, "timeout=", "set_timeout");
|
2775
|
+
rb_define_alias(rb_cLPSolve, "total_iter", "get_total_iter");
|
2776
|
+
rb_define_alias(rb_cLPSolve, "trace=", "set_trace");
|
2777
|
+
rb_define_alias(rb_cLPSolve, "variables", "get_variables");
|
2778
|
+
rb_define_alias(rb_cLPSolve, "verbose", "get_verbose");
|
2779
|
+
rb_define_alias(rb_cLPSolve, "verbose=", "set_verbose");
|
2780
|
+
}
|
2781
|
+
|
2782
|
+
|
2783
|
+
/* A revised version of print_lp or REPORT_lp. */
|
2784
|
+
#include <lpsolve/lp_report.h>
|
2785
|
+
void print(lprec *lp)
|
2786
|
+
{
|
2787
|
+
int i, j;
|
2788
|
+
unsigned int max_rowname = sizeof("lowbo")-1;
|
2789
|
+
char row_fmt[30];
|
2790
|
+
|
2791
|
+
if(lp->outstream == NULL)
|
2792
|
+
return;
|
2793
|
+
|
2794
|
+
if(lp->matA->is_roworder) {
|
2795
|
+
report(lp, IMPORTANT, "REPORT_lp: Cannot print lp while in row entry mode.\n");
|
2796
|
+
return;
|
2797
|
+
}
|
2798
|
+
|
2799
|
+
fprintf(lp->outstream, "Model name: %s\n", get_lp_name(lp));
|
2800
|
+
|
2801
|
+
for(j = 1; j <= lp->rows; j++) {
|
2802
|
+
unsigned int row_len = strlen(get_row_name(lp, j));
|
2803
|
+
if (max_rowname < row_len)
|
2804
|
+
max_rowname = row_len;
|
2805
|
+
}
|
2806
|
+
|
2807
|
+
memset(row_fmt, 0, sizeof(row_fmt));
|
2808
|
+
snprintf(row_fmt, sizeof(row_fmt), "%%-%ds ", max_rowname);
|
2809
|
+
fprintf(lp->outstream, row_fmt, " ");
|
2810
|
+
|
2811
|
+
for(j = 1; j <= lp->columns; j++)
|
2812
|
+
fprintf(lp->outstream, "%8s ", get_col_name(lp,j));
|
2813
|
+
|
2814
|
+
fprintf(lp->outstream, "\n%simize:\n", (is_maxim(lp) ? "Max" : "Min"));
|
2815
|
+
fprintf(lp->outstream, row_fmt, " ");
|
2816
|
+
|
2817
|
+
for(j = 1; j <= lp->columns; j++)
|
2818
|
+
{
|
2819
|
+
REAL val = get_mat(lp, 0, j);
|
2820
|
+
if (0.0 == val)
|
2821
|
+
fprintf(lp->outstream, "%8s ", "");
|
2822
|
+
else {
|
2823
|
+
fprintf(lp->outstream, "%8g ", get_mat(lp, 0, j));
|
2824
|
+
}
|
2825
|
+
}
|
2826
|
+
|
2827
|
+
fprintf(lp->outstream, "\n\nSubject to:\n");
|
2828
|
+
|
2829
|
+
for(i = 1; i <= lp->rows; i++) {
|
2830
|
+
fprintf(lp->outstream, row_fmt, get_row_name(lp, i));
|
2831
|
+
for(j = 1; j <= lp->columns; j++)
|
2832
|
+
{
|
2833
|
+
REAL val = get_mat(lp, i, j);
|
2834
|
+
if (0.0 == val)
|
2835
|
+
fprintf(lp->outstream, "%8s ", "");
|
2836
|
+
else {
|
2837
|
+
fprintf(lp->outstream, "%8g ", val);
|
2838
|
+
}
|
2839
|
+
}
|
2840
|
+
if(is_constr_type(lp, i, GE))
|
2841
|
+
fprintf(lp->outstream, ">= ");
|
2842
|
+
else if(is_constr_type(lp, i, LE))
|
2843
|
+
fprintf(lp->outstream, "<= ");
|
2844
|
+
else
|
2845
|
+
fprintf(lp->outstream, " = ");
|
2846
|
+
|
2847
|
+
fprintf(lp->outstream, "%8g", get_rh(lp, i));
|
2848
|
+
|
2849
|
+
if(is_constr_type(lp, i, GE)) {
|
2850
|
+
if(get_rh_upper(lp, i) < lp->infinite)
|
2851
|
+
fprintf(lp->outstream, " %s = %8g", "upbo ", get_rh_upper(lp, i));
|
2852
|
+
}
|
2853
|
+
else if(is_constr_type(lp, i, LE)) {
|
2854
|
+
if(get_rh_lower(lp, i) > -lp->infinite)
|
2855
|
+
fprintf(lp->outstream, " %s = %8g", "lowbo", get_rh_lower(lp, i));
|
2856
|
+
}
|
2857
|
+
fprintf(lp->outstream, "\n");
|
2858
|
+
}
|
2859
|
+
|
2860
|
+
fprintf(lp->outstream, "\n");
|
2861
|
+
fprintf(lp->outstream, row_fmt, "Type");
|
2862
|
+
for(i = 1; i <= lp->columns; i++) {
|
2863
|
+
if(is_int(lp,i))
|
2864
|
+
fprintf(lp->outstream, " Int ");
|
2865
|
+
else
|
2866
|
+
fprintf(lp->outstream, " Real ");
|
2867
|
+
}
|
2868
|
+
|
2869
|
+
fprintf(lp->outstream, "\n");
|
2870
|
+
fprintf(lp->outstream, row_fmt, "upbo ");
|
2871
|
+
for(i = 1; i <= lp->columns; i++)
|
2872
|
+
if(get_upbo(lp, i) >= lp->infinite)
|
2873
|
+
fprintf(lp->outstream, " Inf ");
|
2874
|
+
else
|
2875
|
+
fprintf(lp->outstream, "%8g ", get_upbo(lp, i));
|
2876
|
+
fprintf(lp->outstream, "\n");
|
2877
|
+
fprintf(lp->outstream, row_fmt, "lowbo");
|
2878
|
+
for(i = 1; i <= lp->columns; i++)
|
2879
|
+
if(get_lowbo(lp, i) <= -lp->infinite)
|
2880
|
+
fprintf(lp->outstream, " -Inf ");
|
2881
|
+
else
|
2882
|
+
fprintf(lp->outstream, "%8g ", get_lowbo(lp, i));
|
2883
|
+
fprintf(lp->outstream, "\n");
|
2884
|
+
fprintf(lp->outstream, row_fmt, "SOS ");
|
2885
|
+
for(i = 1; i <= lp->columns; i++) {
|
2886
|
+
if(is_SOS_var(lp, i)) {
|
2887
|
+
fprintf(lp->outstream, " true ");
|
2888
|
+
} else
|
2889
|
+
fprintf(lp->outstream, " false ");
|
2890
|
+
}
|
2891
|
+
fprintf(lp->outstream, "\n");
|
2892
|
+
if (lp->SOS) {
|
2893
|
+
SOSgroup *SOS_group = lp->SOS;
|
2894
|
+
SOSrec **sos_list;
|
2895
|
+
sos_list = SOS_group->sos_list;
|
2896
|
+
fprintf(lp->outstream, "\nSOS groups:\n");
|
2897
|
+
for (i=0; i<lp->SOS->sos_count; i++) {
|
2898
|
+
unsigned int j;
|
2899
|
+
fprintf(lp->outstream, "\t%s: Type: %d, with %d members",
|
2900
|
+
sos_list[i]->name, sos_list[i]->type, sos_list[i]->size);
|
2901
|
+
for(j = 1; j <= sos_list[i]->size; j++) {
|
2902
|
+
int i_col_num = sos_list[i]->members[j];
|
2903
|
+
char *psz_col_name;
|
2904
|
+
if (i_col_num <= lp->columns) {
|
2905
|
+
psz_col_name = get_col_name(lp, i_col_num);
|
2906
|
+
if (NULL != psz_col_name)
|
2907
|
+
fprintf(lp->outstream, "%s%s", (j > 1) ? ", " : ": ",
|
2908
|
+
psz_col_name);
|
2909
|
+
}
|
2910
|
+
}
|
2911
|
+
fprintf(lp->outstream, "\n");
|
2912
|
+
}
|
2913
|
+
}
|
2914
|
+
fflush(lp->outstream);
|
2915
|
+
}
|