Changeset 297
- Timestamp:
- 07/07/10 12:59:19 (6 years ago)
- Location:
- branches/alta/mystic-0.2a1
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/alta/mystic-0.2a1/constraint_tools.py
r295 r297 332 332 return target + ' = ' + str(soln[0]) 333 333 334 def form_constraints_nonlinear (equations_string, ndim, x0=None, \334 def form_constraints_nonlinear_old(equations_string, ndim, x0=None, \ 335 335 lower_bounds=None, upper_bounds=None, varname='x'): 336 336 """Use Sympy to simplify/invert equations to find a formulation of … … 473 473 varname=varname) 474 474 475 def form_constraints_nonlinear_sub(equations_string, ndim, varname='x'): 476 """Simplify using substitution, algebraically with help from Sympy. 477 Algorithm: 478 Same as using linear algebra to simplify a linear system.... 479 Treat the list of equations as a matrix. 480 """ 475 def form_constraints_nonlinear(equations_string, ndim, varname='x', x0=None,\ 476 lower_bounds=None, upper_bounds=None): 477 """Simplify a linear or nonlinear system using substitution with help from Sympy. 478 479 Input parameters: 480 equations_string -- A string with constraints equations on each line 481 ndim -- Number of parameters. 482 483 Optional inputs: 484 x0 -- Initial x value. 485 lower_bounds -- Lower bounds on x. 486 upper_bounds -- Upper bounds on x. 487 varname -- A string, default is 'x'. 488 489 Returns a constraints function. 490 """ 491 # Figure out if trying various permutations is necessary 492 strict = False 493 if (x0 and lower_bounds) or (x0 and upper_bounds): 494 strict = True 495 481 496 eqns = equations_string.splitlines() 482 497 # Remove empty strings: … … 485 500 if eqns[j]: 486 501 actual_eqns.append(eqns[j]) 502 orig_eqns = actual_eqns[:] 487 503 488 504 neqns = len(actual_eqns) 489 505 490 # Sort the list actual_eqns so that any equation containing x1 is first, etc. 491 sorted_eqns = [] 492 actual_eqns_copy = actual_eqns[:] 493 for i in range(ndim): 494 variable = varname + str(i+1) 495 for eqn in actual_eqns_copy: 496 if eqn.find(variable) == -1: 497 pass 498 else: 499 sorted_eqns.append(eqn) 500 actual_eqns_copy.remove(eqn) 501 break 502 actual_eqns = sorted_eqns 503 504 for i in range(neqns): 505 # Trying to use xi as a pivot. Loop through the equations looking for one 506 # containing xi. 507 target = varname + str(i+1) 508 for eqn in actual_eqns[i:]: 509 invertedstring = invert_equation(eqn, ndim, varname=varname, target=target) 510 if invertedstring: 511 break 512 # substitute into the remaining equations. the equations' order in the list 513 # newsystem is like in a linear coefficient matrix. 514 newsystem = ['']*neqns 515 j = actual_eqns.index(eqn) 516 newsystem[j] = eqn 517 othereqns = actual_eqns[:j] + actual_eqns[j+1:] 518 for othereqn in othereqns: 519 expression = invertedstring.split("=")[1] 520 fixed = othereqn.replace(target, '(' + expression + ')') 521 k = actual_eqns.index(othereqn) 522 newsystem[k] = fixed 523 actual_eqns = newsystem 524 525 # Invert so that it can be fed properly to form_constraints_directly 526 simplified = [] 527 for eqn in actual_eqns: 528 target = varname + str(actual_eqns.index(eqn) + 1) 529 simplified.append(invert_equation(eqn, ndim, varname=varname, target=target)) 530 #print 'simplified:' 531 #print '\n'.join(simplified) 532 533 # Turn this into a constraints function 534 return form_constraints_directly('\n'.join(simplified), ndim, varname=varname) 506 # Some of the permutations will give the same answer; look into reducing the number 507 # of repeats? 508 for p in permutations(range(ndim)): 509 thisorder = p 510 # Sort the list actual_eqns so that any equation containing x1 is first, etc. 511 sorted_eqns = [] 512 actual_eqns_copy = orig_eqns[:] 513 for i in thisorder:#range(ndim): 514 variable = varname + str(i+1) 515 for eqn in actual_eqns_copy: 516 if eqn.find(variable) == -1: 517 pass 518 else: 519 sorted_eqns.append(eqn) 520 actual_eqns_copy.remove(eqn) 521 break 522 if actual_eqns_copy: 523 for item in actual_eqns_copy: 524 sorted_eqns.append(item) 525 actual_eqns = sorted_eqns 526 527 for i in range(neqns): 528 # Trying to use xi as a pivot. Loop through the equations looking for one 529 # containing xi. 530 target = varname + str(thisorder[i] + 1)#str(i+1) 531 for eqn in actual_eqns[i:]: 532 invertedstring = invert_equation(eqn, ndim, varname=varname, target=target) 533 if invertedstring: 534 break 535 # substitute into the remaining equations. the equations' order in the list 536 # newsystem is like in a linear coefficient matrix. 537 newsystem = ['']*neqns 538 j = actual_eqns.index(eqn) 539 newsystem[j] = eqn 540 othereqns = actual_eqns[:j] + actual_eqns[j+1:] 541 for othereqn in othereqns: 542 expression = invertedstring.split("=")[1] 543 fixed = othereqn.replace(target, '(' + expression + ')') 544 k = actual_eqns.index(othereqn) 545 newsystem[k] = fixed 546 actual_eqns = newsystem 547 548 # Invert so that it can be fed properly to form_constraints_directly 549 simplified = [] 550 for eqn in actual_eqns: 551 target = varname + str(thisorder[actual_eqns.index(eqn)]+1)#actual_eqns.index(eqn) + 1) 552 simplified.append(invert_equation(eqn, ndim, varname=varname, target=target)) 553 554 cf = form_constraints_directly('\n'.join(simplified), ndim, varname=varname) 555 556 if not strict: 557 return cf 558 else: 559 compatible = constraints_inside_bounds(cf, x0, lower_bounds=\ 560 lower_bounds, upper_bounds=upper_bounds) 561 satisfied = verify_constraints_satisfied(equations_string, cf(x0), ndim, disp=False) 562 if compatible and satisfied: 563 return cf 564 print 'Warning! Initial x value cannot satisfy constraints and bounds, \ 565 or constraints cannot be enforced correctly. Returning a constraints function \ 566 anyways, but it may not work correctly.' 567 return cf 535 568 536 569 … … 538 571 varname='x', disp=True): 539 572 """For debugging. Makes sure that constraints are *really* satisified. 540 constraints_string is the constraints string 573 constraints_string is the constraints string -- Note: not the function! 541 574 x is cf(x), i.e. some array that is supposed to satisfy the constraints. 542 575 ndim is number of dimensions. … … 612 645 def test5(): 613 646 # Test a nonlinear constraints example with x0 and bounds. 614 #XXX This is a case where it does not work properly because the second line615 # erases the effects of the first line, and since it's nonlinear, Sympy can't616 # simplify it. If it were linear, form_constraints_linear would pass both617 # equations simultaneously to Sympy to simplify, and this would not be618 # a problem. In order to solve something like this, you would have to solve for619 # one variable and then plug that into the other equation. Can get bad if there620 # are many equations and many dimensions though. Maybe I could try to hack621 # something together that tries to eliminate variables?? For example, solves for x1,622 # then plugs that into x1 everywhere....623 647 string = """ 624 648 x2 - 2.*x1*x3 = 1. 625 x3 = x1 *x2 + 3.649 x3 = x1/x2 + 3. 626 650 """ 627 651 # string2 is linear … … 630 654 2.*x1 - 3.*x3 = 0.5*x2""" 631 655 x0 = [0.8,1.2,-0.7] 632 lb = [-1., -1., -1.] 656 lb = [-1., -1., -1.] 633 657 ub = [200., 100., 200.] 634 #cf = form_constraints_function(string2, len(x0), x0=x0, \ 635 # lower_bounds=lb, upper_bounds=ub) 636 cf = form_constraints_nonlinear_sub(string, len(x0)) 658 cf = form_constraints_function(string, len(x0), x0=x0, \ 659 lower_bounds=lb, upper_bounds=ub) 637 660 c = cf(x0) 638 print 'constraints satisfied? ', verify_constraints_satisfied(string, c, len(x0))661 print 'constraints satisfied?\n', verify_constraints_satisfied(string, c, len(x0)) 639 662 print 'Strict: constraints(x0) = ', c 640 663 … … 662 685 #print 'cf([1.]*4)', cf([1.]*4) 663 686 #print 'cf(cf([1.]*4))', cf(cf([1.]*4)) 664 cf = form_contsraints_nonlinear _sub(eqnstring, 4)#form_constraints_function(eqnstring, 4)687 cf = form_contsraints_nonlinear(eqnstring, 4)#form_constraints_function(eqnstring, 4) 665 688 print 'cf([1.]*4)', cf([1.]*4) 666 689 print 'cf(cf([1.]*4))', cf(cf([1.]*4)) … … 669 692 # Test a nonlinear constraints example with no x0 or bounds and not too many 670 693 # variables in the same equation. 671 # Notes: string1 works poorly due to a **(1/2) being evaluated as **(0) by python.694 # string1 now works fine. 672 695 # stringlinear works fine, and can be compared to form_constraints_linear. 673 696 # string2 works fine. 674 string = """697 string1 = """ 675 698 x2*x3 = 1. + x1*0.9 676 699 x3 = x1/x2 - 3. + x4 … … 680 703 x2 + 0.5*x1 = x3*2. + x4 + 2. 681 704 5.*x3 - x2 = x1 + x4*3. 705 x1 = x2 682 706 """ 683 707 string2 = """ … … 687 711 """ 688 712 x0 = [0.8,1.2,-0.7, 1.3] 713 lb = [-5., -5., -5., -5.] 714 ub = [10., 10., 10., 10.] 689 715 #cf=form_constraints_function(stringlinear, len(x0)) 690 cf = form_constraints_nonlinear_sub(string2, len(x0)) 716 cf = form_constraints_nonlinear(string1, len(x0), x0=x0, lower_bounds=lb,\ 717 upper_bounds=ub) 691 718 c = cf(x0) 692 719 print 'consistent?', verify_constraints_consistent(c, cf) 693 print 'satisfied? ', verify_constraints_satisfied(string2, c, len(x0))720 print 'satisfied?\n', verify_constraints_satisfied(string1, c, len(x0)) 694 721 695 722 if __name__ == '__main__': … … 698 725 #test3() 699 726 #test4() 700 test5()727 #test5() 701 728 #test6() 702 729 #test7() 703 #test8()730 test8() -
branches/alta/mystic-0.2a1/differential_evolution.py
r288 r297 229 229 the current parameter vector. [default = None] 230 230 disp -- non-zero to print convergence messages. 231 231 usebounceback -- True to use 'bounce back'. 232 232 """ 233 233 #allow for inputs that don't conform to AbstractSolver interface … … 238 238 callback=None #user-supplied function, called after each step 239 239 disp=0 #non-zero to print convergence messages 240 usebounceback = True # True to use 'bounce back'. 240 241 if kwds.has_key('strategy'): strategy = kwds['strategy'] 241 242 if kwds.has_key('CrossProbability'): \ … … 244 245 if kwds.has_key('callback'): callback = kwds['callback'] 245 246 if kwds.has_key('disp'): disp = kwds['disp'] 247 if kwds.has_key('usebounceback'): usebounceback = kwds['usebounceback'] 246 248 #------------------------------------------------------------- 247 249 … … 315 317 316 318 # Use 'bounce back'. Helps a little when soln is on the boundary. 317 self._keepSolutionWithinRangeBoundary(base) 319 if usebounceback: 320 self._keepSolutionWithinRangeBoundary(base) 318 321 319 322 if costfunction(self.constraints(self.trialSolution[:])) != inf: … … 461 464 encounters a parameter set that satisfies user-supplied constraints. 462 465 disp -- non-zero to print convergence messages. 466 usebounceback -- True to use 'bounce back'. 463 467 """ 464 468 #allow for inputs that don't conform to AbstractSolver interface … … 469 473 callback=None #user-supplied function, called after each step 470 474 disp=0 #non-zero to print convergence messages 475 usebounceback = True # True to use 'bounce back'. 471 476 if kwds.has_key('strategy'): strategy = kwds['strategy'] 472 477 if kwds.has_key('CrossProbability'): \ … … 475 480 if kwds.has_key('callback'): callback = kwds['callback'] 476 481 if kwds.has_key('disp'): disp = kwds['disp'] 482 if kwds.has_key('usebounceback'): usebounceback = kwds['usebounceback'] 477 483 #------------------------------------------------------------- 478 484 … … 561 567 strategy(self, candidate) 562 568 563 # Use 'bounce back'. Helps a little when soln is on the boundary. 564 self._keepSolutionWithinRangeBoundary(base) 569 if usebounceback: 570 # Use 'bounce back'. Helps a little when soln is on the boundary. 571 self._keepSolutionWithinRangeBoundary(base) 565 572 566 573 # Only apply constraints if they don't violate bounds.
Note: See TracChangeset
for help on using the changeset viewer.