追寻单纯形法的几何直观

10 篇文章 0 订阅
先上代码,等忙完年终检查再补上。
require 'pp'
require 'set'

DEBUG = false

class String
	def to_terms() self.gsub("-", "+-").split(/\s*\+/).select{|e| e != ""} end
	
	def to_pair
		r = /
			 ( (\-)? (\d+(\.\d+)?)? )	# e.g. -3.2, 4, -
			 \*?
			 (\w+ (\d+)?)				# e.g. x2
			/x
		if r =~ self.gsub(/\s+/, "")
			c = $3.nil? ? 1 : $3.to_f
			c = -c if not $2.nil?
			return $5.to_sym, c
		else
			p "err!"
		end
	end
end

class Array
	def scalar_mult!(c) self.map! {|e| e*c} end
	def scalar_mult(c) self.map {|e| e*c} end
	def vector_add!(v) self.each_with_index {|_, i| self[i] += v[i]} end
end

class Hash
	def dot_prod
		e = []
		self.each do |k, v|
			if v != 0
				if v == 1
					e << k.to_s
				elsif v == -1
					e << ("-" + k.to_s)
				else
					e << (v.to_s + k.to_s)
				end
			end
		end
		e.join(' + ').gsub("+ -", "- ")
	end
end

class Simplex
	def initialize(path)
		m = /
			 (max|Maximize) \s+ (.+?) \n
			 \s* (s\.t\.|subject \s+ to) \s+ (.+?)\.
			/mx
		
		if m =~ File.read(path)
			@z_equ = {:b => 0}			# objective equation
			$2.to_terms.each do |term|
				k, v = term.to_pair
				@z_equ[k] = -v
			end
	 
			@nonbasic_vars = []
			@basic_vars = []
			@matrix = []
			idx = 1
			$4.split(/[\n,]/).each do |inequalities|
				if / (\w+(\d+)?) \s* >= \s* 0 /x =~ inequalities		# xi >= 0
					@nonbasic_vars << $1.to_sym
				elsif / \s* (.+?) \s* <= \s* (\d+(\.\d+)?) /x =~ inequalities
					lhs, rhs = $1.to_s, $2.to_f
					equ = {:b => rhs, :"$#{idx}" => 1}
					@basic_vars << :"$#{idx}"
					idx += 1
					lhs.to_terms.each do |t|
						k, v = t.to_pair
						equ[k] = v
					end
					@matrix << equ
				else
					p "err!"
				end
			end
		else
			p "err!"
		end
	end
	
	def canonical_form
		@vars = @nonbasic_vars + @basic_vars
		@mtr = [[]]		# coefficient matrix
		@vars.each_with_index do |x, k|
			@mtr[0][k] = @z_equ[x] || 0
		end
		@mtr[0] << @z_equ[:b]
		@matrix.each_with_index do |row, i|
			ary = []
			@vars.each_with_index do |x, j|
				ary[j] = row[x] || 0
			end
			ary << row[:b]
			@mtr << ary
		end
		puts "max " + @z_equ.dot_prod
		print "s.t.\n"
		@matrix.each {|r| print "#{r.select{|k, v| k!=:b}.dot_prod} = #{r[:b]}\n"}
		print "and " + @vars.join(" >= 0, ") + " >= 0.\n"
		
		
	end
	
	def mtr_display()
		@mtr.each do |r|
			puts Hash[*@vars.zip(r).flatten].dot_prod + " = #{r[-1]}"
		end
	end
	
	def solve
		DEBUG && puts("---------------------------------------------------------------")
		DEBUG && mtr_display
		pivot_c = @mtr[0].min
		pivot_var = @mtr[0].index pivot_c
		if pivot_c >= 0
			@z_max = @mtr[0][-1]
		else
			n = @mtr.size - 1
			idx = 1
			_a = @mtr[1][pivot_var]
			_b = @mtr[1][-1]
			(1..n).each do |i|
				idx = i if _a * @mtr[i][-1] < _b * @mtr[i][pivot_var]
			end
			v_i = @vars.index :"$#{idx}"
			c = 1.0/@mtr[idx][pivot_var]
			@mtr[idx].scalar_mult! c
			@mtr.each_with_index do |row, i|
				if i != idx
					row.vector_add!(@mtr[idx].scalar_mult(-@mtr[i][pivot_var])) 
				end
			end
			DEBUG && puts("			...(#{@vars[v_i]} -> #{@vars[pivot_var]})...")
			DEBUG && mtr_display
			self.solve
		end
		@z_max
	end
end

s = Simplex.new("./simplex.data")
s.canonical_form
puts "\nf(z)_max = #{s.solve}"


simplex.data:

max 2x1 + x2
s.t.  	x1 <= 4
		2x1 + 3x2 <= 12
		x1 + x2 <= 5
		x1 >= 0, x2 >= 0.

输出:

max -2.0x1 - x2
s.t.
$1 + x1 = 4.0
$2 + 2.0x1 + 3.0x2 = 12.0
$3 + x1 + x2 = 5.0
and x1 >= 0, x2 >= 0, $1 >= 0, $2 >= 0, $3 >= 0.

f(z)_max = 9.0


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值