Skip to content

Commit

Permalink
Use finalizer to free GLPK problem.
Browse files Browse the repository at this point in the history
  • Loading branch information
wtaysom committed Jan 3, 2012
1 parent 720dfb9 commit 034c984
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 119 deletions.
33 changes: 23 additions & 10 deletions lib/rglpk.rb
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -68,14 +68,15 @@ def initialize
@rows = RowArray.new @rows = RowArray.new
@cols = ColArray.new @cols = ColArray.new
Glpk_wrapper.glp_create_index(@lp) Glpk_wrapper.glp_create_index(@lp)

ObjectSpace.define_finalizer(self, self.class.finalizer(@lp))
end end


def destroy! def self.finalizer(lp)
Glpk_wrapper.glp_delete_prob(@lp) proc do

Glpk_wrapper.glp_delete_index(lp)
Glpk_wrapper.delete_intArray(@_ia) Glpk_wrapper.glp_delete_prob(lp)
Glpk_wrapper.delete_intArray(@_ja) end
Glpk_wrapper.delete_doubleArray(@_ar)
end end


def name=(n) def name=(n)
Expand Down Expand Up @@ -125,6 +126,7 @@ def del_rows(a)
r = Glpk_wrapper.new_intArray(a.size + 1) r = Glpk_wrapper.new_intArray(a.size + 1)
a.each_with_index{|n, i| Glpk_wrapper.intArray_setitem(r, i + 1, n)} a.each_with_index{|n, i| Glpk_wrapper.intArray_setitem(r, i + 1, n)}
Glpk_wrapper.glp_del_rows(@lp, a.size, r) Glpk_wrapper.glp_del_rows(@lp, a.size, r)
Glpk_wrapper.delete_intArray(r)


a.each do |n| a.each do |n|
@rows.send(:delete_at, n) @rows.send(:delete_at, n)
Expand All @@ -143,6 +145,7 @@ def del_cols(a)
r = Glpk_wrapper.new_intArray(a.size + 1) r = Glpk_wrapper.new_intArray(a.size + 1)
a.each_with_index{|n, i| Glpk_wrapper.intArray_setitem(r, i + 1, n)} a.each_with_index{|n, i| Glpk_wrapper.intArray_setitem(r, i + 1, n)}
Glpk_wrapper.glp_del_cols(@lp, a.size, r) Glpk_wrapper.glp_del_cols(@lp, a.size, r)
Glpk_wrapper.delete_intArray(r)


a.each do |n| a.each do |n|
@cols.send(:delete_at, n) @cols.send(:delete_at, n)
Expand Down Expand Up @@ -170,11 +173,11 @@ def set_matrix(v)
Glpk_wrapper.doubleArray_setitem(ar, y + 1, x) Glpk_wrapper.doubleArray_setitem(ar, y + 1, x)
end end


@_ia = ia
@_ja = ja
@_ar = ar

Glpk_wrapper.glp_load_matrix(@lp, v.size, ia, ja, ar) Glpk_wrapper.glp_load_matrix(@lp, v.size, ia, ja, ar)

Glpk_wrapper.delete_intArray(ia)
Glpk_wrapper.delete_intArray(ja)
Glpk_wrapper.delete_doubleArray(ar)
end end


private private
Expand Down Expand Up @@ -273,6 +276,9 @@ def set(v)
Glpk_wrapper.doubleArray_setitem(val, y + 1, x)} Glpk_wrapper.doubleArray_setitem(val, y + 1, x)}


Glpk_wrapper.glp_set_mat_row(@p.lp, @i, v.size, ind, val) Glpk_wrapper.glp_set_mat_row(@p.lp, @i, v.size, ind, val)

Glpk_wrapper.delete_intArray(ind)
Glpk_wrapper.delete_doubleArray(val)
end end


def get def get
Expand All @@ -285,6 +291,8 @@ def get
j = Glpk_wrapper.intArray_getitem(ind, i + 1) j = Glpk_wrapper.intArray_getitem(ind, i + 1)
row[j - 1] = v row[j - 1] = v
end end
Glpk_wrapper.delete_intArray(ind)
Glpk_wrapper.delete_doubleArray(val)
row row
end end


