Advertisement
Guest User

Untitled

a guest
Jan 22nd, 2018
90
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 15.71 KB | None | 0 0
  1. #!/usr/bin/env python3
  2.  
  3. # author vas 17226
  4.  
  5. import numpy as np
  6. from fractions import Fraction
  7. import matplotlib.pyplot as plt
  8. from copy import *
  9. import math
  10.  
  11. def sgntostr(sgn):
  12. if sgn < 0:
  13. return "<"
  14. elif sgn > 0:
  15. return ">"
  16. else:
  17. return "="
  18.  
  19. class LPT:
  20. def __init__(self, kind, c, A, b, lim_signs, free_nrs, letter = 'x'):
  21. if kind != 'min' and kind != 'max':
  22. raise SystemError("Invalid kind")
  23. self.kind = kind
  24. self.n = A.shape[1]
  25. self.m = A.shape[0]
  26. self.c = c
  27. self.A = A
  28. self.b = b
  29. self.lim_signs = lim_signs
  30. self.free_nrs = list(map(lambda idx : idx - 1, free_nrs))
  31. self.letter = letter
  32. self.__xs_strs = [str(i + 1) for i in range(0, self.n)]
  33.  
  34. def zero_var(self, idx):
  35. self.n -= 1
  36. self.c = np.delete(self.c, idx)
  37. self.A = np.delete(self.A, idx, axis=1)
  38. if idx in self.free_nrs:
  39. self.free_nrs = self.free_nrs.remove(idx)
  40. del self.__xs_strs[idx]
  41.  
  42. def xs_strs(self, i):
  43. return self.letter + self.__xs_strs[i]
  44.  
  45. def xs_comb_str(self, coefs):
  46. res =''
  47. for i in range(0, self.n):
  48. sign = ' +'
  49. if coefs[i] < 0:
  50. sign = ' -'
  51. res += sign + str(abs(coefs[i])) + self.xs_strs(i)
  52. return res
  53.  
  54. def __str__(self):
  55. res = ''
  56. res += 'N=' + str(self.n) + " ; M=" + str(self.m) + '\n'
  57. res += self.xs_comb_str(self.c) + ' -> ' + self.kind + '\n'
  58. for rnum in range(0, self.A.shape[0]):
  59. res += self.xs_comb_str(self.A[rnum])
  60. sign = ''
  61. if self.lim_signs[rnum] == -1:
  62. sign = ' <= '
  63. elif self.lim_signs[rnum] == 0:
  64. sign = ' == '
  65. elif self.lim_signs[rnum] == 1:
  66. sign = ' >= '
  67. res += sign
  68. res += str(self.b[rnum])
  69. res += '\n'
  70.  
  71. for i in range(0, self.n):
  72. isfree = ''
  73. if i in self.free_nrs:
  74. isfree = self.xs_strs(i) + ' free'
  75. else:
  76. isfree = self.xs_strs(i) + ' >= 0'
  77. res += isfree + '\n'
  78.  
  79. return res
  80.  
  81. def dual_classic_straight(self):
  82. res = copy(self)
  83. for rnum in range(0, res.m):
  84. if (res.kind == 'min' and res.lim_signs[rnum] == -1) or (res.kind == 'max' and res.lim_signs[rnum] == 1):
  85. res.A[rnum] *= -1
  86. res.b[rnum] *= -1
  87. res.lim_signs[rnum] *= -1
  88.  
  89. return res
  90.  
  91. def dual(self):
  92. res = self.dual_classic_straight()
  93.  
  94. old_free_nrs = res.free_nrs.copy()
  95.  
  96. res.free_nrs = []
  97. for i in range(0, res.m):
  98. if res.lim_signs[i] == 0:
  99. res.free_nrs += [i]
  100.  
  101. res.lim_signs = [0 for i in range(0, res.n)]
  102. for i in range(0, res.n):
  103. if not (i in old_free_nrs):
  104. if res.kind == 'min':
  105. res.lim_signs[i] = -1
  106. elif res.kind == 'max':
  107. res.lim_signs[i] = 1
  108. else:
  109. raise SystemError('haha lol')
  110.  
  111. res.A = res.A.transpose()
  112. res.n, res.m = res.m, res.n
  113. res.c, res.b = res.b, res.c
  114. if res.kind == 'min':
  115. res.kind = 'max'
  116. else:
  117. res.kind = 'min'
  118.  
  119. if res.letter == 'x':
  120. res.letter = 'y'
  121. else:
  122. res.letter = 'x'
  123.  
  124. res.__xs_strs = [str(i + 1) for i in range(0, res.n)]
  125.  
  126. return res
  127.  
  128. def get_lim_signs(self, vec):
  129. lims = self.A.dot(vec)
  130. res = [0 for i in range(0, self.m)]
  131. for i in range(0, self.m):
  132. if lims[i] > self.b[i]:
  133. res[i] = 1
  134. elif lims[i] < self.b[i]:
  135. res[i] = -1
  136. else:
  137. res[i] = 0
  138. return lims, res
  139.  
  140.  
  141. def is_feasible(self, vec):
  142. for i in range(0, self.n):
  143. if (not (i in self.free_nrs)) and vec[i] < 0:
  144. return False, self.xs_strs(i) + ' < 0 (J1 failed)', 0
  145.  
  146. lims, lim_signs_vec = self.get_lim_signs(vec)
  147. for i in range(0, self.m):
  148. if self.lim_signs[i] != lim_signs_vec[i] and (lim_signs_vec[i] != 0):
  149. err = 'For limitation #%s (counting from 1): %s [%s, should be %s] %s' \
  150. % ((i+1), lims[i], lim_signs_vec[i], self.lim_signs[i], self.b[i])
  151. return False, err, 0
  152.  
  153. return True, ','.join(map(sgntostr, lim_signs_vec)), self.c.dot(vec)
  154.  
  155. def for_vec(self, vec):
  156. if len(vec) != self.n:
  157. raise SystemError('lenvec != self.n')
  158. msg = ''
  159. msg += 'For vector ' + str(vec) + ':\n'
  160. is_fsb, msg_fsb, obj_val = self.is_feasible(vec)
  161. msg += 'Feasibility: ' + str((is_fsb, msg_fsb, obj_val))
  162. msg += '\n'
  163. print(msg)
  164. return is_fsb, obj_val
  165.  
  166.  
  167. def find_feasible_basis(A, b):
  168. At = A.transpose()
  169. ncols = At.shape[0]
  170. any_found = False
  171. for i in range(0, ncols):
  172. for j in range(i + 1, ncols):
  173. for k in range(j + 1, ncols):
  174. basis = np.array([At[i], At[j], At[k]])
  175. try:
  176. det = np.linalg.det(basis)
  177. print('det: %s' % det)
  178. print('i j k: %s %s %s' % (i + 1, j + 1, k + 1))
  179. print('B=\n' + str(basis.transpose()))
  180. print('B^-1 * b=' + str(basis_inv.dot(b)))
  181. basis_inv = np.linalg.inv(basis)
  182. if abs(det) > 1e-2 and np.all(np.greater_equal(basis_inv.dot(b), np.zeros(b.shape))):
  183. any_found = True
  184. print('det = ' + str(det))
  185. print('')
  186. except:
  187. continue
  188.  
  189. if not any_found:
  190. print('No feasible basis found')
  191.  
  192.  
  193. # sols' rows are solutions
  194. def is_solutions_optimal():
  195. xs_to_check = np.array([
  196. [0, 5./2, 1./2, -1./2],
  197. [1., 0, 0, -2.],
  198. [0, 0., 0, 1]
  199. ])
  200.  
  201. kind = 'min'
  202. c = np.array([1., 5, -3, -5])
  203. A = np.array([
  204. [-2., -1, 4, 1],
  205. [1, -1, 1, 2],
  206. [3, 2, -1, -1]
  207. ])
  208. b = np.array([1., -3, 5])
  209. lim_signs = np.array([-1, -1, 0])
  210. free_nrs = [1, 4]
  211.  
  212. ############
  213.  
  214. straight = LPT(kind, c, A, b, lim_signs, free_nrs)
  215. dual = straight.dual()
  216. print('Straight: ', straight, '\n', 'Dual: ', dual, '')
  217.  
  218. min_fsb_x = None
  219. min_func_obj = 10000000
  220. for x in xs_to_check:
  221. is_fsb, func_obj = straight.for_vec(x)
  222. if is_fsb and func_obj < min_func_obj:
  223. min_func_obj = func_obj
  224. min_fsb_x = x
  225.  
  226. if min_fsb_x is None:
  227. print('No feasible X found!')
  228. return
  229.  
  230. print('\nSolving for x=%s, f(x)=%s' % (min_fsb_x, min_func_obj))
  231.  
  232. # True, ','.join(map(sgntostr, lim_signs_vec)), self.c.dot(vec)
  233. lim_signs = straight.get_lim_signs(min_fsb_x)[1]
  234. print('lim_signs (Написать, что прямые ограничения выполняются со знаком): %s' % lim_signs)
  235.  
  236. y_test = [0. for i in range(0, dual.n)]
  237.  
  238. for i in range(0, straight.n):
  239. if abs(min_fsb_x[i]) > 1e-2: # then c_j = y*A_j
  240. print('По 2ой теореме выполняется равенство в двойственном ограничении #%s' % (i+1))
  241. dual.lim_signs[i] = 0
  242.  
  243. for i in range(0, straight.m):
  244. if lim_signs[i] != 0:
  245. print('По 2ой теореме, так как прямое ограничение выполняется как неравенство, то y%s = 0' % (i+1))
  246. dual.zero_var(i)
  247.  
  248. print('\nNew dual: ', dual)
  249.  
  250. n_equalities = 0
  251. equality_A = np.zeros((dual.n, dual.n))
  252. equality_b = np.array((dual.n, 1))
  253. for i in range(0, dual.m):
  254. if dual.lim_signs[i] == 0:
  255. equality_A[n_equalities] = dual.A[i]
  256. equality_b[n_equalities] = dual.b[i]
  257. n_equalities += 1
  258.  
  259. if n_equalities == dual.n:
  260. print('Можно решить систему')
  261. ys = np.linalg.solve(equality_A, equality_b)
  262. print('Игреки: ' + str(ys))
  263.  
  264.  
  265. def dual_geom_plot():
  266. kind = 'min'
  267. c = np.array([1., 1.])
  268. A = np.array([
  269. [3., 2.],
  270. [2., 2.],
  271. [1., -1.],
  272. [4., -1.]
  273. ])
  274. b = np.array([6., 3., -1., -2.])
  275. lim_signs = np.array([0, 1, 1, 1])
  276. free_nrs = [2]
  277.  
  278. ######
  279.  
  280. straight = LPT(kind, c, A, b, lim_signs, free_nrs)
  281. dual = straight.dual()
  282. print('Straight: ', straight, '\n', 'Dual: ', dual, '')
  283.  
  284. if dual.n != 2:
  285. raise ValueError("dual.n != 2 !!!")
  286.  
  287. t = np.arange(-5., 5., 0.1)
  288. # y1 - horizontal , y2 vertival
  289. patches = []
  290. plt.axis('equal')
  291. for i in range(0, dual.m):
  292. a = dual.A[i, 0]
  293. b = dual.A[i, 1]
  294. c = dual.b[i]
  295. import matplotlib.patches as mpatches
  296. color=np.random.rand(3,)
  297. patch = mpatches.Patch(label='(%s) y1 + (%s) y2 ?? %s' % (a, b, c), color=color)
  298. patches += [patch]
  299. plt.plot(t, (c - a*t)/b, color=color)
  300. plt.legend(handles=patches)
  301. plt.grid()
  302. plt.show()
  303.  
  304.  
  305. def example_1():
  306. kind = 'max'
  307. c = np.array([6, 3, -1, -2])
  308. A = np.array([[3, 2, 1, 4],
  309. [2, 2, -1, -1]])
  310. b = np.array([0, 1])
  311. lim_signs = np.array([-1, 0])
  312. free_nrs = [1]
  313.  
  314. lpt = LPT(kind, c, A, b, lim_signs, free_nrs)
  315.  
  316. print('STRAIGHT: ' + str(lpt))
  317.  
  318. lpt.for_vec([0, 2.5, 0.5, -0.5])
  319. lpt.for_vec([1, 0, 0, -2])
  320. lpt.for_vec([0, 0, 0, 1])
  321.  
  322. lpt2 = lpt.dual()
  323. print('DUAL: ' + str(lpt2))
  324.  
  325.  
  326.  
  327. class STable:
  328. def __init__(self, T, initial_sigma, initial_omega):
  329. self.T = T.copy().astype('object')
  330. for i in range(0,self.T.shape[0]):
  331. for j in range(0, self.T.shape[1]):
  332. self.T[i,j]=Fraction(int(self.T[i,j]))
  333.  
  334. self.sigma = initial_sigma
  335. self.omega = initial_omega
  336. if not self.straight_dop():
  337. raise SystemError('not straight dop')
  338.  
  339. def straight_dop(self):
  340. col = np.array(self.T[1:,0])
  341. return np.all(np.greater_equal(col, np.zeros(col.shape)))
  342.  
  343. def dual_dop(self):
  344. row = np.array(self.T[0,1:])
  345. return np.all(np.greater_equal(row, np.zeros(row.shape)))
  346.  
  347. def doswitch(self, rnum, snum):
  348. for i in range(0, self.T.shape[0]):
  349. if i != rnum:
  350. coef = self.T[i,snum] / self.T[rnum,snum]
  351. self.T[i] -= self.T[rnum] * coef
  352.  
  353. self.T[rnum] /= self.T[rnum,snum]
  354. self.sigma[rnum] = self.omega[snum]
  355.  
  356. def dancig_choose(self):
  357. snum = 1
  358. min_val = 100000000.
  359. min_val_snum = 1
  360. while snum < self.T.shape[1]:
  361. if self.T[0,snum] < min_val and self.T[0, snum] < 0:
  362. min_val = self.omega[snum]
  363. min_val_snum = snum
  364. snum += 1
  365.  
  366. rnum = 1
  367. min_coef = 100000000.
  368. min_coef_rnum = 1
  369. while rnum < self.T.shape[0]:
  370. coef = self.T[rnum,0] / self.T[rnum, min_val_snum]
  371. if coef < min_coef:
  372. min_coef = coef
  373. min_coef_rnum = rnum
  374. rnum += 1
  375.  
  376. return min_coef_rnum, min_val_snum
  377.  
  378. def blend_choose(self):
  379. snum = 1
  380. min_omega = 1000000
  381. min_omega_snum = 1
  382. while snum < self.T.shape[1]:
  383. if self.omega[snum] < min_omega and self.T[0,snum] < 0:
  384. min_omega = self.omega[snum]
  385. min_omega_snum = snum
  386. snum += 1
  387.  
  388. rnum = 1
  389. min_sigma = 1000000
  390. min_sigma_rnum = 1
  391. while rnum < self.T.shape[0]:
  392. if self.sigma[rnum] < min_sigma and self.T[rnum,min_omega_snum] > 0:
  393. min_sigma = self.sigma[rnum]
  394. min_sigma_rnum = rnum
  395. rnum += 1
  396.  
  397. return min_sigma_rnum, min_omega_snum
  398.  
  399. def bdr(self):
  400. res = [0.0 for i in range(1,len(self.omega))]
  401. for rnum in range(1, self.T.shape[0]):
  402. res[self.sigma[rnum]] = self.T[rnum, 0]
  403. return res
  404.  
  405. def smethod(self):
  406. while True:
  407. print('-----------------------------------------------------------')
  408. print('omega: %s\nsigma: %s\n' % (self.omega[1:], self.sigma[1:]))
  409. table_str = ''
  410. for r in self.T:
  411. for v in r:
  412. if v.denominator == 1:
  413. table_str += '%6s' % str(v.numerator)
  414. else:
  415. table_str += '%6s' % (str(v.numerator) + '/' + str(v.denominator))
  416. table_str += ' '
  417. table_str += '\n'
  418. print('table: \n%s' % table_str)
  419.  
  420. if self.dual_dop():
  421.  
  422. print('\nFound solution=%s at vector %s' % (-self.T[0,0], self.bdr()))
  423. return
  424.  
  425. rnum, snum = self.blend_choose()
  426. # rnum, snum = self.dancig_choose()
  427. print('\nUsing [row=%s, col=%s] (numerating from 0)' % (rnum, snum))
  428.  
  429. if np.all(np.less_equal(self.T[1:,snum], np.zeros(self.T[1:,snum].shape))):
  430. print('\nTheres no solution!!')
  431. return
  432.  
  433. self.doswitch(rnum, snum)
  434.  
  435.  
  436.  
  437. def example_2():
  438. T = np.array([
  439. [-6, 0, 0, 0, -3, 1],
  440. [3, 0, 0, 1, 4, -2],
  441. [8, 1, 0, 0, 8, 1],
  442. [16, 0, 1, 0, 19, -2]
  443. ])
  444.  
  445. # first value is omitted
  446. sigma = np.array([0,3,1,2])
  447.  
  448. # first value is omitted
  449. omega = np.array([0,1,2,3,4,5])
  450.  
  451. st = STable(T, sigma, omega)
  452. st.smethod()
  453.  
  454. def slayter(test_pt, phis):
  455. for phi in phis:
  456. if phi(test_pt) >= 0:
  457. return False
  458.  
  459. return True
  460.  
  461. def find_active(test_pt, phis):
  462. active_idxs = []
  463. for i in range(0, len(phis)):
  464. phi = phis[i]
  465. if abs(phi(test_pt)) < 1e-4:
  466. active_idxs += [i]
  467. return active_idxs
  468.  
  469. def select_by_indices(arr, indices):
  470. res = []
  471. for i in indices:
  472. res += [arr[i]]
  473. return res
  474.  
  475. def example_3():
  476.  
  477. check_points = [
  478. [2.,math.log(2.)],
  479. [math.e, 0.],
  480. [1.,0.]
  481. ]
  482.  
  483. phis = [
  484. (lambda x: -math.log(x[0]) + x[1]),
  485. (lambda x: -x[0]),
  486. (lambda x: -x[1])
  487. ]
  488.  
  489. slayter_pt = np.array([math.exp(2), 0.5])
  490.  
  491. # производная f
  492. f_d = lambda x: [math.exp(x[0]+x[1]) + 2.*x[0],
  493. math.exp(x[0]+x[1]) - 2.]
  494.  
  495. phi_ds = [
  496. lambda x: [ #Phi1
  497. -1./x[0],
  498. 1.
  499. ],
  500. lambda x: [ #Phi2
  501. -1.,
  502. 0.
  503. ],
  504. lambda x: [
  505. 0.,
  506. -1.
  507. ]
  508. ]
  509.  
  510. print('Slayter: ', slayter(slayter_pt, phis))
  511. for xs in check_points:
  512. print('\ntesting point %s' % xs)
  513.  
  514. active_idxs = find_active(xs, phis)
  515. print('active idxs: %s' % list(map(lambda idx : idx+1, active_idxs)))
  516. b = -1.*np.array(f_d(xs))
  517. A = np.column_stack(tuple(
  518. list(phi_i_d(xs) for phi_i_d in select_by_indices(phi_ds, active_idxs))
  519. ))
  520. print('A: \n%s\n b: %s' % (A, b))
  521. # lambdas = np.linalg.solve(A, b)
  522. # print('Lambdas: ' + str(lambdas))
  523.  
  524. def main():
  525. # A = np.array([
  526. # [2., -1., 1., 1., 1.],
  527. # [-4., 3., -1., -1., -3.],
  528. # [3., 2., 3., 5., 0.]
  529. # ])
  530. # print(A.shape)
  531. # b= np.array([2., -4., 3.])
  532. # find_feasible_basis(A, b)
  533.  
  534.  
  535. # is_solutions_optimal()
  536. dual_geom_plot()
  537.  
  538. main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement