Icon representing a recipe

Recipe: Simulated Annealing 3.0

created by KarenCH

Profile


Name
Simulated Annealing 3.0
ID
100951
Shared with
Public
Parent
None
Children
Created on
May 03, 2015 at 22:25 PM UTC
Updated on
May 03, 2015 at 22:25 PM UTC
Description

various upgrades

Best for


Code


-------------------------------------------------------------------- -- Code for Simulated Annealing algorithm -------------------------------------------------------------------- -- Performs "modifications" of a protein and accepts or rejects them depending on "temperature" -- and on how much they improved the score (if + improvement, yes; if not too bad score drop -- and temperature is "high", then maybe yes). Temperature starts high, but drops gradually to 0 -- by end of run. -- -- On Win7 box with ~50 AAs, a 100 step run takes 30 min - 1 hour; with ~100 AAs, ~90 min -- Plan runs accordingly. -- -- TODO: -- 1. Cysteine: Include band-two-cysteines together (locate closest ones, match together, etc). -- Consider throwing out actions that break connections. -- 2. Gui: Upgrade advanced options so users can directly choose more things (especially in MarchWiggle). -- 3. Wigglers: Play with banded wiggles - compare them, try adjusting target deltas -- depending on "lateness" in folding. -- Compare qStabWiggler with and without the fuse action - time vs score -- Study cementing behavior wrt fusing and LocalWiggle. -- 4. SA-Temperature functions: Study effects of different choices of these (probably depending on lateness). -- 5. Rebuild: Review all my rebuilders, see if there's a way to clean them up. -- Bring secondary structure into play better. Rebuild with compressor bands. -- 6. Idealize: Compare with cuts versus without, see if lengths should vary. Maybe put a compressor instead -- of zlb? -- 7. Contactmaps: Try more actions such as "put band(s)" + rebuild at low ci; use ZLB-wiggler. "Til contact is -- made" banded wiggler. TEST comp-band mods: are they working propery? -- 8. See if the LowCI stuff can take the place of my other scripts, or should follow, or what? -- -- Code ideas and/or thefts come from: -- (tlaloc) tlaloc Random Tug 4.00 -- (spvincent) Helix Twister 1.0, Loop rebuild 5.0 (NC), Local Quake 1.0, Quaking Rebuild V2 1.0 -- (susume2) Cut and Wiggle Everything v0.1 -- (MurloW) Shock v0.1, Fracture v1.6 -- (MurloW, drjr) Idealize by 3+ -- (porkythepundit) NC Kichen KaboodlEnz 14, Porky's Cement Crusher 1.0 (and ideas for fuses and banded worm) -- (rav3n_pl) Rav3n_pl GAB BiS v2.0.1 w30 [NC], Rav3n_pl Voids Killer v0.5 NC, -- Rav3n_pl Push v3, LS Quake v1.1, Worm LWS v2 -- (StackOverflow) Freeze Burst v1.0 -- (tlaloc, rav3n_pl, Seagat2011, thom001) ST - Glycine Hinge REPOST -- (drjr) drjr - RandomizeR 1.20, Idealize by 3 -- (BitSpawn) general "how to do low CI" (any failures to do right are mine, not his) -- -------------------------------------------------------------------------------- -- some oddballs that users might want to set USENORMALSCORE = true -- exploration puzzles would set false DEBUGRUN = true -- mostly goes with DebugPrint, but could get more use later SHOW_STATS_REPORT = true -- what to do with user state (bands, cuts) when running, and what cleanup is best at end PRESERVE_USER_BANDS = true PRESERVE_USER_CUTS = false RESTORE_BEST_AT_END = true PERFORM_CLEANUP_AT_END = true KILLING_FILTERS = false -- simple bander options COREPULLING_CI = 0.70 BAND_STRENGTH_DEFAULT = 1.0 -- not really meaningful; wigglers strength-modify BAND_STRENGTH_REGION = 1.0 BAND_MINCOMPRESS = 0.75 BAND_MAXEXPAND = 1.25 BANDEDWIGGLE_TRYCT = 5 BANDEDWIGGLE_TARGET = 500.0 BIS_LENGTH = 5.0 -- max length of a BIS BAND_TO_SIDECHAINS = true BAND_ADD_RANDOMS = true RANDOMBAND_COUNT = 3 -- when random bands are added, this is a plausible count -- default time to use in shaking SHAKESIDECHAIN_ITERS = 1 -- values for controlling in-step wiggle timing and gain QUICKWIGGLE_ITERS = 2 QUICKWIGGLE_GAIN = 0.50 -- for iterative wiggles that happen in quickwiggle time PROB_QSTAB_EXTRA = 0.50 PROB_LOCALWIGGLE = 0.50 -- see what happens, anyway -- values for controlling behavior of slow wiggle that's done after an acceptable neighbor is found USE_SLOWWIGGLE = false -- if false, skip touch-up fuse SLOWWIGGLE_ITERS = 2 SLOWWIGGLE_GAIN = 0.10 SLOWWIGGLE_THRESHOLD = 50.0 PROB_SLOWWIGGLE_CUTFUSE = 0.75 PROB_SLOWWIGGLE_LOCAL = 0.00 -- for now, we're just going to kill this one PROB_SLOWWIGGLE_BLUEFUSE = 0.25 -- values for controlling how mutations are handled ALLOW_SPOT_MUTATION = false -- this is for performing local "spot" changes MUTATE_NOT_SHAKE = false -- this is for choosing between shake and mutate NOMUTATELIST = {} -- aa-numbers to not mutate. currently only manually settable (right here) -- values associated with idealize IDEALIZE_USE_CUTS = true IDEALIZE_FORBID_UNHEALED_CUTS = true IDEALIZE_MAXTRIES = 5 -- a "try" fails if cuts not healed. increase ZLBstrength, try again. IDEALIZE_ZLB_STRENGTH = 2.0 IDEALIZE_TUBE_RADIUS = 4.0 IDEALIZE_MAX_SEGLEN = 5 -- values associated with rebuilding REBUILD_FAILSBEFOREQUIT = 75 REBUILD_TRYCOUNT = 5 REBUILD_ADDIDEALIZE = true REBUILD_USECUTS = true REBUILD_MAX_SEGLEN = 9 REBUILD_MAX_EARLY_SCOREDROP = 3000.0 REBUILD_MAX_MEDIUM_SCOREDROP = 500.0 REBUILD_MAX_LATE_SCOREDROP = 100.0 -- Clash Importance SCALE_MAXCI = 1.0 -- values for contact map reading CONTACTMAP_THRESHOLD = 0.96 CONTACTMAP_TAKEDROPS = false -- allow drops if they improve contact map CONTACTMAP_MAX_DROP = 25.0 CONTACTMAP_CONTACTING_GOAL = 0.90 CONTACTMAP_NONCONTACTING_GOAL = 0.70 CONTACTMAP_CONTACTING_STRENGTH = 0.50 CONTACTMAP_NONCONTACTING_STRENGTH = 1.50 -- atoms in an amino acid BETA_CARBON = 5 TERMINAL_BETA = 6 CENTER_CARBON = 2 --this is the default atom for bands to attach to ------------------------------------------------------------------------------------------------------------- ------------ VALUES USERS SHOULD NOT BE TOUCHING --------------------------------- ------------------------------------------------------------------------------------------------------------- -------------- CONSTANTS THAT PROBABLY SHOULD NEVER CHANGE -------------- REBUILD_INNER_TUBE_RADIUS = 12.0 -- 9.0 has been seen, 7 or 8 recommended for contact map REBUILD_OUTER_TUBE_RADIUS = 18.0 REBUILD_CM_INNER_TUBE_RADIUS = 8.0 REBUILD_CM_OUTER_TUBE_RADIUS = 16.0 HELIX_DISTANCE_SKIP4 = 6.3 -- for skips of 4 HELIX_DISTANCE_SKIP5 = 8.6 -- for skips of 5 -- QUICKSAVE slots used herein (QS_Run equivalent is taken by QS_TopLevelTemp) QS_Start = 1 QS_CmBest = 2 QS_Best = 3 QS_ShortUseTemp1 = 94 -- used by low-level subroutines that stash state for short time QS_ShortUseTemp2 = 95 -- used by low-level subroutines that stash state for short time QS_NeighborTemp1 = 96 -- used by "Neighbor Generation" subroutines (mid-level managers) QS_NeighborTemp2 = 97 -- used by "Neighbor Generation" subroutines (mid-level managers) QS_NeighborTemp3 = 98 -- used by "Neighbor Generation" subroutines (mid-level managers) QS_TopLevelTemp = 99 -- used by top-level manager subroutines that call low-level managers --------------- THINGS THE PROGRAM LEARNS AND REMEMBERS -------------- PuzzleAllowsMutate = false PuzzleHasLockedSegs = false PuzzleHasContactMap = false PuzzleUsesFilters = false PuzzleIsDesigner = false ChangedSecondaryStructure = false ChangedFrozenness = false EndCalled = false StartTime = 0 InitialScore = 0.0 CurrentBestScore = 0.0 ContactMapScore = 0.0 InitialBandCount = band.GetCount( ) InitialClashImportance = behavior.GetClashImportance() HasContactMapSegList = {} InitialFrozenTable = {} IsSlowFilterDisabled = behavior.GetSlowFiltersDisabled( ) helixStarts = {} helixEnds = {} sheetStarts = {} sheetEnds = {} loopStarts = {} loopEnds = {} NonLockedSegList = {} SecStructList = {} segCt = structure.GetCount() MinUnlockedSeg = 1 MaxUnlockedSeg = segCt ---------------- STATISTICS-TRACKING --------------------- algName = "none" -- for tracking statistics about how successful an operation is algNameList = {} algStats = { name = "none", posScoreDelta = 0.0, scoreDelta = 0.0, runTime = 0, callCount = 0, failCount = 0, } TotalShakeTime = 0 ---------------------------------------------------------------------- -- ---- SIMULATED-ANNEALING-SPECIFIC STUFF -- ---------------------------------------------------------------------- OperationChosen = "none" -- Simulated Annealing "core" values SA_STEPSPERRUN = 100.0 SA_NUMSTARTS = 4 SA_MINGAIN = 5.0 SA_FAILIFNOGAIN = math.floor( SA_STEPSPERRUN / 2 ) SA_REBUILD_NUMSTARTS = 8 -- values for choosing the "scale" of modification to try in SA-Midgame PROB_TARGETED = 0.00 -- local or midsize action, pointed at "worst-scoring" segment(s) PROB_LOCAL = 0.15 PROB_MIDSIZE = 0.70 PROB_LARGESCALE = 0.15 PROB_MUTATESIMILAR = 0.75 -- values for controlling final "polishing" wiggles and cleaning MF_STEPSPERRUN = 30.0 MF_FAILSBEFORERESTART = 15 MARCHWIGGLE_MINGAIN = 15.0 -- if wiggles gain this much, try other actions for luck FINALWIGGLE_ITERS = 8 FINALRUN_WIGGLE_GAIN = 0.001 -- for final "drag out points" activities PROB_PUTBAND = 1.0 -- how often do we put bands in banded-worm wiggle steps? PROB_BIS_NOT_BETWEEN = 0.50 -- do we prefer BIS or bands between segs in banded-worm wiggle PROB_BETWEEN_USES_TIP = 0.50 -- between: should wiggled seg have band from aa tip for banded-worm PROB_CHOOSE_CONTACTMAP = 0.80 -- or some other way of saying we like these bands in banded-worm -- user dialog picker... DEFAULT_PICK_AT_START = true ---------------------------------------------------------------------- -- ROUTINES FOR CHOOSING ACTIONS ---------------------------------------------------------------------- function PickActionFromList( allowedActions, idx ) local doVariableStrength = false local skipWiggler = false local okToAddRandomBands = false algName = ChooseAlgorithm( allowedActions ) if algName == "BIS" then changeSucceeded = PickSingleBandInSpace( idx ) skipWiggler = true elseif algName == "BandBetween" then changeSucceeded = PickBandToRandomSeg( idx ) doVariableStrength = true elseif algName == "SpotMutator" then changeSucceeded = PickMutatorAlgorithm( idx ) elseif algName == "GlycineHinge" then changeSucceeded = PickGlycineHinge( idx ) elseif algName == "RotatorBands" then changeSucceeded = PickRotatorBands( idx ) skipWiggler = true elseif algName == "PusherBands" then changeSucceeded = PickPusherBands( idx ) skipWiggler = true elseif algName == "MoverBands" then changeSucceeded = PickMoverBands( idx ) skipWiggler = true elseif algName == "FlexerBands" then changeSucceeded = PickFlexerBands( idx ) skipWiggler = true elseif algName == "GeneralHinge" then changeSucceeded = PickGeneralHingeBands( idx ) elseif algName == "SheetStraightener" then changeSucceeded = PickSheetStraightenerBands( idx ) elseif algName == "HelixUniform" then changeSucceeded = PickHelixUniformBands( idx ) elseif algName == "HelixCompressor" then changeSucceeded = PickHelixCompressorBands( idx ) elseif algName == "HelixFixer" then changeSucceeded = PickHelixFixerBands( idx ) elseif algName == "PushPull" then changeSucceeded = PickPushPullAction( idx ) doVariableStrength = true elseif algName == "VoidCrusher" then changeSucceeded = PickVoidCrusherAction( idx ) doVariableStrength = true elseif algName == "IdealizePoint" then changeSucceeded = PickIdealizePointAction( idx ) skipWiggler = true elseif algName == "IdealizeInRange" then changeSucceeded = PickIdealizeRangeAction( idx ) skipWiggler = true elseif algName == "IdealizeSimpleRange" then changeSucceeded = PickSimpleIdealizeAction( idx ) skipWiggler = true elseif algName == "RebuildInRange" then changeSucceeded = PickRebuildPointAction( idx ) skipWiggler = true elseif algName == "RebuildSimple" then changeSucceeded = PickRebuildSimpleAction( idx ) skipWiggler = true elseif algName == "RebuildSimple2" then changeSucceeded = PickRebuildSimple2Action( idx ) skipWiggler = true elseif algName == "RebuildSimpleRange" then changeSucceeded = PickSimpleRebuildRangeAction( idx ) skipWiggler = true elseif algName == "MultiBander" then changeSucceeded = PickMultiBander( ) doVariableStrength = true elseif algName == "CentralBander" then changeSucceeded = PickCentralBander( ) doVariableStrength = true elseif algName =="EveryXToY" then changeSucceeded = PickEveryXToEveryYBanding( ) doVariableStrength = true elseif algName == "GentleComp" then changeSucceeded = PickGentleCompBander( ) doVariableStrength = true elseif algName == "CoreStirrer" then changeSucceeded = PickCoreStirrer( ) skipWiggler = true elseif algName == "SheetSewer" then changeSucceeded = PickSheetSewerAction( ) doVariableStrength = true elseif algName == "LSQuaker" then changeSucceeded = PickLSQuaker( ) doVariableStrength = true elseif algName == "LocalQuake" then changeSucceeded = PickLocalQuake( idx ) doVariableStrength = true elseif algName == "ContactMapper" then changeSucceeded = PickContactMapper( ) okToAddRandomBands = BAND_ADD_RANDOMS elseif algName == "ContactMapTwoRegions" then changeSucceeded = PickCMTwoRegionBander( idx ) okToAddRandomBands = BAND_ADD_RANDOMS elseif algName == "ContactTwoSegs" then changeSucceeded = PickSingleContactMapBand( idx ) doVariableStrength = true okToAddRandomBands = BAND_ADD_RANDOMS elseif algName == "SomeContactMapBands" then changeSucceeded = PickSomeContactMapBands( ) doVariableStrength = true okToAddRandomBands = BAND_ADD_RANDOMS elseif algName == "ContactMapForSeg" then changeSucceeded = PickContactMapBandsForSeg( idx ) okToAddRandomBands = BAND_ADD_RANDOMS elseif algName == "PushPullContactMap" then changeSucceeded = PickPushPullContactMapAction( idx ) doVariableStrength = true elseif algName == "VoidCrusherContactMap" then changeSucceeded = PickVoidCrusherContactMapAction( idx ) doVariableStrength = true elseif algName == "ContactMapRebuildRange" then changeSucceeded = PickContactMapRebuildRangeAction( idx ) skipWiggler = true elseif algName == "ContactMapRebuildSS" then changeSucceeded = PickContactMapRebuildSSAction( idx ) skipWiggler = true elseif algName == "ContactMapRebuildAll" then changeSucceeded = PickContactMapRebuildAllAction( ) skipWiggler = true else print( "Error - invalid action: ".. algName ) exit( ) end if changeSucceeded and okToAddRandomBands then if random( ) < 0.50 then -- consider making a global to control this decision local ctRandBands = random( RANDOMBAND_COUNT - 2, RANDOMBAND_COUNT + 2 ) local strength = random(0.5, 1.5) * BAND_STRENGTH_DEFAULT PutGentleCompBands( ctRandBands, 14.0, 30.0, 5, strength, 0.7 ) -- 0.7 is compression end end if changeSucceeded and not skipWiggler then PickBeforeAndAfterWiggler( doVariableStrength ) end ResetFrozenness( ) DelBands( ) ResetCuts( ) selection.DeselectAll( ) if not changeSucceeded then print( "CHANGE FAILED" ) end return changeSucceeded end function AddRegionBanderActions(allowedActions, idx ) allowedActions[ #allowedActions + 1 ] = "RotatorBands" allowedActions[ #allowedActions + 1 ] = "PusherBands" allowedActions[ #allowedActions + 1 ] = "MoverBands" local startSeg, endSeg = GetRegionForOperation( idx ) local regionLength = endSeg - startSeg + 1 local isSheetRegion = structure.GetSecondaryStructure( idx ) == 'E' local isHelixRegion = structure.GetSecondaryStructure( idx ) == 'H' if not isSheetRegion and not isHelixRegion then -- actions that only make sense for loops allowedActions[ #allowedActions + 1 ] = "GeneralHinge" end --if not isHelixRegion then -- actions that don't make sense for helices (only sheets and loops) -- allowedActions[ #allowedActions + 1 ] = "SheetStraightener" -- end if regionLength > 6 and isHelixRegion then -- actions that only make sense for helices (and not just "curls" of helix-ness) allowedActions[ #allowedActions + 1] = "HelixUniform" end if regionLength > 5 and isHelixRegion then -- actions that only make sense for helices (and not just "curls" of helix-ness) allowedActions[ #allowedActions + 1] = "HelixCompressor" allowedActions[ #allowedActions + 1] = "HelixFixer" end if regionLength >= 5 then allowedActions[ #allowedActions + 1] = "FlexerBands" end return allowedActions end function PickLocalOperation( idx ) if idx == nil then idx = randomUnlockedSeg( ) end local allowedActions = { "BIS", "BandBetween", "IdealizePoint", "RebuildSimple", "RebuildSimple2", } if (idx > 1) and (idx < segCt) and (structure.GetAminoAcid( idx ) == 'g') then allowedActions[ #allowedActions + 1 ] = "GlycineHinge" end if not IsNoMutate( idx ) then allowedActions[ #allowedActions + 1 ] = "SpotMutator" end if PuzzleHasContactMap and SegHasContactData( idx, CONTACTMAP_THRESHOLD ) then allowedActions[ #allowedActions + 1] = "ContactTwoSegs" end return PickActionFromList( allowedActions, idx ) end function PickMidsizeOperation( idx ) if idx == nil then idx = randomUnlockedSeg( ) end local allowedActions = { "PushPull", "VoidCrusher", "RebuildInRange", "IdealizeInRange", } if PuzzleHasContactMap then allowedActions[ #allowedActions + 1] = "ContactMapTwoRegions" allowedActions[ #allowedActions + 1] = "ContactMapRebuildRange" allowedActions[ #allowedActions + 1] = "ContactMapRebuildSS" if SegHasContactData( idx, CONTACTMAP_THRESHOLD ) then allowedActions[ #allowedActions + 1] = "ContactMapForSeg" end end allowedActions = AddRegionBanderActions( allowedActions, idx ) return PickActionFromList( allowedActions, idx ) end function PickLargeScaleOperation( ) local allowedActions = { "MultiBander", "CentralBander", "EveryXToY", "GentleComp", "CoreStirrer", "LSQuaker", -- "LocalQuake" -- too slow for standard use. } if #sheetStarts > 1 then allowedActions[#allowedActions + 1] = "SheetSewer" end if PuzzleHasContactMap then allowedActions[ #allowedActions + 1] = "ContactMapper" allowedActions[ #allowedActions + 1] = "SomeContactMapBands" end return PickActionFromList( allowedActions, nil ) end function PickTargetedOperation( idx ) if idx == nil or idx == 0 then idx = randomLowScoringSeg( random(10) ) end if random( ) < PROB_LOCAL / ( PROB_MIDSIZE + PROB_LOCAL ) then return PickLocalOperation( idx ) else return PickMidsizeOperation( idx ) end end function PickNormalOperation( idx ) if idx == nil or idx == 0 then idx = randomUnlockedSeg( ) end local which = random( ) if which < PROB_TARGETED then return PickTargetedOperation( idx ) elseif which < PROB_TARGETED + PROB_LOCAL then return PickLocalOperation() elseif which < PROB_TARGETED + PROB_LOCAL + PROB_MIDSIZE then return PickMidsizeOperation() else return PickLargeScaleOperation() end end function PickContactMapOperation( idx ) if idx == nil or idx == 0 then idx = randomContactableSeg( ) end local allowedActions = { "ContactMapper", "SomeContactMapBands", "ContactMapForSeg", "ContactTwoSegs", "ContactMapTwoRegions", "ContactMapRebuildRange", "ContactMapRebuildSS", "ContactMapRebuildAll", } return PickActionFromList( allowedActions, idx ) end function PickEarlyGameOperation( idx ) if idx == nil or idx == 0 then idx = randomUnlockedSeg( ) end local allowedActions = { "CentralBander", "EveryXToY", "GentleComp", "PushPull", "VoidCrusher", "RebuildInRange", "IdealizeInRange", } if PuzzleHasContactMap then allowedActions[ #allowedActions + 1] = "ContactMapper" allowedActions[ #allowedActions + 1] = "SomeContactMapBands" allowedActions[ #allowedActions + 1] = "ContactMapTwoRegions" allowedActions[ #allowedActions + 1] = "ContactMapRebuildRange" allowedActions[ #allowedActions + 1] = "ContactMapRebuildSS" allowedActions[ #allowedActions + 1] = "ContactMapRebuildAll" end return PickActionFromList( allowedActions, idx ) end function PickLowCIOperation( idx ) if idx == nil or idx == 0 then idx = randomUnlockedSeg( ) end local allowedActions = { } if PuzzleHasContactMap then allowedActions[ #allowedActions + 1] = "ContactMapper" allowedActions[ #allowedActions + 1] = "SomeContactMapBands" allowedActions[ #allowedActions + 1] = "ContactMapTwoRegions" allowedActions[ #allowedActions + 1] = "ContactMapRebuildRange" if SegHasContactData( idx, CONTACTMAP_THRESHOLD ) then allowedActions[ #allowedActions + 1] = "PushPullContactMap" allowedActions[ #allowedActions + 1] = "VoidCrusherContactMap" allowedActions[ #allowedActions + 1] = "ContactMapForSeg" else allowedActions[ #allowedActions + 1] = "PushPull" allowedActions[ #allowedActions + 1] = "VoidCrusher" end else allowedActions[ #allowedActions + 1] = "CentralBander" allowedActions[ #allowedActions + 1] = "EveryXToY" allowedActions[ #allowedActions + 1] = "GentleComp" allowedActions[ #allowedActions + 1] = "PushPull" allowedActions[ #allowedActions + 1] = "VoidCrusher" end allowedActions[ #allowedActions + 1] = "RebuildSimpleRange" allowedActions[ #allowedActions + 1] = "IdealizeSimpleRange" return PickActionFromList( allowedActions, idx ) end function PickCompressOperation( idx ) if idx == nil or idx == 0 then idx = randomUnlockedSeg( ) end local allowedActions = { "CentralBander", "EveryXToY", "GentleComp", "PushPull", "VoidCrusher", "LocalQuake", } if PuzzleHasContactMap then allowedActions[ #allowedActions + 1] = "ContactMapper" allowedActions[ #allowedActions + 1] = "SomeContactMapBands" allowedActions[ #allowedActions + 1] = "ContactMapTwoRegions" end return PickActionFromList( allowedActions, idx ) end function PickLateGameOperation( idx ) if idx == nil or idx == 0 then idx = randomUnlockedSeg( ) end local allowedActions = { "CentralBander", "EveryXToY", "PushPull", "VoidCrusher", "BIS", "BandBetween", "RebuildSimple", "RebuildSimple2", } if PuzzleHasContactMap and SegHasContactData( idx, CONTACTMAP_THRESHOLD ) then allowedActions[ #allowedActions + 1] = "ContactTwoSegs" end allowedActions = AddRegionBanderActions( allowedActions, idx ) return PickActionFromList( allowedActions, idx ) end function PickRandomRebuildOperation( idx ) changeSucceeded = false if idx == nil or idx == 0 then idx = randomUnlockedSeg( ) end local rebuildLength = random( math.floor( REBUILD_MAX_SEGLEN / 2 ) ) changeSucceeded = PickRebuildPointAction( idx, rebuildLength ) ResetCuts( ) if not changeSucceeded then print( " CHANGE FAILED" ) end return changeSucceeded end function PickRandomLoopRebuildOperation( idx ) maxFall = REBUILD_MAX_EARLY_SCOREDROP changeSucceeded = false if idx == nil or idx == 0 then local segList = {} for i=1, segCt do if IsMovableSeg( i ) and structure.GetSecondaryStructure( i ) == 'L' then segList[ #segList + 1 ] = i end end idx = segList[ random( #segList ) ] end startIdx, endIdx = GetRegionForOperation( idx ) startIdx = math.max( idx - math.floor( REBUILD_MAX_SEGLEN / 2 ), startIdx ) endIdx = math.min( idx + math.floor( REBUILD_MAX_SEGLEN / 2 ), endIdx ) changeSucceeded = PickRebuildRangeAction( startIdx, endIdx, maxFall ) -- clean up any mess we may have left behind... ResetCuts( ) if not changeSucceeded then print( " CHANGE FAILED" ) end return changeSucceeded end ------------------------------------------------------------------------------ -- SLOW ENDGAME WIGGLERS ------------------------------------------------------------------------------ --------------------------------- FUSES ------------------------------------ function PinkFuse( iters ) recentbest.Save() ShakeWiggleFuse( 0.10, 0.70, iters ) WiggleShakeWiggleFuse( iters ) recentbest.Restore() ShakeWiggleFuse( 0.30, 0.60, iters ) WiggleShakeWiggleFuse( iters ) recentbest.Restore() WiggleWiggleWiggleFuse( 0.50, 0.70, iters ) WiggleShakeWiggleFuse( iters ) recentbest.Restore() WiggleWiggleWiggleFuse( 0.70, 0.50, iters ) WiggleShakeWiggleFuse( iters ) recentbest.Restore() SetCI( 1.0 ) end function CementCrusherFuse( iters ) CIlow = {0.98, 0.89, 0.55, 0.34, 0.21, 0.13, 0.08, 0.05, 0.03, 0.02, 0.01} for i=1, #CIlow do WiggleWiggleSimpleFuse( CIlow[i], 1.00, 1, iters ) end end function EvoSqueezeHwpFuse( iters ) WiggleWiggleSimpleFuse( 0.03, 1.00, 4, iters ) -- 10 for LWP, 14 for HWP end function MonsterBagOfFuses( iters ) save.Quicksave( QS_ShortUseTemp1 ) local startScore = getScore() ShakeWiggleFuse( 0.3, 0.6, iters ) WiggleShakeWiggleFuse( iters ) local newScore = getScore( ) if newScore > startScore then save.Quicksave( QS_ShortUseTemp1 ) end save.Quickload( QS_ShortUseTemp1 ) print("First fuse got gain "..getScore() - startScore ) startScore = getScore() WiggleWiggleWiggleFuse( 0.5, 0.7, iters ) local newScore = getScore( ) if newScore > startScore then save.Quicksave( QS_ShortUseTemp1 ) end save.Quickload( QS_ShortUseTemp1 ) print("Second fuse got gain "..getScore() - startScore ) startScore = getScore() ShakeWiggleFuse( 0.05, 1, iters ) newScore = getScore( ) if newScore > startScore then save.Quicksave( QS_ShortUseTemp1 ) end save.Quickload( QS_ShortUseTemp1 ) print("Third fuse got gain "..getScore() - startScore ) startScore = getScore() WiggleWiggleWiggleFuse( 0.7, 0.5, iters ) WiggleShakeWiggleFuse( iters ) newScore = getScore( ) if newScore > startScore then save.Quicksave( QS_ShortUseTemp1 ) end save.Quickload( QS_ShortUseTemp1 ) print("4th fuse got gain "..getScore() - startScore ) startScore = getScore() ShakeWiggleFuse( 0.07, 1, iters ) newScore = getScore( ) if newScore > startScore then save.Quicksave( QS_ShortUseTemp1 ) end save.Quickload( QS_ShortUseTemp1 ) print("5th fuse got gain "..getScore() - startScore ) startScore = getScore() WiggleWiggleWiggleFuse( 0.3, 1, iters ) newScore = getScore( ) if newScore > startScore then save.Quicksave( QS_ShortUseTemp1 ) end save.Quickload( QS_ShortUseTemp1 ) print("6th fuse got gain "..getScore() - startScore ) startScore = getScore() BlueFuse( ) newScore = getScore( ) if newScore > startScore then save.Quicksave( QS_ShortUseTemp1 ) end save.Quickload( QS_ShortUseTemp1 ) print("Blue fuse got gain "..getScore() - startScore ) startScore = getScore() PinkFuse( iters ) newScore = getScore( ) if newScore > startScore then save.Quicksave( QS_ShortUseTemp1 ) end save.Quickload( QS_ShortUseTemp1 ) print("Pink fuse got gain "..getScore() - startScore ) startScore = getScore() CementCrusherFuse( iters ) newScore = getScore( ) if newScore > startScore then save.Quicksave( QS_ShortUseTemp1 ) end save.Quickload( QS_ShortUseTemp1 ) print("CementCrush fuse got gain "..getScore() - startScore ) startScore = getScore() SetCI( 0.2 ) ShakeOrMutate( 2 ) SetCI( 1.0 ) structure.WiggleAll( 25 ) newScore = getScore( ) if newScore > startScore then save.Quicksave( QS_ShortUseTemp1 ) end save.Quickload( QS_ShortUseTemp1 ) print("Closing shake/wiggle got gain "..getScore() - startScore ) end function FuseBurstIterateCi ( baseIters ) recentbest.Save() ci = 0.01 while ( ci < 1 ) do SetCI( ci ) structure.WiggleAll ( baseIters ) ShakeOrMutate( baseIters ) ci = ci * 2 end SetCI( 1.0 ) structure.WiggleAll ( 2*baseIters ) ShakeOrMutate( 1 ) recentbest.Restore() end function QuickFuseBurst( baseIters ) WiggleShakeSimpleFuse( 0.01, baseIters ) WiggleShakeSimpleFuse( 0.50, baseIters ) WiggleShakeSimpleFuse( 1.00, baseIters*2 ) end function FreezeBurstFuse( baseIters ) local frozenCt = math.floor( segCt/ 2 ) - 1 while ( frozenCt > 1 ) do print( "Freezing "..frozenCt.." segments") local currScore = getScore( ) recentbest.Save() local idxList = {} getBestScoringAAs( idxList, frozenCt ) -- should be able to ask for "movable" aas! for i = 1, frozenCt do freeze.Freeze( idxList[i] , true , true ) end QuickFuseBurst( baseIters ) recentbest.Restore() freeze.UnfreezeAll () local endScore = getScore( ) if endScore > currScore then print( ">>> Gained "..TrimNum( endScore - currScore ).. " points (now "..TrimNum( endScore )..")" ) end frozenCt = math.floor( frozenCt / 2 ) end freeze.UnfreezeAll () end function FullIterativeCutAndWiggle( baseIters, minGain, maxShift, randomizeShifts ) save.Quicksave( QS_ShortUseTemp1 ) local fakeprimes = {1,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101} local shiftsLt = {} for i=1, #fakeprimes do -- called fake because 1 is among them if fakeprimes[ i ] > maxShift then break end shiftsLt[ #shiftsLt + 1 ] = fakeprimes[ i ] end if randomizeShifts then randomizeIndexList( shiftsLt ) end local startScore = getScore() local bestscore = startScore for i=1, #shiftsLt do save.Quickload( QS_ShortUseTemp1 ) local gain = 0.0 local currscore = getScore() local newscore = currscore local shift = shiftsLt[ i ] for offset = 1, shift do save.Quickload( QS_ShortUseTemp1 ) print("C&W: shift="..shift.." offset="..offset.." score="..bestscore) BasicCutAndWiggleFuse( baseIters, shift, offset ) newscore = getScore() if newscore > bestscore then save.Quicksave( QS_ShortUseTemp1 ) bestscore = newscore end end -- FOR offset gain = bestscore - currscore if TrimNum( gain ) > 0 then print( "C&W (shift "..shift..") had gain="..TrimNum( gain ) ) end end -- FOR i < #shiftsLt save.Quickload( QS_ShortUseTemp1 ) local endScore = getScore( ) if endScore > startScore then print( "C&W End Score="..TrimNum( endScore ).." gain="..TrimNum( endScore - startScore ) ) end end --------------------------------- WALKERS ------------------------------------ function WiggleLocalByChunk( iters, startSeg, endSeg, chunkSize, passCount, addFreeze ) currOffset = 0 for i=1, passCount do if (passCount == 1 or chunkSize == 1) then currOffset = 0 else currOffset = random(chunkSize - 1) end ctBlocks = (endSeg - startSeg) / chunkSize for idx = 0,ctBlocks do startIdx = startSeg + currOffset + chunkSize*idx WiggleRange(iters, startIdx, startIdx + chunkSize, addFreeze, false ) end end end function WormWiggle( ) local iters = 20 local lens = {2,5,11,3,13,4,7,1,6} save.Quicksave( QS_ShortUseTemp1 ) for i=1, #lens do local currScore = getScore( ) WiggleLocalByChunk( iters, 1, segCt, lens[ i ], 1, false ) local newScore = getScore( ) local gain = newScore - currScore if gain > 0 then save.Quicksave( QS_ShortUseTemp1 ) if TrimNum( gain ) > 0 then print( "Worm " .. i .. ": len=" .. lens[ i ] .. " gain=" .. TrimNum( gain ) ) end else save.Quickload( QS_ShortUseTemp1 ) end end save.Quickload( QS_ShortUseTemp1 ) end function PutSingleRandomBandToSeg( idx ) changeSucceeded = false local strength = random( 0.5 * BAND_STRENGTH_DEFAULT, 1.5 * BAND_STRENGTH_DEFAULT, true ) local doBIS = random( ) < PROB_BIS_NOT_BETWEEN if doBIS then changeSucceeded = PutBandInSpace( idx, BIS_LENGTH, strength ) else if SegHasContactData( idx, CONTACTMAP_THRESHOLD ) and random( ) > PROB_CHOOSE_CONTACTMAP then local doSidechain = random( ) < PROB_BETWEEN_USES_TIP changeSucceeded = PutSomeContactMapBands( CONTACTMAP_THRESHOLD, strength, 1, doSidechain ) else local atom = PickAtomNumberForBand( idx ) changeSucceeded = PutBandToRandomSeg( idx, strength, atom ) end end return changeSucceeded end function BandedWorm( ) pattern={ 2,5,11,3,13,4,7,1,6 } recentbest.Save( ) SetCI( 1.0 ) SaveBest( ) local ss = getScore() for w = 1, #pattern do len = pattern[ w ] local sw = getScore() local swCurr = sw print( "Starting BandedWorm of len " .. len .. ", score: ".. TrimNum( getScore() ) ) for s=1, segCt - len + 1 do selection.DeselectAll() selection.SelectRange( s, s + len - 1 ) local idx = random( s, s + len - 1 ) if random( ) < PROB_PUTBAND then PutSingleRandomBandToSeg( idx ) structure.LocalWiggleSelected( 2 ) DelBands( ) structure.WiggleAll( 2 ) end structure.LocalWiggleSelected( 2 ) local swNew = getScore( ) local gain = swNew - swCurr if gain > 0 then structure.LocalWiggleSelected( 20 ) recentbest.Restore( ) DelBands( ) swNew = getScore( ) gain = swNew - swCurr if TrimNum( gain ) > 0 then print( ">>>> At " .. s .. ": Gained ".. TrimNum( gain ) ) end SaveBest( ) swCurr = swNew end recentbest.Restore( ) DelBands( ) end print( "Pattern gain: ".. getScore( ) - sw ) SaveBest( ) end selection.DeselectAll( ) local endScore = getScore( ) print( "Total BandedWorm gain: " .. TrimNum( endScore - ss ) ) if endScore - ss > 5.0 then BandedWorm( ) end -- my very own tail-recursion end ----------------- Other March-Wiggle Actions ----------------------- function PointRebuilder( ) local movableSegs = { } save.Quicksave( QS_NeighborTemp1 ) for i=1, segCt do if IsMovableSeg( i ) then movableSegs[ #movableSegs + 1 ] = i end end randomizeIndexList( movableSegs ) print( "PR: ".. #movableSegs ) for i=1, #movableSegs do print( "Rebuild "..i.." at "..movableSegs[ i ] ) save.Quickload( QS_NeighborTemp1 ) local currScore = getScore( ) if random( ) > 0.50 then RebuildSimple( movableSegs[ i ], 1 ) else RebuildSimple2( movableSegs[ i ], 1 ) end BlueFuse( ) local endScore = getScore( ) local gain = endScore - currScore if gain > 0 then save.Quicksave( QS_NeighborTemp1 ) if TrimNum( gain ) > 0 then print( ">>>> RebuildSimple gain "..TrimNum( gain ).." score="..endScore ) end end end save.Quickload( QS_NeighborTemp1 ) end -------------------------------------------------------------------------------------------------------- -- NEIGHBOR-GENERATION -------------------------------------------------------------------------------------------------------- function GetNeighborState( threshold, NeighborGenerationFunction ) local oldCreditBest = creditbest.GetScore( ) -- to find out if we've missed transients local oldScoreMat = {} local oldQuickScore = getQuickScore( ) local oldScore = getScore( ) ConstructScoreMatrix( oldScoreMat ) SetCI( 1.0 ) DelBands( ) selection.DeselectAll( ) ResetFrozenness( ) recentbest.Save( ) local rbscore = getRBScore( ) save.Quicksave( QS_NeighborTemp1 ) local goodNeighbor = false while not goodNeighbor do local oldTime = os.time( ) local changeSucceeded = false goodNeighbor = false save.Quickload( QS_NeighborTemp1 ) changeSucceeded = NeighborGenerationFunction( 0 ) if changeSucceeded then local newScore = getScore( ) goodNeighbor = IsProteinChanged( oldQuickScore, oldScoreMat, threshold ) if not goodNeighbor then AddFailToStats( ) print( "NEIGHBOR REJECTED (score:"..newScore..")") else local deltaScore = newScore - oldScore local deltaTime = os.time() - oldTime AddActionToStats( deltaScore, deltaTime ) end else AddFailToStats( ) end end -- END while not goodNeighbor local newScore = getScore( ) local newCreditBest = creditbest.GetScore( ) if newCreditBest ~= oldCreditBest and newCreditBest ~= newScore then -- we missed a transient print( " !!!(1) CreditBest changed: old="..oldCreditBest.." new="..newCreditBest ) end DoCleanupWiggle( USE_SLOWWIGGLE, SLOWWIGGLE_ITERS, SLOWWIGGLE_GAIN ) newScore = getScore( ) newCreditBest = creditbest.GetScore( ) if newCreditBest ~= oldCreditBest and newCreditBest ~= newScore then -- we missed a transient print( " !!!(2) CreditBest changed: old="..oldCreditBest.." new="..newCreditBest ) end DebugPrint( "Neighbor Score: " .. newScore) end ---------------------------------------------------------------------- -- ---- SIMULATED ANNEALING ALGORITHM FUNCTIONS -- ---------------------------------------------------------------------- -- Real research could be done (rosetta folks have done) on what a "good" -- Temperature function is for these purposes. 1/x does well enough for me. -- Note that "num" goes from 0 to 1 over the life of the SA function. function T_OneOverX_Old( num ) -- This goes +INF -> 0 as 1/x (for +INF ~= 1000000) return ( 1.0 / (num + 0.000001) ) - 1.0 end function T_OneOverX( num ) -- trying to make start a bit less "wild". max=100 return ( 1.0 / (num + 0.01) ) - ( 1.0 / 1.01 ) end function T_OneOverX2( num ) x = ( 1.0 / (num + 0.001) ) - 1.0 return x * x end function T_MiddlingX( num ) return 10.0 * (1.0 - num) end function T_LowX( num ) return 1.0 - num end function T_ColdX( num ) return 0.1 * (1.0 - num) end function T_Zero( num ) return 0.0 -- causes SA to drop to normal march-forward behavior. end -- this is the standard probability function in Simulated Annealing algorithms function P( ecurr, enew, T ) if enew < ecurr then return 1.0 end return math.exp( (ecurr - enew)/T ) end -- must negate score to function as a Simulated Annealing energy function function E( ) return 8000.0 - getScore( ) -- 8000 is irrelevant, just for scaling end function SA( kmax, emax, qs_best, failNoGainPt, NeighborGenerationFunction, TempFunc ) -- emax is expected to "never happen" if TempFunc == nil then TempFunc = T_OneOverX end local estart = E( ) local ecurr = estart save.Quicksave( QS_TopLevelTemp ) -- a private slot local ebest = ecurr local startTime = os.time( ) local k = 0.0 while k < kmax and ecurr > emax do save.Quickload( QS_TopLevelTemp ) local T = TempFunc( k / kmax ) print("##"..(k+1)..": temp="..TrimNum( T ).." score="..TrimNum( getScore( ) ).." time: "..os.time( )-startTime ) GetNeighborState( 0.1, NeighborGenerationFunction ) local enew = E( ) local p = P(ecurr, enew, T) local r = random( ) if p > r then print( ">>>> accepting state with score " .. TrimNum( getScore( )) ) save.Quicksave( QS_TopLevelTemp ) ecurr = enew end if k +1 >= failNoGainPt and ebest >= estart then print( "<< Reached step "..(k+1).." with no improvement - bailing" ) return k+1 -- give up: we've not achieved any improvement and we think we never will end if enew < ebest then save.Quicksave( qs_best ) ebest = enew end k = k + 1.0 end return k end function PerformSA( failNoGainPt, ctRestarts, stepsPerRun, minGainPerRun, NeighborGenerationFunction, TempFunc ) if minGainPerRun == nil then minGainPerRun = 0 end local saInitialTime = os.time( ) local saInitialScore = getScore( ) local bestScore = saInitialScore local newscore = 0.0 local stepCount = 0 SaveBest( ) for i=1, ctRestarts do LoadBest( ) local saRunStartScore = getScore( ) local saRunStartTime = os.time( ) print( "START: SA#"..i.." score="..TrimNum( saRunStartScore ).." time="..saRunStartTime - saInitialTime ) stepCount = stepCount + SA( stepsPerRun, -999999.0, QS_Best, failNoGainPt, NeighborGenerationFunction, TempFunc ) LoadBest( ) newscore = getScore( ) gain = newscore - bestScore if newscore > bestScore then bestScore = newscore end print( "FINISH: SA#"..i.." score="..TrimNum( newscore ).. " gain=".. newscore - saRunStartScore .." time="..os.time( ) - saRunStartTime ) if gain < minGainPerRun then print( " Insufficient Gain "..gain.." - halting SA" ) break end end print( "SA: steps=".. stepCount .. " gain="..getScore( ) - saInitialScore .." time="..os.time( ) - saInitialTime ) end function PerformMarchingRebuild( maxRunsNoGain ) if neighborThreshold == nil then neighborThreshold = 0.01 end local ctRunsWithoutGain = 0 local mrInitialTime = os.time( ) local mrInitialScore = getScore( ) local bestScore = mrInitialScore local len = REBUILD_MAX_SEGLEN local segStartList = {} for i=1, segCt-len+1, math.floor( (len+1) / 2 ) do if IsMovableSeg( i ) then segStartList[ #segStartList+1] = i end end randomizeIndexList( segStartList ) print( "MR START " .. " score=".. TrimNum( mrInitialScore ).." time=".. os.time( ) - mrInitialTime ) local ct = 0 repeat ct = ct + 1 if ctRunsWithoutGain >= maxRunsNoGain then return end LoadBest( ) local prevscore = getScore() print( "MR# ".. ct .. ": score=".. TrimNum( prevscore ).." failcount=".. ctRunsWithoutGain.." time="..os.time( ) - mrInitialTime ) changeSucceeded = PickRebuildRangeAction( segStartList[ ct ], segStartList[ ct ] + len - 1 ) if changeSucceeded then -- we don't want to preserve results that left cuts behind! local currscore = getScore() if currscore > bestScore then ctRunsWithoutGain = 0 gain = currscore - bestScore bestScore = currscore SaveBest( ) print( ">>>> Gain of ".. gain .. " points" ) else gain = 0 ctRunsWithoutGain = ctRunsWithoutGain + 1 LoadBest( ) end if ct == #segStartList then -- re-randomize the seglist, pick a different len, and start over segStartList = {} if len > 3 then len = len - 2 else len = REBUILD_MAX_SEGLEN - 1 end for i=1, segCt-len+1 do segStartList[ i ] = i end randomizeIndexList( segStartList ) ct = 0 end end if ct >= #segStartList then break end until ctRunsWithoutGain > maxRunsNoGain print( "MR FINISH: gain ="..bestScore-mrInitialScore.." time="..os.time( ) - mrInitialTime ) end function PerformMarchForward( maxRunsNoGain, stepsWanted, neighborThreshold ) if neighborThreshold == nil then neighborThreshold = 0.01 end local ctRunsWithoutGain = 0 local mfInitialTime = os.time( ) local mfInitialScore = getScore( ) local bestScore = mfInitialScore SaveBest( ) print( "MF START " .. " score=".. TrimNum( mfInitialScore ).." time="..os.time( ) - mfInitialTime ) for i=1, stepsWanted do if ctRunsWithoutGain >= maxRunsNoGain then break end LoadBest( ) local prevscore = getScore() print( "MF STEP ".. i.. " score=".. TrimNum( prevscore ).." time="..os.time( ) - mfInitialTime ) GetNeighborState( neighborThreshold, PickLateGameOperation ) local currscore = getScore() if currscore > bestScore then ctRunsWithoutGain = 0 gain = currscore - bestScore bestScore = currscore SaveBest( ) print( ">>>> Gain of ".. gain .. " points" ) else gain = 0 ctRunsWithoutGain = ctRunsWithoutGain + 1 LoadBest( ) end end print( "MF FINISH: gain="..bestScore-mfInitialScore.." time="..os.time( ) - mfInitialTime ) end function PerformMarchWiggle( lastScore, marchThreshold, whichWiggle ) SetCI( 1.0 ) algName = whichWiggle LoadBest( ) local mwInitialScore = getScore() local startScore = mwInitialScore local mwInitialTime = os.time( ) local wiggleStartTime = mwInitialTime local iters = FINALWIGGLE_ITERS local rewiggleGain = FINALRUN_WIGGLE_GAIN print( "MW START " .. " score=".. TrimNum( mwInitialScore ).." time="..os.time( ) - mwInitialTime ) -- see if we should attempt some PerformMarchForward if mwInitialScore - lastScore > marchThreshold then PerformOperation( "PerformMarchForward" ) lastScore = getScore() wiggleStartTime = mwInitialTime print("Wiggle beginning: score="..TrimNum( lastScore ).." time="..os.time( ) - wiggleStartTime ) startScore = lastScore if getScore() > startScore then DelBands( ) ResetFrozenness( ) selection.DeselectAll( ) SaveBest( ) else LoadBest( ) end end -- perform a default version of whatever wiggle the user asked for print( " "..whichWiggle ) if whichWiggle == "IterativeWiggleLocalByChunk-freeze" then IterativeWiggleLocalByChunk( iters, 1, segCt, rewiggleGain, random(3,5), true ) elseif whichWiggle == "IterativeWiggleLocalByChunk" then IterativeWiggleLocalByChunk( iters, 1, segCt, rewiggleGain, random(3,5), false ) elseif whichWiggle == "FreezeBurst" then FreezeBurstFuse( iters ) elseif whichWiggle == "IterativeWiggleAll" then IterativeWiggleAll( iters, rewiggleGain, true, true) elseif whichWiggle == "MonsterBagOfFuses" then MonsterBagOfFuses( iters ) elseif whichWiggle == "FuseBurstIterateCi" then FuseBurstIterateCi ( iters ) elseif whichWiggle == "FullIterativeCutAndWiggle" then FullIterativeCutAndWiggle( iters, rewiggleGain, 17, true) ResetCuts( ) -- really shouldn't be any cuts left lying around... elseif whichWiggle == "WormWiggle" then WormWiggle( ) elseif whichWiggle == "BandedWorm" then BandedWorm( ) elseif whichWiggle == "PointRebuilder" then PointRebuilder( ) else print("!! no such wiggle") end if getScore( ) > startScore then DelBands( ) -- shouldn't be any, but just to be safe... ResetFrozenness( ) selection.DeselectAll( ) SaveBest( ) else SaveBest( ) end local bestScore = getScore( ) local deltaScore = bestScore - startScore local deltaTime = os.time() - mwInitialTime AddActionToStats( deltaScore, deltaTime ) print( "MW FINISH: gain="..bestScore-mwInitialScore.." time="..os.time( ) - mwInitialTime ) return lastScore end function PerformMarchWiggleSequence( algSequence ) local marchInitialTime = os.time( ) local marchInitialScore = getScore( ) print( "MarchWiggle START " .. " score: ".. TrimNum( marchInitialScore ).." time: "..os.time( ) - marchInitialTime ) if algSequence == nil or #algSequence == 0 then algSequence = { "FullIterativeCutAndWiggle", "BandedWorm", "FreezeBurst", "IterativeWiggleAll", "WormWiggle", "FuseBurstIterateCi", "MonsterBagOfFuses", "IterativeWiggleLocalByChunk-freeze", "IterativeWiggleLocalByChunk", "BandedWorm", "PointRebuilder", } end USE_SLOWWIGGLE = true local lastScore = getScore() -- first call won't do march forward local minGain = MARCHWIGGLE_MINGAIN for i=1, #algSequence do lastScore = PerformMarchWiggle( lastScore, minGain, algSequence[ i ] ) end print( " MarchWiggle FINISH: gain="..lastScore-marchInitialScore.." time="..os.time( ) - marchInitialTime ) end function PerformRebuildAndSA( ) SaveBest( ) local dsInitialTime = os.time( ) local dsInitialScore = getScore( ) print( " Begin Rebuild+SA sequence: time="..dsInitialTime ) USE_SLOWWIGGLE = false PerformOperation( "SARebuild" ) PerformOperation( "SAEarly" ) PerformOperation( "SAMidgame" ) ReportStats( ) ResetStats( ) -- clear out old preconceptions of how well wigglers and such behave -- set up for slower, more careful runs with fusing USE_SLOWWIGGLE = true if REBUILD_MAX_SEGLEN > 4 then REBUILD_MAX_SEGLEN = math.floor ( REBUILD_MAX_SEGLEN / 2 ) end PerformOperation( "SAMidgame" ) PerformOperation( "SAVeryLate" ) print( " End Rebuild+SA sequence: gain="..getScore( ) - dsInitialScore.." time="..os.time( ) - dsInitialTime ) end function PerformOperation( OperationChosen ) local moInitialScore = getScore( ) local moInitialTime = os.time( ) local numSteps = 0 local failNoGain = 0 SaveBest( ) if OperationChosen == "SARebAndNormal" then PerformRebuildAndSA( ) elseif OperationChosen == "SALoopRebuild" then for i=1, #loopStarts do if IsMovableSeg( loopStarts[i] ) or IsMovableSeg( loopEnds[i] ) then numSteps = numSteps + 1 + math.floor( (loopEnds[i]-loopStarts[i])/2 ) end end numSteps = math.min( numSteps, SA_STEPSPERRUN ) failNoGain = math.floor( numSteps / 2 ) print( "LoopRebuilds for "..numSteps.." steps; will fail if no gain by "..failNoGain ) PerformSA( failNoGain, SA_REBUILD_NUMSTARTS, numSteps, SA_MINGAIN, PickRandomLoopRebuildOperation, T_OneOverX ) print( "LoopRebuild finished" ) elseif OperationChosen == "SARebuild" then numSteps = math.min( math.floor( (#NonLockedSegList+2) / 2 ), SA_STEPSPERRUN ) failNoGain = math.floor( numSteps / 2 ) print( "SARebuild for "..numSteps.." steps; fail if no gain by "..failNoGain ) PerformSA( failNoGain, SA_REBUILD_NUMSTARTS, numSteps, SA_MINGAIN, PickRandomRebuildOperation, T_OneOverX ) print( "SARebuild finished" ) elseif OperationChosen == "SACompress" then print( "SA-Compress for "..SA_STEPSPERRUN.." steps and "..SA_NUMSTARTS.. " runs; fail if no gain by "..SA_FAILIFNOGAIN ) local maxExpandOld = BAND_MAXEXPAND BAND_MAXEXPAND = 1.0 + ( (BAND_MAXEXPAND - 1.0) / 2 ) PerformSA( SA_FAILIFNOGAIN, SA_NUMSTARTS, SA_STEPSPERRUN, SA_MINGAIN, PickCompressOperation, T_OneOverX ) BAND_MAXEXPAND = maxExpandOld print( "SA-Compress finished" ) elseif OperationChosen == "SAEarly" then print( "SA-Early for "..SA_STEPSPERRUN.." steps and "..SA_NUMSTARTS.. " runs; fail if no gain by "..SA_FAILIFNOGAIN ) PerformSA( SA_FAILIFNOGAIN, SA_NUMSTARTS, SA_STEPSPERRUN, SA_MINGAIN, PickEarlyGameOperation, T_OneOverX ) print( "SA-Early finished" ) elseif OperationChosen == "SALowCI" then USE_LOWCI_WIGGLES = true print( "SA-LowCI for "..SA_STEPSPERRUN.." steps and "..SA_NUMSTARTS.. " runs; fail if no gain by "..SA_FAILIFNOGAIN ) PerformSA( SA_FAILIFNOGAIN, SA_NUMSTARTS, SA_STEPSPERRUN, SA_MINGAIN, PickLowCIOperation, T_OneOverX ) --T_LowX ) USE_LOWCI_WIGGLES = false print( "SA-LowCI finished" ) elseif OperationChosen == "SAMidgame" then print( "SA-Midgame for "..SA_STEPSPERRUN.." steps and "..SA_NUMSTARTS.. " runs; fail if no gain by "..SA_FAILIFNOGAIN ) PerformSA( SA_FAILIFNOGAIN, SA_NUMSTARTS, SA_STEPSPERRUN, SA_MINGAIN, PickNormalOperation, T_OneOverX ) print( "SA-Midgame finished" ) elseif OperationChosen == "SALate" then print( "SA-Late for "..SA_STEPSPERRUN.." steps and "..SA_NUMSTARTS.. " runs; fail if no gain by "..SA_FAILIFNOGAIN ) PerformSA( SA_FAILIFNOGAIN, SA_NUMSTARTS, SA_STEPSPERRUN, SA_MINGAIN, PickLateGameOperation, T_OneOverX ) print( "SA-Late finished" ) elseif OperationChosen == "SAVeryLate" then print( "SA-VeryLate for "..SA_STEPSPERRUN.." steps and "..SA_NUMSTARTS.. " runs; fail if no gain by "..SA_FAILIFNOGAIN ) local qwg = QUICKWIGGLE_GAIN local swg = SLOWWIGGLE_GAIN QUICKWIGGLE_GAIN = 0.1 SLOWWIGGLE_GAIN = 0.01 USE_SLOWWIGGLE = true PerformSA( SA_FAILIFNOGAIN, SA_NUMSTARTS, SA_STEPSPERRUN, SA_MINGAIN, PickNormalOperation, T_OneOverX ) PerformSA( SA_FAILIFNOGAIN, SA_NUMSTARTS, SA_STEPSPERRUN, SA_MINGAIN, PickLateGameOperation, T_OneOverX ) print( "SA-VeryLate finished" ) QUICKWIGGLE_GAIN = qwg SLOWWIGGLE_GAIN = swg elseif OperationChosen == "SAContact" then print( "SA-Contact for "..SA_STEPSPERRUN.." steps and "..SA_NUMSTARTS.. " runs; fail if no gain by "..SA_FAILIFNOGAIN ) PerformSA( SA_FAILIFNOGAIN, SA_NUMSTARTS, SA_STEPSPERRUN, SA_MINGAIN, PickContactMapOperation, T_OneOverX ) print( "SA-Contact finished" ) elseif OperationChosen == "PerformMarchForward" then USE_SLOWWIGGLE = true PerformMarchForward( MF_FAILSBEFORERESTART, MF_STEPSPERRUN ) elseif OperationChosen == "MarchWiggle" then PerformMarchWiggleSequence( ) -- support an algSequence here! elseif OperationChosen == "PerformMarchingRebuild" then PerformMarchingRebuild( REBUILD_FAILSBEFOREQUIT ) else print( "!! Unknown operation" ) end LoadBest( ) local endScore = getScore( ) end ----------------------------------------------------------------------------- -- DIALOG BOX SEQUENCE FROM THE NETHERWORLD -- Still missing: -- Mutate-related options -- Individual wiggles, banders, rebuilders, idealizers (especially the -- slow wigglers in MarchWiggle) ----------------------------------------------------------------------------- -- currently MarchOptions are unused function PutMarchOptionsInBox( dlg ) dlg.sep = dialog.AddLabel( "-----------------March Options-----------------------" ) dlg.mfstepsper = dialog.AddSlider( "MarchSteps", MF_STEPSPERRUN, 5, 100, 0 ) dlg.mffails = dialog.AddSlider( "FailsBeforeQuit", MF_FAILSBEFORERESTART, 5, 100, 0 ) end function SetMarchOptions( dlg ) MF_STEPSPERRUN = dlg.mfstepsper.value MF_FAILSBEFORERESTART = dlg.mffails.value DebugPrint("PerformMarchForward steps="..MF_STEPSPERRUN) DebugPrint("PerformMarchForward failsallowed="..MF_FAILSBEFORERESTART) end function PutQuickWiggleOptionsInBox( dlg ) dlg.sepQWSA = dialog.AddLabel( "----------------Quick Wiggle During Step---------------------" ) --dlg.qwiter = dialog.AddSlider( "QuickWiggleIters", QUICKWIGGLE_ITERS, 1, 10, 0) dlg.qwgain = dialog.AddSlider( "QuickWiggleGain", QUICKWIGGLE_GAIN, 0, 1, 2) end function SetQuickWiggleOptions( dlg ) --QUICKWIGGLE_ITERS = dlg.qwiter.value QUICKWIGGLE_GAIN = dlg.qwgain.value -- DebugPrint("QuickIters="..QUICKWIGGLE_ITERS) DebugPrint("QuickGain="..QUICKWIGGLE_GAIN) end function PutSlowWiggleOptionsInBox( dlg ) dlg.sepSWSA = dialog.AddLabel( "----------------Slow Wiggle After Step------------------------" ) --dlg.switer = dialog.AddSlider( "SlowWiggleIters", SLOWWIGGLE_ITERS, 2, 14, 0 ) dlg.swgain = dialog.AddSlider( "SlowWiggleGain", SLOWWIGGLE_GAIN, 0, 0.50, 2 ) dlg.comment = dialog.AddLabel( "Fuse-wiggle values are 'probabilities' - scaled to sum to 1" ) dlg.wloc = dialog.AddSlider( "LocalWiggler", PROB_SLOWWIGGLE_LOCAL, 0, 1, 2 ) -- rather slow but very good dlg.wbfuse= dialog.AddSlider( "BlueFuse", PROB_SLOWWIGGLE_BLUEFUSE, 0, 1, 2 ) -- untested dlg.wcwfuse= dialog.AddSlider( "C&WFuse", PROB_SLOWWIGGLE_CUTFUSE, 0, 1, 2 ) -- slow, moderately good end function SetSlowWiggleOptions( dlg ) --SLOWWIGGLE_ITERS = dlg.switer.value SLOWWIGGLE_GAIN = dlg.swgain.value local t1 = dlg.wloc.value local t2 = dlg.wbfuse.value local t3 = dlg.wcwfuse.value if t1 + t2 + t3 == 0 then t1 = .25 -- not a problem that don't sum to 1: they'll be scaled t2 = .25 t3 = .25 end PROB_SLOWWIGGLE_LOCAL = t1 / ( t1 + t2 + t3 ) PROB_SLOWWIGGLE_BLUEFUSE = t2 / ( t1 + t2 + t3 ) PROB_SLOWWIGGLE_CUTFUSE = t3 / ( t1 + t2 + t3 ) --DebugPrint( "SlowIters="..SLOWWIGGLE_ITERS ) DebugPrint( "SlowGain="..SLOWWIGGLE_GAIN ) DebugPrint( "Prob_slowwiggle-local="..PROB_SLOWWIGGLE_LOCAL ) DebugPrint( "Prob_slowwiggle-bluefulse="..PROB_SLOWWIGGLE_BLUEFUSE ) DebugPrint( "Prob_slowwiggle-cutfulse="..PROB_SLOWWIGGLE_CUTFUSE ) end function PutBanderOptionsInBox( dlg ) dlg.sepBander = dialog.AddLabel( "----------------Bander Options---------------------" ) dlg.bdcpci = dialog.AddSlider( "CorePulling CI", COREPULLING_CI, 0.01, 1.0, 2 ) dlg.bdregstren = dialog.AddSlider( "RegionBandStrength", BAND_STRENGTH_REGION, 0.50, 2.0, 1 ) dlg.bdwigtryct = dialog.AddSlider( "BWig TryCount", BANDEDWIGGLE_TRYCT, 1, 10, 0 ) dlg.bdwigtargdelta = dialog.AddSlider( "BWig ScoreDelta", BANDEDWIGGLE_TARGET, 50, 1000, 0 ) dlg.bdwigmincompress = dialog.AddSlider( "MinCompress", BAND_MINCOMPRESS, 0.20, 1.00, 2 ) dlg.bdwigmaxexpand = dialog.AddSlider( "MaxExpand", BAND_MAXEXPAND, 1.00, 5.00, 2 ) end function SetBanderOptions( dlg ) COREPULLING_CI = dlg.bdcpci.value BAND_STRENGTH_REGION = dlg.bdregstren.value BANDEDWIGGLE_TRYCT = dlg.bdwigtryct.value BANDEDWIGGLE_TARGET = dlg.bdwigtargdelta.value BAND_MINCOMPRESS = dlg.bdwigmincompress.value BAND_MAXEXPAND = dlg.bdwigmaxexpand.value DebugPrint("Core-pullling CI="..COREPULLING_CI ) DebugPrint("Region-bander strength="..BAND_STRENGTH_REGION ) DebugPrint("Banded Wiggler TryCount="..BANDEDWIGGLE_TRYCT ) DebugPrint("Banded Wiggler Target Delta="..BANDEDWIGGLE_TARGET ) DebugPrint("Min Compress="..BAND_MINCOMPRESS) DebugPrint("Max Expand="..BAND_MAXEXPAND ) end function PutIdealizeOptionsInBox( dlg ) dlg.sepIdealizer = dialog.AddLabel( "--------------Idealizer Options--------------------" ) dlg.idMaxRange = dialog.AddSlider( "MaxIdealizeRange", IDEALIZE_MAX_SEGLEN, 1, 20, 0 ) dlg.idusecuts = dialog.AddCheckbox( "Allow cuts during idealize", IDEALIZE_USE_CUTS ) dlg.idmusthealcuts = dialog.AddCheckbox( "Forbid unhealed cuts after idealize", IDEALIZE_FORBID_UNHEALED_CUTS ) end function SetIdealizeOptions( dlg ) IDEALIZE_MAX_SEGLEN = dlg.idMaxRange.value IDEALIZE_USE_CUTS = dlg.idusecuts.value IDEALIZE_FORBID_UNHEALED_CUTS = dlg.idmusthealcuts.value DebugPrint("Idealize max range="..IDEALIZE_MAX_SEGLEN ) if IDEALIZE_USE_CUTS then DebugPrint("Cuts will be made") else DebugPrint("Cuts are forbidden") end if IDEALIZE_FORBID_UNHEALED_CUTS then DebugPrint("Cuts must heal to be accepted") else DebugPrint("Cuts permitted to survive") end end function PutGeneralRebuildOptionsInBox( dlg ) dlg.sepRb = dialog.AddLabel( "---------------Rebuilder Options------------------" ) dlg.rebMaxTries = dialog.AddSlider( "TriesPerStep", REBUILD_TRYCOUNT, 1, 20, 0 ) dlg.rebFailsbeforequit = dialog.AddSlider( "FailsAllowed", REBUILD_FAILSBEFOREQUIT, 10, 100, 0 ) dlg.rebuildMaxRange = dialog.AddSlider( "MaxRebuildRange", REBUILD_MAX_SEGLEN, 3, 20, 0 ) dlg.rebWantIdealize = dialog.AddCheckbox( "Idealize", REBUILD_ADDIDEALIZE ) dlg.rebIdealizeShouldUseCuts = dialog.AddCheckbox( "Idealize uses cuts", REBUILD_USECUTS ) end function SetGeneralRebuildOptions( dlg ) REBUILD_TRYCOUNT = dlg.rebMaxTries.value REBUILD_FAILSBEFOREQUIT = dlg.rebFailsbeforequit.value REBUILD_MAX_SEGLEN = dlg.rebuildMaxRange.value REBUILD_ADDIDEALIZE = dlg.rebWantIdealize.value REBUILD_USECUTS = dlg.rebIdealizeShouldUseCuts.value DebugPrint( "TriesPerStep="..REBUILD_TRYCOUNT ) DebugPrint( "FailsBeforeQuit="..REBUILD_FAILSBEFOREQUIT ) DebugPrint( "MaxRebuildSegmentLength="..REBUILD_MAX_SEGLEN ) if REBUILD_ADDIDEALIZE then DebugPrint( "Rebuilds followed by idealize" ) else DebugPrint( "Rebuild do not idealize" ) end if REBUILD_USECUTS then DebugPrint( "Rebuild+idealize can use cuts" ) else DebugPrint( "Rebuild+idealize cannot use cuts" ) end end function PutSAScaleOptionsInBox( dlg ) dlg.sepScaleSA = dialog.AddLabel( "----------------Scales of Action of Steps---------------------" ) dlg.comment1 = dialog.AddLabel( "Scale actions are 'probabilities' - scaled to sum to 1" ) dlg.scaleLocal = dialog.AddSlider( "S-Local", PROB_LOCAL, 0, 1, 2 ) dlg.scaleMid = dialog.AddSlider( "S-Midsize", PROB_MIDSIZE, 0, 1, 2 ) dlg.scaleTarg = dialog.AddSlider( "S-Targeted", PROB_TARGETED, 0, 1, 2 ) dlg.scaleLarge= dialog.AddSlider( "S-Largescale", PROB_LARGESCALE, 0, 1, 2 ) end function SetSAScaleOptions( dlg ) local t1 = dlg.scaleLocal.value local t2 = dlg.scaleMid.value local t3 = dlg.scaleTarg.value local t4 = dlg.scaleLarge.value if t1 + t2 + t3 + t4 == 0 then t1 = .25 t2 = .25 t3 = .25 t4 = .25 end PROB_LOCAL = t1 / (t1 + t2 + t3 + t4) PROB_MIDSIZE = t2 / (t1 + t2 + t3 + t4) PROB_TARGETED = t3 / (t1 + t2 + t3 + t4) PROB_LARGESCALE = t4 / (t1 + t2 + t3 + t4) DebugPrint( "Prob_local="..PROB_LOCAL ) DebugPrint( "Prob_midsize="..PROB_MIDSIZE ) DebugPrint( "Prob_targetd="..PROB_TARGETED ) DebugPrint( "Prob_largescale="..PROB_LARGESCALE ) end function PutWiggleOptionsInBox( dlg ) PutQuickWiggleOptionsInBox( dlg ) if USE_SLOWWIGGLE then PutSlowWiggleOptionsInBox( dlg ) end end function SetWiggleOptions( dlg ) SetQuickWiggleOptions( dlg ) if USE_SLOWWIGGLE then SetSlowWiggleOptions( dlg ) end end function PutAdvancedSAOptionsInBox( dlg ) PutSAScaleOptionsInBox( dlg ) PutWiggleOptionsInBox( dlg ) --PutBanderOptionsInBox( dlg ) end function SetAdvancedSAOptions( dlg ) SetSAScaleOptions( dlg ) SetWiggleOptions( dlg ) --SetBanderOptions( dlg ) end function PutSimpleSAOptionsInBox( dlg ) dlg.stepsper = dialog.AddSlider( "StepsPerRun", SA_STEPSPERRUN, 10, 200, 0 ) dlg.starts = dialog.AddSlider( "RunStarts", SA_NUMSTARTS, 1, 20, 0 ) dlg.samingain = dialog.AddSlider( "MinGainForRun", SA_MINGAIN, 0, 5, 1 ) dlg.quitnogain = dialog.AddSlider( "StopIfNoGain", SA_FAILIFNOGAIN, 1, 200, 0 ) end function SetSimpleSAOptions( dlg ) SA_STEPSPERRUN = dlg.stepsper.value SA_NUMSTARTS = dlg.starts.value SA_MINGAIN = dlg.samingain.value SA_FAILIFNOGAIN = dlg.quitnogain.value DebugPrint("SA steps per run="..SA_STEPSPERRUN ) DebugPrint("Step to stop at if no gain="..SA_FAILIFNOGAIN ) DebugPrint("SA run starts="..SA_NUMSTARTS ) DebugPrint("SA halt if gain < "..SA_MINGAIN) end function PutMarchWiggleOptionsInBox( dlg ) dlg.sepMW = dialog.AddLabel( "-----------------March Wiggler Options-----------------------" ) dlg.fwiter = dialog.AddSlider( "Wiggle Iters", FINALWIGGLE_ITERS, 2, 20, 0 ) dlg.comment = dialog.AddLabel( "WiggleGain is decimal places: 1, 0.1, .., 0.0001") dlg.fwgain = dialog.AddSlider( "Wiggle Gain", 3, 0, 4, 0 ) -- there is no good constant to use here! dlg.mwmingain = dialog.AddSlider( "Remarch Gain", MARCHWIGGLE_MINGAIN, 1, 25, 1 ) dlg.stepstomarch = dialog.AddSlider( "Remarch Steps", MF_STEPSPERRUN, 0, 100, 0 ) dlg.failstoquit = dialog.AddSlider( "Remarch Quit Pt", MF_FAILSBEFORERESTART, 0, 100, 0 ) end function SetMarchWiggleOptions( dlg ) FINALWIGGLE_ITERS = dlg.fwiter.value MARCHWIGGLE_MINGAIN = dlg.mwmingain.value MF_STEPSPERRUN = dlg.stepstomarch.value MF_FAILSBEFORERESTART = dlg.failstoquit.value if dlg.fwgain.value == 0 then FINALRUN_WIGGLE_GAIN = 1 elseif dlg.fwgain.value == 1 then FINALRUN_WIGGLE_GAIN= 0.1 elseif dlg.fwgain.value == 2 then FINALRUN_WIGGLE_GAIN = 0.01 elseif dlg.fwgain.value == 3 then FINALRUN_WIGGLE_GAIN = 0.001 elseif dlg.fwgain.value == 4 then FINALRUN_WIGGLE_GAIN = 0.0001 end DebugPrint("FinalWiggle iters="..FINALWIGGLE_ITERS) DebugPrint("MarchWiggle mingain="..MARCHWIGGLE_MINGAIN) DebugPrint("FinalWiggle mingain="..FINALRUN_WIGGLE_GAIN) DebugPrint("Remarch Steps="..MF_STEPSPERRUN) DebugPrint("Remarch Give-up Point="..MF_FAILSBEFORERESTART) end function PutSAROptionsInBox( dlg ) dlg.sepRebSA1= dialog.AddLabel( "----------------Rebuild-SA Options---------------------" ) dlg.rbstarts = dialog.AddSlider( "RunStarts", SA_NUMSTARTS, 1, 20, 0 ) dlg.rbsamingain = dialog.AddSlider( "MinGainForRun", SA_MINGAIN, 0, 10, 1 ) end function SetSAROptions( dlg ) SA_NUMSTARTS = dlg.rbstarts.value SA_MINGAIN = dlg.rbsamingain.value DebugPrint("SA run starts="..SA_NUMSTARTS ) DebugPrint("SA halt if gain < "..SA_MINGAIN) end function PutRebuildSAOptionsInBox( dlg, includeCleanup ) PutSAROptionsInBox( dlg ) PutGeneralRebuildOptionsInBox( dlg ) end function SetRebuildSAOptions( dlg ) SetSAROptions( dlg ) SetGeneralRebuildOptions( dlg ) end function LetUserChooseParams( ) dlg = dialog.CreateDialog( "Simulated Annealing And More" ) dlg.cmt1 = dialog.AddLabel( "Pick one of following (topmost checked will be run)" ) dlg.wantRebSA = dialog.AddCheckbox( "Low/Auto wiggle: Rebuild+SA", DEFAULT_PICK_AT_START ) dlg.wantJustMW = dialog.AddCheckbox( "Med/High wiggle: MarchWiggle", false ) dlg.cmt2 = dialog.AddLabel( "Other miscellaneous options" ) dlg.wantJustSA = dialog.AddCheckbox( "SA - Simple", false ) dlg.wantSALowCI = dialog.AddCheckbox( "SA - LowCI", false ) dlg.wantSaRebuilder = dialog.AddCheckbox( "SA - Rebuild", false ) dlg.wantSAEarly = dialog.AddCheckbox( "SA - EarlyGame", false ) dlg.wantSALate = dialog.AddCheckbox( "SA - LateGame", false ) dlg.wantSAVeryLate = dialog.AddCheckbox( "SA - VeryLateLowWiggle", false ) if PuzzleHasContactMap then dlg.wantSAContact = dialog.AddCheckbox( "SA - ContactMap", false ) end dlg.modLabel = dialog.AddLabel( "------------------Option(s)-----------------------" ) dlg.maxCI = dialog.AddSlider( "MaxCI", SCALE_MAXCI, 0, 1, 2 ) dlg.doslowwiggle = dialog.AddCheckbox( "Perform Fuse in 'misc' actions", USE_SLOWWIGGLE ) if PuzzleHasContactMap then dlg.cmForceContactBettering = dialog.AddCheckbox( "Contact map tries to improve", CONTACTMAP_TAKEDROPS ) dlg.cmInfo = dialog.AddLabel( "If tries to improve: Max score drop allowed" ) dlg.cmMaxDrop = dialog.AddSlider( " Drop", CONTACTMAP_MAX_DROP, 5, 100, 0 ) end if PuzzleAllowsMutate then dlg.cmMutateOrShake = dialog.AddCheckbox( "Mutate instead of shake", true ) dlg.cmAllowPointMutate = dialog.AddCheckbox( "Perform single-aa mutations", ALLOW_SPOT_MUTATION ) end if PuzzleUsesFilters then dlg.cmKillFilters = dialog.AddCheckbox( "DisableFilters", KILLING_FILTERS ) end dlg.preserveCuts = dialog.AddCheckbox( "Preserve user cuts", PRESERVE_USER_CUTS ) if InitialBandCount > 0 then dlg.preserveBands = dialog.AddCheckbox( "Preserve user bands", true ) end dlg.moreOptions = dialog.AddCheckbox( "Advanced options", false ) dlg.ok = dialog.AddButton( "OK", 1 ) dlg.cancel = dialog.AddButton( "Cancel", 0 ) if dialog.Show( dlg ) == 0 then return false end if dlg.wantRebSA.value then OperationChosen = "SARebAndNormal" elseif dlg.wantJustMW.value then OperationChosen = "MarchWiggle" elseif dlg.wantJustSA.value then OperationChosen = "SAMidgame" elseif dlg.wantSALowCI.value then OperationChosen = "SALowCI" elseif dlg.wantSaRebuilder.value then OperationChosen = "SARebuild" elseif dlg.wantSAEarly.value then OperationChosen = "SAEarly" elseif dlg.wantSALate.value then OperationChosen = "SALate" elseif dlg.wantSAVeryLate.value then OperationChosen = "SAVeryLate" elseif PuzzleHasContactMap and dlg.wantSAContact.value then OperationChosen = "SAContact" else return false -- something went wrong... end DEFAULT_PICK_AT_START = false SCALE_MAXCI = dlg.maxCI.value DebugPrint( "Using MaxCI="..SCALE_MAXCI ) if PuzzleHasContactMap then CONTACTMAP_TAKEDROPS = dlg.cmForceContactBettering.value if CONTACTMAP_TAKEDROPS then print( "Score drops of ".. CONTACTMAP_MAX_DROP .. " accepted if ContactMap improves" ) else print( "No score drops permitted" ) end end if PuzzleAllowsMutate then MUTATE_NOT_SHAKE = dlg.cmMutateOrShake.value ALLOW_SPOT_MUTATION = dlg.cmAllowPointMutate.value end if PuzzleUsesFilters then KILLING_FILTERS = dlg.cmKillFilters.value end USE_SLOWWIGGLE = dlg.doslowwiggle.value DebugPrint( "Cleanup wiggle after? ".. BoolStr( USE_SLOWWIGGLE) ) if InitialBandCount > 0 then BANDS_PRESERVE_USER = dlg.preserveBands.value if not BANDS_PRESERVE_USER then InitialBandCount = 0 DelBands( ) end DebugPrint( "Preserve user bands? ".. BoolStr( PRESERVE_USER_BANDS ) ) end PRESERVE_USER_CUTS = dlg.preserveCuts.value if PRESERVE_USER_CUTS then IDEALIZE_USE_CUTS = false REBUILD_USECUTS = false PROB_SLOWWIGGLE_CUTFUSE = 0.00 PROB_SLOWWIGGLE_LOCAL = 0.20 PROB_SLOWWIGGLE_BLUEFUSE = 0.80 end DebugPrint( "Preserve user cuts? ".. BoolStr( PRESERVE_USER_CUTS ) ) if not dlg.moreOptions.value then return true end -- user wants to keep talking to dialog boxes... if OperationChosen == "SARebuild" then dlg = dialog.CreateDialog( "Rebuild-Simulated Annealing Parameters" ) PutRebuildSAOptionsInBox( dlg, true ) dlg.RbWigglerPars= dialog.AddCheckbox( "Set Wiggle Options", false ) dlg.ok = dialog.AddButton( "OK", 1 ) dlg.cancel = dialog.AddButton( "Cancel", 0 ) if dialog.Show( dlg ) == 0 then return false end SetRebuildSAOptions( dlg, true ) if dlg.RbWigglerPars.value then dlg = dialog.CreateDialog( "Rebuilder Wiggle Options" ) PutWiggleOptionsInBox( dlg ) dlg.ok = dialog.AddButton( "OK", 1 ) dlg.cancel = dialog.AddButton( "Cancel", 0 ) if dialog.Show( dlg ) == 0 then return false end SetWiggleOptions( dlg ) end end if OperationChosen == "SAEarly" or OperationChosen == "SALate" or OperationChosen == "SAContact" or OperationChosen == "SALowCI" then dlg = dialog.CreateDialog( "Simulated Annealing Special-purpose Parameters" ) PutSimpleSAOptionsInBox( dlg ) dlg.SAAdvancedPars= dialog.AddCheckbox( "Advanced parameters", false ) dlg.ok = dialog.AddButton( "OK", 1 ) dlg.cancel = dialog.AddButton( "Cancel", 0 ) if dialog.Show( dlg ) == 0 then return false end SetSimpleSAOptions( dlg ) if dlg.SAAdvancedPars.value then dlg = dialog.CreateDialog( "Advanced SA Special-purpose Options" ) PutWiggleOptionsInBox( dlg ) --PutBanderOptionsInBox( dlg ) dlg.IdRAdvancedPars= dialog.AddCheckbox( "Idealize/Rebuild obscure params", false ) dlg.ok = dialog.AddButton( "OK", 1 ) dlg.cancel = dialog.AddButton( "Cancel", 0 ) if dialog.Show( dlg ) == 0 then return false end SetWiggleOptions( dlg ) --SetBanderOptions( dlg ) if dlg.IdRAdvancedPars.value then dlg = dialog.CreateDialog( "Idealize/Rebuild Options" ) PutIdealizeOptionsInBox( dlg ) PutGeneralRebuildOptionsInBox( dlg ) dlg.ok = dialog.AddButton( "OK", 1 ) dlg.cancel = dialog.AddButton( "Cancel", 0 ) if dialog.Show( dlg ) == 0 then return false end SetIdealizeOptions( dlg ) SetGeneralRebuildOptions( dlg ) end end end if OperationChosen == "SAMidgame" then dlg = dialog.CreateDialog( "Simulated Annealing Parameters" ) PutSimpleSAOptionsInBox( dlg ) dlg.SAAdvancedPars= dialog.AddCheckbox( "Advanced parameters", false ) dlg.ok = dialog.AddButton( "OK", 1 ) dlg.cancel = dialog.AddButton( "Cancel", 0 ) if dialog.Show( dlg ) == 0 then return false end SetSimpleSAOptions( dlg ) if dlg.SAAdvancedPars.value then dlg = dialog.CreateDialog( "Advanced SA Parameters" ) PutAdvancedSAOptionsInBox( dlg ) dlg.IdRAdvancedPars= dialog.AddCheckbox( "Idealize/Rebuild obscure params", false ) dlg.ok = dialog.AddButton( "OK", 1 ) dlg.cancel = dialog.AddButton( "Cancel", 0 ) if dialog.Show( dlg ) == 0 then return false end SetAdvancedSAOptions( dlg ) if dlg.IdRAdvancedPars.value then dlg = dialog.CreateDialog( "Idealize/Rebuild Options" ) PutIdealizeOptionsInBox( dlg ) PutGeneralRebuildOptionsInBox( dlg ) dlg.ok = dialog.AddButton( "OK", 1 ) dlg.cancel = dialog.AddButton( "Cancel", 0 ) if dialog.Show( dlg ) == 0 then return false end SetIdealizeOptions( dlg ) SetGeneralRebuildOptions( dlg ) end end end if OperationChosen == "MarchWiggle" then dlg = dialog.CreateDialog( "March-Wiggle Parameters" ) PutMarchWiggleOptionsInBox( dlg ) dlg.ok = dialog.AddButton( "OK", 1 ) dlg.cancel = dialog.AddButton( "Cancel", 0 ) if dialog.Show( dlg ) == 0 then return false end SetMarchWiggleOptions( dlg ) end if OperationChosen == "SARebAndNormal" then dlg = dialog.CreateDialog( "Rebuild+SA Parameters" ) PutSimpleSAOptionsInBox( dlg ) PutSAROptionsInBox( dlg ) dlg.SAAdvancedPars = dialog.AddCheckbox( "Advanced parameters", false ) dlg.ok = dialog.AddButton( "OK", 1 ) dlg.cancel = dialog.AddButton( "Cancel", 0 ) if dialog.Show( dlg ) == 0 then return false end SetSimpleSAOptions( dlg ) SetSAROptions( dlg, false ) if dlg.SAAdvancedPars.value then dlg = dialog.CreateDialog( "Advanced SA Parameters" ) PutAdvancedSAOptionsInBox( dlg ) dlg.IdRAdvancedPars= dialog.AddCheckbox( "Idealize/Rebuild obscure params", false ) dlg.ok = dialog.AddButton( "OK", 1 ) dlg.cancel = dialog.AddButton( "Cancel", 0 ) if dialog.Show( dlg ) == 0 then return false end SetAdvancedSAOptions( dlg ) if dlg.IdRAdvancedPars.value then dlg = dialog.CreateDialog( "Idealize/Rebuild Options" ) PutIdealizeOptionsInBox( dlg ) PutGeneralRebuildOptionsInBox( dlg ) dlg.ok = dialog.AddButton( "OK", 1 ) dlg.cancel = dialog.AddButton( "Cancel", 0 ) if dialog.Show( dlg ) == 0 then return false end SetIdealizeOptions( dlg ) SetGeneralRebuildOptions( dlg ) end end end return true end ---------------------------------------------------------------- -- ---------------- BOILERPLATE --------------------- -- ---------------------------------------------------------------- ---------------------------------------------------------------- -- SIMPLE HELPER FUNCTIONS ---------------------------------------------------------------- function DebugPrint( str ) if DEBUGRUN then print( str ) end end function BoolStr( bval ) if bval then return "true" end return "false" end function TrimNum( val ) return val - val % 0.001 end ---------------------------------------------------------------- -- SLOW FILTER FUNCTIONS ---------------------------------------------------------------- function TurnOnSlowFilters( ) if behavior.GetSlowFiltersDisabled( ) then --print("slow filters are now ON") behavior.SetSlowFiltersDisabled( false ) end end function TurnOffSlowFilters( ) if not behavior.GetSlowFiltersDisabled( ) then --print("slow filters are now OFF") behavior.SetSlowFiltersDisabled( true ) end end function ResetSlowFilterState( ) behavior.SetSlowFiltersDisabled( IsSlowFilterDisabled ) end function CheckForSlowFilters( ) TurnOffSlowFilters( ) local retval = not current.AreConditionsMet() ResetSlowFilterState( ) return retval end ---------------------------------------------------------------- -- BASIC SCORE FUNCTIONS ---------------------------------------------------------------- -- Not for "external" use - call getScore. This could change if customers want -- something besides current or recentbest. function internalGetScore( wantRB, useFilter ) if wantRB == nil then wantRB = false end if useFilter and KILLING_FILTERS then TurnOnSlowFilters( ) end local s=0.0 if not USENORMALSCORE then if wantRB then s = recentbest.GetEnergyScore( ) else s=current.GetEnergyScore( ) end else if wantRB then s = recentbest.GetScore( ) else s=current.GetScore( ) end end if useFilter and KILLING_FILTERS then TurnOffSlowFilters( ) end return s end function getScore( ) return internalGetScore( false, true ) end function getQuickScore( ) return internalGetScore( false, false ) end function getRBScore( ) return internalGetScore( true, true ) end function SaveBest( forceBest ) -- most callers will leave as nil. local score = getScore( ) if forceBest or score >= CurrentBestScore then save.Quicksave( QS_Best ) -- use "score >=" because same-with-unfrozen/unbanded is better CurrentBestScore = score end if PuzzleHasContactMap then cmScore = GetContactScore( ) if forceBest or (cmScore >= CurrentBestCmTotal and CONTACTMAP_TAKEDROPS and score > CurrentBestScore - CONTACTMAP_MAX_DROP) then save.Quicksave( QS_CmBest ) CurrentBestCmScore = score CurrentBestCmTotal = cmScore end if CONTACTMAP_TAKEDROPS and CurrentBestScore ~= CurrentBestCmScore then DebugPrint(" In Best("..QS_Best.."): score="..CurrentBestScore ) DebugPrint(" In CmBest("..QS_CmBest.."): score="..CurrentBestCmScore.." ("..CurrentBestCmTotal..")" ) end end end function LoadBest( ) if PuzzleHasContactMap and CONTACTMAP_TAKEDROPS and CurrentBestCmScore >= CurrentBestScore - CONTACTMAP_MAX_DROP then save.Quickload( QS_CmBest ) else save.Quickload( QS_Best ) end end function GetBestScore( ) if PuzzleHasContactMap and CONTACTMAP_ALLOWDROP and CurrentBestCmScore >= CurrentBestScore - CONTACTMAP_MAX_DROP then return CurrentBestCmScore else return CurrentBestScore end end ---------------------------------------------------------------- -- MATHY FUNCTIONS (random, matrix, primes, sorting) ---------------------------------------------------------------- function seedRandom( ) seed=os.time( )/math.abs( getQuickScore( ) ) seed=seed%0.001 seed=1/seed while seed<10000000 do seed=seed*1000 end seed=seed-seed%1 DebugPrint( "Seed is: "..seed ) math.randomseed( seed ) -- throw away a couple of randoms math.random( ) math.random( ) end function random( n1,n2, forceFloat ) --random function returns int or float depends on input vars if forceFloat == nil then forceFloat = false end if n1==nil then return math.random( ) else if n2==nil then if n1 == 0 then return 0 end -- a random number between 0 and 0 is 0 if n1%1==0 then -- can't test for "forceFloat", so caller must beware return math.random( n1) --integer else return math.random( ) * n1 --float end else if n1%1==0 and n2%1==0 and not forceFloat then return math.random( n1, n2 ) --integer between else return math.random( ) * (n2 - n1) + n1 --float between end end end end function randomDice( ctDice, minValPerDie, maxValPerDie ) -- distro that prefers "middle" values total = 0 for i=1, ctDice do total = total + random( minValPerDie, maxValPerDie ) end return total end function randomThetaPhi( ) return math.acos( random( -1.0, 1.0, true ) ), random( 2 * math.pi ) end function randomizeIndexList( idxList ) for i=1, #idxList do j = random( #idxList ) if j ~= i then idxList[i], idxList[j] = idxList[j], idxList[i] end end end function randomSeg( ) return random( segCt ) end function randomUnlockedSeg( ) if not PuzzleHasLockedSegs then return randomSeg( ) end return NonLockedSegList[ random( #NonLockedSegList ) ] end function randomAASeg( whichAA ) local segs = {} for i=1, #NonLockedSegList do if structure.GetAminoAcid( i ) == whichAA then segs[ #segs + 1 ] = i end end if #segs == 0 then return 0 end return segs[ random( #segs ) ] end function randomMovableSeg( ) for i=1, 20 do local seg = randomUnlockedSeg( ) local bb, sc = freeze.IsFrozen( seg ) if not bb then return seg end end -- if we are here, then we had a hard time finding a nonfrozen seg. -- make an array and search the hard way. local movables = {} for i=1, #NonLockedSegList do local bb, sc = freeze.IsFrozen( seg ) if not bb then movables[ #movables + 1 ] = i end end if #movables == 0 then return 1 end -- nothing we can do return movables[ random( #movables ) ] end function randomMovableFarSeg( segOrigin, minSep, minDist, maxDist ) local segList = {} for e=1, segCt do if IsMovableSeg( e ) and (e <= segOrigin - minSep or e >= segOrigin + minSep ) then dist = structure.GetDistance( segOrigin, e ) if dist >= minDist and dist <= maxDist then segList[ #segList + 1 ] = e end end end if #segList >= 1 then return segList[ random( #segList ) ] else return 0 end end function randomLowScoringSeg( ctIndicesToChooseAmong, subscore ) local idxList = {} getWorstScoringAAs( idxList, ctIndicesToChooseAmong, subscore ) return idxList[ random( #idxList ) ] end function randomContactableSeg( ) return HasContactMapSegList[ random( #HasContactMapSegList ) ] end function randomContactSeg( segIn, heatThreshold ) local segOpts = {} for i = 1, segCt do if i < segIn - 1 or i > segIn + 1 then if contactmap.GetHeat( segIn, i ) >= heatThreshold then segOpts[ #segOpts + 1] = i end end end if #segOpts == 0 then return 0 end return segOpts[ random( #segOpts ) ] end function RandomPrimeNotMoreThan( max ) local primes = {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101} lastIdx = #primes for i=1, #primes do if primes[ i ] > max then break end lastIdx = i end return primes[ math.random( lastIdx ) ] end function Coprime( n ) -- find the highest prime < 70% of "n" that is coprime with "n" local primes = {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101} for i = #primes, 1, -1 do if primes[ i ] < 0.70*n and n % primes[ i ] ~= 0 then return primes[ i ] end end return 1 end function GetEuclideanDistanceVector( scmat1, scmat2, vecOut ) score = 0.0 for j=1, #scmat1[1] do vecOut[j] = 0.0 end for i=1, segCt do for j=1, #scmat1[i] do vecOut[j] = vecOut[j] + (scmat2[i][j] - scmat1[i][j]) * (scmat2[i][j] - scmat1[i][j]) end end for j=1, #vecOut do vecOut[j] = math.sqrt( vecOut[j] ) end end function sortAllByScore(segs, scores) table.sort(segs, function(n1,n2) return scores[n1] < scores[n2] end) end ---------------------------------------------------------------- -- SCORE-USING FUNCTIONS ---------------------------------------------------------------- function ConstructScoreMatrix( scmat ) -- TODO: Get the list of "active" subscores from puzzle info; use that info here. for i=1, segCt do scmat[i] = {} scmat[i][1] = current.GetSegmentEnergySubscore( i, "backbone" ) scmat[i][2] = current.GetSegmentEnergySubscore( i, "sidechain" ) scmat[i][3] = current.GetSegmentEnergySubscore( i, "clashing" ) scmat[i][4] = current.GetSegmentEnergySubscore( i, "packing" ) scmat[i][5] = current.GetSegmentEnergySubscore( i, "density" ) scmat[i][6] = current.GetSegmentEnergySubscore( i, "hiding" ) scmat[i][7] = current.GetSegmentEnergySubscore( i, "bonding" ) scmat[i][8] = current.GetSegmentEnergySubscore( i, "disulfides" ) scmat[i][9] = current.GetSegmentEnergySubscore( i, "ideality" ) scmat[i][10] = current.GetSegmentEnergySubscore( i, "pairwise" ) scmat[i][11] = current.GetSegmentEnergySubscore( i, "other" ) end end function IsNeighborDifferentFromOld( oldScoreMat, threshold ) local newScoreMat = {} local scoreVector = {} ConstructScoreMatrix( newScoreMat ) GetEuclideanDistanceVector( oldScoreMat, newScoreMat, scoreVector ) for i=1, #scoreVector do if scoreVector[i] > threshold then return true end end return false end function IsProteinChanged( oldQuickScore, oldScoreMat, threshold ) if (not KILLING_FILTERS) and (not current.AreConditionsMet( )) then return false end local currScore = getQuickScore( ) if currScore > oldQuickScore then return true end return IsNeighborDifferentFromOld( oldScoreMat, threshold ) end -- returns all aas in order of score (if subscore is nil then does GetSegmentEnergyScore) function getWorstScoringAAs( idxList, maxWanted, subscore ) local scoreList = {} local idxes = {} for i=1, segCt do idxes[i] = i end for i=1, segCt do if subscore == nil then scoreList[i] = current.GetSegmentEnergyScore(i) else scoreList[i] = current.GetSegmentEnergySubscore( i, subscore ) end end sortAllByScore( idxes, scoreList ) for i = 1, math.min( maxWanted, segCt ) do idxList[i] = idxes[i] end end function getBestScoringAAs( idxList, maxWanted, subscore ) local scoreList = {} local idxes = {} for i=1, segCt do idxes[i] = i end for i=1, segCt do if subscore == nil then scoreList[i] = current.GetSegmentEnergyScore(i) else scoreList[i] = current.GetSegmentEnergySubscore( i, subscore ) end end sortAllByScore( idxes, scoreList ) for i = 1, math.min( maxWanted, segCt ) do idxList[i] = idxes[segCt - i + 1] end end function isBadScorer(idx, mustBeAtLeastThisBad) local idxList = {} getWorstScoringAAs( idxList, mustBeAtLeastThisBad) for i=1, #idxList do if idxList[i] == idx then return true end end return false end function SortIdxListBySubscore( idxList, subscoreName ) local subscoreList = {} for i=1, #idxList do subscoreList[ i ] = current.GetSegmentEnergySubscore( idxList[ i ], subscoreName ) end sortAllByScore( idxList, subscoreList ) end function GetWorstScoringRegions( idxList, len ) scoreList = { } for i=1, segCt - len + 1 do scoreList[ i ] = 0.0 idxList[ i ] = i for j = 0, len - 1 do scoreList[ i ] = scoreList[ i ] + current.GetSegmentEnergyScore( i + j ) end end sortAllByScore( idxList, scoreList ) end ---------------------------------------------------------------- -- DISTANCE FUNCTIONS ---------------------------------------------------------------- function computeDistanceSums(distList) for i=1, segCt do distList[i] = 0.0 end for i=1, segCt-1 do for j=i+1, segCt do distList[i] = distList[i] + structure.GetDistance( i, j ) / segCt distList[j] = distList[j] + structure.GetDistance( i, j ) / segCt end end end function getCentralAAs( idxList ) local distList = {} for i=1, segCt do idxList[i] = i end computeDistanceSums( distList ) sortAllByScore( idxList, distList ) end -- returns all hydrophobics in order of "centralness" function getCentralHydrophobics(idxList, ctWanted) local idxListInternal = {} getCentralAAs(idxListInternal) for i=1, #idxListInternal do if structure.IsHydrophobic( idxListInternal[ i ] ) then idxList[ #idxList + 1 ] = idxListInternal[ i ] if #idxList == ctWanted then return end end end end function isCentralHydrophobic( idx, mustBeAtLeastThisGood ) local idxList = {} getCentralHydrophobics( idxList, mustBeAtLeastThisGood ) for i=1, #idxList do if idxList[i] == idx then return true end end return false end function getSegsWithinSphere( idxList, centerIdx, radius, includeCenter ) if includeCenter then idxList[ #idxList + 1 ] = centerIdx end for i=1, segCt do if i ~= centerIdx and structure.GetDistance( centerIdx, i ) <= radius then idxList[ #idxList + 1 ] = i end end end function getSegsOutsideSphere( idxList, centerIdx, radius ) for i=1, segCt do if i ~= centerIdx and structure.GetDistance( centerIdx, i ) > radius then idxList[ #idxList + 1 ] = i end end end function getCMSegsWithinSphere( idxList, centerIdx, radius, includeCenter, heatThreshold ) if includeCenter then idxList[ #idxList + 1 ] = centerIdx end for i=1, segCt do if i ~= centerIdx and structure.GetDistance( centerIdx, i ) <= radius and contactmap.GetHeat( centerIdx, i ) >= heatThreshold then idxList[ #idxList + 1 ] = i end end end function getCMSegsOutsideSphere( idxList, centerIdx, radius, heatThreshold ) for i=1, segCt do if i ~= centerIdx and structure.GetDistance( centerIdx, i ) > radius and contactmap.GetHeat( centerIdx, i ) >= heatThreshold then idxList[ #idxList + 1 ] = i end end end function getSegsWithinRangeOfTube( idxList, startSeg, endSeg, radius ) -- if a seg is "near" to one of the ones in our [startSeg, endSeg] range, then we want it for i=1, segCt do for j=startSeg, endSeg do if structure.GetDistance( i, j ) < radius then idxList[ #idxList + 1] = i break end end -- for j end -- for i end function IsLocalMinimum( segCenter, segCheck) if segCheck == segCenter then return false end -- exclude selfies ckDist = structure.GetDistance(segCenter, segCheck) if segCheck > 1 then ckDist1 = structure.GetDistance( segCenter, segCheck - 1 ) if ckDist1 < ckDist then return false end if segCheck > 2 then ckDist2 = structure.GetDistance( segCenter, segCheck - 2 ) if ckDist2 < ckDist then return false end end end if segCheck < segCt then ckDist1 = structure.GetDistance( segCenter, segCheck + 1 ) if ckDist1 < ckDist then return false end if segCheck < segCt - 1 then ckDist2 = structure.GetDistance( segCenter, segCheck + 2 ) if ckDist2 < ckDist then return false end end end return true end function IsLocalMaximum( segCenter, segCheck) if segCheck == segCenter then return false end -- exclude selfies ckDist = structure.GetDistance(segCenter, segCheck) if segCheck > 1 then ckDist1 = structure.GetDistance( segCenter, segCheck - 1 ) if ckDist1 > ckDist then return false end if segCheck > 2 then ckDist2 = structure.GetDistance( segCenter, segCheck - 2 ) if ckDist2 > ckDist then return false end end end if segCheck < segCt then ckDist1 = structure.GetDistance( segCenter, segCheck + 1 ) if ckDist1 > ckDist then return false end if segCheck < segCt - 1 then ckDist2 = structure.GetDistance( segCenter, segCheck + 2 ) if ckDist2 > ckDist then return false end end end return true end ---------------------------------------------------------------- -- ACTION STATISTICS ---------------------------------------------------------------- function WhereIsStringInArray( array, str ) for i=1, #array do if str == array[ i ] then return i end end return 0 end function AddActionToStats( scoreDelta, timeDelta ) if WhereIsStringInArray( algNameList, algName ) == 0 then algNameList[ #algNameList + 1] = algName end if algStats[ algName ] == nil then algStats[ algName ] = { posScoreDelta = 0.0, scoreDelta = 0.0, runTime = 0, callCount = 0, gainCount = 0, failCount = 0, } end if scoreDelta > 0.0 then algStats[ algName ].posScoreDelta = algStats[ algName ].posScoreDelta + scoreDelta algStats[ algName ].gainCount = algStats[ algName ].gainCount + 1 end algStats[ algName ].scoreDelta = algStats[ algName ].scoreDelta + scoreDelta algStats[ algName ].runTime = algStats[ algName ].runTime + timeDelta algStats[ algName ].callCount = algStats[ algName ].callCount + 1 end function AddFailToStats( ) if WhereIsStringInArray( algNameList, algName ) == 0 then algNameList[ #algNameList + 1] = algName end if algStats[ algName ] == nil then algStats[ algName ] = { posScoreDelta = 0.0, scoreDelta = 0.0, runTime = 0, callCount = 0, gainCount = 0, failCount = 1, } return end algStats[ algName ].failCount = algStats[ algName ].failCount + 1 end function ChooseAlgorithm( algList ) -- we dither runs and gains by 1 partly to avoid divide-by-zero, and -- partly to encourage bringing in not-yet-used algorithms. local scaleValue = 0.0 local funcValues = {} for i = 1, #algList do local runs = 0 local gains = 0 if algStats[ algList[ i ] ] == nil then runs = 1 gains = 1 else -- failCount/2 is a bit artificial, but failed actions should count against an algorithm too. runs = 1 + algStats[ algList[ i ] ].callCount + math.floor( algStats[ algList[ i ] ].failCount / 2 ) gains = 1 + algStats[ algList[ i ] ].gainCount end funcValues[ i ] = gains / runs -- finding value of this item scaleValue = scaleValue + funcValues[ i ] -- finding total size of bucket end local which = random( ) local sum = 0.0 for i = 1, #funcValues do sum = sum + ( funcValues[ i ] / scaleValue ) if which < sum then return algList[ i ] end end return algList[ #algList ] end function ReportStats( ) print("Action stats:") for i = 1, #algNameList do local t = algNameList[ i ] if algStats[ t ] ~= nil and algStats[ t ].callCount > 0 then print( " " .. t .. ": scoreDel=" .. TrimNum( algStats[ t ].scoreDelta ) .. " posScore=" .. TrimNum( algStats[ t ].posScoreDelta ) .. " runTime=" .. algStats[ t ].runTime .. " runs=" .. algStats[ t ].callCount .. " gains=" .. algStats[ t ].gainCount .. " fails=" .. algStats[ t ].failCount ) end end end function ResetStats( ) for i = 1, #algNameList do local t = algNameList[ i ] if algStats[ t ] ~= nil then algStats[ t ].scoreDelta = 0 algStats[ t ].posScoreDelta = 0 algStats[ t ].runTime = 0 algStats[ t ].callCount = 0 algStats[ t ].gainCount = 0 algStats[ t ].failCount = 0 end end end ---------------------------------------------------------------- -- SIDECHAIN AND ATOM FUNCTIONS ---------------------------------------------------------------- aaCount = 20 aaPhilCount = 9 aaPhobCount = 11 function AA(idx) -- hydrophilics if idx == 1 then return "r" elseif idx == 2 then return "s" elseif idx == 3 then return "t" elseif idx == 4 then return "n" elseif idx == 5 then return "d" elseif idx == 6 then return "q" elseif idx == 7 then return "e" elseif idx == 8 then return "h" elseif idx == 9 then return "k" -- hydrophobics elseif idx == 10 then return "g" elseif idx == 11 then return "a" elseif idx == 12 then return "c" elseif idx == 13 then return "v" elseif idx == 14 then return "l" elseif idx == 15 then return "i" elseif idx == 16 then return "m" elseif idx == 17 then return "p" elseif idx == 18 then return "f" elseif idx == 19 then return "y" else return "w" end -- idx == 20 end function AAphilic(idx) -- hydrophilics if idx == 1 then return "r" elseif idx == 2 then return "s" elseif idx == 3 then return "t" elseif idx == 4 then return "n" elseif idx == 5 then return "d" elseif idx == 6 then return "q" elseif idx == 7 then return "e" elseif idx == 8 then return "h" else return "k" -- idx == 9 end end function AAphobic(idx) -- hydrophobics if idx == 1 then return "g" elseif idx == 2 then return "a" elseif idx == 3 then return "c" elseif idx == 4 then return "v" elseif idx == 5 then return "l" elseif idx == 6 then return "i" elseif idx == 7 then return "m" elseif idx == 8 then return "p" elseif idx == 9 then return "f" elseif idx == 10 then return "y" else return "w" -- idx == 11 end end -- for branched aas, simply picks one (longer, one with donor/acceptor tip, or if no difference then either) function GetAtomOfTip( aa ) if aa == "a" then return 10 elseif aa == "c" then return 10 elseif aa == "d" then return 8 elseif aa == "e" then return 9 elseif aa == "f" then return 20 elseif aa == "g" then return 0 -- glycine has no tip. just use a backbone atom elseif aa == "h" then return 17 elseif aa == "i" then return 18 elseif aa == "k" then return 9 elseif aa == "l" then return 16 elseif aa == "m" then return 17 elseif aa == "n" then return 14 elseif aa == "p" then return 13 elseif aa == "q" then return 9 elseif aa == "r" then return 22 elseif aa == "s" then return 11 elseif aa == "t" then return 6 elseif aa == "v" then return 13 elseif aa == "w" then return 24 elseif aa == "y" then return 12 else return 0 end end function GetTipAtomOfSeg( idx ) return GetAtomOfTip( structure.GetAminoAcid( idx )) end function PickAtomNumberForBand( idx ) if not BAND_TO_SIDECHAINS then return CENTER_CARBON end local r = random( 1, 3 ) -- consider adjusting probability? if r == 1 then return BETA_CARBON elseif r == 2 then return GetTipAtomOfSeg( idx ) else return CENTER_CARBON end end ---------------------------------------------------------------- -- MUTATION-RELATED FUNCTIONS ---------------------------------------------------------------- function checkAla( ) local ala=0 for n = 1, segCt do segType = structure.GetAminoAcid(n) if segType == 'a' or segType == 'g' then ala=ala+1 end end return ala == segCt end function IsPuzzleMutable( ) for i=1, segCt do if structure.IsMutable(i) then return true end end return false end function IsNoMutate( idx ) if not ALLOW_SPOT_MUTATION then return true end if not PuzzleAllowsMutate then return true end if not structure.IsMutable(idx) then return true end for i=1,#NOMUTATELIST do if idx == NOMUTATELIST[i] then return true end end return false end ---------------------------------------------------------------- -- LOCKED/FROZEN FUNCTIONS ---------------------------------------------------------------- function FindAllMovableSegs( ) for i=1, segCt do if structure.IsLocked( i ) then PuzzleHasLockedSegs = true else NonLockedSegList[ #NonLockedSegList + 1] = i end end if PuzzleHasLockedSegs then for i=1, segCt do if IsUnlockedSeg( i ) then MinUnlockedSeg = i break end end for i=segCt, 1, -1 do if IsUnlockedSeg( i ) then MaxUnlockedSeg = i break end end end return false end function IsMovableSeg( seg1 ) if seg1 == nil or seg1 < 1 or seg1 > segCt then return false end local BB, SC = freeze.IsFrozen( seg1 ) local sl = structure.IsLocked( seg1 ) return not (BB or SC or sl) end function IsUnlockedSeg( seg ) return not structure.IsLocked( seg ) end function IsAllMovableRange(seg1, seg2) if seg1 == nil or seg2 == nil then return false end if seg1 > seg2 then seg1, seg2 = seg2, seg1 end if seg1 < 1 or seg2 > segCt then return false end for i=seg1, seg2 do if not IsMovableSeg( i ) then return false end end return true end function SelectAllMovable( ) for i=1, segCt do if IsMovableSeg( i ) then selection.Select( i ) end end end function ResetFrozenness( ) freeze.UnfreezeAll( ) for i=1, segCt do bFroz, sFroz = InitialFrozenTable[ i ] if bFroz or sFroz then freeze.Freeze( i, bFroz, sFroz ) end end ChangedFrozenness = false end function SaveFrozenness( ) for i=1, segCt do -- save "frozenness" local bFroz, sFroz = freeze.IsFrozen( i ) InitialFrozenTable[ i ] = bFroz, sFroz end end ---------------------------------------------------------------- -- CONTACT MAP FUNCTIONS ---------------------------------------------------------------- function CheckForContactMap( ) PuzzleHasContactMap = false local saveval = 0.0 for i=1, segCt-1 do for j=i+1, segCt do val = contactmap.GetHeat( i, j ) if saveval ~= 0.0 and val ~= saveval then PuzzleHasContactMap = true ContactMapScore = GetContactScore( ) return -- all we wanted to know was whether scores exist end if saveval == 0.0 then saveval = val end end end return end function SegHasContactData( segIn, heatThreshold ) for i = 1, segCt do if i < segIn - 1 or i > segIn + 1 then if contactmap.GetHeat( segIn, i ) >= heatThreshold then return true end end end return false end function InitializeContactMapSegList( heatThreshold ) HasContactMapSegList = {} for i = 1, segCt do if SegHasContactData( i, heatThreshold ) then HasContactMapSegList[ #HasContactMapSegList + 1 ] = i end end end function GetContactScore( ) if not PuzzleHasContactMap then return 0 end local sum = 0.0 local segCt = structure.GetCount( ) for i = 1,segCt-1 do for j = i + 1, segCt do if contactmap.IsContact( i, j ) then sum = sum + contactmap.GetHeat( i, j ) end end end return sum end function ActionDamagedContactMap( ) if PuzzleHasContactMap then local sc = GetContactScore( ) if sc < ContactMapScore then return true end ContactMapScore = sc -- now we have a "better" score, so keep that one end return false end ---------------------------------------------------------------- -- SECONDARY STRUCTURES ---------------------------------------------------------------- function getHelices( ) inside = false for i=MinUnlockedSeg, MaxUnlockedSeg do if ( IsUnlockedSeg( i ) and structure.GetSecondaryStructure(i) == "H" ) then if ( inside == false ) then inside = true helixStarts[ #helixStarts + 1] = i end elseif ( IsUnlockedSeg( i ) and inside == true ) then inside = false helixEnds[ #helixEnds + 1] = i - 1 end -- if ( "H" ) elseif ( within ) end -- for (segCt) -- deal with "last seg is helix" if ( inside == true ) then helixEnds[ #helixEnds + 1] = MaxUnlockedSeg end end function getSheets( ) inside = false for i=MinUnlockedSeg, MaxUnlockedSeg do if ( IsUnlockedSeg( i ) and structure.GetSecondaryStructure(i) == "E" ) then if ( inside == false ) then inside = true sheetStarts[ #sheetStarts + 1 ] = i end elseif (IsUnlockedSeg( i ) and inside == true ) then inside = false sheetEnds[ #sheetEnds + 1 ] = i - 1 end -- if/else 'E' end -- for (segCt) -- deal with "last seg is sheet" if ( inside == true ) then sheetEnds[ #sheetEnds + 1 ] = MaxUnlockedSeg end end function getLoops( ) inside = false for i=MinUnlockedSeg, MaxUnlockedSeg do if ( IsUnlockedSeg( i ) and structure.GetSecondaryStructure(i) == "L" ) then if ( inside == false ) then inside = true loopStarts[ #loopStarts + 1 ] = i end elseif ( IsUnlockedSeg( i ) and inside == true ) then inside = false loopEnds[ #loopEnds + 1 ] = i - 1 end -- if/else 'L' end -- for (segCt) -- deal with "last seg is loop" if ( inside == true ) then loopEnds[ #loopEnds + 1 ] = MaxUnlockedSeg end end function GetRegionStartAndEnd( idx ) s = idx e = idx if not IsUnlockedSeg( idx ) then return idx,idx end local typeIdx = structure.GetSecondaryStructure( idx ) if idx > MinUnlockedSeg then s = idx - 1 while s >= MinUnlockedSeg do if structure.GetSecondaryStructure( s ) ~= typeIdx or not IsUnlockedSeg( s ) then break end s = s - 1 end s = s + 1 end if idx < MaxUnlockedSeg then e = idx + 1 while e <= MaxUnlockedSeg do if structure.GetSecondaryStructure( e ) ~= typeIdx or not IsUnlockedSeg( e ) then break end e = e + 1 end e = e - 1 end return s, e end -- uses GetRegionStartAndEnd, but tries to tune "loop" regions a bit function GetRegionForOperation( idx ) -- try to find an acceptable region (really bizarre choices of SS can give trouble) if not IsUnlockedSeg( idx ) then return idx, idx end sIdx, eIdx = GetRegionStartAndEnd( idx ) -- Check: if our entire region is only 1 or 2 segs long, then see about expanding it local regionType = structure.GetSecondaryStructure( idx ) if eIdx - sIdx <= 1 then -- small range. Try to expand it... local sIdx2, eIdx2 if sIdx > 2 then if structure.GetSecondaryStructure(sIdx - 1) == regionType then sIdx2, eIdx2 = GetRegionStartAndEnd( sIdx - 1) sIdx = sIdx2 end end if eIdx < segCt - 1 then if structure.GetSecondaryStructure( eIdx + 1 ) == regionType then sIdx2, eIdx2 = GetRegionStartAndEnd( eIdx + 1 ) eIdx = eIdx2 end end -- END try to fix small range if eIdx - sIdx <= 1 then return idx,idx end -- failed end -- Check: if loop and more than 30-long, then only take part of it if regionType == 'L' and eIdx - sIdx > 30 then -- trim it; it is too long if idx - sIdx < 15 then eIdx = idx + 15 -- trim the other, longer side elseif eIdx - idx < 15 then sIdx = idx - 15 -- trim the other, longer side else -- more than 15 segs slop on both sides! -- try to be random and "medium-long": 3d5 on each side should do sIdx = idx - randomDice(3, 1, 5) eIdx = idx + randomDice(3, 1, 5) end end return sIdx, eIdx end function ResetSecondaryStructures( min, max ) selection.DeselectAll( ) for i=min, max do if SecStructList[ i ] == "l" then selection.Select( i ) end end structure.SetSecondaryStructureSelected( "l" ) selection.DeselectAll( ) for i=min, max do if SecStructList[ i ] == "e" then selection.Select( i ) end end structure.SetSecondaryStructureSelected( "e" ) selection.DeselectAll( ) for i=min, max do if SecStructList[ i ] == "h" then selection.Select( i ) end end structure.SetSecondaryStructureSelected( "h" ) selection.DeselectAll( ) end function StoreSecondaryStructure( ) for i=1, segCt do SecStructList[ i ] = structure.GetSecondaryStructure( i ) end end function SetSS( min, max, type ) selection.DeselectAll( ) selection.SelectRange( min, max ) structure.SetSecondaryStructureSelected( type ) selection.DeselectAll( ) end function SetAllLoop( min, max ) SetSS( min, max, "l" ) end ---------------------------------------------------------------- -- CLASH IMPORTANCE ---------------------------------------------------------------- function SetCI( ci ) behavior.SetClashImportance( SCALE_MAXCI * ci ) end function ExactSetCI( ci ) behavior.SetClashImportance( ci ) end ---------------------------------------------------------------------- -- CUTTING FUNCTIONS ---------------------------------------------------------------------- function DeleteCutAtIndex( idx ) if idx == nil or idx < 1 or idx > segCt then return true end local sc = getQuickScore( ) structure.DeleteCut( idx ) return getQuickScore( ) ~= sc -- if no score change at all, then cut deletion didn't happen! end function AddRandomCuts( cutList, maxCuts ) for i=1, maxCuts do local seg = randomUnlockedSeg( ) local gotMatch = false for j=1, #cutList do if cutList[ j ] == seg then gotMatch = true end end if not gotMatch then structure.InsertCut( seg ) cutList[ #cutList + 1 ] = seg end end end function CleanCutsInList( cutList ) changeSucceeded = true for i=1, #cutList do changeSucceeded = DeleteCutAtIndex( cutList[ i ] ) and changeSucceeded end return changeSucceeded end function ResetCuts( ) if not PRESERVE_USER_CUTS then for i=1, segCt do DeleteCutAtIndex( i ) end -- any cuts that appeared better go now, too end end ---------------------------------------------------------------------- -- BARE-BONE REBUILD FUNCTION ---------------------------------------------------------------------- function RebuildSelected( iters ) band.DisableAll( ) structure.RebuildSelected( iters ) band.EnableAll( ) end ---------------------------------------------------------------- -- MULTI-TRY ACTION CONTROLLER ---------------------------------------------------------------- function MultitryActOnRegion( NumberOfStarts, NumberOfActionsPerTry, startIdx, endIdx, ActionFunction ) print( "MultitryActOnRegion for "..NumberOfStarts.." starts with "..NumberOfActionsPerTry.." steps" ) BestScore=getScore( ) LoadBest( ) save.Quicksave( QS_NeighborTemp1 ) save.Quicksave( QS_NeighborTemp2 ) save.Quicksave( QS_NeighborTemp3 ) for k=1, NumberOfStarts do save.Quickload( QS_NeighborTemp1 ) -- always start over from initial state save.Quicksave( QS_NeighborTemp2 ) print( "Starting try " .. k.. ": Score="..getScore( ) ) local initscore = getScore( ) for j=1, NumberOfActionsPerTry do -- use "best so far" save.Quickload( QS_NeighborTemp2 ) local currScore = getScore( ) ActionFunction( startIdx, endIdx ) local endScore = getScore( ) if endScore > currScore then print( ">>>> At ".. j ..": score="..endScore ) save.Quicksave( QS_NeighborTemp2 ) currScore = endScore end if endScore > BestScore then save.Quicksave( QS_NeighborTemp3 ) BestScore = endScore end SaveBest( ) end -- FOR j<actions save.Quickload( QS_NeighborTemp2 ) local endScore = getScore( ) print( "Finishing try " .. k.. " Score: "..endScore ) end -- FOR k<starts LoadBest( ) end ------------------------------------------------------------------------------ -- ---- WIGGLER FUNCTIONS -- ------------------------------------------------------------------------------ ------------------------------------------------------------------------------ -- GENERAL-PURPOSE SHAKERS AND WIGGLERS ------------------------------------------------------------------------------ -- no recentbest here because sometimes we'd call while decreasing score function ShakeOrMutate( iters, idxList ) local startTime = os.time( ) if iters == nil then iters = 1 end if idxList == nil then if MUTATE_NOT_SHAKE then structure.MutateSidechainsAll( iters ) else structure.ShakeSidechainsAll( iters ) end else selection.DeselectAll( ) for i=1, #idxList do selection.Select( i ) end if MUTATE_NOT_SHAKE then structure.MutateSidechainsSelected( iters ) else structure.ShakeSidechainsSelected( iters ) end selection.DeselectAll( ) end TotalShakeTime = TotalShakeTime + ( os.time( ) - startTime ) end -- no recentbest here because sometimes we'd call while decreasing score function WiggleRange( iters, startSeg, endSeg, addFreeze, doGlobal ) local firstSeg = math.max( MinUnlockedSeg, startSeg ) local lastSeg = math.min( endSeg, MaxUnlockedSeg ) if lastSeg < firstSeg then return end -- nothing to do -- set up for the local wiggle selection.DeselectAll( ) if addFreeze then ChangedFrozenness = true if firstSeg > MinUnlockedSeg then freeze.Freeze( firstSeg - 1, true, true ) end if lastSeg < MaxUnlockedSeg then freeze.Freeze( lastSeg + 1, true, true ) end end -- actually perform the local wiggle selection.SelectRange( firstSeg, lastSeg ) if doGlobal then structure.WiggleSelected( iters, true, true ) else structure.LocalWiggleSelected( iters, true, true ) end -- clean up what we did ResetFrozenness( ) selection.DeselectAll( ) end -- no recentbest here because sometimes we'd call while decreasing score function IterativeWiggleAll( iters, minGain, doBackbone, doSidechain ) local lastScore = getQuickScore( ) local gain = minGain recentbest.Save( ) while gain >= minGain do structure.WiggleAll( iters, doBackbone, doSidechain ) -- do's ok for nil recentbest.Restore( ) gain = getQuickScore( ) - lastScore lastScore = getQuickScore( ) end end --------------------------------------------- -- SIMPLE STABILIZER WIGGLES --------------------------------------------- function IterativeWiggleList( idxList, iters, minGain, doBackbone, doSidechain ) selection.DeselectAll( ) for i=1, #idxList do selection.Select( i ) end local lastScore = getQuickScore( ) local gain = minGain while gain >= minGain do structure.WiggleSelected( iters, doBackbone, doSidechain ) -- do's ok for nil gain = getQuickScore( ) - lastScore lastScore = getQuickScore( ) end selection.DeselectAll( ) end function IterativeWiggleShakeWiggle( idxList, iters ) recentbest.Save( ) sc = getQuickScore( ) IterativeWiggleList( idxList, iters, QUICKWIGGLE_GAIN ) recentbest.Restore( ) ShakeOrMutate( SHAKESIDECHAIN_ITERS, idxList ) recentbest.Restore( ) if math.abs( getQuickScore( ) - sc) > 1 then -- otherwise, why bother? IterativeWiggleAll(iters, QUICKWIGGLE_GAIN, true, true ) end recentbest.Restore( ) end function qStabWiggle( iters, doExtraWork ) if doExtraWork == nil then doExtraWork = false end SetCI( 1.0 ) recentbest.Save( ) ShakeOrMutate( SHAKESIDECHAIN_ITERS ) recentbest.Restore( ) if doExtraWork then SetCI( 0.4 ) IterativeWiggleAll( iters, QUICKWIGGLE_GAIN, true, true ) recentbest.Restore( ) SetCI( 1.0) ShakeOrMutate( SHAKESIDECHAIN_ITERS ) recentbest.Restore( ) end SetCI( 1.0) IterativeWiggleAll( iters, QUICKWIGGLE_GAIN, true, true ) recentbest.Restore( ) end -- the only user for now is the idealizer function WiggleZlbNicely( iters, strength, skipLower, skipUpper ) if skipLower == nil then skipLower = MaxUnlockedSeg+1 end if skipUpper == nil then skipUpper = MinUnlockedSeg-1 end recentbest.Save( ) ZLB(strength, skipLower, skipUpper) IterativeWiggleAll( iters, QUICKWIGGLE_GAIN, true, true ) recentbest.Restore( ) DelBands( ) recentbest.Save( ) ShakeOrMutate( SHAKESIDECHAIN_ITERS ) recentbest.Restore( ) end function SimpleRegionWiggle( iters, idxLo, idxHi, pickGlobalWiggle, wiggleExpansion ) if wiggleExpansion == nil then wiggleExpansion = 1 + random( math.floor( segCt / 6 )) end local startIdx = math.max( MinUnlockedSeg, idxLo - wiggleExpansion ) local endIdx = math.min( MaxUnlockedSeg, idxHi + wiggleExpansion ) WiggleRange( iters, startIdx, endIdx, false, pickGlobalWiggle ) end --------------------------------------------------------- --BAND-CHANGING WRAPUP WIGGLERS --------------------------------------------------------- function BandedWiggleUntilEnoughChange( iters, scoreThreshold, pullingCI ) if pullingCI == nil then pullingCI = COREPULLING_CI end SetCI( pullingCI ) local ss=getQuickScore( ) for str=0.30, 1.50, 0.11 do --search enough band strength to move SetMyBandStrengths( str ) if random( ) < PROB_LOCALWIGGLE then structure.LocalWiggleAll( iters ) else structure.WiggleAll( iters ) end if math.abs( ss-getQuickScore( ) ) > scoreThreshold then -- we've changed the structure "enough", send it off break end end SetCI( 1.0 ) return math.abs( ss - getQuickScore( ) ) end function SimpleBandedWiggleWrapper( iters, minChangeWanted, pullingCI ) print( "SimpleBandedWiggleWrapper" ) local scoreThreshold = math.min( minChangeWanted, getQuickScore( ) / 500.0) recentbest.Save( ) local oldRbScore = getRBScore( ) BandedWiggleUntilEnoughChange( iters, scoreThreshold, pullingCI ) local newRbScore = getRBScore( ) if newRbScore > oldRbScore then recentbest.Restore( ) end DelBands( ) ResetFrozenness( ) recentbest.Save( ) qStabWiggle( iters, random( ) < PROB_QSTAB_EXTRA ) recentbest.Restore( ) end function BandedWiggleUntilTargetMet( iters, scoreDeltaTarget, maxTries, pullingCI ) print( "BandedWiggleUntilTargetMet" ) save.Quicksave( QS_ShortUseTemp1 ) save.Quicksave( QS_ShortUseTemp2 ) if pullingCI == nil then pullingCI = COREPULLING_CI end SetCI( pullingCI ) local s1=getQuickScore( ) local str=0.50 local tries = 0 local s2best = 99999 while tries < maxTries do save.Quickload( QS_ShortUseTemp1) SetMyBandStrengths( str) structure.WiggleAll( iters ) local s2 = math.abs( getQuickScore( ) - s1 ) if s2 > scoreDeltaTarget * 1.2 then str = str * ( 0.85 + random( 0.10 ) ) elseif s2 < scoreDeltaTarget * 0.8 then str = str + ( 1.0 - str ) * ( 0.05 + random( 0.1 ) ) else return math.abs( getQuickScore( ) - s1 ) -- we're good enough end if math.abs( s2 - scoreDeltaTarget ) < s2best then save.Quicksave( QS_ShortUseTemp2 ) s2best = math.abs( s2 - scoreDeltaTarget ) end tries = tries + 1 end save.Quickload( QS_ShortUseTemp2 ) -- the best we could come up with... return math.abs( getQuickScore( ) - s1 ) -- returns the actual delta in case caller cares end function RegionWiggleBeforeAndAfter( iters, startIdx, endIdx ) print( "RegionWiggleBeforeAndAfter" ) recentbest.Save( ) local oldRbScore = getRBScore( ) SetCI( COREPULLING_CI ) SimpleRegionWiggle( iters, startIdx, endIdx, false, random( 4 ) ) local newRbScore = getRBScore( ) if newRbScore > oldRbScore then recentbest.Restore( ) end DelBands( ) -- if we put in bands, they should go now ResetFrozenness( ) -- if we froze anything, we should clean that up now SetCI( 1.0 ) if random( ) < 0.50 then qStabWiggle( iters, random( ) < PROB_QSTAB_EXTRA ) else recentbest.Save( ) ShakeOrMutate( SHAKESIDECHAIN_ITERS ) recentbest.Restore( ) SimpleRegionWiggle( iters, startIdx, endIdx, true, random( 4, 8 ) ) recentbest.Restore( ) IterativeWiggleAll( iters, QUICKWIGGLE_GAIN, true, true ) end recentbest.Restore( ) end function GlobalBeforeAndQStabAfter( iters ) print( "GlobalBeforeAndQStabAfter" ) recentbest.Save( ) local oldRbScore = getRBScore( ) SetCI( COREPULLING_CI ) if random( ) < PROB_LOCALWIGGLE then structure.LocalWiggleAll( QUICKWIGGLE_ITERS ) else structure.WiggleAll( QUICKWIGGLE_ITERS ) end ShakeOrMutate( SHAKESIDECHAIN_ITERS ) local newRbScore = getRBScore( ) if newRbScore > oldRbScore then recentbest.Restore( ) end SetCI( 1.0 ) DelBands( ) -- if we put in bands, they should go now ResetFrozenness( ) -- if we froze anything, we should clean that up now recentbest.Save( ) qStabWiggle( iters, random( ) < PROB_QSTAB_EXTRA ) recentbest.Restore( ) end function VerySimpleWiggleBeforeAndAfter( iters ) recentbest.Save( ) local oldRbScore = getRBScore( ) ShakeOrMutate( 1 ) if random( ) < PROB_LOCALWIGGLE then structure.LocalWiggleAll( 1 ) else structure.WiggleAll( 1 ) end local newRbScore = getRBScore( ) if newRbScore > oldRbScore then recentbest.Restore( ) end DelBands( ) ResetFrozenness( ) recentbest.Save( ) ShakeOrMutate( 1 ) IterativeWiggleAll( iters, QUICKWIGGLE_GAIN, true, true ) recentbest.Restore( ) end function VerySimpleNonBandedWiggler( iters ) recentbest.Save( ) ExactSetCI( 0.05 ) ShakeOrMutate( SHAKESIDECHAIN_ITERS ) SetCI( 1.0 ) IterativeWiggleAll( iters, QUICKWIGGLE_GAIN, true, true ) recentbest.Restore( ) end function PickBeforeAndAfterWiggler( doVariableStrength ) local iters = QUICKWIGGLE_ITERS if USE_LOWCI_WIGGLES then VerySimpleWiggleBeforeAndAfter( iters ) elseif doVariableStrength then SimpleBandedWiggleWrapper( iters, BANDEDWIGGLE_TARGET, COREPULLING_CI ) else GlobalBeforeAndQStabAfter( iters ) end end function nudge( ) SetCI( 0.3 ) structure.WiggleSelected( 1 ) SetCI( 1 ) structure.WiggleSelected( 8 ) end function WiggleAndShakeForRebuilder( initScore, maxFall ) print( "WiggleAndShakeForRebuilder" ) -- initScore is the score before our rebuild happened recentbest.Save( ) scoreA = getQuickScore( ) if initScore - scoreA > maxFall then ShakeOrMutate( 2*SHAKESIDECHAIN_ITERS ) elseif initScore - scoreA > maxFall/2 then ShakeOrMutate( SHAKESIDECHAIN_ITERS ) end scoreA = getQuickScore( ) if random( ) < PROB_LOCALWIGGLE then structure.LocalWiggleAll( 15 ) else structure.WiggleAll( 15 ) end recentbest.Restore( ) scoreB = getQuickScore( ) if scoreB - scoreA < 10 and initScore - scoreB > 30 then -- The wiggle got stuck and didn't achieve anything. try a nudge to see if that helps nudge( ) recentbest.Restore( ) scoreB = getQuickScore( ) end if initScore - scoreB <= 100.0 then ShakeOrMutate( SHAKESIDECHAIN_ITERS ) structure.WiggleSelected( 10 ) recentbest.Restore( ) nudge( ) recentbest.Restore( ) end -- else not worth the effort end -------------------------------------------------- -- SLOW CLEANUP WIGGLERS -------------------------------------------------- function BlueFuse( ) recentbest.Save( ) SetCI( .05 ) structure.ShakeSidechainsAll( SHAKESIDECHAIN_ITERS ) SetCI( 1 ) structure.WiggleAll( 5 ) recentbest.Restore( ) SetCI( .07 ) structure.ShakeSidechainsAll( SHAKESIDECHAIN_ITERS ) SetCI( 1 ) structure.WiggleAll( 5 ) recentbest.Restore( ) SetCI( .3 ) structure.WiggleAll( 8 ) SetCI( 1 ) structure.WiggleAll( 15 ) recentbest.Restore( ) end function IterativeWiggleLocalByChunk(iters, startSeg, endSeg, minGain, chunkSize, addFreeze) recentbest.Save( ) currOffset = 0 local lastScore = getQuickScore( ) gain = minGain while gain >= minGain do if chunkSize == 1 then currOffset = 0 else currOffset = random( chunkSize - 1 ) end ctBlocks = math.floor( (endSeg - startSeg + 1) / chunkSize ) for idx = 0,ctBlocks do local score = getQuickScore( ) startIdx = startSeg + currOffset + chunkSize*idx WiggleRange(iters, startIdx, math.min( startIdx + chunkSize, endSeg ), addFreeze, false ) recentbest.Restore( ) if addFreeze then ResetFrozenness( ) end end local currScore = getQuickScore( ) gain = currScore - lastScore lastScore = currScore end recentbest.Restore( ) if addFreeze then ResetFrozenness( ) end end function BasicCutAndWiggleFuse( baseIters, shift, offset ) if shift == nil then shift = 3 end if offset == nil then offset = MinUnlockedSeg else offset = MinUnlockedSeg + (offset % shift) end for i = offset, MaxUnlockedSeg-1, shift do structure.InsertCut( i ) end WiggleWiggleSimpleFuse( 0.30, 1.0, baseIters, 2*baseIters ) ResetCuts( ) WiggleWiggleSimpleFuse( 0.30, 1.0, baseIters, 4*baseIters ) SetCI( 1.0 ) end function IterativeCutAndWiggle( baseIters, minGain, shift ) local score = getQuickScore( ) local gain = minGain save.Quicksave( QS_ShortUseTemp1 ) recentbest.Save( ) repeat save.Quickload( QS_ShortUseTemp1 ) BasicCutAndWiggleFuse( baseIters, shift, random( shift ) ) local newscore = getQuickScore( ) gain = 0.0 if newscore >= score then save.Quicksave( QS_ShortUseTemp1 ) gain = newscore - score score = newscore end until gain < minGain save.Quickload( QS_ShortUseTemp1 ) recentbest.Restore( ) end -------------------------------------------------- -- BASIC FUSE WIGGLERS -------------------------------------------------- function WiggleShakeSimpleFuse( ci, iters ) SetCI( ci ) structure.WiggleAll( iters ) -- instead of IterativeWiggleAll... ShakeOrMutate( SHAKESIDECHAIN_ITERS ) end function WiggleWiggleSimpleFuse( ci1, ci2, shortiter, longiter ) recentbest.Save( ) local oldRbScore = getRBScore( ) SetCI( ci1 ) structure.WiggleAll( shortiter ) local newRbScore = getRBScore( ) if newRbScore > oldRbScore then recentbest.Restore( ) end SetCI( ci2 ) recentbest.Save( ) structure.WiggleAll( longiter ) -- "long" wiggle recentbest.Restore( ) end function ShakeWiggleFuse( ci1, ci2, iters ) -- aka Fuze1 SetCI( ci1 ) ShakeOrMutate( SHAKESIDECHAIN_ITERS ) SetCI( ci2 ) IterativeWiggleAll( iters, QUICKWIGGLE_GAIN, true, true ) end function WiggleWiggleWiggleFuse( ci1, ci2, iters ) -- aka Fuze2 SetCI( ci1 ) IterativeWiggleAll( iters, QUICKWIGGLE_GAIN, true, true ) SetCI( 1.00 ) IterativeWiggleAll( iters, QUICKWIGGLE_GAIN, true, true ) SetCI( ci2 ) IterativeWiggleAll( iters, QUICKWIGGLE_GAIN, true, true ) end function WiggleShakeWiggleFuse( iters ) -- aka FuzeEnd SetCI( 1.00 ) IterativeWiggleAll( iters, QUICKWIGGLE_GAIN, true, true ) ShakeOrMutate( SHAKESIDECHAIN_ITERS ) IterativeWiggleAll( iters, QUICKWIGGLE_GAIN, true, true ) end ---------------------------------------------------------------- -- THE CLEANUP WIGGLER ---------------------------------------------------------------- function DoCleanupWiggle( doFuseWiggle, iters, minGainForIteration ) SetCI( 1.0 ) recentbest.Save( ) ShakeOrMutate( SHAKESIDECHAIN_ITERS ) recentbest.Restore( ) oldScore = getQuickScore( ) oldTime = os.time( ) algName = "IterativeWiggleAll" IterativeWiggleAll( iters, minGainForIteration, true, true) recentbest.Restore( ) deltaScore = getQuickScore( ) - oldScore deltaTime = os.time( ) - oldTime AddActionToStats( deltaScore, deltaTime ) oldScore = getQuickScore( ) oldTime = os.time( ) if doFuseWiggle and deltaScore <= SLOWWIGGLE_THRESHOLD then local r = random( ) if r < PROB_SLOWWIGGLE_LOCAL then print( "IterativeWiggleLocalByChunk" ) algName = "IterativeWiggleLocalByChunk" IterativeWiggleLocalByChunk( iters, 1, segCt, minGainForIteration, random( 3, 6 ), false ) elseif r < PROB_SLOWWIGGLE_LOCAL + PROB_SLOWWIGGLE_BLUEFUSE then print( "BlueFuse" ) algName = "BlueFuse" BlueFuse( ) else -- PROB_SLOWWIGGLE_CUTFUSE print( "IterativeCutAndWiggle") algName = "IterativeCutAndWiggle" IterativeCutAndWiggle( iters, minGainForIteration, random( 3,11 ) ) end end local deltaScore = getQuickScore( ) - oldScore local deltaTime = os.time( ) - oldTime AddActionToStats( deltaScore, deltaTime ) recentbest.Restore( ) if PROB_SLOWWIGGLE_CUTFUSE > 0.0 and USE_SLOWWIGGLE then for i=1, segCt do -- deliberate non-use of ResetCuts DeleteCutAtIndex( i ) end end end ---------------------------------------------------------------------- -- ---- BANDER FUNCTIONS -- ---------------------------------------------------------------------- function DelBands( ) if not PRESERVE_USER_BANDS then band.DeleteAll( ) else local ct = band.GetCount( ) for i=ct, InitialBandCount+1, -1 do band.Delete( i ) end end end function SetMyBandStrengths( strength ) for i=InitialBandCount+1, band.GetCount( ) do band.SetStrength( i, strength ) end end function BandBetweenSegsWithParameters( seg1, seg2, strength, goalLength, atom1, atom2 ) if not ( IsUnlockedSeg( seg1 ) or IsUnlockedSeg( seg2 ) ) then return false end if atom1 == nil then atom1 = CENTER_CARBON end if atom2 == nil then atom2 = CENTER_CARBON end local bIdx = band.AddBetweenSegments( seg1, seg2, atom1, atom2 ) if bIdx ~= band.GetCount( ) then DebugPrint( "failed to add band from "..seg1.." to "..seg2) return false end if bIdx <= InitialBandCount then return true end -- don't change user-supplied bands if goalLength ~= nil then band.SetGoalLength( bIdx, goalLength ) end if strength ~= nil and strength > 0.0 then band.SetStrength( bIdx, strength ) end return true end function BandInSpaceWithParameters( seg, segFini, segInit, rho, theta, phi, strength, goalLength ) if not ( IsUnlockedSeg( seg) ) then return false end local bIdx = band.Add( seg, segFini, segInit, rho, theta, phi ) if bIdx ~= band.GetCount( ) then return false end if bIdx <= InitialBandCount then return true end -- don't change user-supplied bands if goalLength ~= nil then band.SetGoalLength( bIdx, goalLength ) end if strength ~= nil and strength ~= 0.0 then band.SetStrength( bIdx, strength ) end return true end function ZLB( strength, skipLower, skipUpper ) if skipLower == nil then skipLower = MaxUnlockedSeg + 1 end if skipUpper == nil then skipUpper = MinUnlockedSeg - 1 end for i=MinUnlockedSeg+1, MaxUnlockedSeg-1 do if i < skipLower or i > skipUpper then BandInSpaceWithParameters( i, i+1, i-1, 0.01, 0.0, 0.0, strength, 0.01) end end if skipLower > 1 then BandInSpaceWithParameters( 1, 2, 3, 0.01, 0.0, 0.0, strength, 0.01) end if skipUpper < segCt then BandInSpaceWithParameters( segCt, segCt-1, segCt-2, 0.01, 0.0, 0.0, strength, 0.01) end end ---------------------------------------------------------------------- -- SMALL-SCALE BANDERS -- try making a cysteine joiner ---------------------------------------------------------------------- function PutBandInSpace( idx, maxRho, strength ) local idx2, idx3 if idx < segCt then idx2 = idx + 1 else idx2 = idx - 2 end if idx > 1 then idx3 = idx - 1 else idx3 = idx + 2 end -- random point in sphere of radius maxRho local theta, phi = randomThetaPhi( ) local rho = ( maxRho * random( )^(1/3) ) + 0.001 return BandInSpaceWithParameters( idx, idx2, idx3, rho, theta, phi, strength ) end function PutBandToRandomSeg( idx, strength, atom ) needNew = true local failedTries = 0 while ( needNew and failedTries < 20 ) do idx2 = randomSeg( ) -- ok if this one isn't movable (we assume idx is movable) if idx2 > idx + 1 or idx2 < idx - 1 then needNew = false break else failedTries = failedTries + 1 end end if not needNew then return BandBetweenSegsWithParameters( idx, idx2, strength, nil, atom, nil ) end return false end function PutGlycineHingeBands( glycineIdx, strength ) print( "PutGlycineHingeBands at ".. glycineIdx ) if glycineIdx == 1 or glycineIdx == segCt then return false end changeSucceeded = false selection.DeselectAll ( ) -- construct the rods for the hinge (freeze before and after the glycine) local sR, eR = GetRegionStartAndEnd( glycineIdx + 1 ) if eR < segCt and eR - glycineIdx < 3 then eR = eR + 1 end selection.SelectRange ( glycineIdx + 1 , eR ) local sL, eL = GetRegionStartAndEnd( glycineIdx - 1 ) if eL > 1 and glycineIdx - eL < 3 then eL = eL - 1 end selection.SelectRange ( sL, glycineIdx - 1 ) ChangedFrozenness = true freeze.FreezeSelected ( true, true ) selection.DeselectAll ( ) -- put bands connecting the two rods local maxLen = math.min( eR - sR + 1, eL - sL + 1 ) if maxLen > 4 or (glycineIdx >= 4 and glycineIdx <= segCt - 4) then maxLen = 4 -- try very hard to have 4 instead of only 2 or 3, even if it means bands beyond end of rods elseif maxLen < 1 then return changeFailed -- should only happen if glycine at an end end for i=1, maxLen do if BandBetweenSegsWithParameters( math.max(1, glycineIdx - i), math.min(segCt, glycineIdx + i), strength ) then changeSucceeded = true end end return changeSucceeded end ---------------------------------------------------------------------- -- MID-SCALE BANDERS ---------------------------------------------------------------------- function PutGeneralHingeBands( startHinge, endHinge, strength ) print( "PutGeneralHingeBands at "..startHinge.." to "..endHinge ) if startHinge > endHinge then startHinge, endHinge = endHinge, startHinge end if startHinge == 1 or endHinge == segCt then return false end changeSucceeded = false selection.DeselectAll( ) -- construct the rods for the hinge (freeze before and after the region) local sR, eR = GetRegionStartAndEnd( endHinge + 1 ) if eR < segCt and eR - endHinge < 3 then eR = eR + 1 end selection.SelectRange( endHinge + 1 , eR ) local sL, eL = GetRegionStartAndEnd( startHinge - 1 ) if eL > 1 and startHinge - eL < 3 then eL = eL - 1 end selection.SelectRange( sL, startHinge - 1 ) ChangedFrozenness = true freeze.FreezeSelected( true, true ) selection.DeselectAll( ) -- put bands connecting the two rods local maxLen = math.min( eR - sR + 1, eL - sL + 1 ) if maxLen > 4 then maxLen = 4 -- we will surely have it be at least 2 by choice of eR and eL elseif maxLen < 1 then return changeFailed -- should only happen if startHinge or endHinge is at an end end for i=1, maxLen do if BandBetweenSegsWithParameters( math.max(1, startHinge - i), math.min(segCt, endHinge + i), strength ) then changeSucceeded = true end end return changeSucceeded end function PutPushPullBands( badSeg, bandsWanted, center, strength, wantPushNotPull ) print( "PutPushPullBands at "..badSeg.." centered at "..center ) changeSucceeded = false local okSegList = {} local SC = structure.GetDistance( badSeg, center ) local SR for i=1, segCt do local RC=structure.GetDistance( i, center ) SR=structure.GetDistance( i, badSeg ) if SR<15 and RC<SC-3 and math.abs( i - badSeg ) > 5 and math.abs( i - center ) > 3 then okSegList[#okSegList + 1] = i end end randomizeIndexList( okSegList ) local bandsAdded = 0 for i=1, #okSegList do SR=structure.GetDistance( i, badSeg ) if wantPushNotPull then SR=SR + 4 else SR=SR - 4 end if SR>20 then SR=20 end if SR<3 then SR=3 end if BandBetweenSegsWithParameters( badSeg, okSegList[i], strength, SR ) then changeSucceeded = true bandsAdded = bandsAdded + 1 end if bandsAdded >= bandsWanted then break end end -- FOR(i) return changeSucceeded end function PutVoidCrusherBands( idx, strength ) --make band if found void in area of segment "idx" print( "PutVoidCrusherBands at "..idx ) changeSucceeded = false local t={} -- store possible segments for b=1,segCt do --test all segments if math.abs(idx-b) >= 15 then -- else idx,b too near each other count-wise local ab = structure.GetDistance(idx, b) if ab > 10.0 then --no void if less local void=true for c=1,segCt do --searching for any segment between them if c ~= idx and c ~= b then -- don't want c = idx or b local ac = structure.GetDistance(idx,c) local bc = structure.GetDistance(b,c) if ac<ab and bc<ab and ac>4 and bc>4 then if ac+bc<ab+1.5 then void=false break --no void there for sure end end end end -- END for c if void==true then t[#t+1]={idx,b} end end -- END if idx and b are spatially at least 10 apart end -- END if idx and b are count-wise at least 15 apart end -- LOOP over candidate b's if #t>0 then for i=1,#t do local s=t[i][1] local e=t[i][2] local d=structure.GetDistance( s, e ) d = d - 3.0 -- try to compress this much... if d<3 then d=3 end if d>20 then d=20 end if BandBetweenSegsWithParameters( s, e, strength, d ) then changeSucceeded = true end end end return changeSucceeded end function PutHelixUniformDistanceBands( startSeg, endSeg, shift, strength ) print( "PutHelixUniformDistanceBands at "..startSeg..", "..endSeg ) changeSucceeded = false sumDist = 0 for i=startSeg, endSeg-shift do sumDist = sumDist + structure.GetDistance( i, i+shift ) end length = sumDist/( endSeg - shift - startSeg + 1 ) for i=startSeg,endSeg-shift do if BandBetweenSegsWithParameters( i, i+shift, strength, length ) then changeSucceeded = true end end return changeSucceeded end function PutHelixFixerBands( startSeg, endSeg, strength, do4, do5 ) print( "PutHelixFixerBands at "..startSeg..", "..endSeg ) changeSucceeded = false if do4 then for i=startSeg,endSeg-4 do if BandBetweenSegsWithParameters( i, i+4, strength, HELIX_DISTANCE_SKIP4 ) then changeSucceeded = true end end end if do5 then for i=startSeg,endSeg-5 do if BandBetweenSegsWithParameters( i, i+5, strength, HELIX_DISTANCE_SKIP5 ) then changeSucceeded = true end end end return changeSucceeded end function PutHelixCompressorBands( startSeg, endSeg, shift, strength, stretch ) print( "PutHelixCompressorBands at "..startSeg..", "..endSeg ) changeSucceeded = false for i=startSeg,endSeg-shift do dist = structure.GetDistance( i, i+shift ) if BandBetweenSegsWithParameters( i, i+shift, strength, dist*stretch ) then changeSucceeded = true end end return changeSucceeded end function PutRotatorBands( startSeg, endSeg, length, strength, wantClockwise ) print( "PutRotatorBands at "..startSeg..", "..endSeg ) changeSucceeded = false for i = math.max( startSeg , 2 ), math.min( endSeg , segCt - 1 ) do if wantClockwise then if BandInSpaceWithParameters( i, i + 1, i - 1, length, math.pi/2, math.rad ( 315 ), strength ) then changeSucceeded = true end else if BandInSpaceWithParameters( i, i - 1, i + 1, length, math.pi/2, math.rad ( 315 ), strength ) then changeSucceeded = true end end end return changeSucceeded end function PutPusherBands( startSeg, endSeg, length, strength, doForward ) print( "PutPusherBands at "..startSeg..", "..endSeg ) changeSucceeded = false if startSeg > 1 then init = startSeg - 1 else init = startSeg end if endSeg < segCt then fini = endSeg + 1 else fini = endSeg end if not doForward then init, fini = fini, init end for i = init + 1, fini - 1 do if BandInSpaceWithParameters( i, fini, init, length, math.pi/2, 0.0, strength ) then changeSucceeded = true end end return changeSucceeded end function PutMoverBands( startSeg, endSeg, length, strength ) print( "PutMoverBands at "..startSeg..", "..endSeg ) changeSucceeded = false if startSeg > 1 then init = startSeg - 1 else init = startSeg end if endSeg < segCt then fini = endSeg + 1 else fini = endSeg end theta, phi = randomThetaPhi( ) for i = init + 1, fini - 1 do if BandInSpaceWithParameters( i, fini, init, length, theta, phi, strength ) then changeSucceeded = true end end return changeSucceeded end -- TODO consider putting more bands in "between" segments, with lengths that increase -- as they head towards the midpoint function PutFlexerBands( startSeg, endSeg, length, strength ) print( "PutFlexerBands at "..startSeg..", "..endSeg ) if endSeg - startSeg < 3 then return false end changeSucceeded = false if startSeg > 1 then init = startSeg - 1 first = startSeg else init = startSeg first = startSeg + 1 end if endSeg < segCt then fini = endSeg + 1 last = endSeg else fini = endSeg last = endSeg - 1 end midpt = (startSeg + endSeg + 1) / 2 -- initial band points inwards if BandInSpaceWithParameters( first, fini, init, 1.0, math.pi/2.0, 0.0, strength ) then changeSucceeded = true end --final band points inwards, too if BandInSpaceWithParameters( last, init, fini, 1.0, math.pi/2.0, 0.0, strength ) then changeSucceeded = true end -- middle one is longer and points perpendicularly to init-fini line. Consider -- replacing with ramping-up lengths over all "interior" segments. theta, phi = randomThetaPhi( ) -- ignoring phi, because we just want to use 0 if BandInSpaceWithParameters( midpt, fini, init, length, theta, 0.0, strength ) then changeSucceeded = true end return changeSucceeded end function PutSheetStraightenerBands( startSeg, endSeg, strength ) -- 9.5 is "ideal" distance between N and N+2 in sheets. Make a constant for it sometime print( "PutSheetStraightenerBands at "..startSeg..", "..endSeg ) changeSucceeded = false for i=startSeg, endSeg-2 do changeSucceeded = BandBetweenSegsWithParameters( i, i+2, 9.5, strength ) or changeSucceeded end return changeSucceeded end -- bandToNearest=false means "band to farthest" function PutManyBandsToSeg( idx, maxBandCount, strength, compression, bandToNearest ) changeSucceeded = false local segsToBand = {} local idxList = {} local distList = {} local totalDistance = 0.0 local dist = 0.0 -- we will construct segsToBand first, summing totalDistance as we go for i = 3, segCt - 3 do if i ~= idx and IsUnlockedSeg( i ) then if bandToNearest then if IsLocalMinimum( idx, i ) then segsToBand[ #segsToBand + 1 ] = i totalDistance = totalDistance + structure.GetDistance( idx, i ) end else if IsLocalMaximum( idx, i ) then segsToBand[ #segsToBand + 1 ] = i totalDistance = totalDistance + structure.GetDistance( idx, i ) end end end end -- now sort them so we can take only the "best" segments... for i=1, #segsToBand do idxList[ i ] = i end for i=1, #segsToBand do distList[ i ] = structure.GetDistance( idx, i ) end sortAllByScore( idxList, distList ) -- now put the bands, preferring the "nearest" ones for i=1, math.min( #segsToBand, maxBandCount ) do local dist = structure.GetDistance( idx, segsToBand[ idxList[ i ] ] ) if BandBetweenSegsWithParameters( idx, segsToBand[ idxList[ i ] ], strength, compression * dist ) then changeSucceeded = true end end return changeSucceeded end ---------------------------------------------------------------------- -- LARGE-SCALE BANDERS ---------------------------------------------------------------------- function PutSheetSewerBandsAllOver( maxDist, strength ) print( "SheetSewerBands: dist="..maxDist ) changeSucceeded = false for seg1 = 2, segCt - 4 do for seg2 = seg1 + 3, segCt do if IsUnlockedSeg( seg1 ) or IsUnlockedSeg( seg2 ) then if structure.GetDistance( seg1, seg2 ) < maxDist and structure.GetSecondaryStructure( seg1 ) == 'E' and structure.GetSecondaryStructure( seg2 ) == 'E' then local changeSuc = BandBetweenSegsWithParameters(seg1, seg2, strength ) changeSucceeded = changeSucceeded or changeSuc end end end end return changeSucceeded end function PutCoreCompressBands(coreList, skipCt, startOffset, strength, compression, pullPhilics, doSidechains ) print( "PutCoreCompressBands for "..#coreList.." cores with compress="..TrimNum( compression ) ) if doSidechains == nil then doSidechains = false end if pullPhilics == nil then pullPhilics = false end local str = " connecting to " if doSidechains then str=str .. "sides" else str = str .. "backbone" end if pullPhilics then str=str .. ", pulling philics away" else str = str .. ", philics and phobics treated same" end print( str ) local maxToBand = #coreList local bandList = {} local added = 0 -- first put bands between all of our central segs -- notice: there's no protection from some of them being adjacent, but it's ok -- if one or more of these bands fail to be created. for i=1, maxToBand-1 do for j=i+1, maxToBand do if coreList[i] < coreList[j] - 1 or coreList[i] > coreList[j] + 1 then local goalLength= compression * structure.GetDistance( coreList[ i ], coreList[ j ] ) if BandBetweenSegsWithParameters( coreList[ i ], coreList[ j ], strength, goalLength ) then added = added + 1 end end end end -- now put bands between the "rest" of the protein and our chosen ones for i=startOffset, segCt, skipCt do local skipThisI = false for j=1, maxToBand do if coreList [ j ] == i then skipThisI = true break end end if not skipThisI then for j=1, maxToBand do if i < coreList[ j ] - 1 or i > coreList[ j ] + 1 then goalLength= compression * structure.GetDistance( i, coreList[ j ] ) if pullPhilics and not structure.IsHydrophobic( i ) then goalLength= goalLength + 1.0 end atom = nil if BAND_TO_SIDECHAINS and doSidechains then atom = PickAtomNumberForBand( i ) end if BandBetweenSegsWithParameters( i, coreList[ j ], strength, goalLength, atom, nil ) then added = added + 1 end end end end end return added > 0 end function PutBandsEveryXToEveryY( Xrange, Xinit, Yrange, Yinit, strength, compression ) print( "BandsXToY "..Xrange.." x "..Yrange.. " with compress="..TrimNum( compression ) ) local length = 0 local added = 0 for i=Xinit, segCt, Xrange do for j=Yinit, segCt, Yrange do if (i < j - 1 or i > j + 1) then if compression == nil then length = nil else length = compression * structure.GetDistance( i, j ) end if BandBetweenSegsWithParameters( i, j, strength, length ) then added = added + 1 end end end end return added > 0 end function PutGentleCompBands( bandsWanted, minLength, maxLength, minSeparation, strength, compression ) print( "GentleCompBands: compression="..TrimNum( compression ) ) local bandsAdded = 0 local failCount = 0 repeat local s = randomUnlockedSeg( ) local e = randomMovableFarSeg( s, minSeparation, minLength, maxLength ) if e == 0 then failCount = failCount + 1 else -- yes, this would try to add the same segment twice, but that will fail simply... local dist = structure.GetDistance( s, e ) changeSucceeded = BandBetweenSegsWithParameters( s,e, strength, dist * compression ) if changeSucceeded then bandsAdded = bandsAdded + 1 else failCount = failCount + 1 end end until bandsAdded == bandsWanted or failCount >= 100 return true end ---------------------------------------------------------------------- -- CONTACT-MAP BANDERS ---------------------------------------------------------------------- function PutAllContactMapBands( heatThreshold, madeStrength, madeLengthScale, unmadeStrength, unmadeLengthScale, doSidechains, ditherValues ) print( "AllCMBands" ) changeSucceeded = false local baseStrength = strength for i = 1, segCt-2 do for j = i+2, segCt do if contactmap.GetHeat(i, j) >= heatThreshold then local goalLength = structure.GetDistance( i, j ) if contactmap.IsContact( i, j ) then goalLength = madeLengthScale * goalLength strength = madeStrength else goalLength = unmadeLengthScale * goalLength strength = unmadeStrength end if ditherValues then goalLength = random( 0.95, 1.05, true ) * goalLength strength = random( 0.95, 1.05, true ) * strength end local atom1 = nil local atom2 = nil if BAND_TO_SIDECHAINS and doSidechains then atom1 = BETA_CARBON atom2 = BETA_CARBON end changeSucceeded = BandBetweenSegsWithParameters( i, j, strength, goalLength, atom1, atom2 ) or changeSucceeded end end end return changeSucceeded end function PutSomeContactMapBands( heatThreshold, strength, ctBands, doSidechains ) if ctBands > 1 then print( "SomeCMBands with ct="..ctBands ) else print( "SingleCMBand" ) end changeSucceeded = false local hotList = {} for i = 1, segCt-2 do for j = i+2, segCt do local heat = contactmap.GetHeat(i, j) if heat >= heatThreshold and not contactmap.IsContact( i , j ) then hotList[ #hotList + 1] = { i, j, heat } end end end randomizeIndexList( hotList ) for i=1, math.min( ctBands, #hotList ) do local atom1 = nil local atom2 = nil if BAND_TO_SIDECHAINS and doSidechains then atom1 = PickAtomNumberForBand( hotList[i][1] ) atom2 = PickAtomNumberForBand( hotList[i][2] ) end local ch = BandBetweenSegsWithParameters( hotList[i][1], hotList[i][2], strength, nil, atom1, atom2 ) changeSucceeded = ch or changeSucceeded end return changeSucceeded end function PutAllContactMapBandsToSeg( idx, heatThreshold, strength, doComp, doSidechain ) print( "AllCMBandsToSeg ".. idx ) changeSucceeded = false local baseStrength = strength if doComp then -- COMP-style bands for i=1, segCt do if i < idx - 1 or i > idx + 1 then local heat = contactmap.GetHeat( i, idx ) if heat >= heatThreshold then local goalLength = structure.GetDistance( i, idx ) if contactmap.IsContact( i, idx ) then strength = CONTACTMAP_CONTACTING_STRENGTH * baseStrength goalLength = CONTACTMAP_CONTACTING_GOAL * goalLength else strength = CONTACTMAP_NONCONTACTING_STRENGTH * baseStrength goalLength = CONTACTMAP_NONCONTACTING_GOAL * goalLength end local atom = nil if BAND_TO_SIDECHAINS and doSidechain then atom = PickAtomNumberForBand( i ) end local changeSuc = BandBetweenSegsWithParameters( idx, i, strength, goalLength, nil, atom ) changeSucceeded = changeSuc or changeSucceeded end end end else -- only bands to non-contacting segs local hotList = {} for i = 1, segCt do if i < idx - 1 or i > idx + 1 then local heat = contactmap.GetHeat( i, idx ) if heat >= heatThreshold and not contactmap.IsContact( i , idx ) then hotList[ #hotList + 1] = i end end end for i=1, #hotList do if hotList[ i ] ~= idx then -- not supposed to happen! local atom = nil if BAND_TO_SIDECHAINS and doSidechain then atom = PickAtomNumberForBand( hotList[i] ) end local changeSuc = BandBetweenSegsWithParameters( idx, hotList[i], strength * contactmap.GetHeat( i, idx ), nil, nil, atom ) changeSucceeded = changeSuc or changeSucceeded end end end return changeSucceeded end function PutContactMapBandsBetweenRegions( heatThreshold, startIdx1, endIdx1, startIdx2, endIdx2, strength, doComp, doBetaCarbons, ditherValues ) print( "CMTwoRegions: ("..startIdx1..", "..endIdx1..") to ("..startIdx2..", "..endIdx2..")" ) changeSucceeded = false local baseStrength = strength local atom1 = CENTER_CARBON local atom2 = CENTER_CARBON if BAND_TO_SIDECHAINS and doBetaCarbons then atom1 = BETA_CARBON atom2 = BETA_CARBON end for i = startIdx1, endIdx1 do for j = startIdx2, endIdx2 do if contactmap.GetHeat( i, j ) >= heatThreshold then local goalLength = nil if doComp then goalLength = structure.GetDistance( i, j ) if contactmap.IsContact( i, j ) then strength = CONTACTMAP_CONTACTING_STRENGTH * baseStrength goalLength = CONTACTMAP_CONTACTING_GOAL * goalLength else strength = CONTACTMAP_NONCONTACTING_STRENGTH * baseStrength goalLength = CONTACTMAP_NONCONTACTING_GOAL* goalLength end end if ditherValues then strength = random( 0.95, 1.05, true ) * strength goalLength = random( 0.95, 1.05, true ) * goalLength end changeSucceeded = BandBetweenSegsWithParameters( i, j, strength, goalLength, atom1, atom2 ) or changeSucceeded end end end return changeSucceeded end function PutPushPullContactMapBands( badSeg, bandsWanted, center, strength, heatThreshold, wantPushNotPull ) print( "PushPullCM: "..badSeg.." center="..center ) changeSucceeded = false local okSegList = {} local SC = structure.GetDistance( badSeg, center ) local SR for i=1, segCt do local RC=structure.GetDistance( i, center ) SR=structure.GetDistance( i, badSeg ) if SR<15 and RC<SC-3 and math.abs( i - badSeg ) > 5 and math.abs( i - center ) > 3 then okSegList[#okSegList + 1] = i end end randomizeIndexList( okSegList ) local bandsAdded = 0 for i=1, #okSegList do SR=structure.GetDistance( i, badSeg ) if wantPushNotPull then SR=SR + 4 else SR=SR - 4 end if SR>20 then SR=20 end if SR<3 then SR=3 end if BandBetweenSegsWithParameters( badSeg, okSegList[i], strength, SR ) then changeSucceeded = true bandsAdded = bandsAdded + 1 end if bandsAdded >= bandsWanted then break end end -- FOR(i) return changeSucceeded end function PutVoidCrusherContactMapBands( idx, strength, heatThreshold ) print( "VoidCrusherCM at "..idx ) changeSucceeded = false local t={} -- store possible segments for b=1,segCt do --test all segments if math.abs(idx-b) >= 15 and contactmap.GetHeat( idx, b ) >= heatThreshold then local ab = structure.GetDistance(idx, b) if ab > 10.0 then --no void if less local void=true for c=1,segCt do --searching for any segment between them if c ~= idx and c ~= b then -- don't want c = idx or b local ac = structure.GetDistance(idx,c) local bc = structure.GetDistance(b,c) if ac<ab and bc<ab and ac>4 and bc>4 then if ac+bc<ab+1.5 then void=false break --no void there for sure end end end end -- END for c if void==true then t[#t+1]={ idx, b } end end -- END if idx and b are spatially at least 10 apart end -- END if idx and b are count-wise at least 15 apart end -- LOOP over candidate b's if #t>0 then for i=1,#t do local s=t[i][1] local e=t[i][2] local d=structure.GetDistance( s, e ) d = d - 3.0 -- try to compress this much... if d<3 then d=3 end if d>20 then d=20 end if BandBetweenSegsWithParameters( s, e, strength, d ) then changeSucceeded = true end end end return changeSucceeded end -------------------------------------------------------------- -- ---- MUTATOR FUNCTIONS -- TODO: Consider adding a "very similar" mutator -------------------------------------------------------------- -- this one doesn't care what amino used to be at idx function MutateToAny( idx ) local aa = structure.GetAminoAcid( idx ) local aanew = aa local i = 0 while ( aanew == aa ) do i = random( aaCount ) aanew = AA( i ) end print( "mutating " .. aa .. " at " .. idx .. " to " .. aanew ) structure.SetAminoAcid( idx, aanew ) return true end -- this one preserves hydrophob/hydrophil function MutateToSimilar( idx ) local aa = structure.GetAminoAcid( idx ) local i = 0 local aanew = aa while (aanew == aa) do if structure.IsHydrophobic( idx ) then i = random( aaPhobCount ) aanew = AAphobic( i ) else i = random( aaPhilCount ) aanew = AAphilic( i ) end end print( "mutating " .. aa .. " at " .. idx .. " to " .. aanew ) structure.SetAminoAcid( idx, aanew ) return true end ---------------------------------------------------------------------- -- ---- IDEALIZERS AND REBUILDERS -- ---------------------------------------------------------------------- ---------------------------------------------------------------------- -- IDEALIZERS ---------------------------------------------------------------------- function IdealizeInRange( startSeg, endSeg, iters, useCuts ) print( "IdealizeInRange for "..startSeg.." to "..endSeg ) if useCuts == nil then useCuts = true end local idxList = { } changeFailed = false if startSeg > endSeg then startSeg, endSeg = endSeg, startSeg end if startSeg < 1 then startSeg = 1 end if endSeg > segCt then endSeg = segCt end local tries = 0 save.Quicksave( QS_ShortUseTemp1 ) local delta = 0.0 repeat save.Quickload( QS_ShortUseTemp1 ) changeFailed = false if IDEALIZE_MAXTRIES > 1 and tries == IDEALIZE_MAXTRIES - 1 then delta = 0.0 useCuts = false -- overrule the user's request for use of cuts (should always succeed) end if useCuts then if startSeg - 2 > 1 then structure.InsertCut( startSeg - 2 ) end if endSeg + 1 < segCt then structure.InsertCut( endSeg + 1 ) end if startSeg - 3 >= 1 then BandBetweenSegsWithParameters( startSeg-3, startSeg, 1.0 + delta, structure.GetDistance( startSeg-3, startSeg ) ) end if endSeg + 3 <= segCt then BandBetweenSegsWithParameters( endSeg, endSeg + 3, 1.0 + delta, structure.GetDistance( endSeg, endSeg+3 ) ) end end selection.DeselectAll( ) getSegsWithinRangeOfTube( idxList, startSeg, endSeg, IDEALIZE_TUBE_RADIUS ) for i=1, #idxList do selection.Select( idxList[i] ) end structure.IdealizeSelected( ) selection.DeselectAll( ) if useCuts then -- get some wiggling happening print( "WiggleZlbNicely" ) WiggleZlbNicely( iters, IDEALIZE_ZLB_STRENGTH + delta, math.max( 1, startSeg-2 ), math.min( segCt, endSeg+2 ) ) -- now put the protein back in its proper shape if startSeg - 2 > 1 then if not DeleteCutAtIndex(startSeg - 2 ) and IDEALIZE_FORBID_UNHEALED_CUTS then changeFailed = true end end if changeFailed == false and endSeg + 1 < segCt then if not DeleteCutAtIndex(endSeg + 1 ) and IDEALIZE_FORBID_UNHEALED_CUTS then changeFailed = true end end else -- since we didn't put in any cuts, we can try simple wiggling to see how we did print( "WiggleRange" ) recentbest.Save( ) WiggleRange( iters, startSeg - 2, endSeg + 1, false, random( ) < 0.50 ) ShakeOrMutate( SHAKESIDECHAIN_ITERS ) recentbest.Restore( ) end if not changeFailed then DelBands( ) return true end tries = tries + 1 delta = delta + 0.25 until tries >= IDEALIZE_MAXTRIES DelBands( ) return false end ---------------------------------------------------------------------- -- REBUILDERS ---------------------------------------------------------------------- function RebuildInRange( startSeg, endSeg, maxTries, maxFall ) if maxFall == nil then maxFall = REBUILD_MAX_MEDIUM_SCOREDROP end print( "RebuildInRange from "..startSeg.." to "..endSeg ) changeSucceeded = false local iters = QUICKWIGGLE_ITERS local oldScoreMat = {} local locss = {} local killedSS = false local startScore = getQuickScore( ) ConstructScoreMatrix( oldScoreMat ) -- probably PickRebuild should decide whether to do secondary structure stuff for i=startSeg, endSeg do locss[i] = structure.GetSecondaryStructure( i ) end for i=startSeg, endSeg do if structure.GetSecondaryStructure( i ) == 'E' then killedSS = true structure.SetSecondaryStructure( i, 'L' ) end end selection.DeselectAll( ) save.Quicksave( QS_ShortUseTemp1 ) -- holds our "running" pose save.Quicksave( QS_ShortUseTemp2 ) -- holds our "best so far" result bestRescore = -10000.0 for i=1, maxTries do local idxListInner = { } save.Quickload( QS_ShortUseTemp1 ) -- bring up our "running" pose selection.SelectRange( startSeg, endSeg ) RebuildSelected( i ) -- not only up to maxTries times, but up to maxTries iterations per time selection.DeselectAll( ) if math.abs( getQuickScore( ) - startScore ) >= 0.01 then -- give the whole thing a little bit of shake-and-wiggle-time (deliberately not complete) structure.WiggleSelected( iters ) getSegsWithinRangeOfTube( idxListInner, startSeg, endSeg, REBUILD_INNER_TUBE_RADIUS ) ShakeOrMutate( SHAKESIDECHAIN_ITERS, idxListInner ) -- only shake the "nearby" segments structure.WiggleAll( iters, true, true ) -- just a short bit of time on this wiggle to settle things down a bit rescore = getQuickScore( ) if rescore > startScore then -- we have a real improvement! save.Quicksave( QS_ShortUseTemp1 ) -- replace our "running" pose with this better one save.Quicksave( QS_ShortUseTemp2 ) -- our best-so-far is better startScore = rescore bestRescore = rescore changeSucceeded = true else -- not improved, but maybe it's worth keeping anyway? if rescore > bestRescore and IsNeighborDifferentFromOld( oldScoreMat, 0.1 ) then save.Quicksave( QS_ShortUseTemp2 ) -- our best-so-far is better bestRescore = rescore if startScore - rescore < maxFall then changeSucceeded = true end end end end end save.Quickload( QS_ShortUseTemp2 ) if killedSS then for i=startSeg, endSeg do structure.SetSecondaryStructure( i, locss[ i ] ) end end selection.DeselectAll( ) return changeSucceeded end function RebuildSection_Quaker( startSeg, endSeg, maxTries, maxFall ) print( "RebuildSection_Quaker from "..startSeg.." to "..endSeg ) local initScore = getQuickScore( ) local tries = 0 repeat selection.DeselectAll( ) selection.SelectRange( startSeg, endSeg ) tries = tries + 1 RebuildSelected( tries ) newScore = getQuickScore( ) until newScore ~= initScore or tries > maxTries if newScore == initScore then return false -- we failed end recentbest.Save( ) -- N.B. This is exactly the sort of situation recentbest was made for! RebuildSelected( maxTries - 1 ) -- maybe use REBUILD_MAXITERS - 1 ? recentbest.Restore( ) WiggleAndShakeForRebuilder( initScore, maxFall ) -- quaking rebuild put a perform-quake-if-score-not-better-but-not-too-bad here return true end function RebuildSimple( idx, len ) print( "RebuildSimple for ".. idx.. " to "..idx + len - 1 ) local initscore = getQuickScore( ) local idxList = { idx } for i=1, len - 1 do if idx + i <= segCt then idxList[ #idxList + 1 ] = idx + i else break end end selection.DeselectAll( ) selection.SelectRange( idx, math.min( segCt, idx + len - 1 ) ) RebuildSelected( 1 ) if getQuickScore( ) == initscore then return false end recentbest.Save( ) ShakeOrMutate( SHAKESIDECHAIN_ITERS, idxList ) recentbest.Restore( ) structure.IdealizeSelected( ) recentbest.Restore( ) ShakeOrMutate( SHAKESIDECHAIN_ITERS, idxList ) recentbest.Restore( ) structure.WiggleAll( 25 ) recentbest.Restore( ) ShakeOrMutate( SHAKESIDECHAIN_ITERS ) recentbest.Restore( ) IterativeWiggleAll( QUICKWIGGLE_ITERS, QUICKWIGGLE_GAIN, true, true ) recentbest.Restore( ) return true end function RebuildSimple2( idx, len ) print( "RebuildSimple2 for ".. idx.. " to "..idx + len - 1 ) local initscore = getQuickScore( ) selection.DeselectAll( ) selection.SelectRange( idx, idx + len - 1) RebuildSelected( 1 ) if getQuickScore( ) == initscore then return false end recentbest.Save( ) SetCI( 0.5 ) ShakeOrMutate( SHAKESIDECHAIN_ITERS ) SetCI( 1.0 ) structure.WiggleAll( 15 ) recentbest.Restore( ) SetCI( 0.5 ) ShakeOrMutate( SHAKESIDECHAIN_ITERS ) SetCI( 1.0 ) IterativeWiggleAll( QUICKWIGGLE_ITERS, QUICKWIGGLE_GAIN, true, true ) recentbest.Restore( ) return true end function RebuildSimple3( idx, len, addIdealize ) print( "RebuildSimple3 for ".. idx.. " to "..idx + len - 1 ) local initscore = getQuickScore( ) selection.DeselectAll( ) selection.SelectRange( idx, idx + len - 1) RebuildSelected( 4 ) if getQuickScore( ) ~= initscore then recentbest.Save( ) if addIdealize then structure.IdealizeSelected( ) end VerySimpleNonBandedWiggler( QUICKWIGGLE_ITERS ) recentbest.Restore( ) return true end return false end function WiskyRebuildAllAction( ) SelectAllMovable( ) RebuildSelected( 1 ) ShakeOrMutate( SHAKESIDECHAIN_ITERS ) structure.WiggleAll( 10 ) ShakeOrMutate( SHAKESIDECHAIN_ITERS ) IterativeWiggleAll( QUICKWIGGLE_ITERS, QUICKWIGGLE_GAIN, true, true ) end ---------------------------------------------------------------------- -- OPERATION-SPECIFIC CHOOSING FUNCTIONS ---------------------------------------------------------------------- function PickRebuildRangeAction( startSeg, endSeg, maxFall ) local iters = QUICKWIGGLE_ITERS changeSucceeded = false if random( ) < 0.50 then algName = "RebuildInRange" local initScore = getQuickScore( ) changeSucceeded = RebuildInRange( startSeg, endSeg, REBUILD_TRYCOUNT, maxFall ) if changeSucceeded then if REBUILD_ADDIDEALIZE then DebugPrint("Putting Idealize after rebuild") save.Quicksave( QS_ShortUseTemp2 ) -- so we can throw out the idealize if we don't like result local score = getQuickScore( ) local check = IdealizeInRange( startSeg, endSeg, iters, REBUILD_USECUTS ) if check and score < getQuickScore( ) then save.Quicksave( QS_ShortUseTemp2 ) score = getQuickScore( ) end save.Quickload( QS_ShortUseTemp2 ) end local idxListOuter = {} getSegsWithinRangeOfTube( idxListOuter, startSeg, endSeg, REBUILD_OUTER_TUBE_RADIUS ) IterativeWiggleShakeWiggle( idxListOuter, iters ) end else -- this one comes with its own wiggler and skaker built-in algName = "RebuildSectionQ" -- we'll just overrule alg's name choice for the time being changeSucceeded = RebuildSection_Quaker( startSeg, endSeg, 8, maxFall ) -- 8 => REBUILD_TRYCOUNT ? end return changeSucceeded end function PickRebuildPointAction( idx, maxRange, maxFall ) if maxFall == nil then maxFall = REBUILD_MAX_MEDIUM_SCOREDROP end if maxRange == nil then maxRange = math.floor( REBUILD_MAX_SEGLEN / 2 ) end local startIdx = math.max( 1, idx - random( maxRange ) ) local endIdx = math.min( segCt, idx + random( maxRange ) ) for i=idx, endIdx do if not IsMovableSeg(i) then endIdx = i - 1 break end end for i=idx, startIdx, -1 do if not IsMovableSeg(i) then startIdx = i + 1 break end end return PickRebuildRangeAction( startIdx, endIdx, maxFall ) end function PickRebuildSimpleAction( idx ) if idx == nil or idx == 0 then idx = randomMovableSeg( ) end return RebuildSimple( idx, 1 ) end function PickRebuildSimple2Action( idx ) if idx == nil or idx == 0 then idx = randomMovableSeg( ) end return RebuildSimple2( idx, 1 ) end function PickSimpleRebuildRangeAction( idx ) if idx == nil then idx = randomMovableSeg( ) end local iters = QUICKWIGGLE_ITERS local len = random( REBUILD_MAX_SEGLEN ) if idx + len - 1 > segCt then len = segCt - idx + 1 end return RebuildSimple3( idx, len, random( ) < 0.5 ) end function PickContactMapRebuildRangeAction( idx ) if idx == nil then idx = randomMovableSeg( ) end print( "ContactMapRebuildRange at ".. idx ) local iters = QUICKWIGGLE_ITERS changeSucceeded = PickContactMapper( ) if changeSucceeded then local len = random( REBUILD_MAX_SEGLEN ) if idx + len - 1 > segCt then len = segCt - idx + 1 end if USE_LOWCI_WIGGLES then changeSucceeded = RebuildSimple3( idx, len, random( ) < 0.50 ) elseif random( ) < 0.50 then changeSucceeded = RebuildSimple( idx, len ) else changeSucceeded = RebuildSimple2( idx, len ) end end DelBands() if changeSucceeded then qStabWiggle( iters, random() < PROB_QSTAB_EXTRA ) end return changeSucceeded end -- think about all-loop and restoring secondary structure and such function PickContactMapRebuildSSAction( idx ) if idx == nil then idx = randomMovableSeg( ) end print( "Performing PickContactMapRebuildSSAction for "..idx ) local iters = QUICKWIGGLE_ITERS local oldInnerTube = REBUILD_INNER_TUBE_RADIUS local oldOuterTube = REBUILD_OUTER_TUBE_RADIUS REBUILD_INNER_TUBE_RADIUS = REBUILD_CM_INNER_TUBE_RADIUS REBUILD_OUTER_TUBE_RADIUS = REBUILD_CM_OUTER_TUBE_RADIUS changeSucceeded = PickContactMapper( ) if changeSucceeded then local sIdx, eIdx = GetRegionForOperation( idx ) if random( ) < 0.50 then changeSucceeded = RebuildInRange( sIdx, eIdx, REBUILD_TRYCOUNT, REBUILD_MAX_MEDIUM_SCOREDROP ) else changeSucceeded = RebuildSection_Quaker( sIdx, eIdx, REBUILD_TRYCOUNT, REBUILD_MAX_MEDIUM_SCOREDROP ) end end REBUILD_INNER_TUBE_RADIUS = oldInnerTube REBUILD_OUTER_TUBE_RADIUS = oldOuterTube DelBands() if changeSucceeded then qStabWiggle( iters, random() < PROB_QSTAB_EXTRA ) end return changeSucceeded end function PickContactMapRebuildAllAction( ) print( "PickContactMapRebuildAllAction" ) local iters = QUICKWIGGLE_ITERS changeSucceeded = PickContactMapper( ) if changeSucceeded then WiskyRebuildAllAction( ) end DelBands() if changeSucceeded then qStabWiggle( iters, true ) end return changeSucceeded end function PickIdealizeRangeAction( idx ) if idx == nil then idx = randomMovableSeg( ) end print( "PickIdealizeRangeAction for ".. idx ) local iters = QUICKWIGGLE_ITERS local maxSeg = math.min( segCt, idx + random( IDEALIZE_MAX_SEGLEN ) ) local startIdx, endIdx = GetRegionForOperation( idx ) if endIdx - startIdx + 1 > IDEALIZE_MAX_SEGLEN then if idx - startIdx + 1 > IDEALIZE_MAX_SEGLEN then startIdx = math.max( 1, idx - IDEALIZE_MAX_SEGLEN) end end if endIdx - startIdx + 1 > IDEALIZE_MAX_SEGLEN then endIdx = startIdx + IDEALIZE_MAX_SEGLEN - 1 end changeSucceeded = IdealizeInRange( startIdx, endIdx, iters, IDEALIZE_USE_CUTS ) if changeSucceeded then qStabWiggle( iters, random( ) < PROB_QSTAB_EXTRA ) end return changeSucceeded end function PickIdealizePointAction( idx ) if idx == nil then idx = randomMovableSeg( ) end print( "PickIdealizePointAction for ".. idx ) local iters = QUICKWIGGLE_ITERS changeSucceeded = IdealizeInRange( idx, idx, iters, IDEALIZE_USE_CUTS ) if changeSucceeded then qStabWiggle( iters, random( ) < PROB_QSTAB_EXTRA ) end return changeSucceeded end function PickSimpleIdealizeAction( idx ) if idx == nil then idx = randomMovableSeg( ) end print( "SimpleIdealize for segment " .. idx ) local iters = QUICKWIGGLE_ITERS local maxSeg = math.min( segCt, idx + random( IDEALIZE_MAX_SEGLEN ) ) selection.DeselectAll( ) selection.SelectRange( idx, maxSeg ) structure.IdealizeSelected( ) selection.DeselectAll( ) VerySimpleNonBandedWiggler( iters ) return true end function PickSingleBandInSpace( idx ) if idx == nil then idx = randomUnlockedSeg( ) end local iters = QUICKWIGGLE_ITERS local strength = random( BAND_STRENGTH_DEFAULT / 2, BAND_STRENGTH_DEFAULT, true ) -- print is done here because PutBandInSpace is called by other pickers print( "BIS for segment " .. idx.." with strength "..TrimNum( strength ) ) changeSucceeded = PutBandInSpace( idx, BIS_LENGTH, strength ) if changeSucceeded then -- must keep wiggler in-house, lowci isn't useful RegionWiggleBeforeAndAfter( iters, idx, idx ) end return changeSucceeded end function PickBandToRandomSeg( idx ) if idx == nil then idx = randomUnlockedSeg( ) end local strength = BAND_STRENGTH_DEFAULT local atom = PickAtomNumberForBand( idx ) -- print is done here because PutBandToRandomSeg is called by other pickers print( "BandBetween for segment " .. idx.." with strength "..TrimNum( strength ) ) return PutBandToRandomSeg( idx, strength, atom ) end function PickGlycineHinge( idx ) if idx == nil then idx = randomAASeg( ) end if idx == 0 then return false end local strength = random( 0.25, BAND_STRENGTH_DEFAULT, true ) return PutGlycineHingeBands( idx, strength ) end function PickGeneralHingeBands( idx ) if idx == nil then idx = randomMovableSeg( ) end local strength = BAND_STRENGTH_REGION local bisLen = BIS_LENGTH local startSeg, endSeg = GetRegionForOperation( idx ) if endSeg - startSeg <= 1 then return false end -- something's very wrong if startSeg < idx - 2 then startSeg = idx - random( 0, 2 ) end if endSeg > idx + 2 then endSeg = idx + random( 0, 2 ) end return PutGeneralHingeBands( startSeg, endSeg, strength ) end function PickPushPullAction( idx ) if idx == nil then idx = randomUnlockedSeg( ) end local segList = {} local wantPushNotPull = random( ) < 0.50 local ctBands = 5 local strength = BAND_STRENGTH_DEFAULT getSegsOutsideSphere( segList, idx, 8 ) if #segList == 0 then -- nothing we can do! print(" PushPull failed due to lack of distant segs") return false end local centerSeg = segList[ random( #segList) ] return PutPushPullBands( idx, ctBands, centerSeg, strength, wantPushNotPull ) end function PickVoidCrusherAction( idx ) if idx == nil then idx = randomUnlockedSeg( ) end local strength = BAND_STRENGTH_DEFAULT return PutVoidCrusherBands( idx, strength ) end function PickRotatorBands( idx ) if idx == nil then idx = randomMovableSeg( ) end local iters = QUICKWIGGLE_ITERS local strength = BAND_STRENGTH_REGION local bisLen = BIS_LENGTH local goClockwise = random( ) < 0.50 local startSeg, endSeg = GetRegionForOperation( idx ) if endSeg - startSeg <= 1 then return false end -- something's very wrong changeSucceeded = PutRotatorBands( startSeg, endSeg, bisLen, strength, goClockwise ) if changeSucceeded then -- must keep wiggler in-house, lowci isn't useful RegionWiggleBeforeAndAfter( iters, startSeg, endSeg ) end DelBands( ) return changeSucceeded end function PickPusherBands( idx ) if idx == nil then idx = randomMovableSeg( ) end local iters = QUICKWIGGLE_ITERS local strength = BAND_STRENGTH_REGION local bisLen = BIS_LENGTH local goForward = random( ) < 0.50 local startSeg, endSeg = GetRegionForOperation( idx ) if endSeg - startSeg <= 1 then return false end -- something's very wrong changeSucceeded = PutPusherBands( startSeg, endSeg, bisLen, strength, goForward ) if changeSucceeded then -- must keep wiggler in-house, lowci isn't useful RegionWiggleBeforeAndAfter( iters, startSeg, endSeg ) end DelBands( ) return changeSucceeded end function PickMoverBands( idx ) if idx == nil then idx = randomMovableSeg( ) end local iters = QUICKWIGGLE_ITERS local strength = BAND_STRENGTH_REGION local bisLen = BIS_LENGTH local startSeg, endSeg = GetRegionForOperation( idx ) if endSeg - startSeg <= 1 then return false end -- something's very wrong changeSucceeded = PutMoverBands( startSeg, endSeg, bisLen, strength ) if changeSucceeded then -- must keep wiggler in-house, lowci isn't useful RegionWiggleBeforeAndAfter( iters, startSeg, endSeg ) end DelBands( ) return changeSucceeded end function PickFlexerBands( idx ) if idx == nil then idx = randomMovableSeg( ) end local iters = QUICKWIGGLE_ITERS local strength = BAND_STRENGTH_REGION local bisLen = BIS_LENGTH local startSeg, endSeg = GetRegionForOperation( idx ) if endSeg - startSeg <= 1 then return false end -- something's very wrong changeSucceeded = PutFlexerBands( startSeg, endSeg, bisLen, strength ) if changeSucceeded then -- must keep wiggler in-house, lowci isn't useful RegionWiggleBeforeAndAfter( iters, startSeg, endSeg ) end DelBands( ) -- only relevant if PutFlexerBands failed return changeSucceeded end function PickSheetStraightenerBands( idx ) if idx == nil then idx = randomMovableSeg( ) end local strength = BAND_STRENGTH_REGION local startSeg, endSeg = GetRegionForOperation( idx ) if endSeg - startSeg <= 1 then return false end -- something's very wrong return PutSheetStraightenerBands( startSeg, endSeg, strength ) end function PickHelixUniformBands( idx ) if idx == nil then idx = randomMovableSeg( ) end local strength = BAND_STRENGTH_REGION local startSeg, endSeg = GetRegionForOperation( idx ) if endSeg - startSeg <= 1 then return false end -- something's very wrong local regionLength = endSeg - startSeg + 1 local hShift = 4 if random( ) < 0.25 then hShift = math.min( regionLength - 2, randomDice( 4, 1, 2 ) ) -- a number 4 - 8, preferring 6ish end if startSeg < idx - 2 then startSeg = idx - random( 0, 2 ) end if endSeg > idx + 2 then endSeg = idx + random( 0, 2 ) end return PutHelixUniformDistanceBands( startSeg, endSeg, hShift, strength ) end function PickHelixCompressorBands( idx ) if idx == nil then idx = randomMovableSeg( ) end local strength = BAND_STRENGTH_REGION local hComp = random( BAND_MINCOMPRESS, BAND_MAXEXPAND ) local startSeg, endSeg = GetRegionForOperation( idx ) if endSeg - startSeg <= 1 then return false end -- something's very wrong local regionLength = endSeg - startSeg + 1 local hShift = 4 if random( ) < 0.25 then hShift = math.min(regionLength - 2, randomDice(4, 1, 2)) -- a number 4 - 8, preferring 6ish end return PutHelixCompressorBands( startSeg, endSeg, hShift, strength, hComp ) end function PickHelixFixerBands( idx ) if idx == nil then idx = randomMovableSeg( ) end local strength = BAND_STRENGTH_REGION local do4 = random( ) < 0.5 local do5 = random( ) < 0.5 local startSeg, endSeg = GetRegionForOperation( idx ) if endSeg - startSeg <= 1 then return false end -- something's very wrong return PutHelixFixerBands( startSeg, endSeg, strength, do4, do5 ) end function PickSheetSewerAction( ) local maxSheetDistance = random( 4.0, 12.0, true ) -- default choice was 8.0 local strength = BAND_STRENGTH_DEFAULT return PutSheetSewerBandsAllOver( maxSheetDistance, strength ) end function PickMultiBander( ) local strength = random( 0, maxStrength, true ) + 0.001 local ctBandsToMake = randomDice(3, 1, 4) -- at least 3, maybe as many as 12 local bandCt = 0 print( "MultiBander with bands="..ctBandsToMake ) while bandCt < ctBandsToMake do local which = random( 2 ) if which == 1 then local seg = randomUnlockedSeg( ) local maxRho = 1.0 if PutBandInSpace( seg, maxRho, strength ) then changeSucceeded = true bandCt = bandCt + 1 end else local idx = randomUnlockedSeg( ) local atom = PickAtomNumberForBand( idx ) if PutBandToRandomSeg( idx, strength, atom ) then bandCt = bandCt + 1 end end end return changeSucceeded end function PickCentralBander( ) local strength = BAND_STRENGTH_DEFAULT local maxCenters = randomDice( 2, 1, 3) changeSucceeded = false local coreSegs = {} getCentralHydrophobics( coreSegs, maxCenters) local compression = randomDice( 2, BAND_MINCOMPRESS/2, BAND_MAXEXPAND/2 ) local skipCt = random(4, 10) local startOffset = random(1, skipCt) return PutCoreCompressBands( coreSegs, skipCt, startOffset, strength, compression, random( )<0.5, random( )<0.5 ) end function PickCoreStirrer( ) -- not well suited to a lowCI situation local iters = QUICKWIGGLE_ITERS changeSucceeded = false local coreSegs = {} getCentralHydrophobics( coreSegs, math.floor(segCt / 8) ) -- for a 100-seg protein, this is about 13 -- perform an expansion local maxCenters = randomDice( 3, 1, 3 ) -- range 3 to 9, prefers 5-7 local thisCore = {} local expansion = random( 1.00, BAND_MAXEXPAND ) local strength = BAND_STRENGTH_DEFAULT local skipCt = random( 3, 13 ) local startOffset = random( 1, skipCt ) local pullPhilics = random( ) < 0.5 local doSidechains = random( ) < 0.5 getCentralHydrophobics( thisCore, maxCenters ) changeSucceeded = PutCoreCompressBands( thisCore, skipCt, startOffset, strength, expansion, pullPhilics, doSidechains ) if not changeSucceeded then return false end print( "BandedWiggleUntilEnoughChange" ) -- needs to keep its wiggler in-house BandedWiggleUntilEnoughChange( iters, getQuickScore( ) / 40.0, COREPULLING_CI ) DelBands( ) -- -- jiggle a bunch of rotamers, chosen from phobics "near" the center. -- local ctFlips = 0 for i=1, #coreSegs do local ctRots = rotamer.GetCount( coreSegs[ i ] ) if ctRots > 1 then rotamer.SetRotamer( coreSegs[ i ], random( ctRots ) ) end end qStabWiggle( iters, true ) -- complete action of SimpleBandedWiggleWrapper now! return true end function PickEveryXToEveryYBanding( ) local Xinterval = random( math.floor( segCt / 12), math.floor( segCt / 4 ) ) local Yinterval = random( 2 + Xinterval, 2 + math.floor( segCt / 4 ) ) local Xinit = random( 2*Xinterval ) local Yinit = random( 2*Yinterval ) local strength = random( 0.01, BAND_STRENGTH_DEFAULT, true ) local compression = random( BAND_MINCOMPRESS, BAND_MAXEXPAND, true ) return PutBandsEveryXToEveryY( Xinterval , Xinit, Yinterval, Yinit, strength, compression ) end function PickGentleCompBander( ) local minLength = random( 9.0, 16.0, true ) -- 10 and 14 seen in scripts local maxLength = random( 18.0, 32.0, true ) -- 20 and 30 seen in scripts; tempting to do ~2*minLength local minSeparation = random( 4, 12 ) -- 5 and 10 seen in scripts local compression = random( BAND_MINCOMPRESS, 0.90, true ) -- 0.70 seen in scripts local bandsWanted = randomDice( 3, 2, 5 ) -- usually tunable; 7-9 for standalone is typical; 3-5 when added local strength = random( 0.50, 1.50) * BAND_STRENGTH_DEFAULT return PutGentleCompBands( bandsWanted, minLength, maxLength, minSeparation, strength, compression ) end function PickLSQuaker( ) local idx = randomSeg( ) -- we don't care if it's movable local wantFreeze = random( ) < 0.50 local ctBands = randomDice( 2, 2, 4 ) -- was 6 local strength = BAND_STRENGTH_DEFAULT local compression = random( BAND_MINCOMPRESS, BAND_MAXEXPAND ) -- not present before. strength was tuned ResetFrozenness( ) local startIdx, endIdx = GetRegionForOperation( idx ) print( "LS:PutManyBandsToSeg over range "..startIdx..", "..endIdx ) for i=startIdx, endIdx do local changeSuc = PutManyBandsToSeg( i, ctBands, strength, compression, true) changeSucceeded = changeSucceeded or changeSuc end if changeSucceeded then if wantFreeze then selection.DeselectAll( ) selection.SelectRange( startIdx, endIdx ) ChangedFrozenness = true freeze.FreezeSelected( true, true ) selection.DeselectAll( ) end end return changeSucceeded end function PickSingleContactMapBand( idx ) if idx == nil then idx = randomContactableSeg( ) end print( "PickSingleContactMapBand at ".. idx ) changeSucceeded = false local heatThreshold = CONTACTMAP_THRESHOLD local strength = 1.5 * BAND_STRENGTH_DEFAULT return PutSomeContactMapBands( heatThreshold, strength, 1, random( ) < 0.50 ) end function PickSomeContactMapBands( ) print( "PickSomeContactMapBands" ) changeSucceeded = false local heatThreshold = CONTACTMAP_THRESHOLD local strength = BAND_STRENGTH_DEFAULT local ctWanted = random( 5, 10 ) return PutSomeContactMapBands( heatThreshold, strength, ctWanted, random( ) < 0.50 ) end function PickContactMapBandsForSeg( idx ) if idx == nil then idx = randomContactableSeg( ) end changeSucceeded = false local heatThreshold = CONTACTMAP_THRESHOLD local strength = BAND_STRENGTH_DEFAULT local doSidechain = false if BAND_TO_SIDECHAINS then doSidechain = random( ) < 0.50 end return PutAllContactMapBandsToSeg( idx, heatThreshold, strength, true, doSidechain ) end function PickCMTwoRegionBander( idx1 ) if idx1 == nil then idx1 = randomContactableSeg( ) end local strength = BAND_STRENGTH_DEFAULT local heatThreshold = CONTACTMAP_THRESHOLD local startIdx1, endIdx1 = GetRegionStartAndEnd( idx1 ) if startIdx1 == 1 and endIdx1 == segCt then return false end -- we just can't deal with this local idx2 = startIdx1 local tryCount = 0 while idx2 >= startIdx1 and idx2 <= endIdx1 and tryCount < 50 do for i=startIdx1, endIdx1 do idx2 = randomContactSeg( i, CONTACTMAP_THRESHOLD ) if idx2 ~= 0 and (idx2 < startIdx1 or idx2 > endIdx1) then break end -- got one end tryCount = tryCount + 1 end if idx2 == 0 then return false end -- we have failed if tryCount == 50 then return false end local startIdx2, endIdx2 = GetRegionStartAndEnd( idx2 ) return PutContactMapBandsBetweenRegions( heatThreshold, startIdx1, endIdx1, startIdx2, endIdx2, strength, true, random( ) < 0.50, random( ) < 0.50 ) end function PickContactMapper( ) local threshold = CONTACTMAP_THRESHOLD local madeStrength = random( 0.96, 1.04, true ) * CONTACTMAP_CONTACTING_STRENGTH local madeLenScale = random( 0.96, 1.04, true ) * CONTACTMAP_CONTACTING_GOAL local unmadeStrength = random( 0.96, 1.04, true ) * CONTACTMAP_NONCONTACTING_STRENGTH local unmadeLenScale = random( 0.96, 1.04, true ) * CONTACTMAP_NONCONTACTING_GOAL local doSidechains = BAND_TO_SIDECHAINS and random( ) < 0.50 local wantDither = random( ) < 0.50 return PutAllContactMapBands( threshold, madeStrength, madeLenScale, unmadeStrength, unmadeLenScale, doSidechains, wantDither ) end function PickPushPullContactMapAction( badSeg ) if badSeg == nil then badSeg = randomContactableSeg( ) end local segList = {} local wantPushNotPull = random( ) < 0.50 local ctBands = 5 local strength = BAND_STRENGTH_DEFAULT getCMSegsOutsideSphere( segList, badSeg, 8, CONTACTMAP_THRESHOLD ) if #segList == 0 then -- nothing we can do! print( " PushPull failed due to lack of distant 'center' segs" ) return false end centerSeg = segList[ random( #segList ) ] return PutPushPullContactMapBands( badSeg, ctBands, centerSeg, strength, CONTACTMAP_THRESHOLD, wantPushNotPull ) end function PickVoidCrusherContactMapAction( idx ) if idx == nil then idx = randomContactableSeg( ) end local strength = BAND_STRENGTH_DEFAULT return PutVoidCrusherContactMapBands( idx, strength, CONTACTMAP_THRESHOLD ) end function PickCoreCompression( compression ) local thisCore = {} local maxCenters = randomDice( 3, 1, 3 ) -- range 3 to 9, prefers 5-7 local strength = BAND_STRENGTH_DEFAULT local skipCt = random( 3, 13 ) local startOffset = random( 1, skipCt ) local pullPhilics = random( ) < 0.5 local doSidechains = false if BAND_TO_SIDECHAINS then doSidechains = random( ) < 0.50 end getCentralHydrophobics( thisCore, maxCenters) return PutCoreCompressBands( thisCore, skipCt, startOffset, strength, compression, pullPhilics, doSidechains ) end function PickCoreSpreader( ) local iters = QUICKWIGGLE_ITERS local maxBWigTries = 5 changeSucceeded = false compression = random( 1.05, BAND_MAXEXPAND ) local coreSegs = { } getCentralHydrophobics( coreSegs, math.floor(segCt / 8) ) -- for a 100-seg protein, this is about 13 changeSucceeded = PickCoreCompression( compression ) if changeSucceeded then BandedWiggleUntilEnoughChange( iters, BANDEDWIGGLE_TARGET, COREPULLING_CI ) end DelBands( ) return true end function PickStirThenContactMap( ) PickCoreSpreader( ) return PickContactMapper( ) end function PickLocalQuake( idx ) if idx == nil then idx = randomUnlockedSeg( ) end print( "LocalQuake at".. idx ) local iters = QUICKWIGGLE_ITERS local ctBands = randomDice( 2, 2, 4 ) -- was 6 local compression = random( BAND_MINCOMPRESS, BAND_MAXEXPAND ) local strength = BAND_STRENGTH_DEFAULT save.Quicksave( QS_ShortUseTemp1 ) local bestScore = getQuickScore( ) changeSucceeded = false local changeSuc = false local lqIdx = idx for i=1, 10 do save.Quickload( QS_ShortUseTemp1 ) local currScore = getQuickScore( ) DelBands( ) changeSuc = PutManyBandsToSeg( lqIdx, ctBands, strength, compression, true ) if changeSuc then idx2 = math.min( segCt, lqIdx + 3 ) changeSuc = PutManyBandsToSeg( idx2, ctBands, strength, compression, true ) end if changeSuc then if USE_LOWCI_WIGGLES then VerySimpleWiggleBeforeAndAfter( iters ) else SimpleBandedWiggleWrapper( iters, BANDEDWIGGLE_TARGET, COREPULLING_CI ) end newScore = getQuickScore( ) if newScore > currScore then save.Quicksave( QS_ShortUseTemp1 ) end changeSucceeded = true -- we only have to succeed once to count as a success end lqIdx = segCt - 2 while lqIdx > segCt - 3 do lqIdx = randomSeg( ) end end save.Quickload( QS_ShortUseTemp1 ) DelBands( ) return changeSucceeded end function PickMutatorAlgorithm( idx ) if idx == nil then idx = randomMovableSeg( ) end -- better would be random mutable seg print( "SpotMutator for segment " .. idx ) r = random( ) if r < PROB_MUTATESIMILAR then return MutateToSimilar( idx ) else return MutateToAny( idx ) end end -------------------------------------------------------------------------- -- SETUP and CLEANUP -------------------------------------------------------------------------- function CleanPuzzleState( ) ExactSetCI( InitialClashImportance ) selection.DeselectAll( ) ResetFrozenness( ) ResetCuts( ) DelBands( ) ResetSecondaryStructures( 1, segCt ) end function PrintState( ) local gain = getScore( ) - InitialScore if gain < 0.001 then print( " No change" ) else print( " Startscore: "..TrimNum( InitialScore )) print( " Score: "..TrimNum( getScore( ) )) print( " Total gain: "..TrimNum( gain ) ) end print( " Run time: "..os.time( ) - StartTime ) end function End( errstr ) if EndCalled then return end -- no infinite recursion please EndCalled = true print( "" ) if errstr ~= nil then if string.find( errstr, "Cancelled" ) then print( "User cancel" ) else print( errstr ) end end PrintState( ) if SHOW_STATS_REPORT then print("") ReportStats( ) print( "TotalShakeTime="..TotalShakeTime ) -- because I want to know. end if KILLING_FILTERS then ResetSlowFilterState( ) end if RESTORE_BEST_AT_END then LoadBest( ) end if PERFORM_CLEANUP_AT_END then CleanPuzzleState( ) end end function InitializePuzzleState( ) seedRandom( ) InitialScore = getScore( ) CurrentBestScore = InitialScore CurrentBestCmScore = InitialScore save.Quicksave( QS_Start ) save.Quicksave( QS_CmBest ) save.Quicksave( QS_Best ) StartTime = os.time( ) -- learn a few things InitialClashImportance = behavior.GetClashImportance( ) SCALE_MAXCI = InitialClashImportance PuzzleAllowsMutate = IsPuzzleMutable( ) if PuzzleAllowsMutate then PuzzleIsDesigner = checkAla( ) end PuzzleUsesFilters = CheckForSlowFilters( ) KILLING_FILTERS = false -- PuzzleUsesFilters CheckForContactMap( ) if PuzzleHasContactMap then InitializeContactMapSegList( CONTACTMAP_THRESHOLD ) end CurrentBestCmTotal = GetContactScore( ) -- has to wait until after InitializeContactMapSegList StoreSecondaryStructure( ) SaveFrozenness( ) FindAllMovableSegs( ) getHelices( ) getSheets( ) getLoops( ) DelBands( ) selection.DeselectAll( ) recentbest.Save( ) -- do this after DelBands end -------------------------------------------------------------------------- -- MAIN -------------------------------------------------------------------------- function main( ) InitializePuzzleState() didSomething = false print( "Start is in qs="..QS_Start.."; Best is in "..QS_Best.."; CM-best is in "..QS_CmBest ) ------------------------DEBUG STUFF -- if any actions could stand some debugging, put them here -- then multi-line comment from below to end of function ------------------------ while LetUserChooseParams( ) do if KILLING_FILTERS then TurnOffSlowFilters( ) end PerformOperation( OperationChosen ) didSomething = true LoadBest( ) PrintState( ) end print( " Done!" ) if didSomething then End( ) end end xpcall( main, End )

Comments