Expand Down Expand Up @@ -353,6 +361,9 @@ def set(v)
Glpk_wrapper.doubleArray_setitem(val, y + 1, x)} Glpk_wrapper.doubleArray_setitem(val, y + 1, x)}


Glpk_wrapper.glp_set_mat_col(@p.lp, @j, v.size, ind, val) Glpk_wrapper.glp_set_mat_col(@p.lp, @j, v.size, ind, val)

Glpk_wrapper.delete_intArray(ind)
Glpk_wrapper.delete_doubleArray(val)
end end


def get def get
Expand All @@ -365,6 +376,8 @@ def get
j = Glpk_wrapper.intArray_getitem(ind, i + 1) j = Glpk_wrapper.intArray_getitem(ind, i + 1)
col[j - 1] = v col[j - 1] = v
end end
Glpk_wrapper.delete_intArray(ind)
Glpk_wrapper.delete_doubleArray(val)
col col
end end


Expand Down
51 changes: 50 additions & 1 deletion test/helper.rb
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -2,4 +2,53 @@


require 'test/unit' require 'test/unit'
$LOAD_PATH << './ext' $LOAD_PATH << './ext'
require here+'/../lib/rglpk' require here+'/../lib/rglpk'

module Examples
def brief_example
# The same Brief Example as found in section 1.3 of
# glpk-4.44/doc/glpk.pdf.
#
# maximize
# z = 10 * x1 + 6 * x2 + 4 * x3
#
# subject to
# p: x1 + x2 + x3 <= 100
# q: 10 * x1 + 4 * x2 + 5 * x3 <= 600
# r: 2 * x1 + 2 * x2 + 6 * x3 <= 300
#
# where all variables are non-negative
# x1 >= 0, x2 >= 0, x3 >= 0
#
p = Rglpk::Problem.new
p.name = "sample"
p.obj.dir = Rglpk::GLP_MAX

rows = p.add_rows(3)
rows[0].name = "p"
rows[0].set_bounds(Rglpk::GLP_UP, 0, 100)
rows[1].name = "q"
rows[1].set_bounds(Rglpk::GLP_UP, 0, 600)
rows[2].name = "r"
rows[2].set_bounds(Rglpk::GLP_UP, 0, 300)

cols = p.add_cols(3)
cols[0].name = "x1"
cols[0].set_bounds(Rglpk::GLP_LO, 0.0, 0.0)
cols[1].name = "x2"
cols[1].set_bounds(Rglpk::GLP_LO, 0.0, 0.0)
cols[2].name = "x3"
cols[2].set_bounds(Rglpk::GLP_LO, 0.0, 0.0)

p.obj.coefs = [10, 6, 4]

p.set_matrix([
1, 1, 1,
10, 4, 5,
2, 2, 6
])

p.simplex
p
end
end
3 changes: 2 additions & 1 deletion test/test_all.rb
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
require here+'/helper' require here+'/helper'
require here+'/test_basic' require here+'/test_basic'
require here+'/test_problem_kind' require here+'/test_problem_kind'
require here+'/test_brief_example' require here+'/test_brief_example'
require here+'/test_memory_prof'
51 changes: 7 additions & 44 deletions test/test_brief_example.rb
Original file line number Original file line Diff line number Diff line change
@@ -1,50 +1,13 @@
require File.expand_path('helper', File.dirname(__FILE__)) require File.expand_path('helper', File.dirname(__FILE__))


class TestExample < Test::Unit::TestCase class TestBriefExample < Test::Unit::TestCase
def test_example include Examples
# The same Brief Example as found in section 1.3 of
# glpk-4.44/doc/glpk.pdf. def test_brief_example
# p = brief_example
# maximize cols = p.cols
# z = 10 * x1 + 6 * x2 + 4 * x3 rows = p.rows
#
# subject to
# p: x1 + x2 + x3 <= 100
# q: 10 * x1 + 4 * x2 + 5 * x3 <= 600
# r: 2 * x1 + 2 * x2 + 6 * x3 <= 300
#
# where all variables are non-negative
# x1 >= 0, x2 >= 0, x3 >= 0
#
p = Rglpk::Problem.new
p.name = "sample"
p.obj.dir = Rglpk::GLP_MAX


rows = p.add_rows(3)
rows[0].name = "p"
rows[0].set_bounds(Rglpk::GLP_UP, 0, 100)
rows[1].name = "q"
rows[1].set_bounds(Rglpk::GLP_UP, 0, 600)
rows[2].name = "r"
rows[2].set_bounds(Rglpk::GLP_UP, 0, 300)

cols = p.add_cols(3)
cols[0].name = "x1"
cols[0].set_bounds(Rglpk::GLP_LO, 0.0, 0.0)
cols[1].name = "x2"
cols[1].set_bounds(Rglpk::GLP_LO, 0.0, 0.0)
cols[2].name = "x3"
cols[2].set_bounds(Rglpk::GLP_LO, 0.0, 0.0)

p.obj.coefs = [10, 6, 4]

p.set_matrix([
1, 1, 1,
10, 4, 5,
2, 2, 6
])

p.simplex
z = p.obj.get z = p.obj.get
x1 = cols[0].get_prim x1 = cols[0].get_prim
x2 = cols[1].get_prim x2 = cols[1].get_prim
Expand Down
81 changes: 18 additions & 63 deletions test/test_memory_prof.rb
Original file line number Original file line Diff line number Diff line change
@@ -1,75 +1,30 @@
require File.expand_path('helper', File.dirname(__FILE__)) require File.expand_path('helper', File.dirname(__FILE__))


class TestMemoryProf < Test::Unit::TestCase class TestMemoryProf < Test::Unit::TestCase
include Examples

def test_memory_prof def test_memory_prof
while true 5.times do
1000.times do |i| 1000.times do |i|
_test_example brief_example
end end


out = `ps aux | grep "ruby test/test_memory_prof.rb"` change = change_to_real_memory_in_kb
puts out.split("\n")[0] assert (change < 10000), "memory leak #{change}kb"
end end
end end


def _test_example def real_memory_in_kb
# The same Brief Example as found in section 1.3 of # "=" after "rss" strips the header line.
# glpk-4.44/doc/glpk.pdf. `ps -p #{Process.pid} -o rss=`.to_i
# end
# maximize
# z = 10 * x1 + 6 * x2 + 4 * x3 def change_to_real_memory_in_kb
# GC.start
# subject to r = real_memory_in_kb
# p: x1 + x2 + x3 <= 100 @change_to_real_memory_in_kb__prev ||= r
# q: 10 * x1 + 4 * x2 + 5 * x3 <= 600 r - @change_to_real_memory_in_kb__prev
# r: 2 * x1 + 2 * x2 + 6 * x3 <= 300 ensure
# @change_to_real_memory_in_kb__prev = r
# where all variables are non-negative
# x1 >= 0, x2 >= 0, x3 >= 0
#
p = Rglpk::Problem.new
p.name = "sample"
p.obj.dir = Rglpk::GLP_MAX

rows = p.add_rows(3)
rows[0].name = "p"
rows[0].set_bounds(Rglpk::GLP_UP, 0, 100)
rows[1].name = "q"
rows[1].set_bounds(Rglpk::GLP_UP, 0, 600)
rows[2].name = "r"
rows[2].set_bounds(Rglpk::GLP_UP, 0, 300)

cols = p.add_cols(3)
cols[0].name = "x1"
cols[0].set_bounds(Rglpk::GLP_LO, 0.0, 0.0)
cols[1].name = "x2"
cols[1].set_bounds(Rglpk::GLP_LO, 0.0, 0.0)
cols[2].name = "x3"
cols[2].set_bounds(Rglpk::GLP_LO, 0.0, 0.0)

p.obj.coefs = [10, 6, 4]

p.set_matrix([
1, 1, 1,
10, 4, 5,
2, 2, 6
])

p.simplex
z = p.obj.get
x1 = cols[0].get_prim
x2 = cols[1].get_prim
x3 = cols[2].get_prim

result = "z = %g; x1 = %g; x2 = %g; x3 = %g" % [z, x1, x2, x3]
assert_equal "z = 733.333; x1 = 33.3333; x2 = 66.6667; x3 = 0", result
assert_equal Rglpk::GLP_NU, rows[0].get_stat
assert_equal 100, rows[0].get_prim
assert_equal 3.333333333333333, rows[0].get_dual
# File.delete("test.lp") rescue Errno::ENOENT
# p.write_lp("test.lp")
# assert File.exists?("test.lp")

p.destroy!
end end
end end

0 comments on commit 034c984

Please sign in to comment.