Icon representing a recipe

Recipe: Simulated Annealing 5.0

created by KarenCH

Profile


Name
Simulated Annealing 5.0
ID
104020
Shared with
Public
Parent
None
Children
Created on
September 29, 2020 at 21:50 PM UTC
Updated on
September 29, 2020 at 21:50 PM UTC
Description

Very fancy script that tries to "solve poses" - give it a plausible starting pose, it will improve it to a good end result.

Best for


Code


-------------------------------------------------------------------- -- Code for Simulated Annealing Recipe -------------------------------------------------------------------- -- 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. -- -- TODO: -- 1. Future exploration/pose generation round - add a helixifier, -- make a workable tailwhip. Create a cysteine guesser. Use the -- sheet actions. Make a sheet flipper. Other actions: if two -- non-tiny sheets are separated by 2-3 segs, create a tight turn -- between them. -- After an exploration set of actions, see if Stabilizer rounds -- can sort out which poses are best. Use the multitry system to -- do a run of actions + Stabilizer, saving in quickslots and -- transferring best to qs 3/4-8. -- 2. Replace XToY bands in Idealize, Rebuild, Remix actions with -- something more local: fewer total bands, and only between -- sufficiently "nearby" segs. -- -- BUGFIX: I think sheet actions are sometimes miscalculating alignment by 1. -- Still gives a good action, but align/shift are opposite... -- 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, QuakingRebuild -- (MurloW, drjr) Idealize by 3+ -- (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 -- (tlaloc, rav3n_pl, Seagat2011, thom001) ST - Glycine Hinge REPOST -- (drjr) drjr - RandomizeR 1.20, Idealize by 3 -- (brow42) Bridge Wiggle -- SheetAtomBander 1.0 -- SheetStraightener -- (BitSpawn) Rebuilds, GentleComp actions, general "how to do low CI" -- (robgee) multibander actions -- (LociOiling) how-to for filters, dialogs, error messages, Ident, etc -- (Bruno Kestemont) IdentPuzzleType (aka puzzleprop) -- (Steven Pletch et al) AcidTweaker -- (TvdL) deep rebuild and remix actions -------------------------------------------------------------------------------- Recipe = "Simulated Annealing" Version = "5.0" ReVersion = Recipe .. " v" .. Version ---------------------------------------------------------------------- -- ---- SIMULATED-ANNEALING-SPECIFIC STUFF -- ---------------------------------------------------------------------- -- SAStab combines STAB1&2, SAEarly combines EARLY1&2, SARebuild combines REBUILD&2. -- Temperature functions: -- Choices in order of activity level: "OneOverX" "MiddlingX" "LowX" "ColdX" "ZeroX" -- basic info for various stages SA_STEPSPERRUN_STAB1 = 12 SA_NUMSTARTS_STAB1 = 10 TEMPFUNCNAME_STAB1 = "OneOverX" SA_FAILIFNOGAIN_STAB1 = 10 WIGGLEPOWER_STAB1 = 'l' SA_STEPSPERRUN_STAB2 = 12 SA_NUMSTARTS_STAB2 = 30 TEMPFUNCNAME_STAB2 = "OneOverX" SA_FAILIFNOGAIN_STAB2 = 15 WIGGLEPOWER_STAB2 = 'l' SA_STEPSPERRUN_EARLY1 = 12 SA_NUMSTARTS_EARLY1 = 150 TEMPFUNCNAME_EARLY1 = "OneOverX" SA_FAILIFNOGAIN_EARLY1 = 15 WIGGLEPOWER_EARLY1 = 'a' MIN_TRIES_EARLY_OP = 3 -- minumum number of revisits for Early MAX_TRIES_EARLY_OP = 5 -- maximum number of revisits for Early PROB_QSTAB_EXTRA_EARLY1 = 0.5 -- affects whether MOVER actions get qstab fusing SA_STEPSPERRUN_EARLY2 = 12 SA_NUMSTARTS_EARLY2 = 80 TEMPFUNCNAME_EARLY2 = "MiddlingX" SA_FAILIFNOGAIN_EARLY2 = 12 WIGGLEPOWER_EARLY2 = 'a' PROB_QSTAB_EXTRA_EARLY2 = 1.0 -- probably never used! SA_STEPSPERRUN_REBUILD = 15 SA_NUMSTARTS_REBUILD = 80 TEMPFUNCNAME_REBUILD = "MiddlingX" SA_FAILIFNOGAIN_REBUILD = 20 WIGGLEPOWER_REBUILD = 'a' SA_STEPSPERRUN_DEEPREBUILD = 15 SA_NUMSTARTS_DEEPREBUILD = 40 TEMPFUNCNAME_DEEPREBUILD = "MiddlingX" SA_FAILIFNOGAIN_DEEPREBUILD = 10 WIGGLEPOWER_DEEPREBUILD = 'a' SA_STEPSPERRUN_MIDGAME = 12 SA_NUMSTARTS_MIDGAME = 80 TEMPFUNCNAME_MIDGAME = "OneOverX" SA_FAILIFNOGAIN_MIDGAME = 20 WIGGLEPOWER_MIDGAME = 'a' -- ENDGAME does not currently use SA strategy, it uses WALKER. However, just in case -- SA is brought back, the constants last used are provided here. SA_STEPSPERRUN_ENDGAME = 12 SA_NUMSTARTS_ENDGAME = 100 TEMPFUNCNAME_ENDGAME = "ColdX" SA_FAILIFNOGAIN_ENDGAME = 20 MIN_TRIES_ENDGAME = 4 MAX_TRIES_ENDGAME = 12 MIN_GAIN_ENDGAME = 5.0 -- ENDGAME chooses between high and medium wiggle power because high is not always available -- controllers for actions within SASequence option SASEQ_SKIP_STABILIZER = false SASEQ_SKIP_BASICREBUILD = false SASEQ_SKIP_DEEPREBUILD = false SASEQ_SKIP_ENDGAME = true SASEQ_ENDGAME_SKIP_CW = false SASEQ_DISABLE_UBAND_AFTER_STAB = false SASEQ_DISABLE_UBAND_AFTER_EARLY= false DISABLE_ALL_USER_BANDS = false -- actions to perform between or in deciding upon Operations (as 1st Early and later ones) INH_EXH_FOR_CRUSH_ATTEMPT = 5 -- Count of Inhale+Exhale to count as a mid-op crush action. DECEMENT_MIN_GAIN_EARLY = 5.0 -- gain needed for another Early pass after MIN is reached -- De-cement or terminate an operation that's having inadequate gains. FIGHT_CEMENTING_EARLY1 = true -- sets FIGHT_CEMENTING for Early1 FIGHT_CEMENTING_EARLY2 = false -- sets FIGHT_CEMENTING for Early2 SA_STEPSPERRUN_DECEMENT = 15 -- runs with de-cementer actions at start need more time to recover FailsToStartCementBreaking = SA_FAILIFNOGAIN_EARLY1 - 5 -- how many fails before we start fighting StepsForCementBreaking = 5 -- how many initial steps in a run should be cementbreakers SA_MINGAIN = 0.5 -- gain that must be exceeded to not count as a fail -- NON-USER-CONTROLLED parameters in cementing-related actions EXPAND_BEFORE_ACTION = false -- whether PickActionFromList should pre-expand. SA_FAILIFNOGAIN_DEFAULT = 10 -- the default choice for failing if a run has too small gain FIGHT_CEMENTING_DEFAULT = false -- the default choice for FIGHT_CEMENTING FIGHT_CEMENTING = false -- OPERATION controls: Early* or LowCI might change this PossibleCementingState = false -- PerformSA() controls: Sets when fails >= FailsToStartCementBreaking WorthTryingCementBreaker = false -- SA() controls: sets during StepsForCementBreaking of a run CountFails = {} -- PerformSA() stat tracker --------------- Walker constants --------------- ACTION_ORDERPROTOCOL_START_TO_END = 1 ACTION_ORDERPROTOCOL_END_TO_START = 2 ACTION_ORDERPROTOCOL_RANDOMIZE = 3 ACTION_ORDERPROTOCOL_WORST_TO_BEST = 4 MinIdxGainToRepeat = 0.5 ------------ Useful "special" kinds of run ------------ -- The LunchBuffet SA_STEPSPERRUN_BUFFET = 12 SA_NUMSTARTS_BUFFET = 60 TEMPFUNCNAME_BUFFET = "MiddlingX" PROB_TARGETED_BUFFET = 0.0 DO_WALKER_BUFFET = false ACTION_ORDERPROTOCOL_BUFFET = ACTION_ORDERPROTOCOL_START_TO_END LunchBuffetActions = {} -- Stores list of actions user chose -- Test runs SA_STEPSPERRUN_TEST = 12 SA_NUMSTARTS_TEST = 60 TEMPFUNCNAME_TEST = "MiddlingX" PROB_TARGETED_TEST = 0.0 --------------- Actions --------------- ACTION_TYPE_BANDER = 1 ACTION_TYPE_QUAKER = 2 ACTION_TYPE_REBUILD = 3 ACTION_TYPE_REMIXIDEAL = 4 ACTION_TYPE_CONTACTMAP = 5 ACTION_TYPE_ENDGAME = 6 ACTION_TYPE_DUBIOUS = 7 AllActionsList = { -- Filled by GenerateAllActionsList nameStr = "", actionFunc = nil, testFunc = nil, usesIdx = false, actionType = ACTION_TYPE_BANDER } ------------ LESS INTERESTING SA STUFF ------------ -- in case I ever want to overrule belief that some actions are too -- slow for normal use (actions generally permitted for small puzzles): ALLOW_SLOW_ACTIONS_DEFAULT = false ALLOW_SLOW_ACTIONS = false -- some defaults ALLOW_EXPAND_FOR_ACTION = false PROB_USE_EXPANDER = 0.00 PROB_USE_EXPANDER_DEFAULT = 0.00 -- constants for weird SA operations SA_STEPSPERRUN_LOW20 = 15 -- CI <= 0.20 -- first half of "LowCI" SA_NUMSTARTS_LOW20 = 100 TEMPFUNCNAME_LOW20 = "OneOverX" SA_STEPSPERRUN_LOW50 = 15 -- CI <= 0.50 -- second half of "LowCI" SA_NUMSTARTS_LOW50 = 100 TEMPFUNCNAME_LOW50 = "OneOverX" FIGHT_CEMENTING_LOWCI = true SA_STEPSPERRUN_CMAP = 15 -- special Contact map operations SA_NUMSTARTS_CMAP = 100 TEMPFUNCNAME_CMAP = "OneOverX" SA_STEPSPERRUN_LATE = 300 -- Does fuse. not useful at auto or high, maybe at medium? SA_NUMSTARTS_LATE = 1 TEMPFUNCNAME_LATE = "ZeroX" -- For neighbor generation (if "change" is less than this, we think action failed) THRESHOLD_PROTEIN_CHANGED = 0.1 -- when to bail if a protein is mostly locked and therefore rebuilds always fail MAX_REBUILD_FAILS = 20 CtRebuildFails = 0 -- Operation fails if MAX_REBUILD_FAILS reached. -- values for controlling behavior of fusing during Late stage ALLOW_FUSE = false -- true for "SALate" FUSEWIGGLE_ITERS = 2 FUSEWIGGLE_GAIN = 0.10 PROB_FUSEWIGGLE_CUTFUSE = 0.70 PROB_FUSEWIGGLE_LOCAL = 0.00 -- very slow, very poor success rate PROB_FUSEWIGGLE_BLUEFUSE = 0.30 -------------------------------------------------------- -- Options that exist but appear to give no benefit -------------------------------------------------------- -- How often should we target good/bad indices? It seems this is not worthwhile. PROB_TARGETED = 0.00 PROB_TARGETED_DEFAULT = 0.00 PROB_TARGETED_STAB2 = 0.00 PROB_TARGETED_EARLY1 = 0.00 PROB_TARGETED_EARLY2 = 0.00 PROB_TARGETED_REBUILD = 0.00 PROB_TARGETED_DEEPREBUILD = 0.00 PROB_TARGETED_MID = 0.00 -- Fancy Targeting games (not really useful, but ... maybe someday) PROB_TARGETED_WANTS_WINNER = 0.75 -- how often to seek recently-good indices (instead of low-scorers)? PROB_WINNER_WANTS_NEIGHBOR = 0.00 -- if picking winner, do we actually want one of its neighbors? WINNER_CLOCK_TIMEOUT = 20 -- when to take an index off the RecentWinners list WINNER_INDEX_MAX_RADIUS = 7.0 -- far enough to find non-adjacent aas that happen to be near RecentWinners = { {idx=0, clock=0} } -- probably RecentWinners needs to track the algorithm that got a win as well -- but mostly I expect it's just not worth the effort. -------------------------------------------------------- -- Specialty options for specific actions -------------------------------------------------------- BWP_PROB_ADD_SECOND_BAND = 0.25 -- do we want two bands instead of one? BWP_PROB_BIS_NOT_BETWEEN = 0.50 -- do we prefer BIS or bands between segs BWP_PROB_2ND_IS_BIS = 0.50 -- how often should 2nd band be BIS instead of between AT_SPHERE_RADIUS = 8 AT_MAXIMO = 10.0 AT_PROB_DO_REBUILD = 1.0 AT_PROB_PUT_FIX_BANDS = 0.5 AT_PROB_SPHERE_ADD_WORSTS = 0.5 -------------------------------------------------------- -- ---------------- BOILERPLATE --------------------- -- -------------------------------------------------------- ------------------------------------------------------------------------------------------------ -- Standard variables/constants used in my foldit scripts. Some are intended to be changed -- as part of setup of scripts, others are user settable, yet more are unlikely to be changed. -- A separate group, indicated as such, are genuinely intended as constants or as program- -- controlled variables. ------------------------------------------------------------------------------------------------ -- some oddballs that users might want to set DEBUGRUN = false SHOW_STATS_REPORT = true USENORMALSCORE = true -- exploration puzzles would set false -- what to do with user state (bands, cuts, filters) when running, and what cleanup is best at end PRESERVE_USER_BANDS = true -- all actions change if user wants this; dialog changes either way PRESERVE_USER_CUTS = false -- some actions change if user does want this RESTORE_BEST_AT_END = true PERFORM_CLEANUP_AT_END = true KILLING_FILTERS = false FORBID_WIGGLE_POWER_CHANGE = false -- values for controlling wiggles QUICKWIGGLE_ITERS = 2 QUICKWIGGLE_GAIN = 0.10 -- for iterative wiggles that happen in quickwiggle time PROB_LOCALWIGGLE = 1.00 -- I currently believe "before" wiggles should always prefer LocalWiggle over Wiggle. USE_LOWCI_WIGGLES = false -- set true by default in low-ci scripts MAX_FALL_FOR_SHAKEOUT = 1000.0 -- whether to bother to finish an action with a good wiggler -- values for controlling shaking SHAKESIDECHAIN_ITERS = 1 -- default time to use in shaking -- values for controlling mutating MUTATE_NOT_SHAKE = false -- "mutate never" vs "mutate always" (cf MUTATE_ONCE) in mutable puzzles. MUTATE_ONCE = false -- mutate only happens during first "real" shake/mutate action MUTATESIMILAR_PROB = 0.25 -- Only used if LunchBuffet "SpotMutator" is chosen -- cysteine bander constants CYSTEINE_PERFORM_BANDING = false -- whether to have special cysteine bands modifying actions CYSTEINE_BAND_STRENGTH = 5.0 -- >=9.0 is dicy; 8.0 is severe. 5.0 works fine CYSTEINE_MAX_RI_SEPARATION = 15.0 -- if more, then pose is nuts. fail the action that did this CYSTEINE_COUNT_BANDS_USED = 3 -- pick 1..4 or break your script (3 looks best) CYSTEINE_TOTAL_BANDS = 0 -- NOT user controlled CYSTEINE_GOT_MIXUP = false -- NOT user controlled -- bander options BAND_STRENGTH_DEFAULT = 1.0 BAND_STRENGTH_REGION = 1.0 BAND_MAXCOMPRESS = 0.80 BAND_MAXGENTLECOMPRESS = 0.90 BAND_MINCOMPRESS = 0.95 BAND_MINEXPAND = 1.05 BAND_MAXGENTLEEXPAND = 1.10 BAND_MAXEXPAND = 1.20 BANDEDWIGGLE_TARGET = 500.0 BAND_TO_SIDECHAINS = true ZLB_DEFAULT_STRENGTH = 2.0 XTOY_REBUILD_STRENGTH = 0.5 XTOY_REMIX_STRENGTH = 0.5 XTOY_IDEALIZE_STRENGTH = 1.5 BIS_LENGTH = 5.0 -- max length of a normal BIS BIS_LENGTH_LONG = 8.0 -- max length of a "long" BIS BIS_MIN_STRENGTH = 0.3 BIS_MAX_STRENGTH = 1.1 BIS_MIN_GOALLENGTH = 0.2 -- almost a ZLB BIS_MAX_GOALLENGTH = 6.9 -- qstab fusing options FORBID_ALL_QSTAB_FUSE = false PROB_QSTAB_EXTRA = 0.00 PROB_QSTAB_EXTRA_DEFAULT = 0.00 PROB_QSTAB_EXTRA_QUAKE = 0.50 -- Quakes and GentleComp* PROB_QSTAB_EXTRA_MOVERBANDS = 0.50 -- TEST: Mover,Flexer,Pusher,Helix*,Sheet*,*Hinge PROB_QSTAB_EXTRA_VOIDCRUSH = 0.25 -- TESTING: VoidCrusher, PushPull, TailGrab PROB_QSTAB_EXTRA_IDEALIZE = 1.00 -- Idealize* likes qstab fusing PROB_QSTAB_EXTRA_MULTIBAND = 0.00 -- Multi* doesn't benefit from qstab fusing -- values associated with idealize IDEALIZE_USE_CUTS = true IDEALIZE_FORBID_UNHEALED_CUTS = true IDEALIZE_ZLB_MAXTRIES = 5 -- fails if cuts not healed. up ZLBstrength, try again. IDEALIZE_TUBE_SMALL_RADIUS = 4.0 -- the idealizing range for IdealizeZlb and IdealizeRegion IDEALIZE_TUBE_BIG_RADIUS = 10.0 -- the idealizing range for IdealizeRegionXToY IDEALIZE_MIN_SEGLEN = 3 -- See GetIdealizeRange for how it's used IDEALIZE_MAX_SEGLEN = 5 -- See GetIdealizeRange for how it's used -- values associated with rebuild REBUILD_DEEP_MAXTRIES = 5 -- tries in a deep rebuild. also QuakingRebuild and RebuildBitspawn REBUILD_ADDIDEALIZE = true -- Rebuilds that want to also idealize will do so if this is true REBUILD_MIN_SEGLEN = 3 -- See GetRebuildRange for how it's used REBUILD_MAX_SEGLEN = 10 -- See GetRebuildRange for how it's used REBUILD_TUBE_SMALLEST_RADIUS = 9.0 -- quaking rebuild radius for shake/wiggle REBUILD_TUBE_INNER_RADIUS = 12.0 -- deep rebuild quick-check radius for shake/wiggle REBUILD_TUBE_OUTER_RADIUS = 18.0 -- deep rebuild serious radius for shake/wiggle -- values associated with remix REMIX_SLOTS_WANTED = 25 -- check REMIX_MAX_SLOTS_TO_USE before increasing! REMIX_MAX_SLOTS_TO_WIGGLE = 5 -- how many to give real wiggles to REMIX_ADDIDEALIZE = true -- RemixSimple will also idealize if this is true REMIX_MIN_SEGLEN = 4 -- See GetRemixRange for how it's used REMIX_MAX_SEGLEN = 8 -- See GetRemixRange for how it's used REMIX_TUBE_INNER_RADIUS = 9.0 -- for quicker wiggles REMIX_TUBE_OUTER_RADIUS = 12.0 -- for final check wiggles -- Clash Importance CI_MAXSCALE = 1.00 CI_REGIONMOD = 0.10 CI_MUTATE = 0.21 CI_MULTIBAND_SHAKE = 0.21 CI_COREPULLING = 0.70 CI_LOCALWIGGLER_SHAKE = 0.81 CI_MULTIBAND_PULL = 0.90 -- values for contact map actions CONTACTMAP_THRESHOLD = 0.25 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 CONTACTMAP_MAX_NOCONTACT = 10.0 -- longer means disbelieve it's a valid contact CONTACTMAP_BAND_ADD_RANDOMS = true -- whether to add random bands CONTACTMAP_RANDOMBAND_COUNT = 3 -- how many random bands to add CONTACTMAP_REBUILD_TUBE_INNER_RADIUS = 8.0 CONTACTMAP_REBUILD_TUBE_OUTER_RADIUS = 16.0 ---------------------------------------------------------------------------------- ---------------------------------------------------------------------------------- ------------ VALUES USERS SHOULD NOT BE TOUCHING --------------------------------- ---------------------------------------------------------------------------------- RandSeed = 0 -------------- CONSTANTS THAT PROBABLY SHOULD NEVER CHANGE -------------- -- atoms in an amino acid BETA_CARBON = 5 TERMINAL_BETA = 6 CENTER_CARBON = 2 --this is the default atom for bands to attach to AACount = 20 -- how many different AAs do we use? AAPhilCount = 9 -- how many AAs are hydrophilic? AAPhobCount = 11 -- how many AAs are hydrophobic? -- ideal distances HELIX_DISTANCE_SKIP4 = 6.3 -- for skips of 4 HELIX_DISTANCE_SKIP5 = 8.6 -- for skips of 5 DISTANCE_SHEET_TO_SHEET = 4.8 DISTANCE_HELIX_TO_THING = 8.2 DISTANCE_SHEET_SEG_TO_SEG = 6.8 DISTANCE_INSHEET_N_TO_NPLUS2 = 9.5 DISTANCE_CYSTEINE_BOND = 2.05 SCALE_CYSTEINE_OFF_1 = 1.8 DISTANCE_ARO_RING_TO_RING = 3.2 -- "only infrequently less than ~3.2A", sometimes as short as ~2.6 SHEET2SHEET_BONDING_BAND_LENGTH = 1.8 SHEET2SHEET_MAX_DIST_TO_BAND = 7.0 SHEET2SHEET_CENTER_BAND_LENGTH = 3.0 DISTANCE_AA_TO_AA = 3.5 -- QUICKSAVE slots used herein QS_Start = 1 QS_CmBest = 2 QS_Best = 3 QS_Alternate1 = 4 -- these are for scripts offering alternate poses. QS_Alternate2 = 5 QS_Alternate3 = 6 QS_Alternate4 = 7 QS_Alternate5 = 8 QS_SA_BestEarly = 4 QS_SA_BestRebuild = 5 QS_SA_BestMidgame = 6 QS_SA_BestEndgame = 7 -- a quickslot stack for any system that wants such (some rebuilder/remixer scripts want) QS_Base = 9 -- the base of a stack of slots to operate with QS_Top = QS_Base -- the current top of the stack QS_MAX = 24 -- the max top point for the stack -- A collection of slots dedicated to remix QS_RemixSlot1 = 25 -- lots and lots of remix slots. the more the merrier QS_RemixSlotLast = 74 REMIX_MAX_SLOTS_TO_USE = QS_RemixSlotLast - QS_RemixSlot1 + 1 -- A collection of slots dedicated to my multistart system QS_MultiStartSave1 = 75 -- surely nobody will multistart more than 15 times! QS_MultiStartSaveLast = 89 MULTISTART_MAX_SLOTS = QS_MultiStartSaveLast - QS_MultiStartSave1 + 1 -- following slots are intended for use by "actions". Use at will. QS_Swapslot = 91 -- used by quickslot swapping functions. generally usable. QS_Swapslot2 = 92 -- used by quickslot swapping functions. generally usable. QS_ShortUseTemp1 = 93 -- used by low-level actions that stash state for short time QS_ShortUseTemp2 = 94 -- used by low-level actions that stash state for short time -- following slots are not safe to borrow if MultiTry or SA are in play QS_NeighborTempM1 = 95 -- used by MultiTry's "Neighbor Generation" subroutines QS_TopLevelTempMT = 96 -- used by MultiTry top-level manager QS_TopLevelTempM2 = 97 -- used by MultiTry top-level manager QS_NeighborTempSA = 98 -- used by SA's "Neighbor Generation" subroutines QS_TopLevelTempSA = 99 -- used by SA top-level manager --------------- THINGS THE PROGRAM LEARNS AND REMEMBERS -------------- -- why yes, I do wish I knew what aas/atoms bands connect to as well InitialBandCount = 0 InitialBandStates = { {bIdx=0, isEnabled=false} } InitialClashImportance = behavior.GetClashImportance() IsFilterDisabled = behavior.GetFiltersDisabled( ) InitialWigglePower = behavior.GetWigglePower( ) SegCt = structure.GetCount( ) PuzzleAllowsMutate = false PuzzleHasLockedSegs = false PuzzleHasContactMap = false PuzzleUsesFilters = false PuzzleIsDesigner = false -- set but not used PuzzleIsSepsis = false -- set but not used PuzzleIsElectron = false -- set but not used PuzzleIsCentroid = false -- used by acid tweaker PuzzleIsSymmetry = false -- set but not used PuzzleSymmetryLevel = 1 -- set but not used StartTime = 0 InitialScore = 0.0 ContactMapScore = 0.0 HasContactMapSegList = {} InitialFrozenTable = {} -- weird globals controlled by program ChangedSecondaryStructure = false ChangedFrozenness = false EndCalled = false -- Usage of following tables: bounds = All*[i] use bounds.sIdx and bounds.eIdx AllHelices = { {sIdx = 0, eIdx = 0} } AllSheets = { {sIdx = 0, eIdx = 0} } AllLoops = { {sIdx = 0, eIdx = 0} } PossibleHelices = { {sIdx = 0, eIdx = 0} } CysteineBandPairCount = 0 CysteineAaSegList = {} CysteinePairList = {} NonLockedSegList = {} OriginalSecondaryStructures = {} MinUnlockedSeg = 1 MaxUnlockedSeg = SegCt -- this line must come after setter of SegCt NoMutateList = {} ShakeAfterMutateList = {} -- generated from NoMutateList, depending on options wanted by user AllowedActionIndices = {} ---------------- STATISTICS-TRACKING --------------------- AlgName = "none" -- for tracking statistics about how successful an action is AlgNameList = {} AlgStats = { name = "none", posScoreDelta = 0.0, scoreDelta = 0.0, runTime = 0, callCount = 0, failCount = 0, } TotalShakeTime = 0 TotalMutateTime = 0 ---------------------------------------------------------------- -- STRING FUNCTIONS ---------------------------------------------------------------- function DebugPrint( str ) if DEBUGRUN then print( str ) end end function BoolStr( bval ) if bval then return "true" end return "false" end function PadString( strIn, lenWanted ) local strOut = strIn while string.len( strOut ) < lenWanted do strOut = strOut .. " " end return strOut end function PadNumString( numIn, lenWanted ) local strOut = ""..numIn while string.len( strOut ) < lenWanted do strOut = strOut .. " " end return strOut end function TrimNum( val ) return val - val % 0.001 end function printVector( vec, prefix, isFloat ) if isFloat == nil then isFloat = false end local str="" for i=1, #vec do if isFloat then str = str..TrimNum(vec[i]) else str = str..vec[i] end if i < #vec then str = str.."," end end print(prefix.. ": "..str) end -- a function that parses a string of aa indices and returns them as a sorted array. function ParseAaString( str, AaArray ) -- fancy parsing here: Input format is: idx1,idx2-idx3,idx4,idx5,idx6-idx7,... for w in string.gmatch( str, "[^,]+" ) do if string.find( w, "-" ) ~= nil then local s, f = string.match( w, "(%d+)%-(%d+)" ) local start = tonumber( s ) local fin = tonumber( f ) for i=start,fin do local okToAdd = true for j=1,#AaArray do if AaArray[ j ] == i then okToAdd = false break end end if okToAdd then AaArray[ #AaArray+1] = i end end else local seg = tonumber( w ) local okToAdd = true for j=1,#AaArray do if AaArray[ j ] == seg then okToAdd = false break end end if okToAdd then AaArray[ #AaArray+1] = seg end end end if #AaArray > 0 then table.sort(AaArray) end end -- expect a string of form "3,6-12,18-22,33,56-59" function parseRangesStr( str ) local idxListOut = {} local loc = 1 local len = 0 local sep = "" local parseError = false local notDone = true while notDone do loc,len,v1 = string.find( str, "(%d+)", loc ) if loc == nil then notDone = false break end loc = len loc,len,sep = string.find( str, "([,;-])", loc ) if loc == nil then notDone = false idxListOut[#idxListOut+1] = v1+0 break -- must have been end of string elseif sep == '-' then loc = len loc,len,v2 = string.find( str, "(%d+)", loc ) if loc == nil then idxListOut = {} parseError = true notDone = false break end loc = len -- add range to list for i=v1+0, v2+0 do idxListOut[#idxListOut+1] = i end -- move past any following ',' or ';' loc,len,sep = string.find( str, "([,;])", loc ) if loc == nil then notDone = false break -- must have been end of string end loc = len else -- add single number to list idxListOut[#idxListOut+1] = v1+0 end if len == string.len( str ) then break end end return idxListOut end function parseCysteineStr( ctPairsWanted, str ) local cysList = {} -- v1, v2: '(%d+),(%d+)[; ]+' for v1 in string.gfind(str, '-?(%d+)') do v1 = tonumber( v1 ) if v1 < 1 or v1 > SegCt then return false end if structure.GetAminoAcid(v1) ~= 'c' then return false end cysList[#cysList+1] = v1 end if #cysList ~= 2*ctPairsWanted then return false end for i = 1, #cysList-1 do val = cysList[i] for j=i+1, #cysList do if cysList[j+1] == val then return false end end end -- ok, we believe the list is a correct number of distinct cysteines CysteinePairList = {} for i=1, ctPairsWanted do CysteinePairList[#CysteinePairList+1] = {cysList[2*i-1], cysList[2*i]} end end ---------------------------------------------------------------- -- IDENTIFICATION FUNCTIONS ---------------------------------------------------------------- function Ident( slugline ) local function round ( ii ) return ii - ii % 0.001 end print ( slugline ) print ( "Puzzle: " .. puzzle.GetName () .. " (" .. puzzle.GetPuzzleID () .. ")" ) print ( "Track: " .. ui.GetTrackName () ) local gname = user.GetGroupName() if gname ~= nil then gname = " (" .. gname .. ")" else gname = "" end print ( "User: " .. user.GetPlayerName () .. gname ) local scoretype = scoreboard.GetScoreType () local scort = "" if scoretype == 0 then scort = "soloist" elseif scoretype == 1 then scort = "evolver" elseif scoretype == 2 then scort = "all hands" elseif scoretype == 3 then scort = "no score" else scort = "unknown/error" end print ( "Rank: " .. scoreboard.GetRank ( scoretype ) .. " (" .. scort .. ")" ) local sGroup = scoreboard.GetGroupScore () if sGroup ~= nil then print ( "Group rank / score: " .. scoreboard.GetGroupRank () .. " / " .. round ( 10 * ( 800 - sGroup ) ) ) end print( "StartDate: "..os.date( ) ) end function IdentPuzzleType( ) -- originally named puzzleprop, by Bruno Kestemont. some mods local descrTxt = puzzle.GetDescription() local puzzletitle = puzzle.GetName() if #puzzletitle>0 then if (puzzletitle:find("Sym") or puzzletitle:find("Symmetry") or puzzletitle:find("Symmetric") or puzzletitle:find("Dimer") or puzzletitle:find("Trimer") or puzzletitle:find("Tetramer") or puzzletitle:find("Pentamer")) then PuzzleIsSymmetry=true if puzzletitle:find("Dimer") and not puzzletitle:find("Dimer of Dimers") then PuzzleSymmetryLevel=2 elseif puzzletitle:find("Trimer") or puzzletitle:find("Tetramer") then PuzzleSymmetryLevel=3 elseif puzzletitle:find("Dimer of Dimers") or puzzletitle:find("Tetramer") then PuzzleSymmetryLevel=4 elseif puzzletitle:find("Pentamer") then PuzzleSymmetryLevel=5 end end end if not PuzzleIsSymmetry then -- because sometimes the title doesn't tell us about symmetry, so try again here: if #descrTxt>0 and (descrTxt:find("Sym") or descrTxt:find("Symmetry") or descrTxt:find("Symmetric") or descrTxt:find("sym") or descrTxt:find("symmetry") or descrTxt:find("symmetric")) then PuzzleIsSymmetry=true if (descrTxt:find("Dimer") or descrTxt:find("dimer")) and not (descrTxt:find("Dimer of Dimers") or descrTxt:find("dimer of dimers")) then PuzzleSymmetryLevel=2 elseif descrTxt:find("Trimer") or descrTxt:find("trimer") then PuzzleSymmetryLevel=3 elseif (descrTxt:find("Dimer of Dimers") or descrTxt:find("Tetramer")) and not (descrTxt:find("dimer of dimers") or descrTxt:find("tetramer")) then PuzzleSymmetryLevel=4 elseif descrTxt:find("Pentamer") or descrTxt:find("pentamer") then PuzzleSymmetryLevel=5 end end end if #puzzletitle>0 and puzzletitle:find("Sepsis") then -- new BK 17/6/2013 PuzzleIsSepsis=true end if #puzzletitle>0 and puzzletitle:find("Electron Density") then -- for Electron Density PuzzleIsElectron=true end if #puzzletitle>0 and puzzletitle:find("Centroid") then -- New BK 20/10/2013 PuzzleIsCentroid=true end PuzzleAllowsMutate = isPuzzleMutable( ) if PuzzleAllowsMutate then PuzzleIsDesigner = checkDesigner( ) end PuzzleUsesFilters = CheckForFilters( ) if PuzzleUsesFilters then ReportFilters( ) end PuzzleHasContactMap = CheckForContactMap( ) if PuzzleHasContactMap then ContactMapScore = GetContactScore( ) InitializeContactMapSegList( CONTACTMAP_THRESHOLD ) end end ---------------------------------------------------------------- -- ACTION STATISTICS AND PREFERENCES ---------------------------------------------------------------- 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 = 1, gainCount = 0, failCount = 1, } return end AlgStats[ AlgName ].callCount = AlgStats[ AlgName ].callCount + 1 AlgStats[ AlgName ].failCount = AlgStats[ AlgName ].failCount + 1 end function sortStats(nameList, statsIn) table.sort(nameList, function(n1,n2) return statsIn[n1].posScoreDelta / statsIn[n1].runTime > statsIn[n2].posScoreDelta / statsIn[n2].runTime end ) end function reportStats( ) -- scoreDelta turns out to be not very interesting to look at sortStats( AlgNameList, AlgStats ) for i = 1, #AlgNameList do local t = AlgNameList[ i ] if AlgStats[ t ] ~= nil and AlgStats[ t ].callCount > 0 then print( " " .. PadString(t, 20) .. ":" .. " posScore=" .. TrimNum( AlgStats[ t ].posScoreDelta ) .. " tmPerRun=" .. TrimNum( AlgStats[ t ].runTime / AlgStats[t].callCount) .. " scPerTime=" .. TrimNum( AlgStats[ t ].posScoreDelta / AlgStats[ t ].runTime ) .. " runs=" .. AlgStats[ t ].callCount .. " gains=" .. AlgStats[ t ].gainCount .. " fails=" .. AlgStats[ t ].failCount ) else print("no info for "..t) end end print( "Time so far: "..(os.time() - StartTime) ) 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 ---------------------------------------------------------------- -- 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 TurnOnFilters( ) end local score=0.0 if not USENORMALSCORE then if wantRB then score = recentbest.GetEnergyScore( ) else score = current.GetEnergyScore( ) end if useFilter then score = score + filter.GetBonusTotal( ) end else if wantRB then score = recentbest.GetScore( ) else score=current.GetScore( ) end end if useFilter and KILLING_FILTERS then TurnOffFilters( ) end return score end function getScore( ) return internalGetScore( false, true ) end function getQuickScore( ) return internalGetScore( false, false ) end function getRBScore( ) return internalGetScore( true, true ) end function GetTotalSegScore( ) local total=0.0 for i=1, SegCt do total=total + current.GetSegmentEnergyScore(i) end return total end function getSlotScore( qs ) save.Quicksave( QS_Swapslot ) save.Quickload( qs ) local sc = getScore( ) save.Quickload( QS_Swapslot ) return sc end function SaveBest( forceBest, qs_best ) -- most callers will leave both as nil. if qs_best == nil then qs_best = QS_Best end if forceBest == nil then forceBest = false end local score = getScore( ) local currentBestScore = getSlotScore( qs_best ) -- use "score >=" because same-with-unfrozen/unbanded is better if forceBest or score >= currentBestScore then save.Quicksave( qs_best ) currentBestScore = score end if PuzzleHasContactMap then local currentBestCmScore = getSlotScore( QS_CmBest ) local cmScore = GetContactScore( ) if forceBest or (CONTACTMAP_TAKEDROPS and cmScore > currentBestCmScore) then save.Quicksave( QS_CmBest ) currentBestCmScore = score end if CONTACTMAP_TAKEDROPS and currentBestScore ~= currentBestCmScore then DebugPrint(" In Best("..qs_best.."): score="..currentBestScore ) DebugPrint(" In CmBest("..QS_CmBest.. "): score="..currentBestCmScore ) end end end function SaveBests( override, qs ) SaveBest( ) -- never allow an override for QS_Best if qs ~= nil and qs ~= QS_Best then SaveBest( override, qs ) end end function LoadBest( qs_best ) if qs_best == nil then qs_best = QS_Best end local currentBestScore = getSlotScore( qs_best ) if PuzzleHasContactMap and CONTACTMAP_TAKEDROPS and qs_best == QS_Best then local currentBestCmScore = getSlotScore( QS_CmBest ) if currentBestCmScore >= currentBestScore - CONTACTMAP_MAX_DROP then save.Quickload( QS_CmBest ) else save.Quickload( qs_best ) end else save.Quickload( qs_best ) end end function GetBestScore( ) local currentBestScore = getSlotScore( qs_best ) if PuzzleHasContactMap and CONTACTMAP_ALLOWDROP then local currentBestCmScore = getSlotScore( QS_CmBest ) if currentBestCmScore >= currentBestScore - CONTACTMAP_MAX_DROP then return currentBestCmScore else return currentBestScore end else return currentBestScore end end ---------------------------------------------------------------- -- RANDOM FUNCTIONS ---------------------------------------------------------------- -- Using the java LCG random generator function nextRand( ) -- keep 48 bits, so mod 2^48 RandSeed = (RandSeed * 0x5DEECE66D + 11) % 281474976710656 return RandSeed end function nextRandFloat01( ) local val = ( nextRand() + .0 ) / 100000000.0 local junk, valF = math.modf( val ) return valF end function nextRandIntRange( low, high ) if low == high then return low end local val = (high + 1 - low) * nextRandFloat01( ) val = low + math.floor( val ) return val end function seedRandom( ) -- If someone wants to control the random sequence, they can manually set -- RandSeed before run. Keep in mind that rebuild uses its own random, -- so there's only so deterministic the run will end up being! if RandSeed == 0 then -- 79 is a random prime to spread time values out. True to Java would use 0x5DEECE66D local seedI = os.time() * 79 local tmp = math.abs(getQuickScore( )) local junk, seedF = math.modf( tmp ) -- want fractional part of score local seed = math.floor( seedI * seedF) -- result: integer in [0..time*79) RandSeed = seed % 281474976710656 -- mod 2^48: java LCG uses 48 bits end DebugPrint( "Seed is: "..RandSeed ) 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 nextRandFloat01( ) 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 -- caveat caller: can't test for "forceFloat" return nextRandIntRange( 1, n1 ) --integer else return nextRandFloat01( ) * n1 end else if n1%1==0 and n2%1==0 and not forceFloat then --integer between return nextRandIntRange( n1, n2 ) else --float between return nextRandFloat01( ) * (n2 - n1) + n1 end end end end function randomBool( probTrue ) if probTrue == nil then probTrue = 0.5 end if probTrue == 0.0 then return false elseif probTrue == 1.0 then return true else return random() < probTrue end end function randomDice( ctDice, minValPerDie, maxValPerDie ) -- distro that prefers "middle" values local 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 local 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( ) if seg == nil then break end 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 SegIsUsable( idx ) -- if it's locked, then it's not usable local gotMatch = false for i = 1, #NonLockedSegList do if NonLockedSegList[ i ] == idx then gotMatch = true break end end if not gotMatch then return false end -- if it's frozen, then it's not usable for i=1, #NonLockedSegList do local bb, sc = freeze.IsFrozen( idx ) if bb then return false end end -- if we haven't made a restricted list, or if it's on that list, then it's usable if #AllowedActionIndices == 0 then return true end for i=1, #AllowedActionIndices do if AllowedActionIndices[ i ] == idx then return true end end return false -- not usable end function randomMovableFarSeg( segOrigin, minSep, minDist, maxDist ) local segList = {} for i=1, SegCt do if IsMovableSeg( i ) and (i <= segOrigin - minSep or i >= segOrigin + minSep ) then dist = structure.GetDistance( segOrigin, i ) if dist >= minDist and dist <= maxDist then segList[ #segList + 1 ] = i 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} local lastIdx = #primes for i=1, #primes do if primes[ i ] > max then break end lastIdx = i end return primes[ random( lastIdx ) ] end function getCoprime( 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 ---------------------------------------------------------------- -- SCORE-USING FUNCTIONS ---------------------------------------------------------------- function sortByScore(segs, scores) table.sort(segs, function(n1,n2) return scores[n1] < scores[n2] end) end function sortByScoreDecr(segs, scores) table.sort(segs, function(n1,n2) return scores[n1] > scores[n2] end) end 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 getEuclideanDistanceVector( scmat1, scmat2, vecOut ) 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 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 sortByScore( 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 sortByScoreDecr( idxList, scoreList ) 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 sortByScore( idxList, subscoreList ) end function GetWorstScoringRegions( idxList, len ) local 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 sortByScore( idxList, scoreList ) end ---------------------------------------------------------------- -- DISTANCE FUNCTIONS ---------------------------------------------------------------- function computeDistanceSums(distList) -- i-th entry is avg value of distances from every other aa to i-th aa. for i=1, SegCt do distList[i] = 0.0 end for i=1, SegCt-1 do for j=i+1, SegCt do local x = structure.GetDistance( i, j ) / SegCt distList[i] = distList[i] + x distList[j] = distList[j] + x end end end function getCentralAAs( idxList ) local distList = {} for i=1, SegCt do idxList[i] = i end computeDistanceSums( distList ) sortByScore( idxList, distList ) end function computeDistanceMatrix( distMat ) for i=1, SegCt do distMat[i] = {} end for i=1, SegCt-1 do for j=1, SegCt do distMat[i][j] = structure.GetDistance( i, j ) end end end function compareDistanceMatrices( mat1, mat2 ) for i=1, SegCt-1 do for j=i+1, SegCt do local val1 = mat1[ i ][ j ] local val2 = mat2[ i ][ j ] local diff = math.abs( val1 - val2 ) if diff > 2.5 then return false end end end return true 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 SelectSphere( centerIdx, radius ) for i=1, SegCt do if i == centerIdx then selection.Select( i ) elseif structure.GetDistance( centerIdx, i ) < radius then selection.Select( 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 -- produces a list of all AAs "near" the ones in a given inputList function getSegsNearListed( inputList, radius) local retval = {} for i=1, SegCt do for j=1, #inputList do if structure.GetDistance(i,j)<radius then retval[ #retval+1 ] = j break end end end return retval end function isLocalMinimum( segCenter, segCheck ) if segCheck == segCenter then return false end -- exclude selfies local ckDist = structure.GetDistance(segCenter, segCheck) if segCheck > 1 then local ckDist1 = structure.GetDistance( segCenter, segCheck - 1 ) if ckDist1 < ckDist then return false end if segCheck > 2 then local ckDist2 = structure.GetDistance( segCenter, segCheck - 2 ) if ckDist2 < ckDist then return false end end end if segCheck < SegCt then local ckDist1 = structure.GetDistance( segCenter, segCheck + 1 ) if ckDist1 < ckDist then return false end if segCheck < SegCt - 1 then local 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 local ckDist = structure.GetDistance(segCenter, segCheck) if segCheck > 1 then local ckDist1 = structure.GetDistance( segCenter, segCheck - 1 ) if ckDist1 > ckDist then return false end if segCheck > 2 then local ckDist2 = structure.GetDistance( segCenter, segCheck - 2 ) if ckDist2 > ckDist then return false end end end if segCheck < SegCt then local ckDist1 = structure.GetDistance( segCenter, segCheck + 1 ) if ckDist1 > ckDist then return false end if segCheck < SegCt - 1 then local ckDist2 = structure.GetDistance( segCenter, segCheck + 2 ) if ckDist2 > ckDist then return false end end end return true end function getNearestPhobicsOutsideRange( seg, segExcludeStart, segExcludeEnd, nearPhobics, ctWanted ) local idxListInternal = {} local distList = {} for i=1, SegCt do idxListInternal[ #idxListInternal + 1 ] = i end for i=1, segExcludeStart - 1 do if structure.IsHydrophobic( i ) then distList[ #distList + 1 ] = structure.GetDistance( seg, i ) else distList[ #distList + 1 ] = 1000 end end for i=segExcludeStart, segExcludeEnd do distList[ #distList + 1 ] = 10000 end for i=segExcludeEnd + 1, SegCt do if structure.IsHydrophobic( i ) then distList[ #distList + 1 ] = structure.GetDistance( seg, i ) else distList[ #distList + 1 ] = 1000 end end sortByScore( idxListInternal, distList ) for i=1, ctWanted do if i > #idxListInternal then break end nearPhobics[ #nearPhobics + 1 ] = idxListInternal[ i ] end end function getSegsNotInList( list ) table.sort( list ) local result={ } if #list > 0 then for j = 1, list[1]-1 do result[ #result+1 ] = j end end for i = 1, #list-1 do for j = list[ i ]+1, list[ i+1 ]-1 do result[ #result+1 ]=j end end for j = list[ #list ]+1, SegCt do result[ #result+1 ]=j end return result end -- Returns a set of movable indices in a range, at least minLen long, no more than maxLen long -- Perverse situations with unmovable segs interspersed with movable ones could cause trouble function GetActionRange( idx, minLen, maxLen ) local len = random( minLen, maxLen ) if MaxUnlockedSeg - MinUnlockedSeg - 1 < len then -- okay, we cannot succeed. flee the scene of the crime return MinUnlockedSeg, MaxUnlockedSeg end local startIdx = math.max( MinUnlockedSeg, idx - random( 0, len-1) ) local endIdx = math.min( MaxUnlockedSeg, startIdx + len - 1 ) if endIdx == MaxUnlockedSeg then startIdx = endIdx - len + 1 end -- A pointless bit of writhing, but it shouldn't do any harm. for i=idx+1, endIdx do if not IsMovableSeg(i) then endIdx = i - 1 startIdx = startIdx - 1 break end end for i=idx-1, startIdx, -1 do if not IsMovableSeg(i) then startIdx = i + 1 endIdx = endIdx + 1 break end end return startIdx, endIdx end ---------------------------------------------------------------- -- SIDECHAIN AND ATOM FUNCTIONS ---------------------------------------------------------------- -- only customer for these 3 functions is the SpotMutator 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" -- idx == 20 end 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 -- real tip - 1 because maybe cysteine bridge elseif aa == "d" then return 8 elseif aa == "e" then return 9 elseif aa == "f" then return 20 elseif aa == "g" then return CENTER_CARBON -- 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 getPolarAtoms( aa ) if aa == "a" then return {6} elseif aa == "c" then return {7} elseif aa == "d" then return {9} elseif aa == "e" then return {10} elseif aa == "f" then return {12} elseif aa == "g" then return {5} elseif aa == "h" then return {11,17} elseif aa == "i" then return {9} elseif aa == "k" then return {10,20,21,22} elseif aa == "l" then return {9} elseif aa == "m" then return {9} elseif aa == "n" then return {9,13,14} elseif aa == "p" then return nil elseif aa == "q" then return {10,16,17} elseif aa == "r" then return {12,20,21,22,23,24} elseif aa == "s" then return {7,11} elseif aa == "t" then return {8,11} elseif aa == "v" then return {8} elseif aa == "w" then return {15,20} elseif aa == "y" then return {13,21} else return nil end end function GetTipAtomOfSeg( idx ) -- cysteine loses last atom if disulfide bridge if structure.GetAminoAcid( idx ) == "c" then return structure.GetAtomCount( idx ) else return GetAtomOfTip( structure.GetAminoAcid( idx )) end end function GetCysteineSulfurAtom( idx ) if structure.GetAminoAcid(idx) ~= "c" then return 0 end local totalAtoms = structure.GetAtomCount(idx) if totalAtoms == 10 then -- there is a cysteine bond, so things shifted return 7 else return 6 end end function GetBetaCarbonAtom( idx ) local lt = structure.GetAminoAcid( idx ) if isGlycine( idx ) then return CENTER_CARBON elseif idx == SegCt then return TERMINAL_BETA else return BETA_CARBON end end function isGlycine( seg ) local lt = structure.GetAminoAcid( seg ) return (lt == 'G' or lt == 'g') end function isGlycineOrAlanine( seg ) local lt = structure.GetAminoAcid( seg ) return (lt == 'G' or lt == 'g' or lt == 'a' or lt == 'A') end function isCysteine( seg ) local lt = structure.GetAminoAcid( seg ) return (lt == 'c' or lt == 'C') end function isProline( seg ) local lt = structure.GetAminoAcid( seg ) return (lt == 'p' or lt == 'P') end function GetFirstHydrogenAtom( idx ) local lt = structure.GetAminoAcid( idx ) local totalAtoms = structure.GetAtomCount(idx) if lt == 'g' then return 5 elseif lt == 'p' then return 9 elseif lt == 'c' then if totalAtoms == 10 then return 8 else return 7 end else local polarVec = getPolarAtoms( lt ) if polarVec == nil then return CENTER_CARBON end -- should not happen return polarVec[1] end end function PickAtomNumberForBand( idx, noTip ) if noTip == nil then noTip = false end if not BAND_TO_SIDECHAINS then return CENTER_CARBON end local r = 1 if noTip then r = random( 1, 6 ) else r = random( 1, 7 ) end if r <= 3 then -- do for r = 1,2,3 return GetBetaCarbonAtom( idx ) elseif r <= 6 then -- do for r = 4,5,6 return CENTER_CARBON else -- do rarely, because it's rarely good return GetTipAtomOfSeg( idx ) end end function setCysteineSegList( ) CysteineAaSegList = {} for i=1, SegCt do local lt = structure.GetAminoAcid( i ) if lt == "c" or lt == "C" then CysteineAaSegList[#CysteineAaSegList + 1] = i end end end function guessCysteinePairList( ) local ctPairsWanted = math.floor( #CysteineAaSegList / 2 ) CysteinePairList = {} localCystList = {} for i=1, #CysteineAaSegList do localCystList[i] = CysteineAaSegList[i] end for ii = 1, ctPairsWanted do local minDist = 1000000.0 local bestI = 0 local bestJ = 0 for i = 1, #localCystList - 1 do local cyst1 = localCystList[i] for j=i+1, #localCystList do local cyst2 = localCystList[j] -- don't try to match up "adjacent" cysteines. if cyst2 - cyst1 > 2 then distBetween = structure.GetDistance( cyst1, cyst2 ) if distBetween < minDist then bestI = i bestJ = j minDist = distBetween end end end end if bestI == 0 and bestJ == 0 then bestI = 1 bestJ = 2 end CysteinePairList[#CysteinePairList+1] = {localCystList[bestI], localCystList[bestJ]} -- bestJ > bestI so remove in this order: table.remove( localCystList, bestJ ) table.remove( localCystList, bestI ) end return true end function doesCysteineBondExist( idx1, idx2) -- NOTE: I have problems if two cysteine bonds exist involving the -- two given segments but the bonds are not actually between -- my two segments (eg a<->c and b<->d exist, I want a<->b). -- -- My attempts to use distance are kludgy but I don't have -- better (can't ask for distance between atoms), so I will -- leave the problem in situ. -- structure.GetAtomCount could also be checked (10 vs 11) -- but that doesn't help the core problem here. -- dist <= 6.996 seems to correspond to success. local dist = structure.GetDistance(idx1, idx2 ) local dScore1 = current.GetSegmentEnergySubscore( idx1, "disulfides" ) local dScore2 = current.GetSegmentEnergySubscore( idx2, "disulfides" ) local bondExists = (dist < 7.5 and dScore1 ~= 0.0 and dScore2 ~= 0.0) --if bondExists then -- print( "CBond "..idx1.."-"..idx2.. -- " dist="..TrimNum(dist).. -- " sc1="..TrimNum(dScore1).. -- " sc2="..TrimNum(dScore2)) --end return bondExists end function checkCysteineSanity() if not CYSTEINE_PERFORM_BANDING then return true end for i = 1, #CysteinePairList do local pair = CysteinePairList[i] local dist = structure.GetDistance( pair[1], pair[2] ) if dist > CYSTEINE_MAX_RI_SEPARATION then print( "Rejected for cysteine insanity: "..pair[1].." far from "..pair[2]) return false end --print("distance "..pair[1].." to "..pair[2].." is "..dist) end return true end ---------------------------------------------------------------- -- MUTATION-RELATED FUNCTIONS ---------------------------------------------------------------- function checkDesigner( ) local designAa=0 for n = 1, SegCt do segType = structure.GetAminoAcid(n) -- old design puzzles used alanine or glycine. new ones use isoleucine if segType == 'a' or segType == 'g' or segType == 'i' then designAa=designAa+1 end end return designAa == SegCt end function isPuzzleMutable( ) for i=1, SegCt do if structure.IsMutable(i) then return true end end return false end function testIndexIsMutable( idx ) if not PuzzleAllowsMutate then return false end if not structure.IsMutable(idx) then return false end for i=1,#NoMutateList do if idx == NoMutateList[i] then return false end end return true end ---------------------------------------------------------------- -- FILTER FUNCTIONS ---------------------------------------------------------------- -- TODO: If the ability to individually manage filters comes about, -- here is where to put such code. (see also internalGetScore) function TurnOnFilters( ) if behavior.GetFiltersDisabled( ) then --print("filters are now ON") behavior.SetFiltersDisabled( false ) end end function TurnOffFilters( ) if not behavior.GetFiltersDisabled( ) then --print("filters are now OFF") behavior.SetFiltersDisabled( true ) end end function ResetFilterState( ) --if IsFilterDisabled then -- print("filters are now ON") --end behavior.SetFiltersDisabled( IsFilterDisabled ) end function ReportFilters( ) local fnames = filter.GetNames( ) if #fnames > 0 then local filterz = {} for i = 1, #fnames do local fn = fnames[ i ] local sat = filter.ConditionSatisfied( fn ) local bon = filter.HasBonus( fn ) local val = 0 if bon then val = filter.GetBonus( fn ) end filterz[ #filterz + 1 ] = { name = fn, satisfied = sat, hasbonus = bon, value = val } end for i = 1, #filterz do print( " "..i.. ": filter=" .. filterz[ i ].name .. ", satisfied=" .. BoolStr(filterz[ i ].satisfied) .. ", bonus=" .. BoolStr(filterz[ i ].hasbonus) .. ", value=" .. TrimNum( filterz[ i ].value ) ) end end end function CheckForFilters( ) local retval = false local fnames = filter.GetNames( ) if #fnames > 0 then retval = true end print("Has filters? "..BoolStr(retval)) return retval end function GetFilters( fnames ) local filterTable = {} for i = 1, #fnames do local fhasbonus = filter.HasBonus( fnames[ i ] ) local fscore if fhasbonus then fscore = filter.GetBonus( fnames[ i ] ) else fscore = nil end local fsatisfied = filter.ConditionSatisfied( fnames[ i ] ) filterTable[ #filterTable + 1 ] = { name = fnames[ i ], hasbonus = fhasbonus, score = fscore, satisfied = fsatisfied, } end return filterTable end ---------------------------------------------------------------- -- LOCKED/FROZEN FUNCTIONS ---------------------------------------------------------------- function GenerateNonLockedSegList( ) for i=1, SegCt do if structure.IsLocked( i ) then PuzzleHasLockedSegs = true else NonLockedSegList[ #NonLockedSegList + 1] = i end end end function IsUnlockedSeg( seg ) return not structure.IsLocked( seg ) end function FindAllMovableSegs( ) 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 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 selectNonFrozens( idxList ) local segs = { } local segsToCheck = idxList if segsToCheck == nil then segsToCheck = { } for i = 1, SegCt do segsToCheck[ #segsToCheck + 1] = i end end selection.DeselectAll( ) for i = 1, #segsToCheck do local b,s = freeze.IsFrozen( segsToCheck[ i ] ) if not s then segs[ #segs + 1 ] = segsToCheck[ i ] end end for i = 1, #segs do selection.Select( segs[ i ] ) end end function ResetFrozenness( ) freeze.UnfreezeAll( ) for i=1, SegCt do local bFroz, sFroz = InitialFrozenTable[ i ] if bFroz or sFroz then freeze.Freeze( i, bFroz, sFroz ) end end ChangedFrozenness = false end function StoreFrozenness( ) for i=1, SegCt do -- save "frozenness" local bFroz, sFroz = freeze.IsFrozen( i ) InitialFrozenTable[ i ] = bFroz, sFroz end end ---------------------------------------------------------------- -- CLASH IMPORTANCE ---------------------------------------------------------------- function SetCI( ci ) behavior.SetClashImportance( CI_MAXSCALE * ci ) end function ExactSetCI( ci ) behavior.SetClashImportance( ci ) end function GetCI( ) return behavior.GetClashImportance( ) end ---------------------------------------------------------------------- -- CUTTING FUNCTIONS ---------------------------------------------------------------------- function DeleteCutAtIndex( idx ) if idx == nil or idx < MinUnlockedSeg or idx > MaxUnlockedSeg 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 CutEverywhereInRange( min, max ) if min == nil or min > MaxUnlockedSeg then min = MinUnlockedSeg end if max == nil or max < min then max = MaxUnlockedSeg end for i=min, max do structure.InsertCut( i ) end end function DeleteAllCuts( min, max ) if min == nil or min > MaxUnlockedSeg then min = MinUnlockedSeg end if max == nil or max < min then max = MaxUnlockedSeg end for i=min, max do structure.DeleteCut( i ) end end function AddRandomCuts( cutList, maxCuts ) for i=1, maxCuts do local seg = randomMovableSeg( ) 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 ) local 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=MinUnlockedSeg, MaxUnlockedSeg do DeleteCutAtIndex( i ) -- any cuts that appeared better go now, too end end end ---------------------------------------------------------------- -- CONTACT MAP FUNCTIONS ---------------------------------------------------------------- function CheckForContactMap( ) 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 return true -- all we wanted to know was whether scores exist end if saveval == 0.0 then saveval = val end end end return false 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 isExcellentHelixSeg( seg ) local aa = structure.GetAminoAcid( seg ) return aa == 'a' or aa == 'e' or aa == 'm' or aa == 'k' end function isGoodHelixSeg( seg ) local aa = structure.GetAminoAcid( seg ) return isExcellentHelixSeg(seg) or aa == 'f' or aa == 'j' or aa == 'l' or aa == 'q' or aa == 'v' or aa == 'w' end function isOkHelixSeg( seg ) local aa = structure.GetAminoAcid( seg ) return isGoodHelixSeg(seg) or aa == 'h' or aa == 'r' or aa == 's' or aa == 't' end function isHelixBreaker( seg ) return structure.GetAminoAcid( seg ) == 'p' end function isBadNonBreakerHelixSeg( seg ) local aa = structure.GetAminoAcid( seg ) return aa == 'g' or aa == 'd' or aa == 'n' end function LocateHelices( ) local inside = false local helixStart = 0 AllHelices = {} for i=1, SegCt do if IsUnlockedSeg( i ) then lastUnlocked = i end if ( IsUnlockedSeg( i ) and structure.GetSecondaryStructure(i) == "H" ) then if ( inside == false ) then inside = true helixStart = i end elseif inside == true then inside = false AllHelices[#AllHelices+1] = { sIdx = helixStart, eIdx = i-1 } end end -- deal with "last seg is helix" if ( inside == true ) then AllHelices[#AllHelices+1] = {sIdx = helixStart, eIdx = lastUnlocked } end end function LocateSheets( ) local inside = false local sheetStart = 0 AllSheets = {} for i=1, SegCt do if IsUnlockedSeg( i ) then lastUnlocked = i end if ( IsUnlockedSeg( i ) and structure.GetSecondaryStructure(i) == "E" ) then if ( inside == false ) then inside = true sheetStart = i end elseif inside == true then inside = false AllSheets[#AllSheets + 1] = {sIdx = sheetStart, eIdx = i - 1} end -- if/else 'E' end -- for (SegCt) -- deal with "last seg is sheet" if ( inside == true ) then AllSheets[#AllSheets + 1] = {sIdx = sheetStart, eIdx = lastUnlocked} end end function LocateLoops( ) local inside = false local loopStart = 0 AllLoops = {} for i=1, SegCt do if IsUnlockedSeg( i ) then lastUnlocked = i end if ( IsUnlockedSeg( i ) and structure.GetSecondaryStructure(i) == "L" ) then if ( inside == false ) then inside = true loopStart = i end elseif inside == true then inside = false AllLoops[ #AllLoops + 1 ] = {sIdx = loopStart, eIdx = i - 1} end -- if/else 'L' end -- for (SegCt) -- deal with "last seg is loop" if ( inside == true ) then AllLoops[ #AllLoops + 1 ] = {sIdx = loopStart, eIdx = lastUnlocked} end end function FindFirstProbableHelixInSeglist( sIdx, eIdx ) local startHelix = 0 local endHelix = 0 if eIdx - sIdx < 6 then -- not worth looking for one here return 0, 0 end for i = sIdx, eIdx - 5 do startHelix = 0 endHelix = 0 if isGoodHelixSeg( i ) then --print("Possible start at idx="..i.." aa="..structure.GetAminoAcid(i) ) startHelix = i for j=i+1, eIdx do endHelix = j if isOkHelixSeg( j ) then -- reset mediocre count because we don't mind -- isolated mediocres, just don't want 2 in a row --print("Saw good "..structure.GetAminoAcid(j).." at "..j) elseif isHelixBreaker( j ) then endHelix = j-1 --print("Saw proline at "..j) break elseif isBadNonBreakerHelixSeg( j ) then endHelix = j-1 --print("Saw bad "..structure.GetAminoAcid(j).." at "..j) break else --print( "Saw mediocre "..structure.GetAminoAcid(j).." at "..j ) nextOk = true nextNextOk = true if j < SegCt - 1 then nextNextOk = isOkHelixSeg( j + 2 ) end if j < SegCt then nextOk = isOkHelixSeg( j + 1 ) end if not (nextOk and nextNextOk) then break end end end if endHelix - startHelix > 4 then return startHelix, endHelix end end end return 0, 0 end function LocateMissingHelices() PossibleHelices = {} for i = 1, #AllLoops do local bounds = AllLoops[i] --print( "looking at loop: "..bounds.sIdx.."-"..bounds.eIdx ) if bounds.eIdx - bounds.sIdx >= 7 then local currStart = bounds.sIdx while currStart < bounds.eIdx - 4 do local startHelix, endHelix = FindFirstProbableHelixInSeglist( currStart, bounds.eIdx ) if startHelix == 0 then break -- no more helices to find in this stretch of loopiness else --print("Found possible helix at s,e="..startHelix..","..endHelix) PossibleHelices[#PossibleHelices + 1] = {sIdx = startHelix, eIdx = endHelix} currStart = endHelix + 2 end end end end end function isPossibleHelix( idx ) for i = 1, #PossibleHelices do local bound = PossibleHelices[ i ] if bound.sIdx <= idx and bound.eIdx >= idx then --local s = bound.sIdx --local e = bound.eIdx return true end end return false end function GetRegionStartAndEnd( idx ) local s = idx local 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 if typeIdx == 'L' then -- if we think there's a helix hidden here, let's try to offer its boundaries for i = 1, #PossibleHelices do local bound = PossibleHelices[ i ] if bound.sIdx <= idx and bound.eIdx >= idx then s = bound.sIdx e = bound.eIdx return s, e end end end return s, e end function GetExtendedRegionForWiggle( idxStart, idxEnd ) local startExtendedSeg, endExtendedSeg, junk if idxStart <= MinUnlockedSeg then startExtendedSeg = idxStart else startExtendedSeg, junk = GetRegionStartAndEnd( idxStart - 1 ) end if idxEnd >= MaxUnlockedSeg then endExtendedSeg = idxEnd else junk, endExtendedSeg = GetRegionStartAndEnd( idxEnd + 1 ) end -- try harder if we didn't get very much if startExtendedSeg > idxStart - 4 then startExtendedSeg = math.max( idxStart - 4, MinUnlockedSeg ) end if endExtendedSeg < idxEnd + 4 then endExtendedSeg = math.min( idxEnd + 4, MaxUnlockedSeg ) end return startExtendedSeg, endExtendedSeg 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 if eIdx - sIdx <= 1 then -- last try: unless we're at an end, just give ourselves one before and after if sIdx > 1 then sIdx = sIdx - 1 end if eIdx < SegCt then eIdx = eIdx + 1 end end if eIdx - sIdx <= 1 then return idx,idx end -- failed, something is very wrong end -- Check: if loop and more than 30-long, then only take part of it if regionType == 'L' and eIdx - sIdx > 30 and not isPossibleHelix( sIdx ) 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 OriginalSecondaryStructures[ i ] == "l" then selection.Select( i ) end end structure.SetSecondaryStructureSelected( "l" ) selection.DeselectAll( ) for i=min, max do if OriginalSecondaryStructures[ i ] == "e" then selection.Select( i ) end end structure.SetSecondaryStructureSelected( "e" ) selection.DeselectAll( ) for i=min, max do if OriginalSecondaryStructures[ i ] == "h" then selection.Select( i ) end end structure.SetSecondaryStructureSelected( "h" ) selection.DeselectAll( ) end function StoreSecondaryStructure( ) for i=1, SegCt do OriginalSecondaryStructures[ 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 -------------- SHEET-SPECIFIC FUNCTIONS -------------- function GetBoundsOfSheet( seg ) local bounds = {sIdx = 0, eIdx = 0} for i=1, #AllSheets do bounds = AllSheets[ i ] if bounds.sIdx <= seg and bounds.eIdx >= seg then return bounds.sIdx, bounds.eIdx end end return 0, 0 end function GetBoundsOfSheetFromIndex( sheetIdx ) local bounds = {sIdx = 0, eIdx = 0} if sheetIdx < 0 or sheetIdx > #AllSheets then return 0,0 end bounds = AllSheets[ sheetIdx ] return bounds.sIdx, bounds.eIdx end function GetIndexOfSheet( seg ) local bounds = {sIdx = 0, eIdx = 0} for i=1, #AllSheets do bounds = AllSheets[ i ] if bounds.sIdx <= seg and bounds.eIdx >= seg then return i end end return 0 end -- finds segment in sheet that's nearest to segIn function GetNearestSegOfSheet( segIn, sheetIdxIn ) local sIdx, eIdx = GetBoundsOfSheetFromIndex( sheetIdxIn ) if sIdx == 0 or (sIdx <= segIn and eIdx >= segIn) then return 0 end local minDist = structure.GetDistance( segIn, sIdx ) local bestIdx = sIdx for i=sIdx+1, eIdx do dist = structure.GetDistance( segIn, i ) if dist < minDist then minDist = dist bestIdx = i end end return bestIdx end -- much cleverer would be to build a table of all sheet indices that -- aren't in our sheet, then build a distance chart versus segIn, then -- find the shortest distance. we could even get clever and include only -- the "non-satisfied" sheets - the ones that only have one neighbor. function FindNearestSheetToSeg( segIn, maxDistance ) local sIdx, eIdx = GetBoundsOfSheet( segIn ) if sIdx == 0 then return false end sheetLen = eIdx - sIdx + 1 foundSheet = false foundMatch = false local listIdx = {} local sheetListOut = {} listIdx = {} getSegsWithinSphere( listIdx, segIn, maxDistance, false ) for j=1, #listIdx do -- dont want segs from own sheet, so only act if "not" one of them if listIdx[j] < sIdx or listIdx[j] > eIdx then local sheetIdx = GetIndexOfSheet( listIdx[j] ) if sheetIdx > 0 then -- found a sheet, it's not us. make sure we haven't already found it for k=1, #sheetListOut do if sheetIdx == sheetListOut[k] then foundMatch = true break end end if not foundMatch then sheetListOut[#sheetListOut+1] = sheetIdx end foundSheet = true end end end for j=1, #AllSheets do -- ok, we have sheets that aren't far. now find the closest if AllSheets[j].sIdx ~= sIdx then -- not us end end return sheetListOut end function FindNearestSheetsToSheet( segIn, maxDistance ) local sIdx, eIdx = GetBoundsOfSheet( segIn ) if sIdx == 0 then return nil end local listIdx = {} local sheetListOut = {} listIdx = {} getSegsWithinRangeOfTube( listIdx, sIdx, eIdx, maxDistance ) for j=1, #listIdx do -- dont want segs from own sheet, so only act if not one of them if listIdx[j] < sIdx or listIdx[j] > eIdx then local foundMatch = false local sheetIdx = GetIndexOfSheet( listIdx[j] ) if sheetIdx > 0 then -- found a sheet, it's not us. make sure we haven't already found it for k=1, #sheetListOut do if sheetIdx == sheetListOut[k] then foundMatch = true end end if not foundMatch then sheetListOut[#sheetListOut+1] = sheetIdx end end end end return sheetListOut end function IsStraySheet( segIn ) local nbrSheets = FindNearestSheetsToSheet( segIn, 6.0) return #nbrSheets == 0 end function FindNeighborSheets( segIn ) return FindNearestSheetsToSheet( segIn, 6.0) end function IsSheetPairAntiParallel( sheetIdx1, sheetIdx2 ) local sIdx1, eIdx1 = GetBoundsOfSheetFromIndex( sheetIdx1 ) local nearestSegs = {} for i=sIdx1, eIdx1 do nearestSegs[ i + 1 - sIdx1 ] = GetNearestSegOfSheet ( i, sheetIdx2 ) end local countIncreases = 0 local countDecreases = 0 for i=1, #nearestSegs - 1 do if nearestSegs[i+1] > nearestSegs[i] then countIncreases = countIncreases + 1 end if nearestSegs[i+1] < nearestSegs[i] then countDecreases = countDecreases + 1 end end -- this is a rotten metric, but it's probably good enough for my needs return countDecreases > countIncreases end function FindBestOffsetsForSheetMatching( sheetIdx1, sheetIdx2 ) local sIdx1, eIdx1 = GetBoundsOfSheetFromIndex( sheetIdx1 ) local sIdx2, eIdx2 = GetBoundsOfSheetFromIndex( sheetIdx2 ) local isAntiParallel = IsSheetPairAntiParallel( sheetIdx1, sheetIdx2 ) -- look for offsets for aligning the sheets. local startFirst = sIdx1 local endFirst = eIdx1 local deltaFirst, deltaSecond -- figure out what our endpoints are. Start with basics of boundaries of sheets we are matching local nbrList = {} local maxLen1 = eIdx1 - sIdx1 + 1 local maxLen2 = eIdx2 - sIdx2 + 1 local maxLenToTry = math.min( maxLen1, maxLen2 ) -- the length to walk along. too long for "right" answer if maxLenToTry < 2 then -- too short to be worth banding return 0, 0, 0, false end for i=1, maxLenToTry do nbrList[i] = GetNearestSegOfSheet( sIdx1 + i - 1, sheetIdx2 ) end --printVector( nbrList, "Sheet 2 neighbors", false ) -- find the most believable startFirst if nbrList[1] == nbrList[2] and nbrList[1] == nbrList[3] then for i=2, maxLenToTry do if nbrList[i] == nbrList[1] then startFirst = startFirst + 1 --print("startFirst: ", startFirst ) else break end end end maxLenToTry = maxLenToTry - (startFirst - sIdx1) if maxLenToTry < 2 then -- too short to be worth banding return 0, 0, 0, false end deltaFirst = startFirst - sIdx1 -- find the most believable endFirst if nbrList[#nbrList] == nbrList[#nbrList - 1] and nbrList[#nbrList] == nbrList[#nbrList - 2] then for i=maxLenToTry-1, 1, -1 do if nbrList[i] == nbrList[#nbrList] then endFirst = endFirst - 1 --print("endFirst: ", endFirst ) else break end end end local len = endFirst - startFirst + 1 --print( "len="..len.." endFirst="..endFirst.." startFirst="..startFirst ) -- OK, we have a startFirst and endFirst that we at least kind of believe -- Now find the best alignment local deltas = {} for i=startFirst, endFirst do local nearest = GetNearestSegOfSheet( i, sheetIdx2 ) --print("Nearest to "..i.." is "..nearest ) local delta1 = i - startFirst local delta2 if isAntiParallel then delta2 = eIdx2 - nearest - delta1 else delta2 = nearest - sIdx2 - delta1 end --print( "BestOffset: delta="..delta2 ) deltas[#deltas+1] = delta2 end local avgDelta = 0.0 for i=1, #deltas do avgDelta = avgDelta + deltas[ i ] end avgDelta = (avgDelta + 0.0) / #deltas --print("avgDelta = "..avgDelta ) deltaSecond = math.floor(avgDelta) return deltaFirst, deltaSecond, len, isAntiParallel end ------------------------------------------------------------------------------ -- ---- SHAKER MUTATOR AND WIGGLER FUNCTIONS -- ------------------------------------------------------------------------------ ------------------------------------------------------------------------------ -- GENERAL-PURPOSE SHAKERS AND WIGGLERS ------------------------------------------------------------------------------ -- no recentbest here because sometimes we'd call while decreasing score function ShakeSelected( iters, useLowerCi ) -- DO NOT OFFER mutate because we'd have to check NoMutateList and deselect -- those indices, which would damage any follow-on use of the selected set -- DO NOT DESELECT - someone else might want the selection if iters == nil then iters = SHAKESIDECHAIN_ITERS end if useLowerCi == nil then useLowerCi = false end local sav_ci = GetCI( ) local startTime = os.time( ) if useLowerCi then SetCI( 0.31 ) end structure.ShakeSidechainsSelected( iters ) if useLowerCi then SetCI( sav_ci ) end TotalShakeTime = TotalShakeTime + ( os.time( ) - startTime ) end function ShakeOrMutateSelected( iters ) if MUTATE_NOT_SHAKE then structure.MutateSidechainsSelected(iters+1) else structure.ShakeSidechainsSelected(iters) end end function ShakeOrMutate( iters, idxList, onlyShake ) -- "s" (idxList=nil for all) local startTime if iters == nil then iters = SHAKESIDECHAIN_ITERS end if onlyShake == nil then onlyShake = false end local origCI = GetCI( ) if (not onlyShake) and MUTATE_NOT_SHAKE then selectNonFrozens( idxList ) if #NoMutateList > 0 then -- deselect all no-mutate aas for i = 1, #NoMutateList do selection.Deselect( NoMutateList[ i ] ) end end startTime = os.time( ) SetCI( CI_MUTATE ) --print("Mutating") structure.MutateSidechainsSelected( iters ) SetCI( origCI ) TotalMutateTime = TotalMutateTime + ( os.time( ) - startTime ) if #ShakeAfterMutateList > 0 then selection.DeselectAll( ) for i = 1, #ShakeAfterMutateList do local b,s = freeze.IsFrozen( ShakeAfterMutateList[ i ] ) if not s then selection.Select( ShakeAfterMutateList[ i ] ) end end startTime = os.time( ) structure.ShakeSidechainsSelected( iters ) TotalShakeTime = TotalShakeTime + ( os.time( ) - startTime ) end else startTime = os.time( ) selectNonFrozens( idxList ) structure.ShakeSidechainsSelected( iters ) TotalShakeTime = TotalShakeTime + ( os.time( ) - startTime ) end selection.DeselectAll( ) end function SimpleWiggleAll( iters ) -- "wa" on all if iters == nil then iters = QUICKWIGGLE_ITERS end structure.WiggleAll( iters, true, true ) end function SimpleWiggleBackbone( iters ) -- "wb" on all if iters == nil then iters = QUICKWIGGLE_ITERS end structure.WiggleAll( iters, true, false ) end function SimpleWiggleSidechains( iters ) -- "ws" on all if iters == nil then iters = QUICKWIGGLE_ITERS end structure.WiggleAll( iters, false, true ) end function SimpleLocalWiggleAll( iters ) -- "lw" on all if iters == nil then iters = QUICKWIGGLE_ITERS end structure.LocalWiggleAll( iters, true, true ) end function SimpleWiggleSelected( iters ) -- "wa" on selected if iters == nil then iters = QUICKWIGGLE_ITERS end structure.WiggleSelected( iters, true, true ) end function SimpleWiggleBackboneSelected( ) -- "wb" on selected if iters == nil then iters = QUICKWIGGLE_ITERS end structure.WiggleSelected( iters, true, false ) end function SimpleWiggleSidechainsSelected( ) -- "ws" on selected if iters == nil then iters = QUICKWIGGLE_ITERS end structure.WiggleSelected( iters, false, false ) end function SimpleLocalWiggleSelected( iters ) -- "lw" on selected if iters == nil then iters = QUICKWIGGLE_ITERS end structure.LocalWiggleSelected( iters, true, true ) end -- if anybody ever wants "lwb" or "lws", it's easy enough to see how to do them. function LongWiggleAll( ) -- "wa" on all with gain IterativeWiggleAll( true, true ) end function LongWiggleBackbone( ) -- "wb" on all with gain IterativeWiggleAll( true, false ) end function LongWiggleSidechains( ) -- "ws" on all with gain IterativeWiggleAll( false, true ) end function LongWiggleAllLocal( ) -- "lw" on all with gain IterativeLocalWiggleAll( true, true ) end function LongWiggleSelected( ) -- "wa" on selected with gain IterativeWiggleSelected( true, true ) end function LongWiggleBackboneSelected( ) -- "wb" on selected with gain IterativeWiggleSelected( true, false ) end function LongWiggleSidechainsSelected( ) -- "ws" on selected with gain IterativeWiggleSelected( false, true ) end function LongWiggleSelectedLocal( ) -- "lw" on selected with gain IterativeLocalWiggleSelected( true, true ) end function IterativeLocalWiggleAll( doBackbone, doSidechain, minGain ) local lastScore = getQuickScore( ) if minGain == nil then minGain = QUICKWIGGLE_GAIN end recentbest.Save( ) local gain = minGain while gain >= minGain do structure.LocalWiggleAll( QUICKWIGGLE_ITERS, doBackbone, doSidechain ) recentbest.Restore( ) gain = getQuickScore( ) - lastScore lastScore = getQuickScore( ) end end function IterativeWiggleAll( doBackbone, doSidechain, minGain ) local lastScore = getQuickScore( ) if minGain == nil then minGain = QUICKWIGGLE_GAIN end recentbest.Save( ) local gain = minGain while gain >= minGain do structure.WiggleAll( QUICKWIGGLE_ITERS, doBackbone, doSidechain ) recentbest.Restore( ) gain = getQuickScore( ) - lastScore lastScore = getQuickScore( ) end end function IterativeWiggleSelected( doBackbone, doSidechain, minGain ) local lastScore = getQuickScore( ) if minGain == nil then minGain = QUICKWIGGLE_GAIN end recentbest.Save( ) local gain = minGain while gain >= minGain do structure.WiggleSelected( QUICKWIGGLE_ITERS, doBackbone, doSidechain ) recentbest.Restore( ) gain = getQuickScore( ) - lastScore lastScore = getQuickScore( ) end end function IterativeLocalWiggleSelected( doBackbone, doSidechain, minGain ) local lastScore = getQuickScore( ) if minGain == nil then minGain = QUICKWIGGLE_GAIN end recentbest.Save( ) local gain = minGain while gain >= minGain do structure.LocalWiggleSelected( QUICKWIGGLE_ITERS, doBackbone, doSidechain ) recentbest.Restore( ) gain = getQuickScore( ) - lastScore lastScore = getQuickScore( ) end end function WiggleRange( startSeg, endSeg, addFreeze, doGlobal ) if doGlobal == nil then doGlobal = randomBool() end 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 SimpleWiggleSelected( ) else SimpleLocalWiggleSelected( ) end -- clean up what we did ResetFrozenness( ) selection.DeselectAll( ) end --------------------------------------------- -- STABILIZER WIGGLES --------------------------------------------- function WiggleRangeShakeTubeWiggleAll( idxStart, idxEnd, radius ) local idxList = {} selection.DeselectAll( ) selection.SelectRange( idxStart, idxEnd ) SimpleWiggleSelected( ) selection.DeselectAll( ) getSegsWithinRangeOfTube( idxList, idxStart, idxEnd, radius ) ShakeOrMutate( SHAKESIDECHAIN_ITERS, idxList ) -- only shake the "nearby" segments SimpleWiggleAll( ) -- just a short bit of time on this wiggle to settle things down a bit end function WiggleShakeListWiggleAll( idxList, onlyShake ) if onlyShake == nil then onlyShake = false end recentbest.Save( ) local scoreInit = getQuickScore( ) selection.DeselectAll( ) for i=1, #idxList do selection.Select( i ) end LongWiggleSelected( ) selection.DeselectAll( ) recentbest.Restore( ) ShakeOrMutate( SHAKESIDECHAIN_ITERS, idxList, onlyShake ) recentbest.Restore( ) if math.abs( getQuickScore( ) - scoreInit) > 0.1 then -- save money if test fails: we apparently didn't do anything LongWiggleAll( ) recentbest.Restore( ) end end function qStabWiggle( doFuse, shakeOnly ) if doFuse == nil then doFuse = randomBool( PROB_QSTAB_EXTRA ) end SetCI( 1.0 ) recentbest.Save( ) ShakeOrMutate( nil, nil, shakeOnly ) recentbest.Restore( ) if doFuse and not FORBID_ALL_QSTAB_FUSE then SetCI( 0.4 ) LongWiggleAll( ) recentbest.Restore( ) SetCI( 1.0) ShakeOrMutate( nil, nil, shakeOnly ) recentbest.Restore( ) end SetCI( 1.0) LongWiggleAll( ) recentbest.Restore( ) end function ShakeWiggleTillStable( initScore, onlyShake ) if onlyShake == nil then onlyShake = false end local count = 0 local currScore = getQuickScore() if initScore == nil or initScore - currScore < 1000.0 then recentbest.Save( ) ShakeOrMutate( nil, nil, onlyShake) recentbest.Restore( ) local gainShake = getQuickScore() - currScore while gainShake > 0.50 and count < 4 do LongWiggleAll() recentbest.Restore( ) currScore = getQuickScore() ShakeOrMutate( nil, nil, MUTATE_ONCE ) recentbest.Restore( ) gainShake = getQuickScore() - currScore count = count + 1 end if count == 0 or gainShake > 0.10 then LongWiggleAll() recentbest.Restore( ) end end end -- tends to produce transients. the only user is IdealizeRegionZlb function WiggleZlbNicely( 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 ) LongWiggleAll( ) recentbest.Restore( ) DelBands( ) recentbest.Save( ) ShakeOrMutate( ) recentbest.Restore( ) end function SimpleRegionWiggle( 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( startIdx, endIdx, false, pickGlobalWiggle ) end function SimpleWiggleShake( ) recentbest.Save( ) local oldRbScore = getRBScore( ) SetCI( CI_COREPULLING ) if randomBool( PROB_LOCALWIGGLE ) then -- this is currently always SimpleLocalWiggleAll( ) else SimpleWiggleAll( ) end ShakeOrMutate( ) local newRbScore = getRBScore( ) if newRbScore > oldRbScore then recentbest.Restore( ) end end --------------------------------------------------------- -- FAST RELAX WIGGLER --------------------------------------------------------- function PerformFastRelaxWiggler( ctRuns ) if ctRuns == nil then ctRuns = 1 end for i=1, ctRuns do SetCI( 0.02 ) ShakeOrMutate( ) SimpleWiggleAll( ) SetCI( 0.25 ) ShakeOrMutate( ) SimpleWiggleAll( ) SetCI( 0.55 ) ShakeOrMutate( ) SimpleWiggleAll( ) SetCI( 1.00 ) ShakeOrMutate( ) structure.WiggleAll( 20, true, true ) SetCI( 0.07 ) ShakeOrMutate( ) SetCI( 1.00 ) structure.WiggleAll( 20, true, true ) end end --------------------------------------------------------- --CLEAN WRAPUP WIGGLERS --------------------------------------------------------- function CleanQStabWiggleOut( qstabFuseWanted, initScore ) DelBands( ) ResetFrozenness( ) SetCI( 1.0 ) recentbest.Save( ) qStabWiggle( qstabFuseWanted, MUTATE_NOT_SHAKE ) ShakeWiggleTillStable( initScore, MUTATE_ONCE ) recentbest.Restore( ) end function CleanShakeWiggleOut( onlyShake ) DelBands( ) ResetFrozenness( ) SetCI( 1.0 ) ShakeWiggleTillStable( nil, onlyShake) end function ShakeWiggleCleanShakeWiggle( ) recentbest.Save( ) local oldRbScore = getRBScore( ) ShakeOrMutate( ) if randomBool( PROB_LOCALWIGGLE) then -- currently this is always SimpleLocalWiggleAll( 1 ) else SimpleWiggleAll( 1 ) end local newRbScore = getRBScore( ) if newRbScore > oldRbScore then recentbest.Restore( ) end DelBands( ) ResetFrozenness( ) recentbest.Save( ) ShakeOrMutate( nil, nil, MUTATE_ONCE ) LongWiggleAll( ) recentbest.Restore( ) end function WiggleBackboneThenWiggleOut( cutIdx, qstabFuseWanted ) SetCI( CI_MULTIBAND_PULL ) SimpleWiggleBackbone( ) DelBands() if cutIdx ~= 0 then DeleteCutAtIndex( cutIdx ) end recentbest.Save( ) SetCI( CI_MULTIBAND_SHAKE ) ShakeOrMutate( ) SetCI( 1.0 ) qStabWiggle( qstabFuseWanted, MUTATE_ONCE ) ShakeWiggleTillStable( nil, MUTATE_ONCE ) end function WiggleShakeCleanWiggleOut( ) SimpleWiggleShake( ) SetCI( 1.0 ) DelBands( ) -- if we had put in bands, they go now ResetFrozenness( ) -- if we froze anything, clean that up now selection.DeselectAll( ) -- just as a kindness recentbest.Save( ) ShakeWiggleTillStable( nil, MUTATE_ONCE ) recentbest.Restore( ) end function BandedWiggleUntilEnoughChange( scoreThreshold, pullingCI ) if scoreThreshold == nil then scoreThreshold = BANDEDWIGGLE_TARGET end if pullingCI == nil then pullingCI = CI_COREPULLING end SetCI( pullingCI ) local ss=getQuickScore( ) for str=0.30, 1.50, 0.11 do --search enough band strength to move SetMyBandStrengths( str ) if randomBool( PROB_LOCALWIGGLE ) then SimpleLocalWiggleAll( ) else SimpleWiggleAll( ) 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 SimpleBandedWiggleShakeWrapper( minChangeWanted, pullingCI, probQstab ) local initScore = getQuickScore( ) if minChangeWanted == nil then minChangeWanted = BANDEDWIGGLE_TARGET end if pullingCI == nil then pullingCI = CI_COREPULLING end if probQstab == nil then probQstab = PROB_QSTAB_EXTRA end local scoreThreshold = math.min( minChangeWanted, initScore / 500.0) recentbest.Save( ) local oldRbScore = getRBScore( ) BandedWiggleUntilEnoughChange( scoreThreshold, pullingCI ) local newRbScore = getRBScore( ) if newRbScore > oldRbScore then recentbest.Restore( ) end CleanQStabWiggleOut( probQstab, initScore ) recentbest.Restore( ) end -- not currently used, but just in case I change my mind... function nudge( ) SetCI( 0.3 ) SimpleWiggleSelected( 1 ) SetCI( 1 ) SimpleWiggleSelected( 8 ) end function WiggleAndShakeForRebuilder( idxStart, idxEnd, initScore, maxFall ) -- initScore is the score before our rebuild happened recentbest.Save( ) local scoreA = getQuickScore( ) if initScore - scoreA > maxFall/2 then ShakeOrMutate( ) end scoreA = getQuickScore( ) if randomBool( PROB_LOCALWIGGLE ) then LongWiggleAllLocal( ) else LongWiggleAll( ) end recentbest.Restore( ) local scoreB = getQuickScore( ) if scoreB - scoreA < 10.0 and initScore - scoreB > 30.0 then -- The wiggle got stuck: try a nudge to see if that helps nudge( ) recentbest.Restore( ) scoreB = getQuickScore( ) end if initScore - scoreB <= 100.0 then selection.SelectRange( idxStart, idxEnd ) ShakeOrMutate( ) -- should this restrict to range, too? LongWiggleSelected( ) recentbest.Restore( ) nudge( ) recentbest.Restore( ) selection.DeselectAll() end -- else not worth the effort end -------------------------------------------------- -- FUSES AND OTHER SLOW WIGGLERS -------------------------------------------------- function BlueFuse( ) recentbest.Save( ) SetCI( .05 ) ShakeOrMutate( ) SetCI( 1 ) SimpleWiggleAll( 5 ) recentbest.Restore( ) SetCI( .07 ) ShakeOrMutate( ) SetCI( 1 ) SimpleWiggleAll( 5 ) recentbest.Restore( ) SetCI( .3 ) SimpleWiggleAll( 8 ) SetCI( 1 ) SimpleWiggleAll( 15 ) recentbest.Restore( ) end function IterativeWiggleLocalByChunk(startSeg, endSeg, minGain, chunkSize, addFreeze) recentbest.Save( ) local currOffset = 0 local lastScore = getQuickScore( ) local 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( ) local startIdx = startSeg + currOffset + chunkSize*idx WiggleRange( 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 ) end -- setting minGainAsked to 0.0 says to use failCt instead of gain. function IterativeCutAndWiggle( baseIters, minGainAsked, shift ) local score = getQuickScore( ) local gain = minGainAsked save.Quicksave( QS_ShortUseTemp1 ) local failCt = 0 repeat save.Quickload( QS_ShortUseTemp1 ) recentbest.Save( ) BasicCutAndWiggleFuse( baseIters, shift, random( shift ) ) recentbest.Restore( ) local newscore = getQuickScore( ) gain = 0.0 if newscore >= score then save.Quicksave( QS_ShortUseTemp1 ) gain = newscore - score score = newscore else failCt = failCt + 1 end until (minGainAsked > 0.0 and gain < minGain) or failCt >= shift save.Quickload( QS_ShortUseTemp1 ) end function IterativeCutAndWiggleFull( shift ) local baseIters = FUSEWIGGLE_ITERS local score = getQuickScore( ) save.Quicksave( QS_ShortUseTemp1 ) local failCt = 0 local rIdx = {} for i=1, shift do rIdx[ i ] = i end randomizeIndexList( rIdx ) for i=1, shift do save.Quickload( QS_ShortUseTemp1 ) BasicCutAndWiggleFuse( baseIters, shift, rIdx[i] ) ResetCuts() local newscore = getQuickScore( ) if newscore >= score then save.Quicksave( QS_ShortUseTemp1 ) score = newscore end end save.Quickload( QS_ShortUseTemp1 ) end -- BASIC FUSE WIGGLERS function WiggleShakeSimpleFuse( ci ) SetCI( ci ) SimpleWiggleAll( ) ShakeOrMutate( ) end function WiggleWiggleSimpleFuse( ci1, ci2, shortiter, longiter ) recentbest.Save( ) local oldRbScore = getRBScore( ) SetCI( ci1 ) SimpleWiggleAll( shortiter ) local newRbScore = getRBScore( ) if newRbScore > oldRbScore then recentbest.Restore( ) end SetCI( ci2 ) recentbest.Save( ) SimpleWiggleAll( longiter ) -- "long" wiggle recentbest.Restore( ) end function ShakeWiggleFuse( ci1, ci2 ) -- aka Fuse1 SetCI( ci1 ) ShakeOrMutate( ) SetCI( ci2 ) LongWiggleAll( ) end function WiggleWiggleWiggleFuse( ci1, ci2 ) -- aka Fuse2 SetCI( ci1 ) LongWiggleAll( ) SetCI( 1.00 ) LongWiggleAll( ) SetCI( ci2 ) LongWiggleAll( ) end function WiggleShakeWiggleFuse( ) -- aka FuseEnd SetCI( 1.00 ) LongWiggleAll( ) ShakeOrMutate( ) LongWiggleAll( ) end ---------------------------------------------------------------------- -- ---- BANDER FUNCTIONS -- ---------------------------------------------------------------------- function StoreUserBands( ) InitialBandStates = {} for i=1, InitialBandCount do InitialBandStates[#InitialBandStates + 1 ] = {bidx = i, isEnabled = band.IsEnabled( i ) } end end ToldUserAlreadyAboutBands = false function ResetUserBands( wantOriginalState ) if #InitialBandStates == 0 then return end if wantOriginalState == nil then wantOriginalState = false end if band.GetCount() < #InitialBandStates then -- we lost information and don't know what to do! if wantOriginalState or not ToldUserAlreadyAboutBands then print("!!!User band got lost - cannot set correctly; disabling") ToldUserAlreadyAboutBands = true end for i=1, band.GetCount() do band.Disable( InitialBandStates[i].bidx ) end InitialBandCount = band.GetCount( ) return end for i=1, #InitialBandStates do if InitialBandStates[i].isEnabled and (wantOriginalState or not DISABLE_ALL_USER_BANDS) then band.Enable( InitialBandStates[i].bidx ) else band.Disable( InitialBandStates[i].bidx ) end end end function DelBands( alsoCysteine ) if alsoCysteine == nil then alsoCysteine = false end if alsoCysteine and not PRESERVE_USER_BANDS then print("Wiping all bands") band.DeleteAll( ) else local allBandCount = band.GetCount( ) local firstBandToDel = 1 + InitialBandCount if not alsoCysteine then firstBandToDel = firstBandToDel + CYSTEINE_TOTAL_BANDS end for i=allBandCount, firstBandToDel, -1 do -- this *must* go in reverse order band.Delete( i ) end end end function EnableMyBands() local allBandCount = band.GetCount( ) local firstActionBand = InitialBandCount + CYSTEINE_TOTAL_BANDS + 1 for i=firstActionBand, allBandCount do band.Enable( i ) end end function SetMyBandStrengths( strength ) local allBandCount = band.GetCount( ) local firstActionBand = InitialBandCount + CYSTEINE_TOTAL_BANDS + 1 for i=firstActionBand, allBandCount 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 print( "failed to add band from "..seg1.." to "..seg2) return false end if bIdx <= InitialBandCount then -- don't accidentally change user-supplied bands return true end 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 0 end if bIdx <= InitialBandCount+CYSTEINE_TOTAL_BANDS then -- don't change user-supplied bands -- don't expect to hit our cysteine ones, but just to be safe... return false end 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 -- fool with this some more function BandInSpaceFromAtomWithParameters( seg, segFini, segInit, rho, theta, phi, strength, goalLength, atom) if not IsUnlockedSeg( seg ) then return false end local bIdx = band.Add( seg, segFini, segInit, rho, theta, phi, atom) if bIdx ~= band.GetCount( ) then return 0 end if bIdx <= InitialBandCount+CYSTEINE_TOTAL_BANDS then -- don't change special or prior bands -- don't expect to hit them, but just to be safe... return 0 end if goalLength ~= nil then band.SetGoalLength( bIdx, goalLength ) end if strength ~= nil and strength ~= 0.0 then band.SetStrength( bIdx, strength ) end return bIdx end ---------------------------------------------------------------------- -- SPECIAL BANDERS ---------------------------------------------------------------------- function ZLB( strength, lower, upper, bandGivenRange ) if lower == nil then lower = MaxUnlockedSeg + 1 end if upper == nil then upper = MinUnlockedSeg - 1 end if bandGivenRange == nil then bandGivenRange = false end -- default is exclude a range if bandGivenRange then for i=lower, upper do if i == 1 then BandInSpaceWithParameters( i, i+1, i+2, 0.01, 0.0, 0.0, strength, 0.01) elseif i == SegCt then BandInSpaceWithParameters( i, i-1, i-2, 0.01, 0.0, 0.0, strength, 0.01) else BandInSpaceWithParameters( i, i+1, i-1, 0.01, 0.0, 0.0, strength, 0.01) end end else for i=MinUnlockedSeg+1, MaxUnlockedSeg-1 do if i < lower or i > upper then BandInSpaceWithParameters( i, i+1, i-1, 0.01, 0.0, 0.0, strength, 0.01) end end if lower > 1 then BandInSpaceWithParameters( 1, 2, 3, 0.01, 0.0, 0.0, strength, 0.01) end if upper < SegCt then BandInSpaceWithParameters( SegCt, SegCt-1, SegCt-2, 0.01, 0.0, 0.0, strength, 0.01) end end end function EnableAndDisableCysteineBands( ) if InitialBandCount + CYSTEINE_TOTAL_BANDS > band.GetCount() then CYSTEINE_TOTAL_BANDS = band.GetCount() - InitialBandCount CYSTEINE_GOT_MIXUP = true end if CYSTEINE_GOT_MIXUP then -- somehow we've gotten confused. just disable the lot of them local bIdx = InitialBandCount print( "!!! Cannot manage cysteine bands - disabling all of them" ) for i=1, CYSTEINE_TOTAL_BANDS do band.Disable( bIdx + i ) end else for i=1, CysteineBandPairCount do local bIdx = InitialBandCount + CYSTEINE_COUNT_BANDS_USED*(i-1) local pair = CysteinePairList[i] local bondExists = doesCysteineBondExist( pair[1], pair[2] ) for j=1, CYSTEINE_COUNT_BANDS_USED do if bondExists then band.Disable( bIdx + j ) else band.Enable( bIdx + j ) end end end end end function PutCysteineBands( idx1, idx2 ) if idx1 < 1 or idx1 > SegCt or idx2 < 1 or idx2 > SegCt or idx1 == idx2 then return false end if structure.GetAminoAcid( idx1 ) ~= 'c' or structure.GetAminoAcid( idx2 ) ~= 'c' then return false end local at1 = GetTipAtomOfSeg( idx1 ) local at2 = GetTipAtomOfSeg( idx2 ) -- fancy is to put more than one band, going after the sulfur atom: -- Put bands here: -- atS1 -> atS2 dist=d1=DISTANCE_CYSTEINE_BOND -- atS1 -> atS2-1 dist=d2=math.sqrt(d1*d1+1.8*1.8) -- atS1-1 -> atS2 dist=d2 -- atS1-1 -> atS2-1 dist=d3=math.sqrt(d2*d2+1.8*1.8) local atS1 = GetCysteineSulfurAtom( idx1 ) local atS2 = GetCysteineSulfurAtom( idx2 ) local strength = CYSTEINE_BAND_STRENGTH local d1 = DISTANCE_CYSTEINE_BOND if CYSTEINE_COUNT_BANDS_USED == 1 then -- my old way of doing this return BandBetweenSegsWithParameters( idx1, idx2, strength, d1, at1, at2 ) else local d2 = math.sqrt(d1*d1 + SCALE_CYSTEINE_OFF_1*SCALE_CYSTEINE_OFF_1) local d3 = math.sqrt(d2*d2 + SCALE_CYSTEINE_OFF_1*SCALE_CYSTEINE_OFF_1) local chSuc = BandBetweenSegsWithParameters( idx1, idx2, strength, d1, atS1, atS2 ) if not chSuc then return false end chSuc = BandBetweenSegsWithParameters( idx1, idx2, strength, d2, atS1, atS2-1 ) if not chSuc then band.Delete( band.GetCount()) return false end if CYSTEINE_COUNT_BANDS_USED >= 3 then chSuc = BandBetweenSegsWithParameters( idx1, idx2, strength, d2, atS1-1, atS2 ) if not chSuc then band.Delete( band.GetCount()) band.Delete( band.GetCount()) return false end end if CYSTEINE_COUNT_BANDS_USED >= 4 then chSuc = BandBetweenSegsWithParameters( idx1, idx2, strength, d3, atS1-1, atS2-1 ) if not chSuc then band.Delete( band.GetCount()) band.Delete( band.GetCount()) band.Delete( band.GetCount()) return false end end end return true end function PutCysteinePairBands( ) local changeSucceeded = false CysteineBandPairCount = 0 CYSTEINE_TOTAL_BANDS = 0 for i=1, #CysteinePairList do local pair = CysteinePairList[i] local chSuc = PutCysteineBands( pair[1], pair[2] ) if chSuc then -- will fail if user already has one of these in place CysteineBandPairCount = CysteineBandPairCount + 1 CYSTEINE_TOTAL_BANDS = CYSTEINE_TOTAL_BANDS + CYSTEINE_COUNT_BANDS_USED end changeSucceeded = changeSucceeded or chSuc end return changeSucceeded end ---------------------------------------------------------------------- -- SMALL-SCALE BANDERS ---------------------------------------------------------------------- function PutBandInSpace( idx, maxRho, strength, goalLength, atom ) -- ok goalLength, atom = nil 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 if goalLength == nil then goalLength = rho end if atom == nil then atom = CENTER_CARBON end return BandInSpaceFromAtomWithParameters( idx, idx2, idx3, rho, theta, phi, strength, goalLength, atom ) end function PutBandToRandomSeg( idx, strength, atom, bewareCysteine ) local needNew = true local failedTries = 0 local idx2 local applyCaution = bewareCysteine and CysteineBandPairCount > 0 and structure.GetAminoAcid( idx ) == "c" while ( needNew and failedTries < 20 ) do idx2 = randomSeg( ) -- ok if this one isn't movable (we assume idx is movable) if applyCaution and structure.GetAminoAcid( idx2 ) == "c" then failedTries = failedTries + 1 elseif idx2 > idx + 3 or idx2 < idx - 3 then needNew = false break else failedTries = failedTries + 1 end end if not needNew then return BandBetweenSegsWithParameters( idx, idx2, strength, nil, atom, nil ) else return false end end function PutSingleRandomBandToSeg( idx, probBis ) local changeSucceeded = false local strength = random( 0.5 * BAND_STRENGTH_DEFAULT, 1.5 * BAND_STRENGTH_DEFAULT, true ) local doBIS = randomBool( probBis ) if doBIS then return PutBandInSpace( idx, BIS_LENGTH, strength ) else local atom = PickAtomNumberForBand( idx, true ) return PutBandToRandomSeg( idx, strength, atom, false ) end end function PutRandomCompBands() if not CONTACTMAP_BAND_ADD_RANDOMS then return end if randomBool( ) then local ctRandBands = random( CONTACTMAP_RANDOMBAND_COUNT - 2, CONTACTMAP_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 ---------------------------------------------------------------------- -- MID-SCALE BANDERS ---------------------------------------------------------------------- function PutGlycineHingeBands( glycineIdx, strength ) if glycineIdx == MinUnlockedSeg or glycineIdx == MaxUnlockedSeg then return false end local changeSucceeded = false selection.DeselectAll ( ) -- construct the rods for the hinge (freeze before and after the glycine) local sR, eR = GetRegionStartAndEnd( glycineIdx + 1 ) if eR < MaxUnlockedSeg and eR - glycineIdx < 3 then eR = eR + 1 end selection.SelectRange( glycineIdx + 1 , eR ) local sL, eL = GetRegionStartAndEnd( glycineIdx - 1 ) if eL > MinUnlockedSeg 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 <= MaxUnlockedSeg - 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(MinUnlockedSeg, glycineIdx - i), math.min(MaxUnlockedSeg, glycineIdx + i), strength ) then changeSucceeded = true end end return changeSucceeded end function PutGeneralHingeBands( startHinge, endHinge, strength ) if startHinge > endHinge then startHinge, endHinge = endHinge, startHinge end if startHinge == MinUnlockedSeg or endHinge == MaxUnlockedSeg then return false end local changeSucceeded = false selection.DeselectAll( ) -- construct the rods for the hinge (freeze before and after the region) local sR, eR = GetRegionStartAndEnd( endHinge + 1 ) if eR < MaxUnlockedSeg and eR - endHinge < 3 then eR = eR + 1 end selection.SelectRange( endHinge + 1 , eR ) local sL, eL = GetRegionStartAndEnd( startHinge - 1 ) if eL > MinUnlockedSeg 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 -- should only happen if startHinge or endHinge is too close to an end return changeFailed end for i=1, maxLen do if BandBetweenSegsWithParameters( math.max(MinUnlockedSeg, startHinge - i), math.min(MaxUnlockedSeg, endHinge + i), strength ) then changeSucceeded = true end end if not changeSucceeded then ResetFrozenness( ) end return changeSucceeded end function BandableSheetSeg( seg ) return not isGlycine( seg ) and not isProline( seg ) end function PutAntiParallelSheetBandsBetweenSegs( seg1, seg2, strength ) local changeSucceeded = false local chSuc = false local atom1 = 4 local atom1Vec = getPolarAtoms( seg1 ) if atom1Vec ~= nil then atom1 = atom1Vec[1] end local atom2 = 4 local atom2Vec = getPolarAtoms( seg2 ) if atom2Vec ~= nil then atom2 = atom2Vec[1] end if BandableSheetSeg(seg1) and BandableSheetSeg(seg2) then chSuc = BandBetweenSegsWithParameters( seg1, seg2, strength, SHEET2SHEET_BONDING_BAND_LENGTH, 4, atom2 ) local iBand = band.GetCount() if band.GetLength(iBand) > SHEET2SHEET_MAX_DIST_TO_BAND then band.Delete(iBand) end changeSucceeded = changeSucceeded or chSuc chSuc = BandBetweenSegsWithParameters( seg1, seg2, strength, SHEET2SHEET_BONDING_BAND_LENGTH, atom1, 4 ) iBand = band.GetCount() if band.GetLength(iBand) > SHEET2SHEET_MAX_DIST_TO_BAND then band.Delete(iBand) end changeSucceeded = changeSucceeded or chSuc end chSuc = BandBetweenSegsWithParameters( seg1, seg2, strength, SHEET2SHEET_CENTER_BAND_LENGTH) changeSucceeded = changeSucceeded or chSuc return changeSucceeded end function PutParallelSheetBandsBetweenSegs( seg1, seg2, strength ) local changeSucceeded = false local chSuc = false local seg3 = seg2+1 local seg4 = seg2-1 local atom1 = 4 local atom1Vec = getPolarAtoms( seg1 ) if atom1Vec ~= nil then atom1 = atom1Vec[1] end local atom3 = 4 local atom3Vec = getPolarAtoms( seg3 ) if atom3Vec ~= nil then atom3 = atom3Vec[1] end if BandableSheetSeg(seg1) then if seg3 <= MaxUnlockedSeg and BandableSheetSeg(seg3) then chSuc = BandBetweenSegsWithParameters( seg1, seg3, strength, SHEET2SHEET_BONDING_BAND_LENGTH, 4, atom3 ) local iBand = band.GetCount() if band.GetLength(iBand) > SHEET2SHEET_MAX_DIST_TO_BAND then band.Delete(iBand) end changeSucceeded = changeSucceeded or chSuc end if seg4 >= MinUnlockedSeg and BandableSheetSeg(seg4) then chSuc = BandBetweenSegsWithParameters( seg1, seg4, strength, SHEET2SHEET_BONDING_BAND_LENGTH, atom1, 4 ) local iBand = band.GetCount() if band.GetLength(iBand) > SHEET2SHEET_MAX_DIST_TO_BAND then band.Delete(iBand) end changeSucceeded = changeSucceeded or chSuc end end chSuc = BandBetweenSegsWithParameters( seg1, seg2, strength, SHEET2SHEET_CENTER_BAND_LENGTH) changeSucceeded = changeSucceeded or chSuc return changeSucceeded end function PutSheetBands( idxStart1, idxStart2, goForward2, len, strengthBkb, strengthSide ) local idx1, idx2 local changeSucceeded = false local chSuc = false for i=1, len do idx1 = idxStart1 + i - 1 if goForward2 then idx2 = idxStart2 + i - 1 else idx2 = idxStart2 + len - i + 1 end if idx1 < 1 or idx1 > SegCt or idx2 < 1 or idx2 > SegCt then -- we can't put bands here! chSuc = false else if goForward2 then -- PARALLEL chSuc = PutParallelSheetBandsBetweenSegs( idx1, idx2, strengthBkb ) else -- ANTIPARALLEL chSuc = PutAntiParallelSheetBandsBetweenSegs( idx1, idx2, strengthBkb ) end changeSucceeded = changeSucceeded or chSuc if strengthSide > 0.0 and not (isGlycine( idx1 ) or isGlycine( idx2 )) then -- sidechain band chSuc = BandBetweenSegsWithParameters( idx1, idx2, strengthSide, goalLength, GetBetaCarbonAtom(idx1), GetBetaCarbonAtom(idx2) ) changeSucceeded = changeSucceeded or chSuc end end end return changeSucceeded end function PutFlipSheetBands( startSeg, endSeg, length, strength ) local changeSucceeded = false for i = math.max( startSeg, MinUnlockedSeg+1 ), math.min( endSeg, MaxUnlockedSeg - 1 ) do local atom = GetBetaCarbonAtom( i ) local theta = math.rad( 180 ) -- math.pi / 2 local phi = math.rad( 270 ) -- math.rad( 315 ) if BandInSpaceFromAtomWithParameters( i, i + 1, i - 1, length, theta, phi, strength, length, atom ) then changeSucceeded = true end end return changeSucceeded end function BandAdjacentSheets( sheetIdx1, sheetIdx2, deltaToAdd ) local sIdx1, eIdx1 = GetBoundsOfSheetFromIndex( sheetIdx1 ) local sIdx2, eIdx2 = GetBoundsOfSheetFromIndex( sheetIdx2 ) if sIdx1 == 0 or sidx2 == 0 then return false end local strength = 1.0 local goalLength = DISTANCE_SHEET_TO_SHEET local sheetLen = 0 local deltaFirst, deltaSecond, len, isAntiParallel = FindBestOffsetsForSheetMatching( sheetIdx1, sheetIdx2 ) --print( "deltaFirst="..deltaFirst.." deltaSecond="..deltaSecond.." len="..len ) --print( "start1="..(sIdx1 + deltaFirst).." start2="..(sIdx2 + deltaSecond + deltaToAdd) ) return PutSheetBands( sIdx1 + deltaFirst, sIdx2 + deltaSecond + deltaToAdd, not isAntiParallel, len, strength, strength ) end function BandStraySheetToNearestSheet( sheetIdx1 ) local s1,e1 = GetBoundsOfSheetFromIndex( sheetIdx1 ) local lenFirst = e1 - s1 + 1 local sheetIdxList = {} local changeSucceeded = false local strength = 1.0 sheetIdxList = FindNearestSheetToSeg( s1, 25.0 ) -- faraway --print( "Ct Nearest sheets: "..#sheetIdxList ) if #sheetIdxList >= 1 then for i=1, #sheetIdxList do local s,e = GetBoundsOfSheetFromIndex( sheetIdxList[i] ) --print(" #"..sheetIdxList[i]..": "..s.."-"..e ) end local r = random( #sheetIdxList ) local idxFar = GetNearestSegOfSheet( s1, sheetIdxList[r] ) local sIdx2, eIdx2 = GetBoundsOfSheetFromIndex( sheetIdxList[r] ) local maxDelta = idxFar - sIdx2 - lenFirst local idxStartSecondSheet = idxFar - lenFirst - random(0, maxDelta) if idxFar - sIdx2 >= lenFirst then -- we always try to do anti-parallel here changeSucceeded = PutSheetBands( s1, idxStartSecondSheet, false, lenFirst, strength, strength ) end end return changeSucceeded end function PutSheetStraightenerBand( startSeg, endSeg, strength ) local changeSucceeded = BandBetweenSegsWithParameters( startSeg, endSeg, strength, (endSeg-startSeg)*DISTANCE_AA_TO_AA ) return changeSucceeded end function PutHelixUniformDistanceBands( startSeg, endSeg, shift, strength ) if startSeg < MinUnlockedSeg or endSeg > MaxUnlockedSeg or shift < 2 then return false end local changeSucceeded = false local sumDist = 0.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 ) if endSeg < startSeg + 4 then return false end if (not do4) and endSeg < startSeg + 5 then return false end local 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 else 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 ) if startSeg < MinUnlockedSeg or endSeg > MaxUnlockedSeg or shift < 2 then return false end local 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 PutHelixRotatorBands( startSeg, endSeg, length, strength, wantClockwise ) local changeSucceeded = false for i = math.max( startSeg, MinUnlockedSeg+1 ), math.min( endSeg, MaxUnlockedSeg - 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 ) local changeSucceeded = false local init = math.max( MinUnlockedSeg, startSeg - 1 ) local fini = math.min( MaxUnlockedSeg, endSeg + 1 ) if doForward then for i = init + 1, fini - 1 do if BandInSpaceWithParameters( i, fini, init, length, math.pi/2, 0.0, strength ) then changeSucceeded = true end end else for i = fini - 1, init + 1, -1 do if BandInSpaceWithParameters( i, fini, init, length, math.pi/2, 0.0, strength ) then changeSucceeded = true end end end return changeSucceeded end function PutMoverBands( startSeg, endSeg, length, strength ) local changeSucceeded = false local init, fini if startSeg > MinUnlockedSeg then init = startSeg - 1 else init = startSeg end if endSeg < MaxUnlockedSeg then fini = endSeg + 1 else fini = endSeg end local 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 ) if endSeg - startSeg < 3 then return false end local changeSucceeded = false local init, first, fini, last, midpt if startSeg > MinUnlockedSeg then init = startSeg - 1 first = startSeg else init = startSeg first = startSeg + 1 end if endSeg < MaxUnlockedSeg 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. local 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 PutPushPullBands( badSeg, bandsWanted, center, strength, wantPushNotPull ) local 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 if #okSegList == 0 then print( "No suitable segs for idx="..badSeg.." with center="..center) return false 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" local 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 -- bandToNearest=false means "band to farthest" function PutManyBandsToSeg( idx, maxBandCount, strength, compression, bandToNearest ) local 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 = MinUnlockedSeg + 2, MaxUnlockedSeg - 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 sortByScore( 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 function PutTailDetacherBands( fromStart, length ) local s, e, rel, goalLen, phi, theta if fromStart then s = MinUnlockedSeg e = MinUnlockedSeg + length rel = MinUnlockedSeg + 1 + length else s = MaxUnlockedSeg - length - 1 e = MaxUnlockedSeg rel = MaxUnlockedSeg - length - 2 end if rel < MinUnlockedSeg or rel > MaxUnlockedSeg then return 0 end goalLen = 0 phi = random( 0.5 * math.pi ) theta = math.pi/2.0 + random( -0.5 * math.pi, 0.5 * math.pi ) if fromStart then for i=e,s+1,-1 do goalLen = goalLen + 3.5 BandInSpaceWithParameters( i, e+1, e+2, length, theta, phi, 1.0, goalLen ) end else goalLen = goalLen + 3.5 for i=s,e do BandInSpaceWithParameters( i, s-1, s-2, length, theta, phi, 1.0, goalLen ) end end return true end function PutTailAttacherBands( fromStart, length ) local s, e if fromStart then s = MinUnlockedSeg e = MinUnlockedSeg + length else s = MaxUnlockedSeg - length - 1 e = MaxUnlockedSeg end -- Idea is to find hydrophobics between s and e and attach bands -- from some of them to a "randomly" chosen nearby hydrophobic -- not between s and e. local hookAas = { } for i=s, e do if structure.IsHydrophobic( i ) then hookAas[ #hookAas + 1] = i end end if #hookAas == 0 then return false end -- if we have no hydrophobics then give up for now randomizeIndexList( hookAas) local ctToHook = random(1, #hookAas ) for i=1, ctToHook do local nearPhobics = {} local toHook = hookAas[ i ] getNearestPhobicsOutsideRange( toHook, s, e, nearPhobics, 5 ) which = random( 1, #nearPhobics ) BandBetweenSegsWithParameters( toHook, nearPhobics[which], 1.0, 2.0, BETA_CARBON, BETA_CARBON ) end return true end ---------------------------------------------------------------------- -- LARGE-SCALE BANDERS ---------------------------------------------------------------------- function PutSheetSewerBandsAllOver( maxDist, strength ) local changeSucceeded = false for seg1 = MinUnlockedSeg+1, MaxUnlockedSeg - 4 do for seg2 = seg1 + 3, MaxUnlockedSeg 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 ) if doSidechains == nil then doSidechains = false end if pullPhilics == nil then pullPhilics = false end local maxToBand = #coreList local bandList = {} local added = 0 local goalLength -- 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 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 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 ) local length = 0 local added = 0 for i=xInit, MaxUnlockedSeg, xRange do for j=yInit, MaxUnlockedSeg, 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 AddRandomXToYBands( strength ) if strenth == nil then strength = XTOY_DEFAULT_STRENGTH end local length = 0 local added = 0 local validRange = (MaxUnlockedSeg - MinUnlockedSeg + 1) local xInterval = random( math.floor( validRange / 9 ), math.floor( validRange / 5 )) local yInterval = random( 2 + xInterval, 2 + math.floor( validRange / 5 )) local xInit = MinUnlockedSeg + random( xInterval-1 ) - 1 local yInit = MinUnlockedSeg + random( yInterval-1 ) - 1 return PutBandsEveryXToEveryY( xInterval, xInit, yInterval, yInit, strength, 1.0 ) end function PutGentleCompBands( bandsWanted, minLength, maxLength, minSeparation, strength, compression ) local bandsAdded = 0 local failCount = 0 repeat local s = randomMovableSeg( ) 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, omitLongBands ) local changeSucceeded = false local baseStrength = BAND_STRENGTH_DEFAULT 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 not omitLongBands or goalLength < CONTACTMAP_MAX_NOCONTACT then 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 local chSuc = BandBetweenSegsWithParameters( i, j, strength, goalLength, atom1, atom2 ) changeSucceeded = changeSucceeded or chSuc end end end end return changeSucceeded end function PutContactMapBands( ) 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 = randomBool( ) local wantDither = randomBool( ) local doVariableStrength = false return PutAllContactMapBands( threshold, madeStrength, madeLenScale, unmadeStrength, unmadeLenScale, doSidechains, wantDither, true ) end function PutSomeContactMapBands( heatThreshold, strength, ctBands, doSidechains, omitLongBands ) local 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 if not omitLongBands or structure.GetDistance( i, j ) < CONTACTMAP_MAX_NOCONTACT then hotList[ #hotList + 1] = { i, j, heat } end end end end randomizeIndexList( hotList ) for i=1, math.min( ctBands, #hotList ) do local atom1 = nil local atom2 = nil if 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, omitLongBands ) local 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 if not omitLongBands or goalLength < CONTACTMAP_MAX_NOCONTACT then local atom = nil if doSidechain then atom = PickAtomNumberForBand( i ) end local changeSuc = BandBetweenSegsWithParameters( idx, i, strength, goalLength, nil, atom ) changeSucceeded = changeSuc or changeSucceeded end 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 if not omitLongBands or structure.GetDistance( i, idx ) < CONTACTMAP_MAX_NOCONTACT then hotList[ #hotList + 1] = i end end end end for i=1, #hotList do if hotList[ i ] ~= idx then -- not supposed to happen! local atom = nil if 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, omitLongBands ) local 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 not omitLongBands or goalLength < CONTACTMAP_MAX_NOCONTACT then 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 end return changeSucceeded end function PutPushPullContactMapBands( badSeg, bandsWanted, center, strength, heatThreshold, wantPushNotPull ) local 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 ) local 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 ACTION FUNCTIONS -- -- Very Similar AAs: -- leucine/isoleucine (L/I), glycine/alanine (G/A), serine/threonine (S/T), -- glutamine/glutamate (Q/E), asparagine/aspartate (D/N), -- Maybe also aromatics: histidine/phenylalanine/tyrosine/tryptophan (H/F/Y/W) -- Maybe aliphatic = valine/leucine/isoleucine (V/L/I) -- Maybe cysteine/methionine (C/M) -- Possibly arginine/lysine (R/K) -- Proline (P) isn't similar to anything! -------------------------------------------------------------- -- 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 function MutateToVerySimilar( idx ) local aa = structure.GetAminoAcid( idx ) local i = 0 local aanew = aa if aa == "a" then aanew = "g" elseif aa == "c" then aanew = "m" elseif aa == "d" then aanew = "n" elseif aa == "e" then aanew = "q" elseif aa == "g" then aanew = "a" elseif aa == "h" then local r = random(1,3) if r == 1 then aanew = "f" elseif r == 2 then aanew = "y" else aanew = "w" end elseif aa == "i" then local r = random(1,2) if r == 1 then aanew = "l" else aanew = "v" end elseif aa == "k" then aanew = "r" elseif aa == "l" then local r = random(1,2) if r == 1 then aanew = "i" else aanew = "v" end elseif aa == "m" then aanew = "c" elseif aa == "n" then aanew = "d" elseif aa == "p" then aanew = "p" -- proline isn't similar to anything elseif aa == "q" then aanew = "e" elseif aa == "r" then aanew = "k" elseif aa == "s" then aanew = "t" elseif aa == "t" then aanew = "s" elseif aa == "v" then local r = random(1,2) if r == 1 then aanew = "i" else aanew = "l" end elseif aa == "w" then local r = random(1,3) if r == 1 then aanew = "f" elseif r == 2 then aanew = "y" else aanew = "h" end elseif aa == "y" then local r = random(1,3) if r == 1 then aanew = "f" elseif r == 2 then aanew = "h" else aanew = "w" end else aanew = aa -- dunno what it is, but we can't play with it end print( "mutating " .. aa .. " at " .. idx .. " to " .. aanew ) structure.SetAminoAcid( idx, aanew ) return true end ---------------------------------------------------------------------- -- SPECIALTY ACTION HELPER FUNCTIONS ---------------------------------------------------------------------- function BandedWormPairAction( segStart, len, idxFirst, wantGlobalWiggle ) local initScore = getScore( ) selection.DeselectAll( ) selection.SelectRange( segStart, segStart + len - 1 ) PutSingleRandomBandToSeg( idxFirst, BWP_PROB_BIS_NOT_BETWEEN ) if randomBool( BWP_PROB_ADD_SECOND_BAND ) then local idx2 = random( segStart, segStart + len - 1 ) PutSingleRandomBandToSeg( idx2, BWP_PROB_2ND_IS_BIS ) end if wantGlobalWiggle then structure.WiggleSelected( random(2,4) ) else structure.LocalWiggleSelected( random(2,4) ) end DelBands( ) structure.WiggleAll( 2 ) structure.LocalWiggleSelected( 5 ) if getScore( ) - initScore > 0 then structure.LocalWiggleSelected( 20 ) else recentbest.Restore( ) structure.LocalWiggleSelected( 4 ) end recentbest.Restore( ) DelBands( ) return true end function WiggleRangeAction( startIdx, endIdx, wantGlobalWiggle, minGain ) selection.SelectRange( startIdx, endIdx ) local iters = QUICKWIGGLE_ITERS local startScore = getScore( ) gain = minGain while gain >= minGain do local lastScore = getScore() if wantGlobalWiggle then structure.WiggleSelected( iters, true, true) else structure.LocalWiggleSelected( iters, true, true ) end gain = getScore( ) - lastScore end selection.DeselectAll( ) return true end function AT_SelectWorsts( ) for i=1, SegCt do if current.GetSegmentEnergyScore(i) < 0.0 then selection.Select(i) end end end function AT_IsSegScoreAcceptable( seg ) local ss = current.GetSegmentEnergyScore( seg ) if ss < AT_MAXIMO or ss > 600.0 then return false end return true end function AT_Fix( seg ) for i = 1, SegCt do if i ~= seg then local dist=structure.GetDistance(seg, i) if dist<12.0 and dist>6.0 then local bidx = band.AddBetweenSegments(seg, i) band.SetGoalLength(bidx, dist) end end end SimpleWiggleSelected( 1 ) DelBands() end function AT_IterativeWiggleSelected( minGain ) -- DO NOT CALL recentbest.Save() !!! if minGain == nil then minGain = 0.001 end local iters if GetCI( ) < 1.0 then iters = 1 else iters = QUICKWIGGLE_ITERS end local lastScore = getQuickScore( ) local ctLoop = 0 local gain = minGain while gain >= minGain and ctLoop < 6 do structure.WiggleSelected( QUICKWIGGLE_ITERS, true, true ) gain = getQuickScore( ) - lastScore lastScore = getQuickScore( ) ctLoop = ctLoop + 1 end end function AT_wiggle_out( ) SetCI( 0.6 ) SimpleWiggleSelected( 2 ) SetCI( 1.0 ) AT_IterativeWiggleSelected( ) ShakeSelected( 1 ) SetCI( 0.6 ) AT_IterativeWiggleSelected( ) SetCI( 1.0 ) AT_IterativeWiggleSelected( ) recentbest.Restore( ) end function AT_getNear(seg, fixBand, checkScore) if checkScore == nil or getScore() < checkScore - 1000.0 then selection.Deselect( seg ) SetCI( 0.75 ) ShakeSelected( 1 ) SimpleWiggleSidechains( 1 ) selection.Select( seg ) SetCI( 1.0 ) end if checkScore == nil or getScore() < checkScore - 1000.0 then if fixBand then AT_Fix( seg ) else -- this might pick up a transient! recentbest.Restore() return getScore() > checkScore end end return true end function AT_MiniRebuild( seg ) selection.DeselectAll() selection.Select( seg ) --RebuildSelected(2) RebuildSelectedGetBest( 5 ) selection.DeselectAll() end function AT_IsUsableAA( i ) if not SegIsUsable( seg ) then return false end if not AT_IsSegScoreAcceptable( seg ) then return false end if forbidTinySidechains and isGlycineOrAlanine( seg ) then return false end return true end function ATSidechainTweakAction( idx, radius, wantRebuild, includeWorsts, fixBand ) if wantRebuild then AT_MiniRebuild( idx ) end recentbest.Save( ) local checkScore = getScore() selection.DeselectAll( ) selection.Select( idx ) SetCI( 0.0 ) ShakeSelected( 1 ) SetCI( 1.0 ) selection.DeselectAll() SelectSphere( idx, radius ) if includeWorsts then AT_SelectWorsts( ) end if AT_getNear( idx, fixBand, checkScore ) then AT_wiggle_out( ) end selection.DeselectAll() return true end function ATSidechainTweakAroundAction( idx, radius, wantRebuild, includeWorsts, fixBand ) if wantRebuild then AT_MiniRebuild( idx ) end recentbest.Save( ) local g_score = {} for n=1, SegCt do g_score[n] = current.GetSegmentEnergyScore(n) end selection.DeselectAll() selection.Select(idx) local checkScore = getScore() SetCI( 0 ) ShakeSelected( 1 ) SetCI( 1.0 ) SelectSphere(idx, radius) if includeWorsts then AT_SelectWorsts( ) end if getScore() > checkScore - 30.0 then -- good enough, just do a wiggle AT_wiggle_out( ) else -- try harder selection.DeselectAll() for n=1, SegCt do if (current.GetSegmentEnergyScore(n) < g_score[n] - 1) then selection.Select(n) end end selection.Deselect(idx) SetCI( 0.1 ) ShakeSelected( 1 ) SelectSphere(idx, radius, true) if includeWorsts then AT_SelectWorsts( ) end SetCI( 1.0 ) if AT_getNear( idx, fixBand, checkScore ) then AT_wiggle_out( ) end end selection.DeselectAll() return true end function ATSidechainManipulateAction( idx, radius, wantRebuild ) if wantRebuild then AT_MiniRebuild( idx ) end recentbest.Save( ) selection.DeselectAll() rotamers = rotamer.GetCount(idx) save.Quicksave( QS_ShortUseTemp1 ) save.Quicksave( QS_ShortUseTemp2 ) if rotamers > 1 then for r=1, rotamers do save.Quickload(QS_ShortUseTemp1) local checkScore = getScore() rotamer.SetRotamer(idx,r) SetCI(1.0) if getScore() > checkScore - 30.0 then selection.DeselectAll() SelectSphere( idx, radius ) AT_wiggle_out( ) -- this can change the number of rotamers SaveBest( false, QS_ShortUseTemp2 ) end if rotamers > rotamer.GetCount(idx) then break end end end selection.DeselectAll() save.Quickload( QS_ShortUseTemp2 ) return true end ---------------------------------------------------------------------- -- ---- IDEALIZERS AND REBUILDERS -- ---------------------------------------------------------------------- ---------------------------------------------------------------------- -- IDEALIZERS ---------------------------------------------------------------------- function IdealizeSelected( ) recentbest.Save() band.DisableAll( ) structure.IdealizeSelected( ) ResetUserBands( ) EnableMyBands() EnableAndDisableCysteineBands( ) if not checkCysteineSanity() then recentbest.Restore() return false end return true end -- no customers function IdealizeRange( startSeg, endSeg ) selection.DeselectAll() selection.SelectRange( startSeg, endSeg ) return IdealizeSelected( ) end function GetIdealizeRange( idx ) return GetActionRange( idx, IDEALIZE_MIN_SEGLEN, IDEALIZE_MAX_SEGLEN ) end function IdealizeRangeSimple( startSeg, endSeg, useCuts ) local idxList = { } save.Quicksave( QS_ShortUseTemp1 ) local changeFailed = false if startSeg > endSeg then startSeg, endSeg = endSeg, startSeg end if useCuts then if startSeg > MinUnlockedSeg + 1 then structure.InsertCut( startSeg - 1 ) end if endSeg < MaxUnlockedSeg then structure.InsertCut( endSeg ) end end selection.DeselectAll( ) selection.SelectRange( startSeg, endSeg ) local changeSucceeded = IdealizeSelected( ) if not changeSucceeded then save.Quickload( QS_ShortUseTemp1 ) return false end selection.DeselectAll( ) recentbest.Save( ) getSegsWithinRangeOfTube( idxList, startSeg, endSeg, IDEALIZE_TUBE_BIG_RADIUS ) ShakeOrMutate( 1, idxList ) for i=1, #idxList do selection.Select( idxList[i] ) end LongWiggleSelected( ) SimpleWiggleAll( ) -- a short wiggle of everything recentbest.Restore( ) selection.DeselectAll( ) if useCuts then if startSeg > MinUnlockedSeg + 1 then if not DeleteCutAtIndex( startSeg - 1 ) then changeFailed = true end end if endSeg < MaxUnlockedSeg then if not DeleteCutAtIndex( endSeg ) then changeFailed = true end end end if changeFailed then save.Quickload( QS_ShortUseTemp1 ) return false -- just give up end return true end function IdealizeRegionZlb( startSeg, endSeg, useCuts ) if useCuts == nil then useCuts = true end local idxList = { } changeFailed = false if startSeg > endSeg then startSeg, endSeg = endSeg, startSeg end if startSeg < MinUnlockedSeg then startSeg = MinUnlockedSeg end if endSeg > MaxUnlockedSeg then endSeg = MaxUnlockedSeg end local tries = 0 save.Quicksave( QS_ShortUseTemp1 ) local delta = 0.0 repeat save.Quickload( QS_ShortUseTemp1 ) changeFailed = false if IDEALIZE_ZLB_MAXTRIES > 1 and tries == IDEALIZE_ZLB_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 > MinUnlockedSeg then structure.InsertCut( startSeg - 2 ) end if endSeg + 1 < MaxUnlockedSeg then structure.InsertCut( endSeg + 1 ) end if startSeg - 3 >= MinUnlockedSeg then BandBetweenSegsWithParameters( startSeg-3, startSeg, 1.0 + delta, structure.GetDistance( startSeg-3, startSeg ) ) end if endSeg + 3 <= MaxUnlockedSeg then BandBetweenSegsWithParameters( endSeg, endSeg + 3, 1.0 + delta, structure.GetDistance( endSeg, endSeg+3 ) ) end end selection.DeselectAll( ) getSegsWithinRangeOfTube( idxList, startSeg, endSeg, IDEALIZE_TUBE_SMALL_RADIUS ) for i=1, #idxList do selection.Select( idxList[i] ) end changeSucceeded = IdealizeSelected( ) selection.DeselectAll( ) if changeSucceeded then if useCuts then -- get some wiggling happening WiggleZlbNicely( ZLB_DEFAULT_STRENGTH + delta, math.max( 1, startSeg-2 ), math.min( SegCt, endSeg+2 )) DebugPrint( "WiggleZlbNicely") -- now put the protein back in its proper shape if startSeg - 2 > MinUnlockedSeg then if not DeleteCutAtIndex(startSeg - 2 ) and IDEALIZE_FORBID_UNHEALED_CUTS then changeFailed = true end end if changeFailed == false and endSeg + 1 < MaxUnlockedSeg 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 recentbest.Save( ) DebugPrint( "SimpleRegionWiggle") SimpleRegionWiggle( startSeg, endSeg ) ShakeOrMutate( ) recentbest.Restore( ) end end if changeSucceeded and not changeFailed then DelBands( ) return true end tries = tries + 1 delta = delta + 0.25 until tries >= IDEALIZE_ZLB_MAXTRIES DelBands( ) -- we have failed. make sure the bands are gone and flee. return false end function lowCiIdealizer( idealizeMin, idealizeMax ) if idealizeMin == nil then idealizeMin = 1 end if idealizeMax == nil then idealizeMax = SegCt end local old_ci = GetCI() ExactSetCI( 0.05 ) ZLB( IDEALIZEALL_ZLB_STRENGTH ) selection.SelectRange( idealizeMin, idealizeMax ) local changeSucceeded = IdealizeSelected( ) if changeSucceeded then LongWiggleAll( ) -- was structure.WiggleAll( 30 ) ShakeOrMutate( ) LongWiggleAll( true, true ) -- was structure.WiggleAll( 30 ) selection.DeselectAll( ) end DelBands( ) print( "After Initial Idealizer = "..TrimNum( getScore( ))) ExactSetCI( old_ci ) return changeSucceeded end ---------------------------------------------------------------------- -- REBUILDERS ---------------------------------------------------------------------- function RebuildSelected( iters ) recentbest.Save( ) band.DisableAll( ) structure.RebuildSelected( iters ) ResetUserBands( ) EnableMyBands( ) EnableAndDisableCysteineBands( ) if not checkCysteineSanity() then recentbest.Restore() return false end return getQuickScore( ) ~= initscore end function RebuildSelectedGetBest( iters ) if iters == 1 then return RebuildSelected( 1 ) end local changeSucceeded = false local initscore = getQuickScore( ) local newScore = initscore local tries = 0 repeat tries = tries + 1 local chSuc = RebuildSelected( 1 ) changeSucceeded = changeSucceeded or chSuc newScore = getQuickScore( ) until newScore ~= initScore or tries > iters if changeSucceeded then -- N.B. this set of commands does the "get best of iters" attempts recentbest.Save( ) RebuildSelected( iters - 1 ) recentbest.Restore( ) -- recentbest's restore can lose our enabled-ness! ResetUserBands( ) EnableMyBands( ) EnableAndDisableCysteineBands( ) if not checkCysteineSanity() then return false end end return changeSucceeded end function GetRebuildRange( idx ) return GetActionRange( idx, REBUILD_MIN_SEGLEN, REBUILD_MAX_SEGLEN ) end function DeepRebuildRange( idxStart, idxEnd, maxTries ) if maxTries == nil then maxTries = REBUILD_DEEP_MAXTRIES end local wantHelix = isPossibleHelix( idxStart ) local changeSucceeded = false local locss = {} local changedSS = false local startScore = getQuickScore( ) local currScore = startScore local timeStart = os.time() for i=idxStart, idxEnd do locss[i] = structure.GetSecondaryStructure( i ) end for i=idxStart, idxEnd do if wantHelix then -- we think there's a helix, so tell rebuild to go with it changedSS = true structure.SetSecondaryStructure( i, 'H' ) elseif structure.GetSecondaryStructure( i ) == 'E' then -- sheet isn't worth telling rebuild about changedSS = 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 = -100000.0 for i=1, maxTries do local idxListInner = { } save.Quickload( QS_ShortUseTemp1 ) -- bring up our "running" pose selection.SelectRange( idxStart, idxEnd ) changeSucceeded = RebuildSelected( 1 ) selection.DeselectAll( ) if changeSucceeded then -- give the whole thing a little bit of shake-and-wiggle-time timeStart = os.time() WiggleRangeShakeTubeWiggleAll( idxStart, idxEnd, REBUILD_TUBE_INNER_RADIUS ) rescore = getQuickScore( ) print("Try "..i..": time="..(os.time() - timeStart).." Score="..rescore) if rescore > bestRescore then save.Quicksave( QS_ShortUseTemp2 ) -- our best-so-far is better bestRescore = rescore if rescore > currScore then -- we have a real improvement! -- cheat: use the better result as our base for future rebuilds -- instead of original pose save.Quicksave( QS_ShortUseTemp1 ) currScore = rescore end end end end save.Quickload( QS_ShortUseTemp2 ) if changedSS then for i=idxStart, idxEnd do structure.SetSecondaryStructure( i, locss[ i ] ) end end return changeSucceeded end function DeepRebuildRangeAction( idxStart, idxEnd, wantBands ) local changeSucceeded = false local timeStart = os.time() local didIdealize = false local idxList = {} if wantBands then AddRandomXToYBands( XTOY_REBUILD_STRENGTH ) end timeStart = os.time() -- use a rebuilder that wiggles all the ones it sees and gives back the very best changeSucceeded = DeepRebuildRange( idxStart, idxEnd ) if wantBands then DelBands( ) end if changeSucceeded then -- used to offer idealize, but only 1-2% of tries got benefit. -- we did a tiny bit of WSW in DeepRebuildRange, close out with a better wiggler idxList = {} getSegsWithinRangeOfTube( idxList, idxStart, idxEnd, REBUILD_TUBE_OUTER_RADIUS ) DebugPrint( "WiggleShakeListWiggleAll-SWTillStable" ) WiggleShakeListWiggleAll( idxList, MUTATE_ONCE ) ShakeWiggleTillStable( nil, MUTATE_ONCE ) end return changeSucceeded end function RebuildRangeFromQuaker( idxStart, idxEnd, maxTries ) local changeSucceeded = false local initScore = getQuickScore( ) selection.DeselectAll( ) selection.SelectRange( idxStart, idxEnd ) changeSucceeded = RebuildSelectedGetBest( maxTries ) if changeSucceeded then DebugPrint( "WiggleRangeShakeTubeWiggleAll-SWTillStable") WiggleRangeShakeTubeWiggleAll( idxStart, idxEnd, REBUILD_TUBE_OUTER_RADIUS ) ShakeWiggleTillStable( nil, MUTATE_ONCE ) end return changeSucceeded end -- this one actually does a quake if it thinks it's worth doing function QuakingRebuild( idxStart, idxEnd, maxTries ) local changeSucceeded = false local initScore = getQuickScore( ) local tries = 0 selection.DeselectAll( ) selection.SelectRange( idxStart, idxEnd ) changeSucceeded = RebuildSelectedGetBest( maxTries ) if changeSucceeded then DebugPrint( "WiggleRangeShakeTubeWiggleAll") WiggleRangeShakeTubeWiggleAll( idxStart, idxEnd, REBUILD_TUBE_SMALLEST_RADIUS ) ShakeOrMutate( nil, nil, MUTATE_ONCE ) LongWiggleAll( ) currScore = getScore() if currScore < initScore and currScore > initScore - 50.0 then -- LSQuake is the only not-too-slow quake that cares what idxStart/End are whichIdx = math.floor( (idxStart + idxEnd) / 2 ) PerformLSQuakeAction( whichIdx ) else DebugPrint( "ShakeWiggleTillStable" ) ShakeWiggleTillStable( nil, MUTATE_ONCE ) end end return changeSucceeded end -- does a single rebuild, try to make it good function RebuildSimpleCore( idxStart, idxEnd, addIdealize, wantBands, wantRemix ) if idxEnd < MinUnlockedSeg or idxStart > MaxUnlockedSeg then return false end if idxStart < MinUnlockedSeg then idxStart = MinUnlockedSeg end if idxEnd > MaxUnlockedSeg then idxEnd = MaxUnlockedSeg end if addIdealize == nil then addIdealize = REBUILD_ADDIDEALIZE end if wantBands then DebugPrint("Adding X-Y bands") AddRandomXToYBands( XTOY_REBUILD_STRENGTH ) end local initscore = getQuickScore( ) local idxList = { } for i=idxStart, idxEnd do idxList[ #idxList + 1 ] = i end selection.DeselectAll( ) selection.SelectRange( idxStart, idxEnd ) if wantRemix then changeSucceeded = RemixSelectedOnce( ) else changeSucceeded = RebuildSelected( 1 ) end if changeSucceeded then DebugPrint( "RS-Wiggler") recentbest.Save( ) ShakeOrMutate( nil, idxList ) recentbest.Restore( ) if addIdealize then local chSuc = IdealizeSelected( ) if chSuc then recentbest.Restore( ) ShakeOrMutate( nil, idxList, MUTATE_ONCE ) recentbest.Restore( ) structure.WiggleAll( 25 ) recentbest.Restore( ) ShakeOrMutate( nil, nil, MUTATE_ONCE ) end end LongWiggleAll( ) recentbest.Restore( ) DelBands( ) ShakeWiggleTillStable( nil, MUTATE_ONCE ) else DelBands( ) end return changeSucceeded end function RebuildSimple( idxStart, idxEnd, addIdealize ) return RebuildSimpleCore( idxStart, idxEnd, addIdealize, false, false ) end function RebuildSimpleXToY( idxStart, idxEnd, addIdealize ) return RebuildSimpleCore( idxStart, idxEnd, addIdealize, true, false ) end function RemixSimple( idxStart, idxEnd, addIdealize ) return RebuildSimpleCore( idxStart, idxEnd, addIdealize, false, true ) end function RemixSimpleXToY( idxStart, idxEnd, addIdealize ) return RebuildSimpleCore( idxStart, idxEnd, addIdealize, true, true ) end -- Get best scorer of several rebuilds, do good wiggle/shake action function RebuildBitspawn( idxStart, idxEnd, useLowCIRules ) selection.DeselectAll( ) selection.SelectRange( idxStart, idxEnd ) local changeSucceeded = RebuildSelectedGetBest( REBUILD_DEEP_MAXTRIES ) selection.DeselectAll( ) if changeSucceeded then DebugPrint( "RBits-Wiggler") if useLowCIRules then local ciOld = GetCI( ) ExactSetCI( 0.05 ) ShakeOrMutate( ) ExactSetCI( ciOld ) else ShakeOrMutate( nil, nil, MUTATE_NOT_SHAKE ) SimpleWiggleAll( ) ShakeOrMutate( nil, nil, MUTATE_ONCE ) end structure.WiggleAll( 16 ) -- leave it like this. ShakeWiggleTillStable( nil, MUTATE_ONCE ) return true end return changeSucceeded end function PerformWiskyRebuildAllAction( ) print("WiskyRebuildAll") SelectAllMovable( ) local changeSucceeded = RebuildSelected( 1 ) if changeSucceeded then ShakeWiggleTillStable( ) end return changeSucceeded end function PerformRebuildAllWithIdealizeAction( ) print("RebuildAllWithIdealize") SelectAllMovable( ) local changeSucceeded = RebuildSelected( 1 ) if changeSucceeded then ShakeWiggleTillStable( ) lowCiIdealizer() end return changeSucceeded end ---------------------------------------------------------------------- -- REMIX HELPER FUNCTIONS ---------------------------------------------------------------------- function GetRemixRange( idx ) return GetActionRange( idx, REMIX_MIN_SEGLEN, REMIX_MAX_SEGLEN ) end function RemixSelectedOnce( ) local remixCt = structure.RemixSelected( QS_RemixSlot1, REMIX_MAX_SLOTS_TO_USE) if remixCt == 0 then return false end local scMax = -999999.9 local qsBest = QS_RemixSlot1 for i=1, remixCt do local qs = QS_RemixSlot1 + i - 1 local curScore = getSlotScore( qs ) if curScore > scMax or scMax == -999999.9 then scMax = curScore qsBest = qs end end save.Quickload( qsBest ) return true end function RemixAction( idxStart, idxEnd, wantBands ) if wantBands then DebugPrint("Adding X-Y bands") -- I think XToY's default strength is too strong for remix. AddRandomXToYBands( XTOY_REMIX_STRENGTH ) end local initScore = getScore() local bestScore = -10000.0 local bestSlot = 0 local remixesToTry = math.min( REMIX_SLOTS_WANTED, REMIX_MAX_SLOTS_TO_USE ) local minToDoReTry = REMIX_MAX_SLOTS_TO_WIGGLE + math.floor(REMIX_MAX_SLOTS_TO_WIGGLE/2) local actualToRetry = 2*REMIX_MAX_SLOTS_TO_WIGGLE local slotsToDoFullWiggleCheck = REMIX_MAX_SLOTS_TO_WIGGLE selection.SelectRange( idxStart, idxEnd ) local remixCt = structure.RemixSelected( QS_RemixSlot1, remixesToTry ) if remixCt == 0 then print("no remixes found") if wantBands then DelBands() end return false end -- 1st-level Pass - go through all the returned answers, doing a simple shake local slotList = {} local slotIdxes = {} local scoreList = {} local idxList = {} local timeStart = os.time() for i=1, remixCt do -- load an answer save.Quickload( QS_RemixSlot1 + i - 1 ) if checkCysteineSanity() then -- some pre-shaking to help decide which rebuilds are "best" -- NOTE: adding more actions serve only to greatly increase the -- time spent in this phase. Expanding to a tube similarly -- makes actions too expensive. selection.DeselectAll() selection.SelectRange( idxStart, idxEnd ) ShakeSelected( 1, false ) -- Track what we did save.Quicksave( QS_RemixSlot1 + i - 1 ) slotList[ #slotList + 1 ] = QS_RemixSlot1 + i - 1 scoreList[ #scoreList + 1] = getScore( ) slotIdxes[ #slotIdxes + 1] = #slotIdxes + 1 end end if #slotIdxes == 0 then print("no sane remixes found") if wantBands then DelBands() end return false end if #slotIdxes > slotsToDoFullWiggleCheck then print("Check of "..#slotIdxes.." answers took "..(os.time() - timeStart).." seconds") end sortByScoreDecr( slotIdxes, scoreList ) -- 2nd-level Pass - go through the top "actualToRetry", do very simple wiggling timeStart = os.time() if #slotList >= minToDoReTry then local slotList2 = {} local scoreList2 = {} local slotIdxes2 = {} for i=1, math.min( #slotList, actualToRetry) do slotList2[ #slotList2 + 1 ] = slotList[ slotIdxes[i] ] slotIdxes2[ #slotIdxes2 + 1] = #slotIdxes2 + 1 end for i=1, math.min( #slotList, actualToRetry) do -- give top ones extra jiggling local idxList = {} save.Quickload( slotList2[ slotIdxes2[i] ] ) -- try some very simple wiggle action. this time spend money on a tube selection.DeselectAll() getSegsWithinRangeOfTube( idxList, idxStart, idxEnd, REMIX_TUBE_INNER_RADIUS ) for j=1, #idxList do selection.Select(idxList[j]) end SimpleWiggleSidechainsSelected( 1 ) SimpleLocalWiggleSelected( 1 ) scoreList2[ i ] = getScore( ) end slotIdxes = slotIdxes2 scoreList = scoreList2 slotList = slotList2 print("Check of top "..math.min( #slotList, actualToRetry).. " answers took "..(os.time() - timeStart).." seconds") sortByScoreDecr( slotIdxes, scoreList ) end -- 3rd-level Pass - collect the best few and do "real" wiggle+shake/mutate on them local bestI = 0 for i=1, math.min( #slotList, slotsToDoFullWiggleCheck) do selection.DeselectAll() -- load an answer save.Quickload( slotList[ slotIdxes[i] ] ) -- wiggle the result enough to decide which is best local currScore = getScore() local timeStart = os.time() -- TODO: Decide argument: should I mutate here and spend lots of money for more accuracy, -- or do it at the very end instead? WiggleRangeShakeTubeWiggleAll( idxStart, idxEnd, REMIX_TUBE_OUTER_RADIUS ) timeEnd = os.time() print( "RMWiggle["..slotList[slotIdxes[i]].."] score: "..TrimNum(currScore).. " -> "..TrimNum(getScore()).. " time:"..(timeEnd - timeStart)) -- save it so we can reload when we know which one we love best save.Quicksave( slotList[ slotIdxes[i] ] ) -- Pick the highest scoring result local currScore = getScore() if currScore > bestScore then bestScore = currScore bestSlot = slotList[ slotIdxes[i] ] bestI = i end end -- get the best one, do a cleanup wiggle, and flee. if bestSlot == 0 then return false end save.Quickload( bestSlot ) -- finish up the wiggle for our winner! ShakeWiggleTillStable( nil, MUTATE_ONCE ) return true end ---------------------------------------------------------------------- -- FUNCTIONS TO PERFORM SOME SPECIFIC ACTION ---------------------------------------------------------------------- function PerformRemixAction( idx ) if idx == nil or idx == 0 then idx = randomMovableSeg( ) end local startIdx, endIdx = GetRemixRange( idx ) print( "Remix for "..startIdx..","..endIdx ) return RemixAction( startIdx, endIdx, false ) end function PerformRemixXToYAction( idx ) if idx == nil or idx == 0 then idx = randomMovableSeg( ) end local startIdx, endIdx = GetRemixRange( idx ) print( "RemixXToY for "..startIdx..","..endIdx ) return RemixAction( startIdx, endIdx, true ) end function PerformRemixSimpleAction( idx ) if idx == nil or idx == 0 then idx = randomMovableSeg( ) end local idxStart, idxEnd = GetRebuildRange( idx ) print( "RemixSimple for " ..idxStart.. "," ..idxEnd ) return RemixSimple( idxStart, idxEnd, REMIX_ADDIDEALIZE ) end function PerformRemixSimpleXToYAction( idx ) if idx == nil or idx == 0 then idx = randomMovableSeg( ) end local idxStart, idxEnd = GetRebuildRange( idx ) print( "RemixSimpleXToY for " ..idxStart.. "," ..idxEnd ) return RemixSimpleXToY( idxStart, idxEnd, REMIX_ADDIDEALIZE ) end function PerformDeepRebuildAction( idx ) if idx == nil or idx == 0 then idx = randomMovableSeg( ) end local idxStart, idxEnd = GetRebuildRange( idx ) print( "DeepRebuildRange for "..idxStart..","..idxEnd) return DeepRebuildRangeAction( idxStart, idxEnd, false ) end function PerformDeepRebuildXToYAction( idx ) if idx == nil or idx == 0 then idx = randomMovableSeg( ) end local idxStart, idxEnd = GetRebuildRange( idx ) print( "DeepRebuildRangeXToY for "..idxStart..","..idxEnd) return DeepRebuildRangeAction( idxStart, idxEnd, true ) end function PerformDeepRebuildSSAction( idx ) if idx == nil or idx == 0 then idx = randomMovableSeg( ) end -- This uses a range (mostly) matching some Secondary Structure: local idxStart, idxEnd = GetRegionForOperation( idx ) print( "DeepRebuildSS for " ..idxStart.. "," ..idxEnd ) return DeepRebuildRangeAction( idxStart, idxEnd, false ) end function PerformDeepRebuildSSXToYAction( idx ) if idx == nil or idx == 0 then idx = randomMovableSeg( ) end -- This uses a range (mostly) matching some Secondary Structure: local idxStart, idxEnd = GetRegionForOperation( idx ) print( "DeepRebuildSSXToY for " ..idxStart.. "," ..idxEnd ) return DeepRebuildRangeAction( idxStart, idxEnd, true ) end function PerformRebuildSimplePointAction( idx ) if idx == nil or idx == 0 then idx = randomMovableSeg( ) end print( "RebuildSimplePoint for "..idx ) return RebuildSimple( idx, idx, REBUILD_ADDIDEALIZE ) end function PerformRebuildSimpleAction( idx ) if idx == nil or idx == 0 then idx = randomMovableSeg( ) end local idxStart, idxEnd = GetRebuildRange( idx ) print( "RebuildSimple for " ..idxStart.. "," ..idxEnd ) return RebuildSimple( idxStart, idxEnd, REBUILD_ADDIDEALIZE ) end function PerformRebuildSimpleXToYAction( idx ) if idx == nil or idx == 0 then idx = randomMovableSeg( ) end local idxStart, idxEnd = GetRebuildRange( idx ) print( "RebuildSimpleXToY for " ..idxStart.. "," ..idxEnd ) return RebuildSimpleXToY( idxStart, idxEnd, REBUILD_ADDIDEALIZE ) end function PerformRebuildFromQuakerAction( idx ) if idx == nil or idx == 0 then idx = randomMovableSeg( ) end local idxStart, idxEnd = GetRebuildRange( idx ) print( "RebuildFromQuaker for " ..idxStart.. "," ..idxEnd ) return RebuildRangeFromQuaker( idxStart, idxEnd, REBUILD_DEEP_MAXTRIES ) end function PerformRebuildBitspawnAction( idx ) if idx == nil or idx == 0 then idx = randomMovableSeg( ) end local idxStart, idxEnd = GetRebuildRange( idx ) print( "RebuildBitspawn for " ..idxStart.. "," ..idxEnd ) return RebuildBitspawn( idxStart, idxEnd, false ) end function PerformRebuildBitspawnLowCI( idx ) if idx == nil or idx == 0 then idx = randomMovableSeg( ) end local idxStart, idxEnd = GetRebuildRange( idx ) print( "RebuildBitspawnLowCI for " ..idxStart.. "," ..idxEnd ) return RebuildBitspawn( idxStart, idxEnd, true ) end function PerformQuakingRebuild( idx ) if idx == nil or idx == 0 then idx = randomMovableSeg( ) end local idxStart, idxEnd = GetRebuildRange( idx ) print( "QuakingRebuild for " ..idxStart.. "," ..idxEnd ) return QuakingRebuild( idxStart, idxEnd, REBUILD_DEEP_MAXTRIES ) end function PerformIdealizeZlbAction( idx ) if idx == nil then idx = randomMovableSeg( ) end local idxStart, idxEnd = GetIdealizeRange( idx ) print( "IdealizeZlb for ".. idxStart..","..idxEnd ) local changeSucceeded = IdealizeRegionZlb( idxStart, idxEnd, IDEALIZE_USE_CUTS ) DebugPrint( "CleanQStabWiggleOut" ) CleanQStabWiggleOut( PROB_QSTAB_EXTRA_IDEALIZE ) return changeSucceeded end function PerformIdealizeRegionAction( idx ) local idxList = { } if idx == nil then idx = randomMovableSeg( ) end local idxStart, idxEnd = GetIdealizeRange( idx ) print( "IdealizeRegion for ".. idxStart..","..idxEnd ) -- idealize everything in smaller vicinity of idxStart .. idxEnd -- TODO: try IDEALIZE_TUBE_BIG_RADIUS, see how things change getSegsWithinRangeOfTube( idxList, idxStart, idxEnd, IDEALIZE_TUBE_SMALL_RADIUS ) selection.DeselectAll( ) for i=1, #idxList do selection.Select( idxList[i] ) end local changeSucceeded = IdealizeSelected( ) selection.DeselectAll( ) WiggleShakeListWiggleAll( idxList ) DebugPrint( "CleanQStabWiggleOut" ) CleanQStabWiggleOut( PROB_QSTAB_EXTRA_IDEALIZE ) return changeSucceeded end function PerformIdealizeRegionXToYAction( idx ) local idxList = { } if idx == nil then idx = randomMovableSeg( ) end local idxStart, idxEnd = GetIdealizeRange( idx ) print( "IdealizeXToY for ".. idxStart..","..idxEnd ) DebugPrint("Adding X-Y bands") AddRandomXToYBands( XTOY_IDEALIZE_STRENGTH ) -- idealize everything in larger vicinity of idxStart .. idxEnd -- TODO: try IDEALIZE_TUBE_SMALL_RADIUS, see how things change getSegsWithinRangeOfTube( idxList, idxStart, idxEnd, IDEALIZE_TUBE_BIG_RADIUS ) selection.DeselectAll( ) for i=1, #idxList do selection.Select( idxList[i] ) end local changeSucceeded = IdealizeSelected( ) selection.DeselectAll( ) WiggleShakeListWiggleAll( idxList ) DelBands( ) DebugPrint( "CleanQStabWiggleOut" ) CleanQStabWiggleOut( PROB_QSTAB_EXTRA_IDEALIZE ) return changeSucceeded end function PerformIdealizePointAction( idx ) if idx == nil then idx = randomMovableSeg( ) end print( "IdealizePoint for ".. idx ) local changeSucceeded = IdealizeRangeSimple( idx, idx, IDEALIZE_USE_CUTS ) DebugPrint( "ShakeWiggleTillStable" ) ShakeWiggleTillStable( nil, MUTATE_ONCE ) return changeSucceeded end function PerformSpotMutatorAction( idx ) if idx == nil then idx = randomMovableSeg( ) end -- better would be random mutable seg print( "SpotMutator for " .. idx ) local changeSucceeded = false if randomBool( MUTATESIMILAR_PROB ) then if randomBool() then changeSucceeded = MutateToVerySimilar( idx) else changeSucceeded = MutateToSimilar( idx ) end else changeSucceeded = MutateToAny( idx ) end if changeSucceeded then DebugPrint( "WiggleShakeCleanWiggleOut" ) WiggleShakeCleanWiggleOut( ) end return changeSucceeded end function PerformSingleBandInSpaceAction( idx ) if idx == nil then idx = randomMovableSeg( ) end local strength = random( BAND_STRENGTH_DEFAULT / 2, BAND_STRENGTH_DEFAULT, true ) local atom = PickAtomNumberForBand( idx ) local goalLength = random( BIS_MIN_GOALLENGTH, BIS_MAX_GOALLENGTH ) print( "BIS for " .. idx.." with strength "..TrimNum( strength ) ) local changeSucceeded = PutBandInSpace( idx, BIS_LENGTH, strength, goalLength, atom ) if changeSucceeded then DebugPrint( "WiggleShakeCleanWiggleOut" ) WiggleShakeCleanWiggleOut( ) end return changeSucceeded end function PerformBandToRandomSegAction( idx ) if idx == nil then idx = randomMovableSeg( ) end local strength = BAND_STRENGTH_DEFAULT local atom = PickAtomNumberForBand( idx ) print( "BandBetween for " .. idx.." with strength "..TrimNum( strength ) ) local changeSucceeded = PutBandToRandomSeg( idx, strength, atom ) if changeSucceeded then DebugPrint( "WiggleShakeCleanWiggleOut" ) WiggleShakeCleanWiggleOut( ) end return changeSucceeded end function PerformPushPullAction( idx ) if idx == nil then idx = randomMovableSeg( ) end local segList = {} local wantPushNotPull = randomBool( ) local ctBands = 5 local strength = BAND_STRENGTH_DEFAULT print( "PushPull for " .. idx ) 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) ] local changeSucceeded = PutPushPullBands( idx, ctBands, centerSeg, strength, wantPushNotPull ) if changeSucceeded then DebugPrint( "SimpleBandedWiggleShakeWrapper" ) SimpleBandedWiggleShakeWrapper( ) -- nil, nil, PROB_QSTAB_EXTRA_VOIDCRUSH ) end return changeSucceeded end function PerformVoidCrusherAction( idx ) if idx == nil then idx = randomMovableSeg( ) end local strength = BAND_STRENGTH_DEFAULT print( "VoidCrusher for " .. idx ) changeSucceeded = PutVoidCrusherBands( idx, strength ) if changeSucceeded then DebugPrint( "SimpleBandedWiggleShakeWrapper" ) SimpleBandedWiggleShakeWrapper( ) -- nil, nil, PROB_QSTAB_EXTRA_VOIDCRUSH ) end return changeSucceeded end function PerformGlycineHingeAction( idx ) if idx == nil then idx = randomAASeg( ) end if idx == 0 then return false end local strength = random( 0.25, BAND_STRENGTH_DEFAULT, true ) print( "GlycineHinge for "..idx) local startSeg = math.max( 1, idx - 4 - random( 0, 2 )) local endSeg = math.min( SegCt, idx + 4 + random( 0, 2 )) local changeSucceeded = PutGlycineHingeBands( idx, strength ) if changeSucceeded then beginSeg = math.max( 1, startSeg - 3) finalSeg = math.min( SegCt, endSeg + 3) SetCI( CI_REGIONMOD ) SimpleRegionWiggle( beginSeg, finalSeg, false, 2 + random( 4 )) CleanQStabWiggleOut( PROB_QSTAB_EXTRA_MOVERBANDS ) end return changeSucceeded end function PerformGeneralHingeAction( 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 print( "GeneralHinge for "..startSeg..","..endSeg) local changeSucceeded = PutGeneralHingeBands( startSeg, endSeg, strength ) if changeSucceeded then beginSeg = math.max( 1, startSeg - 3) finalSeg = math.min( SegCt, endSeg + 3) SetCI( CI_REGIONMOD ) SimpleRegionWiggle( beginSeg, finalSeg, false, 2 + random( 4 )) CleanQStabWiggleOut( PROB_QSTAB_EXTRA_MOVERBANDS ) end return changeSucceeded end function PerformPusherAction( idx ) if idx == nil then idx = randomMovableSeg( ) end local strength = BAND_STRENGTH_REGION local bisLen = BIS_LENGTH_LONG local goForward = randomBool() local doublePush = randomBool() local startSeg, endSeg = GetRegionForOperation( idx ) print( "Pusher for "..startSeg..","..endSeg) if endSeg - startSeg <= 1 then return false end -- something's very wrong local changeSucceeded = PutPusherBands( startSeg, endSeg, bisLen, strength, goForward ) if changeSucceeded then SetCI( CI_REGIONMOD ) DebugPrint( "SimpleRegionWiggle" ) SimpleRegionWiggle( startSeg, endSeg, false, 2 + random( 4 ) ) end DelBands( ) if doublePush then changeSucceeded = PutPusherBands( startSeg, endSeg, bisLen, strength, goForward ) if changeSucceeded then SetCI( CI_REGIONMOD ) DebugPrint( "SimpleRegionWiggle-2" ) SimpleRegionWiggle( startSeg, endSeg, false, 4 + random( 3 ) ) end end DebugPrint( "CleanQStabWiggleOut" ) CleanQStabWiggleOut( PROB_QSTAB_EXTRA_MOVERBANDS ) return changeSucceeded end function PerformMoverAction( idx ) if idx == nil then idx = randomMovableSeg( ) end local strength = BAND_STRENGTH_REGION local bisLen = BIS_LENGTH_LONG local doubleMove = randomBool() local startSeg, endSeg = GetRegionForOperation( idx ) print( "Mover for "..startSeg..","..endSeg) if endSeg - startSeg <= 1 then return false end -- something's very wrong local changeSucceeded = PutMoverBands( startSeg, endSeg, bisLen, strength ) if changeSucceeded then SetCI( CI_REGIONMOD ) DebugPrint( "SimpleRegionWiggle" ) SimpleRegionWiggle( startSeg, endSeg, false, 2 + random( 4 ) ) end DelBands( ) if doubleMove then changeSucceeded = PutMoverBands( startSeg, endSeg, bisLen, strength ) if changeSucceeded then SetCI( CI_REGIONMOD ) DebugPrint( "SimpleRegionWiggle-2" ) SimpleRegionWiggle( startSeg, endSeg, false, 4 + random( 3 ) ) end end DebugPrint( "CleanQStabWiggleOut" ) CleanQStabWiggleOut( PROB_QSTAB_EXTRA_MOVERBANDS ) return changeSucceeded end function PerformFlexerAction( idx ) if idx == nil then idx = randomMovableSeg( ) end local strength = BAND_STRENGTH_REGION local bisLen = BIS_LENGTH local doubleFlex = randomBool() local startSeg, endSeg = GetRegionForOperation( idx ) print( "Flexer for "..startSeg..","..endSeg) if endSeg - startSeg <= 1 then return false end -- something's very wrong local changeSucceeded = PutFlexerBands( startSeg, endSeg, bisLen, strength ) if changeSucceeded then SetCI( CI_REGIONMOD ) DebugPrint( "SimpleRegionWiggle" ) SimpleRegionWiggle( startSeg, endSeg, false, 2 + random( 4 ) ) end DelBands( ) if doubleFlex then changeSucceeded = PutFlexerBands( startSeg, endSeg, bisLen, strength ) if changeSucceeded then SetCI( CI_REGIONMOD ) DebugPrint( "SimpleRegionWiggle-2" ) SimpleRegionWiggle( startSeg, endSeg, false, 4 + random( 3 ) ) end end DebugPrint( "CleanQStabWiggleOut" ) CleanQStabWiggleOut( PROB_QSTAB_EXTRA_MOVERBANDS ) return changeSucceeded end function PerformSheetAlignerAction( idx ) if idx == nil then idx = randomMovableSeg( ) end local sheetIdxFirst = GetIndexOfSheet( idx ) local nbrSheets = {} local changeSucceeded = false local gotTwoSheet = false local gotStraySheet = false local startSeg, endSeg = GetRegionForOperation( idx ) print( "SheetAligner for "..startSeg..","..endSeg) if endSeg - startSeg <= 1 then return false end -- something's very wrong nbrSheets = FindNeighborSheets( idx ) if #nbrSheets > 0 then if #nbrSheets ==1 or #nbrSheets > 2 then -- just pick one if there's only one or if it's confusing sheetIdxSecond = nbrSheets[random(1, #nbrSheets)] changeSucceeded = BandAdjacentSheets( sheetIdxFirst, sheetIdxSecond, 0 ) else -- if exactly 2 neighbors, try to make them both play nice changeSucceeded = BandAdjacentSheets( sheetIdxFirst, nbrSheets[1], 0 ) local chSuc = BandAdjacentSheets( sheetIdxFirst, nbrSheets[2], 0 ) changeSucceeded = changeSucceeded or chSuc gotTwoSheet = true end else changeSucceeded = BandStraySheetToNearestSheet( sheetIdxFirst ) gotStraySheet = true end if changeSucceeded then SetCI( CI_REGIONMOD ) DebugPrint( "SimpleLocalWiggleAll" ) SimpleLocalWiggleAll( 2 ) -- fancier games did less well. DebugPrint( "CleanQStabWiggleOut" ) CleanQStabWiggleOut( ) -- PROB_QSTAB_EXTRA_MOVERBANDS ) end return changeSucceeded end function PerformSheetShifterAction( idx ) if idx == nil then idx = randomMovableSeg( ) end local sheetIdxFirst = GetIndexOfSheet( idx ) local startSeg, endSeg = GetRegionForOperation( idx ) print( "SheetShifter for "..startSeg..","..endSeg) if endSeg - startSeg <= 1 then return false end -- something's very wrong nbrSheets = FindNeighborSheets( idx ) if #nbrSheets > 0 then local r = random( #nbrSheets ) sheetIdxSecond = nbrSheets[ r ] local delta r = random( 2 ) if r == 1 then delta = 1 else delta = -1 end changeSucceeded = BandAdjacentSheets( sheetIdxFirst, sheetIdxSecond, delta ) else -- no point shifting if there isn't a neighbor! changeSucceeded = false end if changeSucceeded then local startWiggleSeg, endWiggleSeg SetCI( CI_REGIONMOD ) SimpleLocalWiggleAll( 2 ) --DebugPrint( "WiggleRange" ) --startWiggleSeg, endWiggleSeg = GetExtendedRegionForWiggle( startSeg, endSeg ) --WiggleRange( startWiggleSeg, endWiggleSeg, false, false ) DebugPrint( "CleanQStabWiggleOut" ) CleanQStabWiggleOut( ) -- PROB_QSTAB_EXTRA_MOVERBANDS ) else ResetFrozenness( ) DelBands( ) selection.DeselectAll() end return changeSucceeded end function PerformSheetFlipperAction( idx ) if idx == nil then idx = randomMovableSeg( ) end local sheetIdxFirst = GetIndexOfSheet( idx ) local startSeg, endSeg = GetRegionForOperation( idx ) print( "SheetFlipper for "..startSeg..","..endSeg) if endSeg - startSeg <= 1 then return false end -- something's very wrong nbrSheets = FindNeighborSheets( idx ) if #nbrSheets > 0 then DebugPrint("There are "..(#nbrSheets).." neighboring sheets") sheetIdxSecond = nbrSheets[random(1, #nbrSheets)] -- give it some help with the rotation part! ZLB( 8.0, startSeg, endSeg, true ) selection.DeselectAll() selection.SelectRange( startSeg, endSeg ) freeze.FreezeSelected( true, false ) changeSucceeded = PutFlipSheetBands( startSeg, endSeg, BIS_LENGTH, BAND_STRENGTH_REGION ) if changeSucceeded then SetCI( 0 ) DebugPrint( "SimpleRegionWiggle" ) WiggleRange( startSeg, endSeg, false, false ) DelBands( ) ZLB( 8.0, startSeg, endSeg, true ) changeSucceeded = PutFlipSheetBands( startSeg, endSeg, BIS_LENGTH, BAND_STRENGTH_REGION ) WiggleRange( startSeg, endSeg, false, false ) end ResetFrozenness( ) DelBands( ) changeSucceeded = BandAdjacentSheets( sheetIdxFirst, sheetIdxSecond, 1 ) else -- no point flipping if there isn't a neighbor! changeSucceeded = false end if changeSucceeded then SetCI( CI_REGIONMOD ) DebugPrint( "SimpleLocalWiggleAll" ) SimpleLocalWiggleAll( 2 ) DebugPrint( "CleanQStabWiggleOut" ) CleanQStabWiggleOut( ) -- PROB_QSTAB_EXTRA_MOVERBANDS ) end ResetFrozenness( ) DelBands( ) selection.DeselectAll() return changeSucceeded end function PerformSheetSewerAction( ) -- original: always 8.0. More recent: 4-12 local maxSheetDistance = random( 4.0, 10.0, true ) local strength = BAND_STRENGTH_DEFAULT local startScore = getQuickScore() print( "SheetSewer") local changeSucceeded = PutSheetSewerBandsAllOver( maxSheetDistance, strength ) if changeSucceeded then SetCI( CI_REGIONMOD ) SimpleLocalWiggleAll( 2 ) DebugPrint( "CleanQStabWiggleOut" ) CleanQStabWiggleOut( ) -- PROB_QSTAB_EXTRA_MOVERBANDS ) end return changeSucceeded end function PerformSheetStraightenerAction( idx ) if idx == nil then idx = randomMovableSeg( ) end local strength = 3.0 local startSeg, endSeg = GetRegionForOperation( idx ) print( "SheetStraightener for "..startSeg..","..endSeg) if endSeg - startSeg <= 1 then return false end -- something's very wrong local changeSucceeded = PutSheetStraightenerBand( startSeg, endSeg, strength ) if changeSucceeded then SetCI( CI_REGIONMOD ) DebugPrint( "SimpleRegionWiggle" ) SimpleRegionWiggle( startSeg, endSeg, false, 2 + random( 4 ) ) DebugPrint( "CleanQStabWiggleOut" ) CleanQStabWiggleOut( ) -- PROB_QSTAB_EXTRA_MOVERBANDS ) end return changeSucceeded end function PerformHelixUniformAction( idx ) if idx == nil then idx = randomMovableSeg( ) end local strength = BAND_STRENGTH_REGION local startSeg, endSeg = GetRegionForOperation( idx ) print( "HelixUniform for "..startSeg..","..endSeg) if endSeg - startSeg <= 1 then return false end -- something's very wrong local regionLength = endSeg - startSeg + 1 local hShift = 4 if randomBool( 0.25 ) then hShift = math.min( regionLength - 3, random(5,7)) end if startSeg > idx - 2 then startSeg = math.max( 1, idx - random( 2, 4 )) end if endSeg < idx + 2 then endSeg = math.min( SegCt, idx + random( 2, 4 )) end changeSucceeded = PutHelixUniformDistanceBands( startSeg, endSeg, hShift, strength ) if changeSucceeded then SetCI( CI_REGIONMOD ) DebugPrint( "SimpleRegionWiggle" ) SimpleRegionWiggle( startSeg, endSeg, false, 2 + random( 4 ) ) DebugPrint( "CleanQStabWiggleOut" ) CleanQStabWiggleOut( ) -- PROB_QSTAB_EXTRA_MOVERBANDS ) end return changeSucceeded end function PerformHelixCompressorAction( idx ) if idx == nil then idx = randomMovableSeg( ) end local strength = BAND_STRENGTH_REGION local hComp = random( BAND_MAXCOMPRESS, BAND_MAXEXPAND ) local startSeg, endSeg = GetRegionForOperation( idx ) print( "HelixCompressor for "..startSeg..","..endSeg) if endSeg - startSeg <= 1 then return false end -- something's very wrong local regionLength = endSeg - startSeg + 1 local hShift = 4 if randomBool( 0.25 ) then hShift = math.min(regionLength - 2, randomDice(4, 1, 2)) -- a number 4 - 8, preferring 6ish end local changeSucceeded = PutHelixCompressorBands( startSeg, endSeg, hShift, strength, hComp ) if changeSucceeded then SetCI( CI_REGIONMOD ) DebugPrint( "SimpleRegionWiggle" ) SimpleRegionWiggle( startSeg, endSeg, false, 2 + random( 4 ) ) DebugPrint( "CleanQStabWiggleOut" ) CleanQStabWiggleOut( ) -- PROB_QSTAB_EXTRA_MOVERBANDS ) end return changeSucceeded end function PerformHelixFixerAction( idx ) if idx == nil then idx = randomMovableSeg( ) end local strength = BAND_STRENGTH_REGION local do4 = randomBool( ) local startSeg, endSeg = GetRegionForOperation( idx ) print( "HelixFixer for "..startSeg..","..endSeg) if endSeg - startSeg <= 1 then return false end -- something's very wrong local changeSucceeded = PutHelixFixerBands( startSeg, endSeg, strength, do4 ) if changeSucceeded then SetCI( CI_REGIONMOD ) DebugPrint( "SimpleRegionWiggle" ) SimpleRegionWiggle( startSeg, endSeg, false, 2 + random( 4 ) ) DebugPrint( "CleanQStabWiggleOut" ) CleanQStabWiggleOut( ) -- PROB_QSTAB_EXTRA_MOVERBANDS ) end return changeSucceeded end function PerformHelixRotatorAction( idx ) if idx == nil then idx = randomMovableSeg( ) end local strength = BAND_STRENGTH_REGION local bisLen = BIS_LENGTH local goClockwise = randomBool() local doubleRotate = randomBool() local startSeg, endSeg = GetRegionForOperation( idx ) print( "HelixRotator for "..startSeg..","..endSeg) if endSeg - startSeg <= 1 then return false end -- something's very wrong -- Put the bands, use wiggle to do a rotation local changeSucceeded = PutHelixRotatorBands( startSeg, endSeg, bisLen, strength, goClockwise ) if changeSucceeded then SetCI( CI_REGIONMOD ) DebugPrint( "SimpleRegionWiggle" ) SimpleRegionWiggle( startSeg, endSeg, false, 2 + random( 4 ) ) end DelBands( ) if doubleRotate then changeSucceeded = PutHelixRotatorBands( startSeg, endSeg, bisLen, strength, goClockwise ) if changeSucceeded then SetCI( CI_REGIONMOD ) DebugPrint( "SimpleRegionWiggle-2" ) SimpleRegionWiggle( startSeg, endSeg, false, 4 + random( 3 ) ) end end DebugPrint( "CleanQStabWiggleOut" ) CleanQStabWiggleOut( ) -- PROB_QSTAB_EXTRA_MOVERBANDS ) return changeSucceeded end function PerformMultiBisAction( ) local ctBandsToMake = random(3, 7) local bandCt = 0 local cutIdx = 0 local changeSucceeded = false local startScore = getQuickScore() print( "MultiBis ctbands="..ctBandsToMake ) if randomBool() and not PRESERVE_USER_CUTS then recentbest.Save( ) cutIdx = randomMovableSeg( ) structure.InsertCut( cutIdx ) end while bandCt < ctBandsToMake do local strength = random( BIS_MIN_STRENGTH, BIS_MAX_STRENGTH, true ) local idx = randomMovableSeg( ) local atom = PickAtomNumberForBand( idx, true ) local maxRho = BIS_LENGTH local goalLength = random( BIS_MIN_GOALLENGTH, BIS_MAX_GOALLENGTH ) if PutBandInSpace( idx, maxRho, strength, goalLength, atom ) then changeSucceeded = true bandCt = bandCt + 1 end end if changeSucceeded then DebugPrint( "WiggleBackboneThenWiggleOut" ) WiggleBackboneThenWiggleOut( cutIdx, PROB_QSTAB_EXTRA_MULTIBAND ) end return changeSucceeded end function PerformMultiSegBandAction( ) local ctBandsToMake = random(3, 7) local bandCt = 0 local cutIdx = 0 local changeSucceeded = false local startScore = getQuickScore() print( "MultiSegBand ctbands="..ctBandsToMake ) if randomBool() and not PRESERVE_USER_CUTS then recentbest.Save( ) cutIdx = randomMovableSeg( ) structure.InsertCut( cutIdx ) end while bandCt < ctBandsToMake do local strength = random( BIS_MIN_STRENGTH, BIS_MAX_STRENGTH, true ) local idx = randomMovableSeg( ) local atom = PickAtomNumberForBand( idx, true ) if PutBandToRandomSeg( idx, strength, atom, true ) then bandCt = bandCt + 1 changeSucceeded = true end end if changeSucceeded then DebugPrint( "WiggleBackboneThenWiggleOut" ) WiggleBackboneThenWiggleOut( cutIdx, PROB_QSTAB_EXTRA_MULTIBAND ) end return changeSucceeded end function PerformMultiBanderAction( ) local ctBandsToMake = random(3, 7) local bandCt = 0 local cutIdx = 0 local bandType = random( 1, 4 ) -- 1=all-bis, 2=all-segband, else mixed. local changeSucceeded = false local startScore = getQuickScore() print( "MultiBander ctbands="..ctBandsToMake ) if randomBool() and not PRESERVE_USER_CUTS then recentbest.Save( ) cutIdx = randomMovableSeg( ) structure.InsertCut( cutIdx ) end while bandCt < ctBandsToMake do local strength = random( BIS_MIN_STRENGTH, BIS_MAX_STRENGTH, true ) local idx = randomMovableSeg( ) local atom = PickAtomNumberForBand( idx, true ) local which = random( 2 ) if which == 1 then local maxRho = BIS_LENGTH local goalLength = random( BIS_MIN_GOALLENGTH, BIS_MAX_GOALLENGTH ) if PutBandInSpace( idx, maxRho, strength, goalLength, atom ) then changeSucceeded = true bandCt = bandCt + 1 end else if PutBandToRandomSeg( idx, strength, atom, true ) then changeSucceeded = true bandCt = bandCt + 1 end end end if changeSucceeded then DebugPrint( "WiggleBackboneThenWiggleOut" ) WiggleBackboneThenWiggleOut( cutIdx, PROB_QSTAB_EXTRA_MULTIBAND ) end return changeSucceeded end function PerformCentralBanderAction( ) local strength = BAND_STRENGTH_DEFAULT local maxCenters = randomDice( 2, 1, 3) local changeSucceeded = false local coreSegs = {} getCentralHydrophobics( coreSegs, maxCenters) local compression = randomDice( 2, BAND_MAXCOMPRESS/2, BAND_MAXEXPAND/2 ) local skipCt = random(4, 10) local startOffset = random(1, skipCt) print( "CentralBander with centers="..maxCenters ) changeSucceeded = PutCoreCompressBands( coreSegs, skipCt, startOffset, strength, compression, randomBool( ), randomBool( ) ) if changeSucceeded then DebugPrint( "SimpleBandedWiggleShakeWrapper" ) SimpleBandedWiggleShakeWrapper( ) end return changeSucceeded end -- THIS one is the normal action: puts bands, wiggles, deletes bands, then wiggles out function PerformEveryXToEveryYBandAction( ) local compr = random( BAND_MAXCOMPRESS, BAND_MAXEXPAND, true ) local xInterval = random( math.floor( SegCt / 9), math.floor( SegCt / 5 )) local yInterval = random( 2 + xInterval, 2 + math.floor( SegCt / 5 )) local xInit = random( xInterval-1 ) local yInit = random( yInterval-1 ) local strength = random( 0.01, BAND_STRENGTH_DEFAULT, true ) local startScore = getQuickScore() print( "BandEveryXToY for X,Y=" ..xInterval.. "," ..yInterval.. " starting " ..xInit.. "," ..yInit ) local changeSucceeded = PutBandsEveryXToEveryY( xInterval, xInit, yInterval, yInit, strength, compr ) if changeSucceeded then DebugPrint( "BandedWiggleUntilEnoughChange" ) BandedWiggleUntilEnoughChange( BANDEDWIGGLE_TARGET, CI_COREPULLING ) end DelBands( ) ShakeWiggleTillStable( startScore ) return changeSucceeded end -- THIS ONE IS SPECIAL: it is called whenever we want to pre-expand our protein function PerformEveryXToEveryYExpansion( ) local compr = random( BAND_MINEXPAND, BAND_MAXEXPAND, true ) local xInterval = random( math.floor( SegCt / 9), math.floor( SegCt / 5 )) local yInterval = random( 2 + xInterval, 2 + math.floor( SegCt / 5 )) local xInit = random( xInterval-1 ) local yInit = random( yInterval-1 ) local strength = random( 0.5, 1.50, true ) -- FIND OUT: is always strong good? print("XToYExpander: " ..xInterval.. "x" ..yInterval.. " expand="..TrimNum(compr).. " strength="..TrimNum(strength)) local initScore = getScore() local changeSucceeded = PutBandsEveryXToEveryY( xInterval, xInit, yInterval, yInit, strength, compr ) if changeSucceeded then SimpleWiggleShake( ) end DelBands( ) local endScore = getScore() DebugPrint("Expander Score drop = "..TrimNum(endScore-initScore)) return changeSucceeded end function PerformInhaleAndExhaleAction( ctBreaths ) local fightingCementing = FIGHT_CEMENTING and PossibleCementingState and WorthTryingCementBreaker if ctBreaths == nil then ctBreaths = 1 end print("InhaleAndExhale for "..ctBreaths.." breaths") local bestScore = getScore() local foundImprovement = false for i=1,ctBreaths do local compr local xInterval = random( math.floor( SegCt / 9 ), math.floor( SegCt / 5 )) local yInterval = random( 2 + xInterval, 2 + math.floor( SegCt / 5 )) local xInit = random( xInterval-1 ) local yInit = random( yInterval-1 ) local strength = random( BAND_STRENGTH_DEFAULT - 0.25, BAND_STRENGTH_DEFAULT + 0.25 ) local wantCompress = (i==1 and fightingCementing) or randomBool() if wantCompress then compr = random( BAND_MAXGENTLECOMPRESS, BAND_MINCOMPRESS, true ) print( "Breathe out "..TrimNum(compr).." then in..." ) else compr = random( BAND_MINEXPAND, BAND_MAXGENTLEEXPAND, true ) print( "Breathe in "..TrimNum(compr).." then out..." ) end local changeSucceeded = PutBandsEveryXToEveryY( xInterval, xInit, yInterval, yInit, strength, compr ) if changeSucceeded then SimpleLocalWiggleAll( ) ShakeOrMutate( ) CleanShakeWiggleOut( MUTATE_ONCE ) local currScore = getScore() if currScore > bestScore then save.Quicksave( QS_ShortUseTemp1 ) bestScore = currScore foundImprovement = true end end end if foundImprovement then save.Quickload( QS_ShortUseTemp1 ) end return true end function PerformInAndOutAction( ctBreaths ) local fightingCementing = FIGHT_CEMENTING and PossibleCementingState and WorthTryingCementBreaker if ctBreaths == nil then if fightingCementing then ctBreaths = 5 else ctBreaths = 3 end end print("InAndOut for "..ctBreaths.." breaths") local bestScore = getScore() local changeSucceeded = false for i=1,ctBreaths do local compr local xInterval = random( math.floor( SegCt / 9 ), math.floor( SegCt / 5 )) local yInterval = random( 2 + xInterval, 2 + math.floor( SegCt / 5 )) local xInit = random( xInterval-1 ) local yInit = random( yInterval-1 ) local strength = random( BAND_STRENGTH_DEFAULT - 0.25, BAND_STRENGTH_DEFAULT + 0.25 ) if fightingCementing and i == 1 then -- we already did an expander. so start with a compression compr = random( BAND_MAXCOMPRESS, BAND_MINCOMPRESS, true ) else compr = random( BAND_MAXCOMPRESS, BAND_MAXEXPAND, true ) end if compr < 1.0 then print( "Breathe out "..compr.." then in..." ) else print( "Breathe in "..compr.." then out..." ) end local chSuc = PutBandsEveryXToEveryY( xInterval, xInit, yInterval, yInit, strength, compr ) changeSucceeded = changeSucceeded or chSuc if chSuc then SimpleLocalWiggleAll( ) ShakeOrMutate( ) DelBands( ) xInterval = random( math.floor( SegCt / 9 ), math.floor( SegCt / 5 )) yInterval = random( 2 + xInterval, 2 + math.floor( SegCt / 5 )) xInit = random( xInterval-1 ) yInit = random( yInterval-1 ) strength = random( BAND_STRENGTH_DEFAULT - 0.25, BAND_STRENGTH_DEFAULT + 0.25 ) compr = 1 / compr chSuc = PutBandsEveryXToEveryY( xInterval, xInit, yInterval, yInit, strength, compr ) changeSucceeded = changeSucceeded or chSuc if chSuc then SimpleLocalWiggleAll( ) ShakeOrMutate( ) DelBands( ) end end end LongWiggleAll( ) CleanShakeWiggleOut( MUTATE_ONCE ) return changeSucceeded end function PerformGentleCompAction( ) 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_MAXCOMPRESS, BAND_MINCOMPRESS, 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 print( "GentleComp for " ..bandsWanted.. " bands" ) local changeSucceeded = PutGentleCompBands( bandsWanted, minLength, maxLength, minSeparation, strength, compression ) if changeSucceeded then DebugPrint( "SimpleBandedWiggleShakeWrapper" ) SimpleBandedWiggleShakeWrapper( nil, nil, PROB_QSTAB_EXTRA_QUAKE ) end return changeSucceeded end function PerformGentleCompLowCIAction( ) 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 = 15 local compression = 1.0 if randomBool() then compression = random( BAND_MAXCOMPRESS, BAND_MINCOMPRESS, true ) else compression = random( 1.10, BAND_MAXEXPAND, true ) end local bandsWanted = 3 local strength = BAND_STRENGTH_DEFAULT print( "GentleCompLowCI for " ..bandsWanted.. " bands" ) local changeSucceeded = PutGentleCompBands( bandsWanted, minLength, maxLength, minSeparation, strength, compression ) if changeSucceeded then if USE_LOWCI_WIGGLES then DebugPrint( "ShakeWiggleCleanShakeWiggle" ) ShakeWiggleCleanShakeWiggle( ) else DebugPrint( "SimpleBandedWiggleShakeWrapper" ) SimpleBandedWiggleShakeWrapper( nil, nil, PROB_QSTAB_EXTRA_QUAKE ) end end return changeSucceeded end function PerformLSQuakeAction( idx ) -- ok for idx to be not movable, but silly to put it in locked region if idx == nil then idx = random( MinUnlockedSeg, MaxUnlockedSeg) end local wantFreeze = randomBool( ) local ctBands = randomDice( 2, 2, 4 ) -- was 6 local strength = BAND_STRENGTH_DEFAULT local compression = random( BAND_MAXCOMPRESS, BAND_MAXEXPAND ) -- was MINCOMPRESS local changeSucceeded = false ResetFrozenness( ) local startIdx, endIdx = GetRegionForOperation( idx ) print( "LSQuake 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 DebugPrint( "SimpleBandedWiggleShakeWrapper" ) SimpleBandedWiggleShakeWrapper( nil, nil, PROB_QSTAB_EXTRA_QUAKE ) end return changeSucceeded end function PerformSimpleQuakeAction( ) print( "SimpleQuake" ) local changeSucceeded = false for i=1,2 do local ctBands = random( 1, 19 ) local bloat = randomBool( ) for j=1, ctBands do local strength = BAND_STRENGTH_DEFAULT local seg1 = randomMovableSeg( ) local seg2 = seg1 local tryCt = 0 while math.abs( seg2 - seg1 ) < 3 do seg2 = randomMovableSeg( ) tryCt = tryCt + 1 if tryCt > 20 then DelBands() return false end end local leng = structure.GetDistance( seg1, seg2 ) if bloat then leng = leng+4 else local perc=random(50,80) leng = (perc*leng) / 100.0 end local chSuc = BandBetweenSegsWithParameters( seg1, seg2, strength, leng ) changeSucceeded = changeSucceeded or chSuc end if changeSucceeded then SimpleBandedWiggleShakeWrapper( nil, nil, PROB_QSTAB_EXTRA_QUAKE ) end end return changeSucceeded end -- just like SimpleQuake, but 4 runs and add up to 10 Bis's each time. Too pricy function PerformBisQuakeAction( ) print( "BisQuake" ) local changeSucceeded = false for i=1,4 do local ctBands = random( 1, 19 ) local bloat = randomBool( ) for j=1, ctBands do local strength = BAND_STRENGTH_DEFAULT local seg1 = randomMovableSeg( ) local seg2 = seg1 local tryCt = 0 while math.abs( seg2 - seg1 ) < 3 do seg2 = randomMovableSeg( ) tryCt = tryCt + 1 if tryCt > 20 then DelBands() return false end end local leng = structure.GetDistance( seg1, seg2 ) if bloat then leng = leng+4 else local perc=random(50,80) leng = (perc*leng) / 100 end chSuc = BandBetweenSegsWithParameters( seg1, seg2, strength, leng ) changeSucceeded = changeSucceeded or chSuc end local ctBisBands = random( 1, 10 ) for j=1, ctBisBands do local idx = randomMovableSeg( ) PutBandInSpace(idx, 10.0, strength ) end if changeSucceeded then SimpleBandedWiggleShakeWrapper( nil, nil, PROB_QSTAB_EXTRA_QUAKE ) end end return changeSucceeded end -- too pricy to use in normal sequences function PerformLocalQuakeAction( idx ) if idx == nil then idx = randomMovableSeg( ) end print( "LocalQuake at ".. idx ) local ctBands = randomDice( 2, 2, 4 ) -- 2 dice each 2-4; was just 6 local compression = random( BAND_MAXCOMPRESS, BAND_MAXEXPAND ) local strength = BAND_STRENGTH_DEFAULT save.Quicksave( QS_ShortUseTemp1 ) local bestScore = getQuickScore( ) local 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 local idx2 = math.min( SegCt, lqIdx + 3 ) local changeSuc2 = PutManyBandsToSeg( idx2, ctBands, strength, compression, true ) changeSuc = changeSuc or changeSuc2 end if changeSuc then if USE_LOWCI_WIGGLES then ShakeWiggleCleanShakeWiggle( ) else SimpleBandedWiggleShakeWrapper( nil, nil, PROB_QSTAB_EXTRA_QUAKE ) 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 ) return changeSucceeded end function PerformTailWhipAction( idx ) if idx == nil then fromStart = randomBool( ) end if idx < SegCt / 2 then fromStart = true else fromStart = false end local length = 0 local r = randomBool() if r then if fromStart then idx = 1 else idx = SegCt end local st,ed = GetRegionForOperation( idx ) length = ed - st + 1 end if length < 5 then length = random( 5,15 ) end if fromStart then str = "start" else str = "end" end print( "TailWhip at " .. str .. " length="..length ) selection.DeselectAll( ) local s = 1 local e = length if fromStart then changeSucceeded = PutTailDetacherBands( true, length ) else s = SegCt - length + 1 e = SegCt changeSucceeded = PutTailDetacherBands( false, length ) end selection.SelectRange( s, e ) if not changeSucceeded then return false end DebugPrint( "SimpleRegionWiggle" ) SimpleRegionWiggle( s, e, false, random(4) ) -- pull the tail away from the main body DelBands( ) selection.DeselectAll( ) if fromStart then changeSucceeded = PutTailAttacherBands( true, length ) else changeSucceeded = PutTailAttacherBands( false, length ) end selection.SelectRange( s, e ) if not changeSucceeded then return false end DebugPrint( "SimpleRegionWiggle - 2" ) SimpleRegionWiggle( s, e, false, random(4) ) -- bring the tail back to the main body selection.DeselectAll( ) DelBands( ) -- do our own "after" wiggle recentbest.Save( ) ShakeOrMutate( ) DebugPrint( "LongWiggleAll" ) LongWiggleAll( ) recentbest.Restore( ) return true end -- somewhat pricy, but worthwhile function PerformTailGrabAction() print("TailGrab") local strength = BAND_STRENGTH_DEFAULT local first = MinUnlockedSeg local last = MaxUnlockedSeg local middle = math.floor(SegCt/2) local compr=random(0.50,0.80) local leng= compr * structure.GetDistance( first, last ) local changeSucceeded = BandBetweenSegsWithParameters( first, last, strength, leng ) if not changeSucceeded then return false end SetCI(CI_COREPULLING) SimpleBandedWiggleShakeWrapper( ) -- nil, nil, PROB_QSTAB_EXTRA_VOIDCRUSH ) DelBands() LongWiggleAll() local bloat = randomBool() leng=structure.GetDistance( first, middle ) if bloat then leng = leng + 4.0 else local compr=random(0.50,0.80) leng = compr*leng end local chSuc1 = BandBetweenSegsWithParameters( first, middle, strength, leng ) leng=structure.GetDistance( middle, last ) if bloat then leng = leng + 4.0 else local compr=random(0.50,0.80) leng = compr*leng end local chSuc2 = BandBetweenSegsWithParameters( middle, last, strength, leng ) if chSuc1 or chSuc2 then DebugPrint("SimpleBandedWiggleShakeWrapper") SimpleBandedWiggleShakeWrapper( ) -- nil, nil, PROB_QSTAB_EXTRA_VOIDCRUSH ) DelBands() end DebugPrint("LongWiggleAll") LongWiggleAll() return changeSucceeded end function PerformBandedWormPairAction( idx ) local startIdx, endIdx = GetActionRange( idx, 1, 15 ) local len = endIdx - startIdx + 1 local wantGlobalWiggle = randomBool( ) print("BandedWormPair for "..idx.." with len="..len) return BandedWormPairAction( startIdx, len, idx, wantGlobalWiggle ) end function PerformLocalWiggleAction( idx ) local startIdx, endIdx = GetActionRange( idx, 1, 4 ) local wantGlobalWiggle = randomBool( ) local minGain = 0.001 print("LocalWiggle for "..idx) --SetCI( CI_LOCALWIGGLER_SHAKE ) --structure.ShakeSidechainsSelected(1) --SetCI( 1.00 ) return WiggleRangeAction( startIdx, endIdx, false, minGain ) end function PerformLocalFreezeWiggleAction( idx ) local startIdx, endIdx = GetActionRange( idx, 1, 4 ) local wantGlobalWiggle = randomBool( ) local minGain = 0.001 print("LocalFreezeWiggle for "..idx) if startIdx > MinUnlockedSeg then freeze.Freeze( startIdx - 1, true, true ) end if endIdx < MaxUnlockedSeg then freeze.Freeze( endIdx + 1, true, true ) end SetCI( CI_LOCALWIGGLER_SHAKE ) structure.ShakeSidechainsSelected(1) SetCI( 1.00 ) local changeSucceeded = WiggleRangeAction( startIdx, endIdx, false, minGain ) ResetFrozenness( ) return changeSucceeded end function PerformATSidechainTweakAction( idx ) local radius = AT_SPHERE_RADIUS local wantRebuild = randomBool( AT_PROB_DO_REBUILD ) local includeWorsts = randomBool( AT_PROB_SPHERE_ADD_WORSTS ) local fixBand = randomBool( AT_PROB_PUT_FIX_BANDS ) print("ATSidechainTweak for "..idx) return ATSidechainTweakAction( idx, radius, wantRebuild, includeWorsts, fixBand ) end function PerformATSidechainTweakAroundAction( idx ) local radius = AT_SPHERE_RADIUS local wantRebuild = randomBool( AT_PROB_DO_REBUILD ) local includeWorsts = randomBool( AT_PROB_SPHERE_ADD_WORSTS ) local fixBand = randomBool( AT_PROB_PUT_FIX_BANDS ) print("ATSidechainTweakAround for "..idx) return ATSidechainTweakAroundAction( idx, radius, wantRebuild, includeWorsts, fixBand ) end function PerformATSidechainManipulateAction( idx ) local radius = AT_SPHERE_RADIUS local wantRebuild = randomBool( AT_PROB_DO_REBUILD ) print("ATSidechainManipulate for "..idx) return ATSidechainManipulateAction( idx, radius, wantRebuild ) end function PerformSingleContactMapAction( idx ) if idx == nil then idx = randomContactableSeg( ) end print( "SingleContactMapBand at ".. idx ) local changeSucceeded = false local heatThreshold = CONTACTMAP_THRESHOLD local strength = 1.5 * BAND_STRENGTH_DEFAULT changeSucceeded = PutSomeContactMapBands( heatThreshold, strength, 1, randomBool( ), true ) if changeSucceeded then DebugPrint( "SimpleBandedWiggleShakeWrapper" ) SimpleBandedWiggleShakeWrapper( ) end return changeSucceeded end function PerformSomeContactMapBandsAction( ) print( "SomeContactMapBands" ) local changeSucceeded = false local heatThreshold = CONTACTMAP_THRESHOLD local strength = BAND_STRENGTH_DEFAULT local ctWanted = random( 5, 10 ) changeSucceeded = PutSomeContactMapBands( heatThreshold, strength, ctWanted, randomBool( ), true ) if changeSucceeded then PutRandomCompBands() DebugPrint( "SimpleBandedWiggleShakeWrapper" ) SimpleBandedWiggleShakeWrapper( ) end return changeSucceeded end function PerformContactMapBandsForSegAction( idx ) print( "ContactMapBandsForSeg for idx " ..idx ) if idx == nil then idx = randomContactableSeg( ) end local changeSucceeded = false local heatThreshold = CONTACTMAP_THRESHOLD local strength = BAND_STRENGTH_DEFAULT local doSidechain = false if BAND_TO_SIDECHAINS then doSidechain = randomBool( ) end changeSucceeded = PutAllContactMapBandsToSeg( idx, heatThreshold, strength, true, doSidechain, true ) if changeSucceeded then PutRandomCompBands() DebugPrint( "WiggleShakeCleanWiggleOut" ) WiggleShakeCleanWiggleOut( ) end return changeSucceeded end function PerformCMTwoRegionBandAction( idx1 ) print( "CMTwoRegionBander for idx " ..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 ) local changeSucceeded = PutContactMapBandsBetweenRegions( heatThreshold, startIdx1, endIdx1, startIdx2, endIdx2, strength, true, randomBool( ), randomBool( ), true ) if changeSucceeded then PutRandomCompBands() DebugPrint( "WiggleShakeCleanWiggleOut" ) WiggleShakeCleanWiggleOut( ) end return changeSucceeded end function PerformContactMapperAction( ) print("ContactMapper" ) local changeSucceeded = PutContactMapBands( ) if changeSucceeded then PutRandomCompBands() DebugPrint( "SimpleBandedWiggleShakeWrapper" ) SimpleBandedWiggleShakeWrapper( ) end return changeSucceeded end function PerformPushPullContactMapAction( badSeg ) if badSeg == nil then badSeg = randomContactableSeg( ) end local segList = {} local wantPushNotPull = randomBool( ) local ctBands = 5 local strength = BAND_STRENGTH_DEFAULT print("PushPullCM at seg "..badSeg ) 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 local centerSeg = segList[ random( #segList ) ] local changeSucceeded = PutPushPullContactMapBands( badSeg, ctBands, centerSeg, strength, CONTACTMAP_THRESHOLD, wantPushNotPull ) if changeSucceeded then DebugPrint( "SimpleBandedWiggleShakeWrapper" ) SimpleBandedWiggleShakeWrapper( ) end return changeSucceeded end function PerformVoidCrusherContactMapAction( idx ) if idx == nil then idx = randomContactableSeg( ) end local strength = BAND_STRENGTH_DEFAULT print("VoidCrusherCM at seg "..idx ) local changeSucceeded = PutVoidCrusherContactMapBands( idx, strength, CONTACTMAP_THRESHOLD ) if changeSucceeded then DebugPrint( "SimpleBandedWiggleShakeWrapper" ) SimpleBandedWiggleShakeWrapper( ) end return changeSucceeded end function PerformContactMapRebuildRangeAction( idx ) if idx == nil then idx = randomMovableSeg( ) end local idxStart, idxEnd = GetRebuildRange( idx ) print( "ContactMapRebuildRange on range ".. idxStart, idxEnd ) local changeSucceeded = PutContactMapBands( ) if changeSucceeded then if USE_LOWCI_WIGGLES then changeSucceeded = RebuildBitspawn( idxStart, idxEnd, true ) else changeSucceeded = RebuildSimple( idxStart, idxEnd ) end end DebugPrint( "CleanShakeWiggleOut" ) CleanShakeWiggleOut( ) return changeSucceeded end -- think about all-loop and restoring secondary structure and such function PerformContactMapRebuildSSAction( idx ) if idx == nil then idx = randomMovableSeg( ) end local idxStart, idxEnd = GetRegionForOperation( idx ) print( "ContactMapRebuildSS for range "..idxStart..","..idxEnd ) local oldInnerTube = REBUILD_TUBE_INNER_RADIUS local oldOuterTube = REBUILD_TUBE_OUTER_RADIUS REBUILD_TUBE_INNER_RADIUS = CONTACTMAP_REBUILD_TUBE_INNER_RADIUS REBUILD_TUBE_OUTER_RADIUS = CONTACTMAP_REBUILD_TUBE_OUTER_RADIUS local changeSucceeded = PutContactMapBands( ) if changeSucceeded then if randomBool( ) then changeSucceeded = DeepRebuildRange( idxStart, idxEnd, REBUILD_DEEP_MAXTRIES ) else changeSucceeded = RebuildRangeFromQuaker( idxStart, idxEnd, REBUILD_DEEP_MAXTRIES ) end end REBUILD_TUBE_INNER_RADIUS = oldInnerTube REBUILD_TUBE_OUTER_RADIUS = oldOuterTube DebugPrint( "CleanShakeWiggleOut" ) CleanShakeWiggleOut() return changeSucceeded end function PerformContactMapRebuildAllAction( ) print( "ContactMapRebuildAll" ) local changeSucceeded = PutContactMapBands( ) if changeSucceeded then PerformWiskyRebuildAllAction( ) end DebugPrint( "CleanShakeWiggleOut" ) CleanShakeWiggleOut() return changeSucceeded end -------------------------------------------------------------------------------------------------------- -- PERFORMING OF ACTIONS -------------------------------------------------------------------------------------------------------- function GenerateAllActionsList( ) AllActionsList = {} -- idealize, remix, rebuild AllActionsList[ #AllActionsList + 1 ] = {nameStr = "IdealizeZlb", actionFunc=PerformIdealizeZlbAction, testFunc=testSmallPuzzleOk, usesIdx=true, actionType=ACTION_TYPE_REMIXIDEAL} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "IdealizeRegion", actionFunc=PerformIdealizeRegionAction, testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_REMIXIDEAL} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "IdealizeXToY", actionFunc=PerformIdealizeRegionXToYAction, testFunc=testSmallPuzzleOk, usesIdx=true, actionType=ACTION_TYPE_REMIXIDEAL} -- testSmallPuzzleOk AllActionsList[ #AllActionsList + 1 ] = {nameStr = "Remix", actionFunc=PerformRemixAction, testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_REMIXIDEAL} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "RemixSimple", actionFunc=PerformRemixSimpleAction, testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_REMIXIDEAL} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "RemixSimpleXToY", actionFunc=PerformRemixSimpleXToYAction, testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_REMIXIDEAL} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "RemixXToY", actionFunc=PerformRemixXToYAction, testFunc=testSmallPuzzleOk, usesIdx=true, actionType=ACTION_TYPE_REMIXIDEAL} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "DeepRebuildSS", actionFunc=PerformDeepRebuildSSAction, testFunc=testRebuildOk, usesIdx=true, actionType=ACTION_TYPE_REBUILD} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "DeepRebuildSSXToY", actionFunc=PerformDeepRebuildSSXToYAction, testFunc=testRebuildOk, usesIdx=true, actionType=ACTION_TYPE_REBUILD} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "DeepRebuildRange", actionFunc=PerformDeepRebuildAction, testFunc=testRebuildOk, usesIdx=true, actionType=ACTION_TYPE_REBUILD} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "DeepRebuildRangeXToY", actionFunc=PerformDeepRebuildXToYAction, testFunc=testRebuildOk, usesIdx=true, actionType=ACTION_TYPE_REBUILD} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "RebuildSimple", actionFunc=PerformRebuildSimpleAction, testFunc=testRebuildOk, usesIdx=true, actionType=ACTION_TYPE_REBUILD} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "RebuildSimpleXToY", actionFunc=PerformRebuildSimpleXToYAction, testFunc=testRebuildSmallPuzzleOk, usesIdx=true, actionType=ACTION_TYPE_REBUILD} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "RebuildFromQuaker", actionFunc=PerformRebuildFromQuakerAction, testFunc=testRebuildOk, usesIdx=true, actionType=ACTION_TYPE_REBUILD} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "RebuildBitspawn", actionFunc=PerformRebuildBitspawnAction, testFunc=testRebuildOk, usesIdx=true, actionType=ACTION_TYPE_REBUILD} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "RebuildBitspawnLowCI", actionFunc=PerformRebuildBitspawnLowCI, testFunc=testRebuildOk, usesIdx=true, actionType=ACTION_TYPE_REBUILD} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "QuakingRebuild", actionFunc=PerformQuakingRebuild, testFunc=testRebuildOk, usesIdx=true, actionType=ACTION_TYPE_REBUILD} -- banders AllActionsList[ #AllActionsList + 1 ] = {nameStr = "PushPull", actionFunc=PerformPushPullAction, testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_BANDER} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "VoidCrusher", actionFunc=PerformVoidCrusherAction, testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_BANDER} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "PusherBands", actionFunc=PerformPusherAction, testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_BANDER} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "MoverBands", actionFunc=PerformMoverAction, testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_BANDER} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "FlexerBands", actionFunc=PerformFlexerAction, testFunc=testFlexerOk, usesIdx=true, actionType=ACTION_TYPE_BANDER} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "SheetStraightener", actionFunc=PerformSheetStraightenerAction, testFunc=testSheetActionsOk, usesIdx=true, actionType=ACTION_TYPE_BANDER} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "SheetAligner", actionFunc=PerformSheetAlignerAction, testFunc=testSheetActionsOk, usesIdx=true, actionType=ACTION_TYPE_BANDER} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "SheetShifter", actionFunc=PerformSheetShifterAction, testFunc=testNonstraySheetsActionsOk, usesIdx=true, actionType=ACTION_TYPE_BANDER} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "SheetFlipper", actionFunc=PerformSheetFlipperAction, testFunc=testNonstraySheetsActionsOk, usesIdx=true, actionType=ACTION_TYPE_BANDER} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "SheetSewer", actionFunc=PerformSheetSewerAction, testFunc=testSheetActionsOk, usesIdx=true, actionType=ACTION_TYPE_BANDER} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "HelixRotator", actionFunc=PerformHelixRotatorAction, testFunc=testSimpleHelixOk, usesIdx=true, actionType=ACTION_TYPE_BANDER} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "HelixUniform", actionFunc=PerformHelixUniformAction, testFunc=testLargishHelixActionsOk, usesIdx=true, actionType=ACTION_TYPE_BANDER} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "HelixCompressor", actionFunc=PerformHelixCompressorAction, testFunc=testLargishHelixActionsOk, usesIdx=true, actionType=ACTION_TYPE_BANDER} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "HelixFixer", actionFunc=PerformHelixFixerAction, testFunc=testLargishHelixActionsOk, usesIdx=true, actionType=ACTION_TYPE_BANDER} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "GeneralHinge", actionFunc=PerformGeneralHingeAction, testFunc=testGeneralHingeOk, usesIdx=true, actionType=ACTION_TYPE_BANDER} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "GlycineHinge", actionFunc=PerformGlycineHingeAction, testFunc=testGlycineHingeOk, usesIdx=true, actionType=ACTION_TYPE_BANDER} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "LocalQuake", actionFunc=PerformLocalQuakeAction, testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_QUAKER} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "LSQuake", actionFunc=PerformLSQuakeAction, testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_QUAKER} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "BisQuake", actionFunc=PerformBisQuakeAction, testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_QUAKER} -- non-index-using banders AllActionsList[ #AllActionsList + 1 ] = {nameStr = "GentleComp", actionFunc=PerformGentleCompAction, testFunc=nil, usesIdx=false, actionType=ACTION_TYPE_BANDER} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "GentleCompLowCI", actionFunc=PerformGentleCompLowCIAction, testFunc=nil, usesIdx=false, actionType=ACTION_TYPE_BANDER} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "TailGrab", actionFunc=PerformTailGrabAction, testFunc=nil, usesIdx=false, actionType=ACTION_TYPE_BANDER} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "InhaleAndExhale", actionFunc=PerformInhaleAndExhaleAction, testFunc=nil, usesIdx=false, actionType=ACTION_TYPE_QUAKER} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "InAndOut", actionFunc=PerformInAndOutAction, testFunc=nil, usesIdx=false, actionType=ACTION_TYPE_QUAKER} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "SimpleQuake", actionFunc=PerformSimpleQuakeAction, testFunc=nil, usesIdx=false, actionType=ACTION_TYPE_QUAKER} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "MultiBander", actionFunc=PerformMultiBanderAction, testFunc=nil, usesIdx=false, actionType=ACTION_TYPE_QUAKER} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "MultiBis", actionFunc=PerformMultiBisAction, testFunc=nil, usesIdx=false, actionType=ACTION_TYPE_QUAKER} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "MultiSegBand", actionFunc=PerformMultiSegBandAction, testFunc=nil, usesIdx=false, actionType=ACTION_TYPE_QUAKER} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "EveryXToY", actionFunc=PerformEveryXToEveryYBandAction, testFunc=nil, usesIdx=false, actionType=ACTION_TYPE_QUAKER} -- contact map collection (we just assume rebuild doesn't need safety checks here) AllActionsList[ #AllActionsList + 1 ] = {nameStr = "ContactMapper", actionFunc=PerformContactMapperAction, testFunc=nil, usesIdx=false, actionType=ACTION_TYPE_CONTACTMAP} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "SomeContactMapBands", actionFunc=PerformSomeContactMapBandsAction, testFunc=nil, usesIdx=false, actionType=ACTION_TYPE_CONTACTMAP} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "ContactMapRebuildAll", actionFunc=PerformContactMapRebuildAllAction, testFunc=nil, usesIdx=false, actionType=ACTION_TYPE_CONTACTMAP} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "ContactMapRebuildRange", actionFunc=PerformContactMapRebuildRangeAction, testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_CONTACTMAP} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "ContactMapRebuildSS", actionFunc=PerformContactMapRebuildSSAction, testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_CONTACTMAP} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "ContactMapTwoRegions", actionFunc=PerformCMTwoRegionBandAction, testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_CONTACTMAP} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "ContactTwoSegs", actionFunc=PerformSingleContactMapAction, testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_CONTACTMAP} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "ContactMapForSeg", actionFunc=PerformContactMapBandsForSegAction, testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_CONTACTMAP} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "PushPullContactMap", actionFunc=PerformPushPullContactMapAction, testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_CONTACTMAP} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "VoidCrusherContactMap", actionFunc=PerformVoidCrusherContactMapAction, testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_CONTACTMAP} -- oddball endgame actions deserve some love, too AllActionsList[ #AllActionsList + 1 ] = {nameStr = "IdealizePoint", actionFunc=PerformIdealizePointAction, testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_ENDGAME} -- NOTE: by calling this endgame, I lose rebuild sanity check ability AllActionsList[ #AllActionsList + 1 ] = {nameStr = "RebuildSimplePoint", actionFunc=PerformRebuildSimplePointAction, testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_ENDGAME} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "BandedWormPair", actionFunc=PerformBandedWormPairAction, testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_ENDGAME} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "LocalWiggle", actionFunc=PerformLocalWiggleAction, testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_ENDGAME} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "LocalFreezeWiggle", actionFunc=PerformLocalFreezeWiggleAction, testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_ENDGAME} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "ATSidechainTweak", actionFunc=PerformATSidechainTweakAction, testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_ENDGAME} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "ATSidechainTweakAround", actionFunc=PerformATSidechainTweakAroundAction, testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_ENDGAME} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "ATSidechainManipulate", actionFunc=PerformATSidechainManipulateAction, testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_ENDGAME} -- the dubious actions come last AllActionsList[ #AllActionsList + 1 ] = {nameStr = "TailWhip", actionFunc=PerformTailWhipAction, testFunc=testTailWhipOk, usesIdx=true, actionType=ACTION_TYPE_DUBIOUS} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "SpotMutator", actionFunc=PerformSpotMutatorAction, testFunc=testIndexIsMutable, usesIdx=true, actionType=ACTION_TYPE_DUBIOUS} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "BIS", actionFunc=PerformSingleBandInSpaceAction, testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_DUBIOUS} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "BandBetween", actionFunc=PerformBandToRandomSegAction, testFunc=nil, usesIdx=true, actionType=ACTION_TYPE_DUBIOUS} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "CentralBander", actionFunc=PerformCentralBanderAction, testFunc=nil, usesIdx=false, actionType=ACTION_TYPE_DUBIOUS} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "WiskyRebuildAll", actionFunc=PerformWiskyRebuildAllAction, testFunc=nil, usesIdx=false, actionType=ACTION_TYPE_DUBIOUS} AllActionsList[ #AllActionsList + 1 ] = {nameStr = "RebuildAllWithIdealize", actionFunc=PerformRebuildAllWithIdealizeAction, testFunc=nil, usesIdx=false, actionType=ACTION_TYPE_DUBIOUS} end function GetActionMatchingName( name ) for i=1, #AllActionsList do if name == AllActionsList[ i ].nameStr then return AllActionsList[ i ] end end print( "No matching action for "..name ) end function indexIsAllowed( idx ) if #AllowedActionIndices == 0 then return true end for i = 1, #AllowedActionIndices do if idx == AllowedActionIndices[ i ] then return true end end return false end function GenerateAcceptableIndexList( ) local idxList = {} for i = 1, #NonLockedSegList do if indexIsAllowed( NonLockedSegList[i] ) then idxList[ #idxList + 1 ] = NonLockedSegList[i] end end if #idxList == 0 then return nil end randomizeIndexList( idxList ) -- IF TARGETED IS WANTED, THEN PLAY ITS GAMES HERE if randomBool( PROB_TARGETED ) then print("Trying to target") -- winners: put one winner list entry at top if randomBool( PROB_TARGETED_WANTS_WINNER ) then -- get the most recent winner, move it to the top of the list local idx = RecentWinners[ random( #RecentWinners ) ].idx for j=1, #idxList do if idxList[ j ] == idx then idxList[ j ], idxList[ 1 ] = idxList[ 1 ], idxList[ j ] break end end else -- worst: move the five worst-scoring indices to the top of the list local idxBads = {} getWorstScoringAAs( idxBads, 5, subscore ) randomizeIndexList( idxBads ) for i=1, #idxBads do for j=1, #idxList do if idxList[ j ] == idxBads[ i ] then idxList[ j ], idxList[ i ] = idxList[ i ], idxList[ j ] break end end end end end return idxList end function GenerateActionChoice( actionNamesList ) -- Generate a list of usable indices in an appropriate order local idxList = GenerateAcceptableIndexList( ) if actionNamesList == nil or #actionNamesList == 0 or #idxList == 0 then return nil, nil end -- Generate an ordering for the list of actions -- IF WANT TO SUPPORT SOME KIND OF RANKED ORDERING OF ACTIONS, DO IT HERE local actionIdxes = {} for i=1, #actionNamesList do actionIdxes[ i ] = i end randomizeIndexList( actionIdxes ) -- walk through the indices and actions looking for workable combinations for i=1, #idxList do for j = 1, #actionIdxes do local idx = idxList[ i ] local actionToConsider = GetActionMatchingName( actionNamesList[ actionIdxes[ j ] ] ) if actionToConsider ~= nil then if actionToConsider.actionType ~= ACTION_TYPE_REBUILD or #NonLockedSegList > 0 then if actionToConsider.usesIdx == false or actionToConsider.testFunc == nil then if actionToConsider.usesIdx == false then return nil, actionToConsider else return idx, actionToConsider end else if actionToConsider.testFunc(idx) then return idx, actionToConsider end end end end end end -- we has faileded return nil, nil end function PerformAction( action, idx ) AlgName = action.nameStr local initScore = getQuickScore() -- winner circle silliness -- SETUP FOR THE ACTION if CYSTEINE_PERFORM_BANDING then EnableAndDisableCysteineBands( ) -- get cysteine bands just right end ResetUserBands( ) -- enable/disable as user originally had them -- decide whether to perform pre-expansion (used by decementing actions) local likeExpanders = EXPAND_BEFORE_ACTION and WorthTryingCementBreaker if likeExpanders and randomBool( PROB_USE_EXPANDER ) then PerformEveryXToEveryYExpansion() AlgName = "Exp" .. AlgName -- to help stats tracking end -- PERFORM THE ACTION if not action.usesIdx then idx = nil end changeSucceeded = action.actionFunc( idx ) -- WRAPUP AFTER THE ACTION -- cleanup on aisle 6 (not supposed to be needed, but just in case) ResetFrozenness( ) DelBands( ) --ResetCuts( ) -- too pricy, rather risk missing out selection.DeselectAll( ) SetCI( 1.0 ) -- stats and final fuse if user wants such a thing if not changeSucceeded then if action.actionType == ACTION_TYPE_REBUILD then CtRebuildFails = CtRebuildFails + 1 print( "CHANGE FAILED - RB(" .. CtRebuildFails .. ")" ) else print( "CHANGE FAILED - " .. AlgName ) end else if action.actionType == ACTION_TYPE_REBUILD then CtRebuildFails = 0 end -- THE FUSER for those who want such if USE_FUSEWIGGLE then DoFuseWiggle( ) end -- winner's circle tracking (currently useless, but who knows?) -- a better version of this would also track action. if idx ~= nil then UpdateWinners( idx, getScore() > initScore ) end end return changeSucceeded end function PickActionFromList( actionNamesList ) local idx, action = GenerateActionChoice( actionNamesList ) if action == nil then print("!!! No selectable actions") return false end return PerformAction( action, idx ) end ---------------------------------------------------------------- -- WALKER FUNCTIONS ---------------------------------------------------------------- function PerformWalker( orderProtocol, actionNamesList, qs_best, abbr ) if qs_best == nil then qs_best = QS_Best end if abbr == nil then abbr = "WALK" end if actionNamesList == nil or #actionNamesList == 0 then print("no actions to perform") return 0, 0, 0 end local stepCt = 0 local startTime = os.time() local initScore = getScore() -- which indices should we act upon? local idxList = {} local idxIndexer = {} for i = 1, #NonLockedSegList do if indexIsAllowed( NonLockedSegList[i] ) then idxList[ #idxList + 1 ] = NonLockedSegList[i] idxIndexer[ #idxIndexer + 1 ] = #idxIndexer + 1 end end if #idxList == 0 then print("no aas to act upon") return 0, 0, 0 end if orderProtocol == ACTION_ORDERPROTOCOL_START_TO_END then abbr = abbr.."_SE" elseif orderProtocol == ACTION_ORDERPROTOCOL_END_TO_START then abbr = abbr.."_ES" for i=1, math.floor( #idxIndexer/2 ) do local tmp = idxIndexer[ #idxIndexer - i ] idxIndexer[ #idxIndexer - i ] = idxIndexer[ i ] idxIndexer[ i ] = tmp end elseif orderProtocol == ACTION_ORDERPROTOCOL_RANDOMIZE then abbr = abbr.."_R" randomizeIndexList( idxIndexer ) elseif orderProtocol == ACTION_ORDERPROTOCOL_WORST_TO_BEST then abbr = abbr.."_WB" local idxScores = {} for i = 1, #NonLockedSegList do if indexIsAllowed( NonLockedSegList[i] ) then idxScores[ #idxScores + 1 ] = current.GetSegmentEnergyScore( i ) end end sortByScore( idxIndexer, idxScores ) else print("no such protocol") return 0,0,0 end for i = 1, #idxList do LoadBest( qs_best ) -- which index should we act upon? local idx = idxList[ idxIndexer[ i ] ] print( abbr..":"..i.." score="..TrimNum(getScore()) ) local gainForIdx = MinIdxGainToRepeat while gainForIdx >= MinIdxGainToRepeat do local actionIdxes = {} for j=1, #actionNamesList do actionIdxes[ j ] = j end randomizeIndexList( actionIdxes ) local initIdxScore = getScore() for j=1, #actionNamesList do -- what action should we take? LoadBest( qs_best ) local oldScore = getScore() local oldTime = os.time() action = GetActionMatchingName( actionNamesList[actionIdxes[ j ]]) if action == nil then print("No action - wanted: "..actionNamesList[actionIdxes[ j ]]) else if action.testFunc == nil or action.testFunc(idx) then local changeSucceeded = PerformAction( action, idx ) if changeSucceeded then local newScore = getScore( ) local deltaScore = newScore - oldScore local deltaTime = os.time() - oldTime addActionToStats( deltaScore, deltaTime ) if deltaScore > 0.0 then print("+ Action gain: "..deltaScore) SaveBests( false, qs_best ) end else addFailToStats( ) end stepCt = stepCt + 1 end end end LoadBest( qs_best ) gainForIdx = getScore() - initIdxScore if gainForIdx > 0.0 then print("+++ Gain for idx="..idx..": "..gainForIdx.." score="..TrimNum(getScore())) else print("--- No gain for idx="..idx) end end end local endScore = getScore() local endTime = os.time()-startTime return stepCt, endTime, endScore end ---------------------------------------------------------------- -- MULTITRY FUNCTIONS ---------------------------------------------------------------- function FindAlreadyStoredPoseSimilarToCurrentOne( qs_slots ) local currDistMat = {} computeDistanceMatrix( currDistMat ) local currScore = getScore( ) save.Quicksave( QS_Swapslot ) for i=1, #qs_slots do save.Quickload( qs_slots[i] ) local savDistMat = {} computeDistanceMatrix( savDistMat ) local savScore = getScore() if compareDistanceMatrices( savDistMat, currDistMat ) then return qs_slots[i], savScore end end save.Quickload( QS_Swapslot ) return 0, 0 end function SaveTopBests( TopBestSlots ) currScore = getScore() local slot, slotScore = FindAlreadyStoredPoseSimilarToCurrentOne( TopBestSlots ) if slot > 0 then -- ok, we have a slot with extremely similar entry. Decide whether to keep it if slotScore < currScore then print("Saving pose - replacing similar less-scoring pose") save.Quicksave( slot ) else print("Not saving - already have a similar and better pose") end else -- ok, we don't have a slot with extremely similar entry. Put it in score order. save.Quicksave( QS_Swapslot ) for i = 1, #TopBestSlots do save.Quickload( TopBestSlots[ i ] ) savScore = getScore() if currScore > savScore then for j=#TopBestSlots-1, i, -1 do save.Quickload( TopBestSlots[j] ) save.Quicksave( TopBestSlots[j+1] ) end save.Quickload( QS_Swapslot ) print("Storing new pose in slot "..i) save.Quicksave( TopBestSlots[ i ] ) -- save new pose break end end save.Quickload( QS_Swapslot ) end end function GetBestFromList( topBests, wantReport ) -- it's already sorted, so we'll load the first one if wantReport then for i=1, #topBests do save.Quickload( topBests[ i ] ) print( "Score #" .. i .. " = " .. getScore() ) end end save.Quickload( topBests[1] ) end function SetupTopBests( topBests, numberOfSlotsWanted ) if numberOfSlotsWanted > QS_MultiStartSaveLast - QS_MultiStartSave1 + 1 then print( "!!! Asked for more slots than allowed max" ) return false end for i=1, numberOfSlotsWanted do topBests[#topBests+1] = QS_MultiStartSave1 + i - 1 save.Quicksave( QS_MultiStartSave1 + i - 1) end return true end function PerformMultiTryOperation( numberOfStarts, numberOfActionsPerTry, startIdx, endIdx, actionFunction, abbrBase ) if abbrBase == nil then abbrBase = "" end print( "PerformMultiTryOperation for "..numberOfStarts.." starts with ".. numberOfActionsPerTry.." actions per try" ) BestScore=getScore( ) LoadBest( ) local bests = {} local topBests = {} if not SetupTopBests( topBests, numberOfStarts ) then return false end save.Quicksave( QS_TopLevelTempMT ) save.Quicksave( QS_TopLevelTempM2 ) for k=1, numberOfStarts do save.Quickload( QS_TopLevelTempMT ) -- always start over from initial state SaveBest( true, QS_TopLevelTempM2 ) -- make this be best so far --print( "Starting try " .. k.. " of " .. numberOfStarts .. ": Score="..TrimNum(getScore( ))) local initscore = getScore( ) for j=1, numberOfActionsPerTry do if numberOfActionsPerTry > 1 then abbr = abbrBase .. "-MT" .. numberOfStarts .. "." .. numberOfActionsPerTry.. ":" .. k .. "." .. j else abbr = abbrBase .. "-MT" .. numberOfStarts .. ":" .. k end save.Quickload( QS_TopLevelTempM2 ) local currScore = getScore( ) actionFunction( startIdx, endIdx, QS_TopLevelTempM2, abbr ) -- I expect actionFunction to store its best result in QS..M2, -- but I do not expect it to load that result for me. save.Quickload( QS_TopLevelTempM2 ) local endScore = getScore( ) if endScore > currScore then save.Quicksave( QS_TopLevelTempM2 ) currScore = endScore end if endScore > BestScore then BestScore = endScore end SaveBests( false, QS_TopLevelTempM2 ) end -- FOR j save.Quickload( QS_TopLevelTempM2 ) print( abbr .. ": Finishing - Score: "..getScore( ) ) SaveTopBests( topBests ) end -- FOR k GetBestFromList( topBests, true ) print( "Taking result with score " .. TrimNum( getScore() )) return true end ---------------------------------------------------------------------- -- SCRIPT-SPECIFIC FUNCTIONS ---------------------------------------------------------------------- ---------------------------------------------------------------- -- SA's Neighbor generator ---------------------------------------------------------------- function CreateNeighborPose( NeighborGenerationFunction ) -- creditbest code removed because starting from shares runs into foldit bug --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_NeighborTempSA ) local goodNeighbor = false while not goodNeighbor do local oldTime = os.time( ) local changeSucceeded = false goodNeighbor = false save.Quickload( QS_NeighborTempSA ) local changeSucceeded = NeighborGenerationFunction( ) if changeSucceeded then local newScore = getScore( ) goodNeighbor = isProteinChanged( oldQuickScore, oldScoreMat, THRESHOLD_PROTEIN_CHANGED ) 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 if CtRebuildFails > MAX_REBUILD_FAILS then -- sometimes there are no successful ways to do a rebuild, we must bail CtRebuildFails = 0 return false end end -- END while not goodNeighbor -- Look over the result local newScore = getScore( ) --local newCreditBest = creditbest.GetScore( ) --if newCreditBest ~= oldCreditBest and newCreditBest ~= newScore then -- -- we missed a transient -- -- trying to regain it can be problematic for some wigglers -- -- (eg WiggleZlbNicely) because the creditbest pose may have bands. -- print( "!!! CreditBest changed: old="..oldCreditBest.." new="..newCreditBest ) --end print( "Neighbor Score: " .. newScore) return true end function DoFuseWiggle( ) local oldScore = getQuickScore( ) local oldTime = os.time( ) local r = random( ) if r < PROB_FUSEWIGGLE_LOCAL then print( "IterativeWiggleLocalByChunk" ) AlgName = "IterativeWiggleLocalByChunk" IterativeWiggleLocalByChunk( 1, SegCt, FUSEWIGGLE_GAIN, random( 3, 6 ), false ) elseif r < PROB_FUSEWIGGLE_LOCAL + PROB_FUSEWIGGLE_BLUEFUSE then print( "BlueFuse" ) AlgName = "BlueFuse" BlueFuse( ) else -- PROB_FUSEWIGGLE_CUTFUSE print( "IterativeCutAndWiggle") AlgName = "IterativeCutAndWiggle" IterativeCutAndWiggle( FUSEWIGGLE_ITERS, FUSEWIGGLE_GAIN, random( 3,11 ) ) for i=1, SegCt do -- deliberate non-use of ResetCuts DeleteCutAtIndex( i ) end end local deltaScore = getQuickScore( ) - oldScore local deltaTime = os.time( ) - oldTime addActionToStats( deltaScore, deltaTime ) end ---------------------------------------------------------------------- -- ---- SIMULATED ANNEALING ALGORITHM FUNCTIONS -- ---------------------------------------------------------------------- -- Real research could be done (rosetta folks have done) on what a "good" -- Temperature function is for these purposes. -- Note that "num" = i/n and goes from 0 to 1 over the life of the SA function. -- -- FOR COMPARISON PURPOSES -- Rosetta pose generation uses: -- ts1 = (t0-tn)/cosh(5.0*i/n) + t0 -- below: num = i/n -- ts2 = (t0-tn)*i/n + t0 -- stage1: t0=5.0, tn=0.5 ts1 -- runs from 9.0-epsilon to 5.0 -- stage2: t0=5.0, tn=0.5 ts1 -- stage3: t0=5.0, tn=0.5 ts1 -- stage4: t0=5.0, tn=0.0 ts2 -- runs backwards from 0.0 to 5.0 -- stage5: t0=1.0, tn=0.2 ts2 -- runs backwards from 0.2 to 0.8 -- -- Rosetta scoring: -- stage1: only repulsive force of sidechain centroids -- stage2: "score1" = stage1 score + vanderwaals+SS+disulfide -- stage3: interchange "score2" and "score5", similar except for weighting -- stages4&5: use "score3" = stage2 + compactness+solvent accessibility+position of sidechain centroids -- -- Rosetta neighbor generation: -- stage1: operates on 9-mers -- stage2,3: 9-mers and 3-mers -- stage4: 3-mers at start, pairs of 3-mers later -- place 1st at random, 2nd minimizes disruption of 1st location. -- stage5: play with dihedral angles of randomly chosen aa -- repacking: checks a rotamer database for sidechains. -- function T_OneOverX( num ) 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 function PickTempFuncByName( tempName ) if tempName == "OneOverX" then return T_OneOverX elseif tempName == "MiddlingX" then return T_MiddlingX elseif tempName == "LowX" then return T_LowX elseif tempName == "ColdX" then return T_ColdX elseif tempName == "ZeroX" then return T_Zero else return T_OneOverX -- the default temp function end end function PickTempStringByNumber( tempNumber ) if tempNumber == 0 then return "ZeroX" elseif tempNumber == 1 then return "ColdX" elseif tempNumber == 2 then return "LowX" elseif tempNumber == 3 then return "MiddlingX" else return "OneOverX" end end -- this is the standard probability function in Simulated Annealing algorithms function P( ecurr, enew, T ) if enew < ecurr then return 1.0 end -- always accept increased scores if T == 0.0 then return 0.0 end -- always reject decreased scores if temp = 0 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, NeighborGenerationFunction, TempFunc, qs_best, abbr ) -- emax is expected to "never happen" if TempFunc == nil then TempFunc = T_OneOverX end local estart = E( ) local ecurr = estart save.Quicksave( QS_TopLevelTempSA ) -- a private slot local ebest = ecurr local startTime = os.time( ) local emax = -999999.0 local k = 0.0 while k < kmax and ecurr > emax do WorthTryingCementBreaker = (k < StepsForCementBreaking) save.Quickload( QS_TopLevelTempSA ) local T = TempFunc( k / kmax ) print("#" ..abbr .. k+1 .. " T=" .. TrimNum( T ).. " s=" .. TrimNum( getScore( ) ).. " tm=" .. os.time( )-startTime ) local succeeded = CreateNeighborPose( NeighborGenerationFunction ) if not succeeded then return k end local enew = E( ) local p = P(ecurr, enew, T) local r = random( ) if p > r or enew < ecurr then if enew < ecurr then print( "++++ accepting state: score " ..TrimNum( getScore())) if enew < ebest then ebest = enew SaveBests( false, qs_best ) end elseif enew > ecurr then print( "++++ overriding state: score " ..TrimNum( getScore())) else print( "++++ same-score state: score " ..TrimNum( getScore())) end save.Quicksave( QS_TopLevelTempSA ) ecurr = enew end k = k + 1.0 end LoadBest( qs_best ) return k end function PerformSA( ctRestarts, stepsPerRun, quitIfTooManyFails, minGainPerRun, ctTooManyFails, NeighborGenerationFunction, TempFuncName, qs_best, abbr ) if minGainPerRun == nil then minGainPerRun = 0 end local saInitialTime = os.time( ) local saInitialScore = getScore( ) local bestScore = saInitialScore local newscore = 0.0 local stepCount = 0 SaveBests( false, qs_best ) local sav_useExpander = EXPAND_BEFORE_ACTION local sav_probExpander = PROB_USE_EXPANDER local sav_stepsPerRun = stepsPerRun -- contruct the heiroglyphics if abbr == nil then abbr = "SA" else abbr = abbr .. "-SA" end if ctRestarts > 1 then abbr = abbr .. ctRestarts .. "." end abbr = abbr .. stepsPerRun .. ":" -- reset the stat tracking info for i=1, #CountFails do CountFails[i]=0 end -- change temp func string into actual function TempFunc = PickTempFuncByName( TempFuncName ) -- start playing the game! local ctFailedRuns = 0 for i=1, ctRestarts do LoadBest( qs_best ) local saRunStartScore = getScore( ) local saRunStartTime = os.time( ) print( "START: SA score=" ..TrimNum( saRunStartScore ).. " time=" ..saRunStartTime - saInitialTime ) local abbrOut = abbr if ctRestarts > 1 then abbrOut = abbrOut .. i .. "." end stepCount = stepCount + SA( stepsPerRun, NeighborGenerationFunction, TempFunc, qs_best, abbrOut ) LoadBest( qs_best ) newscore = getScore( ) local gain = newscore - bestScore if newscore > bestScore then bestScore = newscore end local str = "FINISH: SA score=" ..TrimNum( bestScore ).. " gain=" ..TrimNum( gain ).. " time=" ..(os.time( ) - saRunStartTime) if quitIfTooManyFails and gain < minGainPerRun then str = str .. " fails="..(ctFailedRuns + 1) end print( str ) if quitIfTooManyFails and gain < minGainPerRun then -- this run wasn't profitable... ctFailedRuns = ctFailedRuns + 1 if #CountFails < ctFailedRuns then CountFails[ctFailedRuns] = 0 end CountFails[ ctFailedRuns ] = CountFails[ ctFailedRuns ] + 1 if i < ctRestarts and ctFailedRuns >= ctTooManyFails then -- ok, it was fun while it lasted, but this is getting silly print( "!!! Too many failed runs - bailing" ) break end elseif gain >= minGainPerRun then -- reset the failure clock ctFailedRuns = 0 end PossibleCementingState = (ctFailedRuns >= FailsToStartCementBreaking) if i < ctRestarts and PossibleCementingState and FIGHT_CEMENTING then -- we fear it's cemented: haul out the badass actions. EXPAND_BEFORE_ACTION = true PROB_USE_EXPANDER = 1.0 stepsPerRun = SA_STEPSPERRUN_DECEMENT print("---Decementing---" ) else -- if all is well, then stop fighting! EXPAND_BEFORE_ACTION = sav_useExpander PROB_USE_EXPANDER = sav_probExpander stepsPerRun = sav_stepsPerRun end end LoadBest( qs_best ) if ctRestarts > 1 then print( "FINAL SA: steps=" ..stepCount.. " gain=" ..TrimNum( getScore( ) - saInitialScore).. " time=" ..os.time( ) - saInitialTime ) end EXPAND_BEFORE_ACTION = sav_useExpander PossibleCementingState = false WorthTryingCementBreaker = false return stepCount end ---------------------------------------------------------------------- -- SA ROUTINES FOR CHOOSING INDICES ---------------------------------------------------------------------- function UpdateWinners( idx, hadGain ) -- everybody's clock gets updated, clean out too-old entries --print( "UW: idx="..idx.." gain? "..BoolStr( hadGain ) ) for i=#RecentWinners, 1, -1 do if RecentWinners[ i ].clock > WINNER_CLOCK_TIMEOUT or RecentWinners[ i ].idx == 0 then table.remove( RecentWinners, i ) else RecentWinners[ i ].clock = RecentWinners[ i ].clock + 1 end end -- if we have a new success, add it (don't mind repeats) if idx > 0 and hadGain then local entry = {} entry.idx = idx entry.clock = 1 table.insert( RecentWinners, 1, entry ) end --for i=1, #RecentWinners do -- print("RW: idx="..(RecentWinners[i].idx).." clock="..(RecentWinners[i].clock) ) --end end function GetWinnerIdx( ) if #RecentWinners == 0 then return 0 end local idx = RecentWinners[ random( #RecentWinners ) ].idx --print( "GetWinnerIdx start with winner idx = "..idx ) if randomBool( PROB_WINNER_WANTS_NEIGHBOR ) then idxNeighbors = {} getSegsWithinSphere( idxNeighbors, idx, WINNER_INDEX_MAX_RADIUS, true) --print( "Picking Neighbor: there are "..#idxNeighbors ) idx = idxNeighbors[ random( #idxNeighbors ) ] end --print( "GetWinnerIdx return idx = "..idx ) return idx end function PickIdxForAction( idx ) -- I currently believe targeted is never worth the effort (both kinds of targeting) if randomBool( PROB_TARGETED ) then -- overrule whatever we may have been given idx = 0 if randomBool( PROB_TARGETED_WANTS_WINNER ) then idx = GetWinnerIdx( ) end if idx == 0 then idx = randomLowScoringSeg( random( #NonLockedSegList / 5 )) end else -- we always end up here of late! if idx == nil or idx == 0 then if #AllowedActionIndices > 0 then local r = random( #AllowedActionIndices ) idx = AllowedActionIndices[ r ] else idx = randomMovableSeg( ) end end end return idx end ---------------------------------------------------------------------- -- SA ROUTINES FOR CHOOSING ACTION COLLECTIONS ---------------------------------------------------------------------- function testSheetActionsOk( idx ) local isSheetRegion = structure.GetSecondaryStructure( idx ) == 'E' return isSheetRegion and #AllSheets > 1 end function testNonstraySheetsActionsOk( idx ) local isSheetRegion = structure.GetSecondaryStructure( idx ) == 'E' return isSheetRegion and #AllSheets > 1 and not IsStraySheet( idx ) end function testSimpleHelixOk( idx ) local isHelixRegion = structure.GetSecondaryStructure( idx ) == 'H' or isPossibleHelix( idx ) return isHelixRegion end function testGlycineHingeOk( idx ) local isHelixRegion = structure.GetSecondaryStructure( idx ) == 'H' or isPossibleHelix( idx ) return isGlycine( idx ) and (not isHelixRegion) and idx >= 5 and idx <= SegCt - 5 end function testGeneralHingeOk( idx ) local isHelixRegion = structure.GetSecondaryStructure( idx ) == 'H' or isPossibleHelix( idx ) return (not isHelixRegion) and idx >= MinUnlockedSeg + 5 and idx <= MaxUnlockedSeg - 5 end function testLargishHelixActionsOk( idx ) local isHelixRegion = structure.GetSecondaryStructure( idx ) == 'H' or isPossibleHelix( idx ) local startSeg, endSeg = GetRegionForOperation( idx ) local regionLength = endSeg - startSeg + 1 return isHelixRegion and regionLength > 6 end function testFlexerOk( idx ) local startSeg, endSeg = GetRegionForOperation( idx ) local regionLength = endSeg - startSeg + 1 return regionLength >= 5 and idx >= MinUnlockedSeg + 4 and idx <= MaxUnlockedSeg - 4 end function testTailWhipOk( idx ) return idx <= MinUnlockedSeg + 5 or idx >= MaxUnlockedSeg - 5 end function testSmallPuzzleOk( idx ) if ALLOW_SLOW_ACTIONS then return true end return MaxUnlockedSeg - MinUnlockedSeg < 100 end function testRebuildOk( idx ) return CtRebuildFails < MAX_REBUILD_FAILS end function testRebuildSmallPuzzleOk( idx ) if CtRebuildFails < MAX_REBUILD_FAILS then return false end if ALLOW_SLOW_ACTIONS then return true end return MaxUnlockedSeg - MinUnlockedSeg < 100 end function PickStab1Action( ) -- Actions that don't change the "shape" except in controllable ways. allowedActions = { "GentleComp", "GentleCompLowCI", "SheetShifter", "SheetAligner", "SheetSewer", "SheetStraightener", "HelixRotator", "HelixUniform", "HelixCompressor", "HelixFixer", } return PickActionFromList( allowedActions ) end function PickStab2Action( ) allowedActions = { "GentleComp", "GentleCompLowCI", "PushPull", "VoidCrusher", "TailGrab", "BisQuake", "LSQuake", "SimpleQuake", "GeneralHinge", "GlycineHinge", "SheetAligner", "SheetShifter", "SheetSewer", "SheetStraightener", "HelixRotator", "HelixUniform", "HelixCompressor", "HelixFixer", --"RebuildSimple", --"RebuildBitspawn", --"RebuildBitspawnLowCI" --"QuakingRebuild", } return PickActionFromList( allowedActions ) end function PickEarly1Action( ) local allowedActions = { } local onlyCementBreakers = PossibleCementingState and WorthTryingCementBreaker and FIGHT_CEMENTING if onlyCementBreakers then allowedActions = { "GentleComp", "GentleCompLowCI", "QuakingRebuild", "LSQuake", "SimpleQuake", "InhaleAndExhale", } else -- the cementbreakers have "normal" uses, too allowedActions = { "GentleComp", "GentleCompLowCI", "LSQuake", "SimpleQuake", "InhaleAndExhale", "PushPull", "VoidCrusher", "TailGrab", "PusherBands", "MoverBands", "FlexerBands", "GeneralHinge", "GlycineHinge", "SheetAligner", "SheetSewer", "SheetShifter", "HelixRotator", "HelixUniform", "HelixCompressor", "HelixFixer", "QuakingRebuild", "RebuildSimple", "RebuildBitspawn", "RebuildBitspawnLowCI", } end return PickActionFromList( allowedActions ) end function PickEarly2Action( ) local onlyCementBreakers = FIGHT_CEMENTING and PossibleCementingState and WorthTryingCementBreaker local allowedActions = { } if onlyCementBreakers then allowedActions = { "GentleComp", "LSQuake", "SimpleQuake", "InhaleAndExhale", } else allowedActions = { "PushPull", "VoidCrusher", "TailGrab", "RebuildSimple", "RebuildBitspawn", "RebuildBitspawnLowCI", "RebuildFromQuaker", "IdealizeRegion", "IdealizeXToY", "IdealizeZlb", "RemixSimple", } end return PickActionFromList( allowedActions ) end function PickRebuildAction( ) local allowedActions = { -- DON'T do expensive ones "RebuildFromQuaker", "RebuildSimple", "RebuildBitspawn", "RebuildBitspawnLowCI", "RebuildSimpleXToY", "QuakingRebuild", "RemixSimple", "RemixSimpleXToY", "IdealizeRegion", "IdealizeZlb", "IdealizeXToY", } return PickActionFromList( allowedActions ) end function PickDeepRebuildAction( ) local allowedActions = { -- NOW do expensive ones "DeepRebuildRange", "DeepRebuildRangeXToY", "DeepRebuildSS", "DeepRebuildSSXToY", "Remix", "RemixXToY", } return PickActionFromList( allowedActions ) end function PickMidgameAction( ) local allowedActions = { "MultiBander", "MultiBis", "MultiSegBand", "BandedWormPair", "LocalWiggle", "LocalFreezeWiggle", } return PickActionFromList( allowedActions ) end function PickEndgameAction( ) local allowedActions = { "IdealizePoint", "RebuildSimplePoint", "BandedWormPair","BandedWormPair","BandedWormPair","BandedWormPair","BandedWormPair","BandedWormPair", "LocalWiggle", "LocalFreezeWiggle", "ATSidechainTweak", "ATSidechainTweakAround", "ATSidechainManipulate", } return PickActionFromList( allowedActions ) end function PickLowCIAction( ) local allowedActions = { "GentleCompLowCI", "VoidCrusher", "RebuildSimple", "RebuildBitspawnLowCI", "GeneralHinge", "GlycineHinge", "SheetAligner", "SheetSewer", "SheetShifter", "HelixRotator", "HelixUniform", "HelixCompressor", "HelixFixer", "PusherBands", "MoverBands", "FlexerBands", } return PickActionFromList( allowedActions ) end function PickLateAction( ) local allowedActions = { "MultiBander", "MultiBis", "MultiSegBand", "EveryXToY", "DeepRebuildRange", "DeepRebuildRangeXToY", "IdealizeZlb", "IdealizeRegion", "IdealizeXToY", "IdealizePoint", "RebuildSimplePoint" } return PickActionFromList( allowedActions ) end function PickContactMapAction( ) local allowedActions = { "ContactMapper", "SomeContactMapBands", "ContactMapForSeg", "ContactTwoSegs", "PushPullContactMap", "VoidCrusherContactMap", "ContactMapTwoRegions", "ContactMapRebuildRange", "ContactMapRebuildSS", "ContactMapRebuildAll", } return PickActionFromList( allowedActions ) end ---------------------------------------------------------------- -- SA OPERATION PERFORMING FUNCTIONS ---------------------------------------------------------------- function SetSAParamDefaults() ALLOW_FUSE = false USE_FUSEWIGGLE = false EXPAND_BEFORE_ACTION = false PROB_QSTAB_EXTRA = PROB_QSTAB_EXTRA_DEFAULT PROB_USE_EXPANDER = PROB_USE_EXPANDER_DEFAULT PROB_TARGETED = PROB_TARGETED_DEFAULT FIGHT_CEMENTING = FIGHT_CEMENTING_DEFAULT ALLOW_SLOW_ACTIONS = ALLOW_SLOW_ACTIONS_DEFAULT behavior.SetWigglePower( InitialWigglePower ) recentbest.Save() end function PerformStab1Operation( allowFailOut, abbr ) SetSAParamDefaults() if abbr == nil then abbr = "STAB1" end if allowFailOut == nil then allowFailOut = true end if not FORBID_WIGGLE_POWER_CHANGE then behavior.SetWigglePower( WIGGLEPOWER_STAB1 ) end local initScore = getScore() local startTime = os.time() local failNoGain = SA_FAILIFNOGAIN_STAB1 local tempFunc = TEMPFUNCNAME_STAB1 local runcount = SA_NUMSTARTS_STAB1 local numSteps = SA_STEPSPERRUN_STAB1 local actionPicker = PickStab1Action print( "SA-Stabilize for " .. runcount .. " runs of " .. numSteps .. " steps using "..tempFunc) if allowFailOut then print("Move on if "..failNoGain.." rounds have too little gain") end local stepCt = PerformSA( runcount, numSteps, allowFailOut, SA_MINGAIN, failNoGain, actionPicker, tempFunc, QS_Best, abbr ) local gain = getScore() - initScore local endScore = getScore() local endTime = os.time() - startTime local str = "{" for i=1,#CountFails do str = str..CountFails[i] if i < #CountFails then str = str.."," else str = str .."}" end end print( abbr..": gain="..TrimNum(gain).. " steps="..stepCt.. " time="..endTime.. " fails="..str ) return stepCt, endTime, endScore end function PerformStab2Operation( allowFailOut, abbr ) SetSAParamDefaults() if abbr == nil then abbr = "STAB2" end if allowFailOut == nil then allowFailOut = true end if not FORBID_WIGGLE_POWER_CHANGE then behavior.SetWigglePower( WIGGLEPOWER_STAB2 ) end local initScore = getScore() local startTime = os.time() local failNoGain = SA_FAILIFNOGAIN_STAB2 local tempFunc = TEMPFUNCNAME_STAB2 local runcount = SA_NUMSTARTS_STAB2 local numSteps = SA_STEPSPERRUN_STAB2 local actionPicker = PickStab2Action print( "SA-Stabilize for " .. runcount .. " runs of " .. numSteps .. " steps using "..tempFunc) if allowFailOut then print("Move on if "..failNoGain.." rounds have too little gain") end local stepCt = PerformSA( runcount, numSteps, allowFailOut, SA_MINGAIN, failNoGain, actionPicker, tempFunc, QS_Best, abbr ) local gain = getScore() - initScore local endScore = getScore() local endTime = os.time() - startTime local str = "{" for i=1,#CountFails do str = str..CountFails[i] if i < #CountFails then str = str.."," else str = str .."}" end end print( abbr..": gain="..TrimNum(gain).. " steps="..stepCt.. " time="..endTime.. " fails="..str ) return stepCt, endTime, endScore end function SimpleStabSA( startIdx, endIdx, qs_best, abbrIn ) -- A single run of SA for use by a MultiTry caller. -- unused: startIdx, endIdx local numSteps = SA_STEPSPERRUN_STAB1 PerformSA( 1, numSteps, false, SA_MINGAIN, SA_FAILIFNOGAIN_STAB1, PickStab1Action, TEMPFUNCNAME_STAB1, qs_best, abbrIn ) end function PerformStab1MultiTry( iters, depthOfMultiTry ) SetSAParamDefaults() local stepCt = 0 for i=1, iters do local currScore = getScore() local abbr = "STABp"..iters..":" .. i PerformMultiTryOperation( depthOfMultiTry, 1, 1, SegCt, SimpleStabSA, abbr ) stepCt = stepCt + depthOfMultiTry*SA_STEPSPERRUN_STAB1 end return stepCt end function PerformStabilizerOperation( ) -- INIT WSWSW local initScore = getScore() local timeStart = os.time() print( "before WSWSW: score="..TrimNum(initScore) ) -- first relax it some, then do swsw... if not FORBID_WIGGLE_POWER_CHANGE then behavior.SetWigglePower( WIGGLEPOWER_STAB1 ) end recentbest.Save() PerformFastRelaxWiggler( 5 ) recentbest.Restore() EnableAndDisableCysteineBands( ) ShakeWiggleTillStable() local scoreWswsw = getScore() local gainWswsw = scoreWswsw - initScore local timeWswsw = os.time( ) - timeStart DelBands( ) -- in case of cysteine bands... SaveBest( ) print( "WSWSW finished: time="..timeWswsw.." gain="..TrimNum(gainWswsw) ) behavior.SetWigglePower( InitialWigglePower ) -- Don't bother with multitry, it buys nothing --stepCt1 = PerformStab1MultiTry( 3, 5 ) -- PERFORM OUR FIRST SA run: Stab1 LoadBest( ) local abbr = "STAB:2.1" local stepsStab1,timeStab1,scoreStab1 = PerformStab1Operation( true, abbr ) print( "Stabilizer1 finished: time="..timeStab1 ) -- PERFORM OUR SECOND SA run: Stab2 abbr = "STAB:2.2" local stepsStab2,timeStab2,scoreStab2 = PerformStab2Operation( true, abbr ) print( "Stabilizer2 finished: time="..timeStab2 ) print( "Finished Stabilizer run" ) print( "Times: wswsw="..timeWswsw.." stab1="..timeStab1.." stab2="..timeStab2) print( "Steps: wswsw="..(1).." stab1="..stepsStab1.." stab2="..stepsStab2) print( "Scores: wswsw="..TrimNum(scoreWswsw).." stab1="..TrimNum(scoreStab1).." stab2="..TrimNum(scoreStab2)) return 1, stepsStab1, stepsStab2, timeWswsw, timeStab1, timeStab2, scoreWswsw, scoreStab1, scoreStab2 end function PerformEarly1Operation( allowFailOut, abbr ) SetSAParamDefaults() if abbr == nil then abbr = "EA1" end if allowFailOut == nil then allowFailOut = true end if not FORBID_WIGGLE_POWER_CHANGE then behavior.SetWigglePower( WIGGLEPOWER_EARLY1 ) end local failNoGain = SA_FAILIFNOGAIN_EARLY1 FIGHT_CEMENTING = FIGHT_CEMENTING_EARLY1 PROB_QSTAB_EXTRA = PROB_QSTAB_EXTRA_EARLY1 local tempFunc = TEMPFUNCNAME_EARLY1 local runcount = SA_NUMSTARTS_EARLY1 local stepcount = SA_STEPSPERRUN_EARLY1 local actionPicker = PickEarly1Action print( "SA-Mover for " .. runcount .. " runs of " .. stepcount .. " steps using "..tempFunc ) if allowFailOut then print("Move on if "..failNoGain.." rounds have too little gain") end local initScore = getScore() local startTime = os.time() local stepCt = PerformSA( runcount, stepcount, allowFailOut, SA_MINGAIN, failNoGain, actionPicker, tempFunc, QS_SA_BestEarly, abbr ) local endScore = getScore() local gain = endScore - initScore local endTime = os.time() - startTime local str = "{" for i=1,#CountFails do str = str..CountFails[i] if i < #CountFails then str = str.."," else str = str .."}" end end print( abbr..": gain="..TrimNum(gain).. " steps="..stepCt.. " time="..endTime.. " fails="..str ) return stepCt, endTime, endScore end function PerformEarly2Operation( allowFailOut, abbr ) SetSAParamDefaults() if abbr == nil then abbr = "EA2" end if allowFailOut == nil then allowFailOut = true end if not FORBID_WIGGLE_POWER_CHANGE then behavior.SetWigglePower( WIGGLEPOWER_EARLY2 ) end local initScore = getScore() local startTime = os.time() FIGHT_CEMENTING = FIGHT_CEMENTING_EARLY2 local failNoGain = SA_FAILIFNOGAIN_EARLY2 PROB_QSTAB_EXTRA = PROB_QSTAB_EXTRA_EARLY2 local tempFunc = TEMPFUNCNAME_EARLY2 local runcount = SA_NUMSTARTS_EARLY2 local stepcount = SA_STEPSPERRUN_EARLY2 local actionPicker = PickEarly2Action print( "SA-Idealize for " .. runcount .. " runs of " .. stepcount .. " steps using "..tempFunc ) if allowFailOut then print("Move on if "..failNoGain.." rounds have too little gain") end local stepCt = PerformSA( runcount, stepcount, allowFailOut, SA_MINGAIN, failNoGain, actionPicker, tempFunc, QS_SA_BestEarly, abbr ) local endScore = getScore() local endTime = os.time() - startTime local gain = endScore - initScore local str = "{" for i=1,#CountFails do str = str..CountFails[i] if i < #CountFails then str = str.."," else str = str .."}" end end print( abbr..": gain="..TrimNum(gain).. " steps="..stepCt.. " time="..endTime.. " fails="..str ) return stepCt, endTime, endScore end function PerformEarlyOperation() SaveBests( true, QS_SA_BestEarly ) local bestScoreSoFar = getScore() local scoresInhaleVector = { 0.0 } -- want same #entries as Early1/2 local scoresEarly1Vector = {} local scoresEarly2Vector = {} local stepsEarly1Vector = {} local stepsEarly2Vector = {} local timesEarly1Vector = {} local timesEarly2Vector = {} local stepCt1 = 0 local stepCt2 = 0 local timeEarly1 = 0 local timeEarly2 = 0 local gainEarly1 = 0.0 local gainEarly2 = 0.0 local gain = DECEMENT_MIN_GAIN_EARLY local ct = 1 while (ct <= MIN_TRIES_EARLY_OP) or (ct <= MAX_TRIES_EARLY_OP and gain >= DECEMENT_MIN_GAIN_EARLY) do local postExhScore = 0.0 local loopStartScore = getScore() LoadBest() if ct > 1 then -- First do InhaleAndExhale cement-breaker. PerformInhaleAndExhaleAction( INH_EXH_FOR_CRUSH_ATTEMPT ) local postScore = getScore() if postScore > bestScoreSoFar then bestScoreSoFar = postScore end SaveBests( true, QS_SA_BestEarly ) postExhScore = getScore() print("Finish inhale/exhale: score="..TrimNum( postExhScore )) scoresInhaleVector[ct] = postExhScore end -- Next do Early1 abbr = "EAv.2:"..ct..".1" local steps,time1,score1 = PerformEarly1Operation( true, abbr ) SaveBests( true, QS_SA_BestEarly ) stepCt1 = stepCt1 + steps scoresEarly1Vector[ct] = score1 stepsEarly1Vector[ct] = steps timesEarly1Vector[ct] = time1 timeEarly1 = timeEarly1 + time1 gainEarly1 = gainEarly1 + score1 - postExhScore -- Last do Early2 abbr = "EAv.2:"..ct..".2" local steps,time2,score2 = PerformEarly2Operation( true, abbr ) SaveBests( false, QS_SA_BestEarly ) stepCt2 = stepCt2 + steps scoresEarly2Vector[ct] = score2 stepsEarly2Vector[ct] = steps timesEarly2Vector[ct] = time2 timeEarly2 = timeEarly2 + time2 gainEarly2 = gainEarly2 + score2 - score1 -- figure out what we accomplished LoadBest( QS_SA_BestEarly ) local endScore = getScore() print("Finish #"..ct.." round: gain="..TrimNum( endScore - postExhScore )) -- calculate our true gain: if none, get back our best-so-far gain = endScore - loopStartScore if gain < 0.0 then local priorBestScore = getSlotScore( QS_Best ) print( "No gain from run. Revert to prior best: "..TrimNum(priorBestScore) ) save.Quickload( QS_Best ) else print( "Got gain from run: new best="..TrimNum(endScore)) save.Quicksave( QS_Best ) end ct = ct + 1 end LoadBest( ) -- REPORT THE RESULTS scoreEarly1 = scoresEarly1Vector[ 1 ] for i=2, #scoresEarly1Vector do if scoresEarly1Vector[i] > scoreEarly1 then scoreEarly1 = scoresEarly1Vector[i] end end scoreEarly2 = scoresEarly2Vector[ 1 ] for i=2, #scoresEarly2Vector do if scoresEarly2Vector[i] > scoreEarly2 then scoreEarly2 = scoresEarly2Vector[i] end end print( "Finished Early run" ) printVector( scoresEarly1Vector, "EA1 scores", true) printVector( stepsEarly1Vector, "EA1 steps") printVector( timesEarly1Vector, "EA1 times") printVector( scoresEarly2Vector, "EA2 scores", true) printVector( stepsEarly2Vector, "EA2 steps") printVector( timesEarly2Vector, "EA2 times") printVector( scoresInhaleVector, "Inhale scores", true) -- Return lots of stuff because SASequence wants to report on it all. return stepCt1, stepCt2, timeEarly1, timeEarly2, scoreEarly1,scoreEarly2 end function PerformBasicRebuildOperation( allowFailOut, abbr ) SetSAParamDefaults() if abbr == nil then abbr = "RB" end if allowFailOut == nil then allowFailOut = true end if #NonLockedSegList == 0 then print( "Cannot do rebuild with no movable segments" ) return 0 end if not FORBID_WIGGLE_POWER_CHANGE then behavior.SetWigglePower( WIGGLEPOWER_REBUILD ) end PROB_TARGETED = PROB_TARGETED_REBUILD local tempFunc = TEMPFUNCNAME_REBUILD local runcount = SA_NUMSTARTS_REBUILD local numSteps = SA_STEPSPERRUN_REBUILD local actionPicker = PickRebuildAction local failNoGain = SA_FAILIFNOGAIN_REBUILD print( "SA-RebuildBasic for " .. runcount .. " runs of " .. numSteps .. " steps using "..tempFunc) if allowFailOut then print("Move on on if "..failNoGain.." rounds have too little gain") end local initScore = getScore() local startTime = os.time() local stepCt = PerformSA( runcount, numSteps, allowFailOut, SA_MINGAIN, failNoGain, actionPicker, tempFunc, QS_SA_BestRebuild, abbr ) local endScore = getScore() local endTime = os.time()-startTime local gain = endScore - initScore local str = "{" for i=1,#CountFails do str = str..CountFails[i] if i < #CountFails then str = str.."," else str = str .."}" end end print( abbr..": gain="..TrimNum(gain).. " steps="..stepCt.. " time="..endTime.. " fails="..str ) return stepCt, endTime, endScore end function PerformDeepRebuildOperation( allowFailOut, abbr ) SetSAParamDefaults() if abbr == nil then abbr = "DPRB" end if allowFailOut == nil then allowFailOut = true end if #NonLockedSegList == 0 then print( "Cannot do rebuild with no movable segments" ) return 0 end if not FORBID_WIGGLE_POWER_CHANGE then behavior.SetWigglePower( WIGGLEPOWER_DEEPREBUILD ) end PROB_TARGETED = PROB_TARGETED_DEEPREBUILD local tempFunc = TEMPFUNCNAME_DEEPREBUILD local runcount = SA_NUMSTARTS_DEEPREBUILD local numSteps = SA_STEPSPERRUN_DEEPREBUILD local actionPicker = PickDeepRebuildAction local failNoGain = SA_FAILIFNOGAIN_DEEPREBUILD print( "SA-DeepRebuild for " .. runcount .. " runs of " .. numSteps .. " steps using "..tempFunc) if allowFailOut then print("Move on if "..failNoGain.." rounds have too little gain") end local initScore = getScore() local startTime = os.time() local stepCt = PerformSA( runcount, numSteps, allowFailOut, SA_MINGAIN, failNoGain, actionPicker, tempFunc, QS_SA_BestRebuild, abbr ) local endScore = getScore() local gain = endScore - initScore local endTime = os.time()-startTime local str = "{" for i=1,#CountFails do str = str..CountFails[i] if i < #CountFails then str = str.."," else str = str .."}" end end print( abbr..": gain="..TrimNum(gain).. " steps="..stepCt.. " time="..endTime.. " fails="..str ) return stepCt, endTime, endScore end function PerformRebuildOperation( ) -- Do Rebuild SaveBests( true, QS_SA_BestRebuild ) local initScore = getScore() local stepCt1,timeRebuild1,scoreRebuild1 if not SASEQ_SKIP_BASICREBUILD then local abbr = "RB" stepCt1,timeRebuild1,scoreRebuild1 = PerformBasicRebuildOperation( true, abbr ) else stepCt1,timeRebuild1,scoreRebuild1 = 0,0,0.0 end local stepCt2,timeRebuild2,scoreRebuild2 if not SASEQ_SKIP_DEEPREBUILD then abbr = "DPRB" stepCt2,timeRebuild2,scoreRebuild2 = PerformDeepRebuildOperation( true, abbr ) else stepCt2,timeRebuild2,scoreRebuild2 = 0,0,0.0 end LoadBest( ) print("Finish round: gain="..TrimNum( scoreRebuild2 - initScore ).. " score="..scoreRebuild2) return stepCt1, stepCt2, timeRebuild1, timeRebuild2, scoreRebuild1, scoreRebuild2 end function PerformMidgameOperation() SaveBests( true, QS_SA_BestMidgame ) SetSAParamDefaults() local abbr = "MID" local failNoGain = SA_FAILIFNOGAIN_MIDGAME local tempFunc = TEMPFUNCNAME_MIDGAME local runcount = SA_NUMSTARTS_MIDGAME local numSteps = SA_STEPSPERRUN_MIDGAME local actionPicker = PickMidgameAction local allowFailOut = true print( "SA-Midgame for " .. runcount .. " runs of " .. numSteps .. " steps using "..tempFunc) if allowFailOut then print("Move on if "..failNoGain.." rounds have too little gain") end local initScore = getScore() local startTime = os.time() local stepCt = PerformSA( runcount, numSteps, allowFailOut, SA_MINGAIN, failNoGain, actionPicker, tempFunc, QS_SA_BestMidgame, abbr ) local endScore = getScore() local endTime = os.time() - startTime local gain = endScore - initScore local str = "{" for i=1,#CountFails do str = str..CountFails[i] if i < #CountFails then str = str.."," else str = str .."}" end end print( abbr..": gain="..TrimNum(gain).. " steps="..stepCt.. " time="..endTime.. " fails="..str ) return stepCt, endTime, endScore end function PerformEndgame_SA( allowFailOut, abbr ) SaveBests( true, QS_SA_BestEndgame ) SetSAParamDefaults() if abbr == nil then abbr = "ENDGAME" end if allowFailOut == nil then allowFailOut = true end local tempFunc = TEMPFUNCNAME_ENDGAME local runcount = SA_NUMSTARTS_ENDGAME local numSteps = SA_STEPSPERRUN_ENDGAME local actionPicker = PickEndgameAction local failNoGain = SA_FAILIFNOGAIN_ENDGAME print( "SA-End for " .. runcount .. " runs of " .. numSteps .. " steps using "..tempFunc) if allowFailOut then print("Move on if "..failNoGain.." rounds have too little gain") end initScore = getScore() startTime = os.time() local stepCt = PerformSA( runcount, numSteps, allowFailOut, SA_MINGAIN, failNoGain, actionPicker, tempFunc, QS_SA_BestEndgame, abbr ) local endScore = getScore() local endTime = os.time()-startTime local gain = endScore - initScore local str = "{" for i=1,#CountFails do str = str..CountFails[i] if i < #CountFails then str = str.."," else str = str .."}" end end print( abbr..": gain="..TrimNum(gain).. " steps="..stepCt.. " time="..endTime.. " fails="..str ) return stepCt, endTime, endScore end function PerformEndgame_W( orderProtocol ) SaveBests( true, QS_SA_BestEndgame ) SetSAParamDefaults() local actionNames = { "IdealizePoint", "RebuildSimplePoint", "BandedWormPair","BandedWormPair","BandedWormPair","BandedWormPair","BandedWormPair", "LocalWiggle", "LocalFreezeWiggle", "ATSidechainTweak", "ATSidechainTweakAround", --"ATSidechainManipulate", } local stepCt, endTime, endScore = PerformWalker( orderProtocol, actionNames, QS_SA_BestEndgame, "ENDGAME" ) return stepCt, endTime, endScore end function PerformEndgameOperation( ) if behavior.HighPowerAllowed( ) and not FORBID_WIGGLE_POWER_CHANGE then behavior.SetWigglePower( 'h' ) else behavior.SetWigglePower( 'm' ) end local initScore = getScore() local startTime = os.time() local cwScore = getScore() local cwTime = 0 local stepCW = 0 if not SASEQ_ENDGAME_SKIP_CW then print("Init score = "..TrimNum(initScore)) print("Performing CutAndWiggle fuse") local lens = {2,3,5,7,11,13,15,17} local lIdx = {1,2,3,4,5, 6, 7, 8 } randomizeIndexList( lIdx ) for i=1, #lIdx/2 do -- TODO decide whether to do all or only some r values IterativeCutAndWiggleFull( lens[ lIdx[i] ] ) print("CW Score (len=" .. lens[ lIdx[i] ] .. "): " ..TrimNum(getScore())) end cwScore = getScore() cwTime = os.time()-startTime stepCW = 1 SaveBests( false, QS_SA_BestEndgame ) print("Finished CutAndWiggle, gain="..TrimNum(cwScore - initScore)) end local stepEnd = 0 local endTime = 0 local endScore = 0 local scoresEndVector = {} local scoresInhaleVector = { 0 } local bestScoreSoFar = getScore() local ct = 0 local gain = MIN_GAIN_ENDGAME while ct < MIN_TRIES_ENDGAME or (ct < MAX_TRIES_ENDGAME and gain >= MIN_GAIN_ENDGAME) do LoadBest( ) local beginScore = getScore() -- CRUSH with InhaleAndExhale if ct > 0 then PerformInhaleAndExhaleAction( INH_EXH_FOR_CRUSH_ATTEMPT ) local postScore = getScore() if postScore > bestScoreSoFar then bestScoreSoFar = postScore end SaveBests( true, QS_SA_BestEndgame ) local postExhScore = getScore() print("Finish inhale/exhale: score="..TrimNum( postExhScore )) scoresInhaleVector[#scoresInhaleVector+1] = postExhScore stepCW = stepCW + 1 end if ct%4 == 0 then print("Do start to end") orderProtocol = ACTION_ORDERPROTOCOL_START_TO_END elseif ct%4 == 1 then print("Do random") orderProtocol = ACTION_ORDERPROTOCOL_RANDOMIZE elseif ct%4 == 2 then print("Do end to start") orderProtocol = ACTION_ORDERPROTOCOL_END_TO_START else print("Do worst to best") orderProtocol = ACTION_ORDERPROTOCOL_WORST_TO_BEST end -- DO IT ALREADY! local stepCt, saTime, saScore = PerformEndgame_W( orderProtocol ) scoresEndVector[ #scoresEndVector ] = saScore gain = saScore - beginScore ct = ct + 1 end LoadBest( ) print( "Finished Endgame run" ) printVector( scoresInhaleVector, "Inhale scores", true) printVector( scoresEndVector, "Inhale scores", true) return stepCW,stepEnd,cwTime,endTime,cwScore,endScore end function PerformLateOperation( ) SetSAParamDefaults() local qwg = QUICKWIGGLE_GAIN local swg = FUSEWIGGLE_GAIN QUICKWIGGLE_GAIN = 0.05 FUSEWIGGLE_GAIN = 0.01 -- I could track the fuse score increase, but this operation just isn't -- that interesting to me USE_FUSEWIGGLE = true IterativeCutAndWiggle( FUSEWIGGLE_ITERS, FUSEWIGGLE_GAIN, random( 3,11 )) local abbr = "LATE" local tempFunc = TEMPFUNCNAME_LATE local runcount = SA_NUMSTARTS_LATE local numSteps = SA_STEPSPERRUN_LATE local actionPicker = PickLateAction local failNoGain = SA_FAILIFNOGAIN_DEFAULT print( "SA-Late for " .. runcount .. " runs of " .. numSteps .. " steps using "..tempFunc) local initScore = getScore() local startTime = os.time() local stepCt = PerformSA( runcount, numSteps, false, SA_MINGAIN, failNoGain, actionPicker, tempFunc, QS_Best, abbr ) local endScore = getScore() local endTime = os.time()-startTime local gain = endScore - initScore local str = "{" for i=1,#CountFails do str = str..CountFails[i] if i < #CountFails then str = str.."," else str = str .."}" end end print( abbr..": gain="..TrimNum(gain).. " steps="..stepCt.. " time="..endTime.. " fails="..str ) QUICKWIGGLE_GAIN = qwg FUSEWIGGLE_GAIN = swg return stepCt,endTime,endScore end function PerformLowCIOperation( ) -- Does not seem worth the time it takes for "stable" poses SetSAParamDefaults() USE_LOWCI_WIGGLES = true savCI = GetCI( ) local abbr = "20CI" FIGHT_CEMENTING = FIGHT_CEMENTING_LOWCI local tempFunc = TEMPFUNCNAME_LOW20 local runcount = SA_NUMSTARTS_LOW20 local numSteps = SA_STEPSPERRUN_LOW20 local actionPicker = PickLowCIAction local failNoGain = SA_FAILIFNOGAIN_DEFAULT print( "SA-LowCI20 for " .. runcount .. " runs of " .. numSteps .. " steps using "..tempFunc) ExactSetCI( 0.20 ) CI_MAXSCALE = 0.20 local initScore = getScore() local startTime = os.time() local stepCt = PerformSA( runcount, numSteps, false, SA_MINGAIN, failNoGain, actionPicker, tempFunc, QS_Best, abbr ) local gain = getScore() - initScore local str = "{" for i=1,#CountFails do str = str..CountFails[i] if i < #CountFails then str = str.."," else str = str .."}" end end print( abbr..": gain="..TrimNum(gain).. " steps="..stepCt.. " time="..(os.time()-startTime).. " fails="..str ) SetSAParamDefaults() abbr = "50CI" tempFunc = TEMPFUNCNAME_LOW50 runcount = SA_NUMSTARTS_LOW50 numSteps = SA_STEPSPERRUN_LOW50 actionPicker = PickLowCIAction failNoGain = SA_FAILIFNOGAIN_DEFAULT print( "SA-LowCI50 for " .. runcount .. " runs of " .. numSteps .. " steps using "..tempFunc) ExactSetCI( 0.50 ) CI_MAXSCALE = 0.50 initScore = getScore() startTime = os.time() stepCt2 = PerformSA( runcount, numSteps, false, SA_MINGAIN, failNoGain, actionPicker, tempFunc, QS_Best, abbr ) local gain = getScore() - initScore local str = "{" for i=1,#CountFails do str = str..CountFails[i] if i < #CountFails then str = str.."," else str = str .."}" end end print( abbr..": gain="..TrimNum(gain).. " steps="..stepCt2.. " time="..(os.time()-startTime).. " fails="..str ) USE_LOWCI_WIGGLES = false ExactSetCI( savCI ) CI_MAXSCALE = savCI return stepCt + stepCt2 end function PerformContactMapOperation( ) SetSAParamDefaults() local abbr = "CMAP" local tempFunc = TEMPFUNCNAME_CMAP local runcount = SA_NUMSTARTS_CMAP local numSteps = SA_STEPSPERRUN_CMAP local actionPicker = PickContactMapAction local failNoGain = SA_FAILIFNOGAIN_DEFAULT print( "SA-Contact for " .. runcount .. " runs of " .. numSteps .. " steps using "..tempFunc) local initScore = getScore() local startTime = os.time() local stepCt = PerformSA( runcount, numSteps, false, SA_MINGAIN, failNoGain, actionPicker, tempFunc, QS_Best, abbr ) local gain = getScore() - initScore local str = "{" for i=1,#CountFails do str = str..CountFails[i] if i < #CountFails then str = str.."," else str = str .."}" end end print( abbr..": gain="..TrimNum(gain).. " steps="..stepCt.. " time="..(os.time()-startTime).. " fails="..str ) return stepCt end function PickLunchBuffetAction( ) local idx = PickIdxForAction( ) return PickActionFromList( LunchBuffetActions, idx ) end function PerformLunchBuffetOperation( ) SetSAParamDefaults() local abbr = "LUNCH" local initScore = getScore() local stepCt, endTime, endScore if DO_WALKER_BUFFET then stepCt, endTime, endScore = PerformWalker( ACTION_ORDERPROTOCOL_BUFFET, LunchBuffetActions, QS_Best, abbr ) else PROB_TARGETED = PROB_TARGETED_BUFFET local tempFunc = TEMPFUNCNAME_BUFFET local runcount = SA_NUMSTARTS_BUFFET local numSteps = SA_STEPSPERRUN_BUFFET local actionPicker = PickLunchBuffetAction failNoGain = SA_FAILIFNOGAIN_DEFAULT print( "SA-Buffet for " .. runcount .. " runs of " .. numSteps .. " steps using "..tempFunc) if #LunchBuffetActions == 0 then print("No actions provided to perform - bailing") return 0 end local startTime = os.time() stepCt = PerformSA( runcount, numSteps, false, SA_MINGAIN, failNoGain, actionPicker, tempFunc, QS_Best, abbr ) endTime = os.time()-startTime endScore = getScore() end local gain = endScore - initScore print( abbr..": gain="..TrimNum(gain).. " steps="..stepCt.. " time="..endTime.. " score="..TrimNum(endScore)) return stepCt end function PickTestAction( ) local idx = PickIdxForAction( ) -- idx = SOMETHING USER WANTS TO FORCE? allowedActions = { } -- put the action to test here! allowedActions[ #allowedActions + 1] = "Remix" allowedActions[ #allowedActions + 1] = "RemixXToY" return PickActionFromList( allowedActions, idx ) end function PerformTestSA( ) SetSAParamDefaults() local abbr = "TEST" PROB_TARGETED = PROB_TARGETED_TEST local tempFunc = TEMPFUNCNAME_TEST local runcount = SA_NUMSTARTS_TEST local numSteps = SA_STEPSPERRUN_TEST local actionPicker = PickTestAction local failNoGain = SA_FAILIFNOGAIN_DEFAULT local allowFailOut = true print( "SA-Test for " .. runcount .. " runs of " .. numSteps .. " steps using "..tempFunc) if allowFailOut then print("Move on if "..failNoGain.." rounds have too little gain") end local initScore = getScore() local startTime = os.time() local stepCt = PerformSA( runcount, numSteps, allowFailOut, SA_MINGAIN, failNoGain, actionPicker, tempFunc, QS_Best, abbr ) local gain = getScore() - initScore local str = "{" for i=1,#CountFails do str = str..CountFails[i] if i < #CountFails then str = str.."," else str = str .."}" end end print( abbr..": gain="..TrimNum(gain).. " steps="..stepCt.. " time="..(os.time()-startTime).. " fails="..str ) return stepCt end function PerformTestOperation( ) -- Options offered so far: -- 1. Pick "Test" operation: Adjust PickTestAction -- 2. Pick a still-being-tested operation that isn't directly offered -- 3. Loop over calls to CreateNeighborPose: Adjust PickTestAction --local steps = PerformTestSA( ) local steps = PerformDeepRebuildOperation( true, "TEST" ) -- for i=1,50 do CreateNeighborPose( PickTestAction ) end return steps end function PerformSASequence( ) SaveBest( ) print( "Begin SA Sequence" ) local scoreInit = getScore( ) timeInit = os.time( ) local stepsLate = 0 local timeLate = 0 local gainLate = 0.0 local stepsWswsw,stepsStab1,stepsStab2,timeWswsw, timeStab1, timeStab2,scoreWswsw,scoreStab1,scoreStab2 if not SASEQ_SKIP_STABILIZER then stepsWswsw, stepsStab1,stepsStab2, timeWswsw, timeStab1, timeStab2, scoreWswsw,scoreStab1,scoreStab2 = PerformStabilizerOperation( ) save.Quicksave( QS_SA_BestEarly ) print( "SASEQ-Stab finished - qs "..QS_SA_BestEarly.. ": time="..timeWswsw+timeStab1+timeStab2 ) else stepsWswsw,stepsStab1,stepsStab2,timeWswsw,timeStab1,timeStab2,scoreWswsw,scoreStab1,scoreStab2 = 0,0,0, 0,0,0, 0.0,0.0,0.0 end if SASEQ_DISABLE_UBAND_AFTER_STAB then DISABLE_ALL_USER_BANDS = true end -- EARLY local stepsEarly1,stepsEarly2, timeEarly1,timeEarly2, scoreEarly1,scoreEarly2 = PerformEarlyOperation() save.Quicksave( QS_SA_BestEarly ) print( "SASEQ-Early finished - qs "..QS_SA_BestEarly.. ": time="..timeEarly1+timeEarly2 ) if SASEQ_DISABLE_UBAND_AFTER_EARLY then DISABLE_ALL_USER_BANDS = true end -- REBUILD local stepsRebuild1,stepsRebuild2, timeRebuild1,timeRebuild2, scoreRebuild1,scoreRebuild2 = PerformRebuildOperation() save.Quicksave( QS_SA_BestRebuild ) print( "SARebuild finished - qs "..QS_SA_BestRebuild.. ": time="..timeRebuild1+timeRebuild2 ) -- MIDGAME local stepsMid,timeMid,scoreMid = PerformMidgameOperation() print( "SAMidgame finished: time="..timeMid ) -- LATE -- I question caller's wisdom, but do as they asked... if ALLOW_FUSE then save.Quicksave( QS_SA_BestMidgame ) print( "SAMidgame result stored in qs "..QS_SA_BestMidgame ) stepsLate,timeLate,scoreLate = PerformLateOperation( ) print( "SALate finished: time="..timeLate ) end -- ENDGAME local stepsCW,stepsEnd,timeCW,timeEnd,scoreCW,scoreEnd if not SASEQ_SKIP_ENDGAME then stepsCW,stepsEnd,timeCW,timeEnd,scoreCW,scoreEnd = PerformEndgameOperation() print( "SAEndgame finished: time="..timeEnd ) else stepsCW,stepsEnd,timeCW,timeEnd,scoreCW,scoreEnd = 0,0, 0,0, 0.0,0.0 end -- GIVE REPORT TO USER local timeEarly = timeEarly1+timeEarly2 local stepsEarly = stepsEarly1+stepsEarly2 local scoreEarly = math.max( scoreEarly1, scoreEarly2 ) print( "End SASequence: initScore=" ..TrimNum(scoreInit).. " gain="..(getScore( ) - scoreInit).. " time="..(os.time( ) - timeInit )) print("Early steps: Early1="..stepsEarly1.." Early2="..stepsEarly2) print("Early times: Early1="..timeEarly1.. " Early2="..timeEarly2) print( " Stage Time Steps Score" ) if not SASEQ_SKIP_STABILIZER then print( " Wswsw: " ..PadNumString(timeWswsw,7).. " " ..PadNumString(stepsWswsw,5).. " " .. TrimNum(scoreWswsw)) print( " Stab1: " ..PadNumString(timeStab1,7).. " " ..PadNumString(stepsStab1,5).. " " .. TrimNum(scoreStab1)) print( " Stab2: " ..PadNumString(timeStab2,7).. " " ..PadNumString(stepsStab2,5).. " " .. TrimNum(scoreStab2)) end print( " Early1/2: " ..PadNumString(timeEarly,7).. " " ..PadNumString(stepsEarly,5).. " " .. TrimNum(scoreEarly)) print( " Rebuild1: " ..PadNumString(timeRebuild1,7).." " ..PadNumString(stepsRebuild1,5).. " " .. TrimNum(scoreRebuild1)) print( " Rebuild2: " ..PadNumString(timeRebuild2,7).." " ..PadNumString(stepsRebuild2,5).. " " .. TrimNum(scoreRebuild2)) print( " Midgame: " ..PadNumString(timeMid,7).. " " ..PadNumString(stepsMid,5).. " " .. TrimNum(scoreMid)) if ALLOW_FUSE then print( " Late: " ..PadNumString(timeLate,7).." " ..PadNumString(stepsLate,5).. " " .. TrimNum(scoreLate)) end if not SASEQ_SKIP_ENDGAME then print( " CW : " ..PadNumString(timeCW,7).. " " ..PadNumString(stepsCW,5).. " " .. TrimNum(scoreCW)) print( " Endgame: " ..PadNumString(timeEnd,7).. " " ..PadNumString(stepsEnd,5).. " " .. TrimNum(scoreEnd)) end print( "Time so far: "..(os.time() - StartTime)) end function PerformOperation( operation ) local moInitialScore = getScore( ) local moInitialTime = os.time( ) local numSteps = 0 local failNoGain = 0 local stepCt = 0 local stepCt2 = 0 CtRebuildFails = 0 -- global that gets incremented when a rebuild fails SaveBest( ) if CtRebuildFails >= MAX_REBUILD_FAILS then print( "rebuild fail count exceeded in PerformOperation") CtRebuildFails = 0 return end if operation == "SASequence" then PerformSASequence( ) elseif operation == "SAStab" then stepCt, stepCt2 = PerformStabilizerOperation( ) stepCt = stepCt + stepCt2 print( "SA-Stabilizer finished" ) elseif operation == "SAEarly" then stepCt, stepCt2 = PerformEarlyOperation( ) stepCt = stepCt + stepCt2 print( "SA-Early finished" ) elseif operation == "SARebuild" then stepCt, stepCt2 = PerformRebuildOperation( ) stepCt = stepCt + stepCt2 print( "SARebuild finished" ) elseif operation == "SAMidgame" then stepCt = PerformMidgameOperation() print( "SA-Midgame finished" ) elseif operation == "SAEndgame" then stepCt, stepCt2 = PerformEndgameOperation() stepCt = stepCt + stepCt2 print( "SA-Endgame finished" ) elseif operation == "SAShortStab" then stepCt = PerformStab1Operation( ) print( "SA-Stab1 finished" ) elseif operation == "SALongStab" then stepCt = PerformStab2Operation( ) print( "SA-Stab2 finished" ) elseif operation == "SAEarlyMove" then stepCt = PerformEarly1Operation( ) print( "SA-EarlyMove finished" ) elseif operation == "SAEarlyIdeal" then stepCt = PerformEarly2Operation( ) print( "SA-EarlyIdeal finished" ) elseif operation == "SARebuildBasic" then stepCt = PerformRebuildOperation( ) print( "SA-RebuildBasic finished" ) elseif operation == "SARebuildDeep" then stepCt = PerformDeepRebuildOperation( ) print( "SA-RebuildDeep finished" ) elseif operation == "SALowCI" then stepCt = PerformLowCIOperation( ) print( "SA-LowCI finished" ) elseif operation == "SALate" then stepCt = PerformLateOperation( ) print( "SA-Late finished" ) elseif operation == "SAContact" then stepCt = PerformContactMapOperation( ) print( "SA-Contact finished" ) elseif operation == "SATest" then stepCt = PerformTestOperation( ) print( "SA-Test finished" ) elseif operation == "SALunchBuffet" then stepCt = PerformLunchBuffetOperation( ) print( "SA-Buffet finished" ) else if operation == nil then print("!! No operation given") else print( "!! Unknown operation: ".. operation ) end end LoadBest( ) return stepCt end ----------------------------------------------------------------------------- -- DIALOG BOX SEQUENCE FROM THE NETHERWORLD ----------------------------------------------------------------------------- function PutMutateOptionsInBox( dlg ) dlg.MutateCI = dialog.AddSlider( "Mutate CI", CI_MUTATE, 0, 1, 2 ) dlg.noMutateAas = dialog.AddTextbox( "No-mutate AAs", "" ) end function SetMutateOptions( dlg ) CI_MUTATE = dlg.MutateCI.value DebugPrint("MutateCI="..CI_MUTATE) if dlg.noMutateAas.value ~= nil and dlg.noMutateAas.value ~= "" then NoMutateList = parseRangesStr( dlg.noMutateAas.value ) DebugPrint("NoMutateList has "..(#NoMutateList).." segs" ) if DEBUGRUN and #NoMutateList > 0 then printVector( NoMutateList, "NoMutate", false ) else DebugPrint("Error Parsing: No ranges selected") end end end function PutSlowWiggleOptionsInBox( dlg ) dlg.swgain = dialog.AddSlider( "Fuse-WiggleGain", FUSEWIGGLE_GAIN, 0, 0.50, 2 ) dlg.swCmt = dialog.AddLabel( "Values will be scaled to sum to 1" ) dlg.wloc = dialog.AddSlider( "LocalWiggler", PROB_FUSEWIGGLE_LOCAL, 0, 1, 2 ) -- slow, poor dlg.wbfuse= dialog.AddSlider( "BlueFuse", PROB_FUSEWIGGLE_BLUEFUSE, 0, 1, 2 ) -- less slow, moderately good dlg.wcwfuse= dialog.AddSlider( "C&WFuse", PROB_FUSEWIGGLE_CUTFUSE, 0, 1, 2 ) -- slow, moderately good end function SetSlowWiggleOptions( dlg ) FUSEWIGGLE_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 these don't sum to 1: they'll be scaled t2 = .25 t3 = .25 end PROB_FUSEWIGGLE_LOCAL = t1 / ( t1 + t2 + t3 ) PROB_FUSEWIGGLE_BLUEFUSE = t2 / ( t1 + t2 + t3 ) PROB_FUSEWIGGLE_CUTFUSE = t3 / ( t1 + t2 + t3 ) DebugPrint( "SlowGain="..FUSEWIGGLE_GAIN ) DebugPrint( "Prob_slowwiggle-local="..PROB_FUSEWIGGLE_LOCAL ) DebugPrint( "Prob_slowwiggle-bluefuse="..PROB_FUSEWIGGLE_BLUEFUSE ) DebugPrint( "Prob_slowwiggle-cutfuse="..PROB_FUSEWIGGLE_CUTFUSE ) end function PutBanderOptionsInBox( dlg ) dlg.bdrbci = dialog.AddSlider( "RegionBandCI", CI_REGIONMOD, 0.01, 1.0, 2 ) dlg.mbshakeci = dialog.AddSlider( "MultiBandShakeCI", CI_MULTIBAND_SHAKE, 0.01, 1.0, 2 ) dlg.mbpullci = dialog.AddSlider( "MultiBandPullCI", CI_MULTIBAND_PULL, 0.01, 1.0, 2 ) dlg.bdcpci = dialog.AddSlider( "CorePullingCI", CI_COREPULLING, 0.01, 1.0, 2 ) dlg.bdwigtargdelta = dialog.AddSlider( "BWig ScoreDelta", BANDEDWIGGLE_TARGET, 50, 1000, 0 ) dlg.bdwigmincompr = dialog.AddSlider( "MinCompress", BAND_MINCOMPRESS, BAND_MINCOMPRESS/2, 1.00, 2 ) dlg.maxgentlecompr = dialog.AddSlider( "MaxGentCompr", BAND_MAXGENTLECOMPRESS, BAND_MAXGENTLECOMPRESS/2, 1.00, 2 ) dlg.bdwigmaxcompr = dialog.AddSlider( "MaxCompress", BAND_MAXCOMPRESS, BAND_MAXCOMPRESS/2, 1.00, 2 ) dlg.bdwigminexpand = dialog.AddSlider( "MinExpand", BAND_MINEXPAND, 1.00, 1.10, 2 ) dlg.maxgentleexpand = dialog.AddSlider( "MaxGentExpand", BAND_MAXGENTLEEXPAND, 1.0, 2.0, 2 ) dlg.bdwigmaxexpand = dialog.AddSlider( "MaxExpand", BAND_MAXEXPAND, 1.00, 3.00, 2 ) end function SetBanderOptions( dlg ) CI_REGIONMOD = dlg.bdrbci.value CI_MULTIBAND_SHAKE = dlg.mbshakeci.value CI_MULTIBAND_PULL = dlg.mbpullci.value CI_COREPULLING = dlg.bdcpci.value BANDEDWIGGLE_TARGET = dlg.bdwigtargdelta.value BAND_MINCOMPRESS = dlg.bdwigmincompr.value BAND_MAXGENTLECOMPRESS = dlg.maxgentlecompr.value BAND_MAXCOMPRESS = dlg.bdwigmaxcompr.value BAND_MINEXPAND = dlg.bdwigminexpand.value BAND_MAXGENTLEEXPAND = dlg.maxgentleexpand.value BAND_MAXEXPAND = dlg.bdwigmaxexpand.value DebugPrint("ReginmBander CI="..CI_REGIONMOD ) DebugPrint("MultiBand Pull CI="..CI_MULTIBAND_SHAKE ) DebugPrint("MultiBand Shake CI="..CI_MULTIBAND_PULL ) DebugPrint("Core-pulling CI="..CI_COREPULLING ) DebugPrint("Banded Wiggler Target Delta="..BANDEDWIGGLE_TARGET ) DebugPrint("Max Compress="..BAND_MAXCOMPRESS) DebugPrint("Max Gentle Compress="..BAND_MAXGENTLECOMPRESS) DebugPrint("Min Compress="..BAND_MINCOMPRESS) DebugPrint("Min Expand="..BAND_MINEXPAND ) DebugPrint("Max Gentle Expand="..BAND_MAXGENTLEEXPAND ) DebugPrint("Max Expand="..BAND_MAXEXPAND ) end function PutIdealizeOptionsInBox( dlg ) dlg.sepIdealizer = dialog.AddLabel( "--------------Idealize Options--------------------" ) dlg.idMinRange = dialog.AddSlider( "MinIdealizeLen", IDEALIZE_MIN_SEGLEN, 1, 20, 0 ) dlg.idMaxRange = dialog.AddSlider( "MaxIdealizeLen", IDEALIZE_MAX_SEGLEN, 1, 20, 0 ) dlg.idradius = dialog.AddSlider( "IdealizeRadius", IDEALIZE_TUBE_SMALL_RADIUS, 1.0, 20.0, 2 ) dlg.idradshake = dialog.AddSlider( "WiggleShakeRadius", IDEALIZE_TUBE_BIG_RADIUS, 1.0, 20.0, 2 ) 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_MIN_SEGLEN = dlg.idMinRange.value IDEALIZE_MAX_SEGLEN = dlg.idMaxRange.value IDEALIZE_TUBE_SMALL_RADIUS = dlg.idradius.value IDEALIZE_TUBE_BIG_RADIUS = dlg.idradshake.value IDEALIZE_USE_CUTS = dlg.idusecuts.value IDEALIZE_FORBID_UNHEALED_CUTS = dlg.idmusthealcuts.value DebugPrint("Idealize range: "..IDEALIZE_MIN_SEGLEN.."-"..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 DebugPrint("Radius of idealization: "..IDEALIZE_TUBE_SMALL_RADIUS) DebugPrint("Radius of shake/wiggle: "..IDEALIZE_TUBE_BIG_RADIUS) end function PutlRebuildSubOptionsInBox( dlg ) dlg.sepRb = dialog.AddLabel( "--------------Rebuild Options--------------------" ) dlg.rebDeepMaxTries = dialog.AddSlider( "Deep Rebuild tries", REBUILD_DEEP_MAXTRIES, 1, 20, 0 ) dlg.rebuildMinRange = dialog.AddSlider( "MinRebuildLength", REBUILD_MIN_SEGLEN, 1, 20, 0 ) dlg.rebuildMaxRange = dialog.AddSlider( "MaxRebuildLength", REBUILD_MAX_SEGLEN, 1, 20, 0 ) dlg.rebDeepInnerRad = dialog.AddSlider( "DeepRebShortRadius", REBUILD_TUBE_INNER_RADIUS, 5.0, 20.0, 2 ) dlg.rebDeepOuterRad = dialog.AddSlider( "DeepRebLongRadius", REBUILD_TUBE_OUTER_RADIUS, 5.0, 25.0, 2 ) dlg.rebQuakingRad = dialog.AddSlider( "QuakeReb radius", REBUILD_TUBE_SMALLEST_RADIUS, 5.0, 20.0, 2 ) dlg.rebWantIdealize = dialog.AddCheckbox( "Idealize with rebuilds?", REBUILD_ADDIDEALIZE ) end function SetRebuildSubOptions( dlg ) REBUILD_DEEP_MAXTRIES = dlg.rebDeepMaxTries.value REBUILD_MIN_SEGLEN = dlg.rebuildMinRange.value REBUILD_MAX_SEGLEN = dlg.rebuildMaxRange.value REBUILD_ADDIDEALIZE = dlg.rebWantIdealize.value REBUILD_TUBE_INNER_RADIUS = dlg.rebDeepInnerRad.value REBUILD_TUBE_OUTER_RADIUS = dlg.rebDeepOuterRad.value REBUILD_TUBE_SMALLEST_RADIUS = dlg.rebQuakingRad.value DebugPrint( "TriesPerStep="..REBUILD_DEEP_MAXTRIES ) DebugPrint( "Rebuild range="..REBUILD_MIN_SEGLEN.."-"..REBUILD_MAX_SEGLEN ) DebugPrint( "Rebuilds can idealize? "..BoolStr( REBUILD_ADDIDEALIZE)) DebugPrint( "DeepReb short radius: "..REBUILD_TUBE_INNER_RADIUS ) DebugPrint( "DeepReb long radius: "..REBUILD_TUBE_OUTER_RADIUS ) DebugPrint( "Quaking Rebuild radius: "..REBUILD_TUBE_SMALLEST_RADIUS ) end function PutRemixOptionsInBox( dlg ) dlg.sepRemix = dialog.AddLabel( "--------------Remix Options--------------------" ) dlg.remixMaxSlots = dialog.AddSlider( "Remix slots", REMIX_SLOTS_WANTED, 1, REMIX_MAX_SLOTS_TO_USE, 0 ) dlg.remixMaxSlotsToWiggle = dialog.AddSlider( "#SlotsToDeepTest", REMIX_MAX_SLOTS_TO_WIGGLE, 1, REMIX_MAX_SLOTS_TO_USE, 0 ) dlg.remixMinRange = dialog.AddSlider( "MinRemixLength", REMIX_MIN_SEGLEN, 1, 20, 0 ) dlg.remixMaxRange = dialog.AddSlider( "MaxRemixLength", REMIX_MAX_SEGLEN, 1, 20, 0 ) dlg.remixInnerRad = dialog.AddSlider( "RemixShortRadius", REMIX_TUBE_INNER_RADIUS, 5.0, 20.0, 2 ) dlg.remixOuterRad = dialog.AddSlider( "RemixLongRadius", REMIX_TUBE_OUTER_RADIUS, 5.0, 25.0, 2 ) end function SetRemixOptions( dlg ) REMIX_SLOTS_WANTED = dlg.remixMaxSlots.value REMIX_MAX_SLOTS_TO_WIGGLE = dlg.remixMaxSlotsToWiggle.value REMIX_MIN_SEGLEN = dlg.remixMinRange.value REMIX_MAX_SEGLEN = dlg.remixMaxRange.value REMIX_TUBE_INNER_RADIUS = dlg.remixInnerRad.value REMIX_TUBE_OUTER_RADIUS = dlg.remixOuterRad.value DebugPrint( "Slots to use="..REMIX_SLOTS_WANTED ) DebugPrint( "Slots to wiggle="..REMIX_MAX_SLOTS_TO_WIGGLE ) DebugPrint( "Remix range="..REBUILD_MIN_SEGLEN.."-"..REBUILD_MAX_SEGLEN ) DebugPrint( "Remix short radius: "..REMIX_TUBE_INNER_RADIUS ) DebugPrint( "Remix long radius: "..REMIX_TUBE_OUTER_RADIUS ) end function PutDecementingOptionsInBox( dlg ) dlg.fightCementEa1 = dialog.AddCheckbox( "Do decement runs in EarlyMover", FIGHT_CEMENTING_EARLY1 ) dlg.fightCementEa2 = dialog.AddCheckbox( "Do decement runs in EarlyIdeal", FIGHT_CEMENTING_EARLY2 ) dlg.whenStartDecem = dialog.AddSlider("Fails till start", FailsToStartCementBreaking, 1, 2*FailsToStartCementBreaking, 0 ) dlg.ctDecement = dialog.AddSlider("Decement steps", StepsForCementBreaking, 1, 2*StepsForCementBreaking, 0 ) dlg.stepsperCem = dialog.AddSlider("Run steps", SA_STEPSPERRUN_DECEMENT, 1, 10*SA_STEPSPERRUN_DECEMENT, 0 ) end function SetDecementingOptions( dlg ) FIGHT_CEMENTING_EARLY1 = dlg.fightCementEa1.value FIGHT_CEMENTING_EARLY2 = dlg.fightCementEa2.value SA_STEPSPERRUN_DECEMENT = dlg.ctDecement.value FailsToStartCementBreaking = dlg.stepsperCem.value StepsForCementBreaking = dlg.whenStartDecem.value DebugPrint("Decement in Early1? "..BoolStr( FIGHT_CEMENTING_EARLY1 )) DebugPrint("Decement in Early2? "..BoolStr( FIGHT_CEMENTING_EARLY2 )) DebugPrint("Decement steps,fails,ctDecement="..SA_STEPSPERRUN_DECEMENT..","..FailsToStartCementBreaking.. ","..StepsForCementBreaking ) end function PutLowCI20OptionsInBox( dlg ) dlg.stepsperLCI20 = dialog.AddSlider( "Steps20CI", SA_STEPSPERRUN_LOW20, 1, 3*SA_STEPSPERRUN_LOW20, 0 ) dlg.startsLCI20 = dialog.AddSlider( "Runs20CI", SA_NUMSTARTS_LOW20, 1, 10*SA_NUMSTARTS_LOW20, 0 ) end function SetLowCI20Options( dlg ) SA_STEPSPERRUN_LOW20 = dlg.stepsperLCI20.value SA_NUMSTARTS_LOW20 = dlg.startsLCI20.value DebugPrint("LowCI steps,starts="..SA_STEPSPERRUN_LOW20..","..SA_NUMSTARTS_LOW20 ) return true end function PutLowCI50OptionsInBox( dlg ) dlg.stepsperLCI50 = dialog.AddSlider( "Steps50CI", SA_STEPSPERRUN_LOW50, 1, 3*SA_STEPSPERRUN_LOW50, 0 ) dlg.startsLCI50 = dialog.AddSlider( "Runs50CI", SA_NUMSTARTS_LOW50, 1, 10*SA_NUMSTARTS_LOW50, 0 ) end function SetLowCI50Options( dlg ) SA_STEPSPERRUN_LOW50 = dlg.stepsperLCI50.value SA_NUMSTARTS_LOW50 = dlg.startsLCI50.value DebugPrint("LowCI steps,starts="..SA_STEPSPERRUN_LOW50..","..SA_NUMSTARTS_LOW50 ) return true end function PutLowCIOptionsInBox( dlg ) PutLowCI20OptionsInBox( dlg ) PutLowCI50OptionsInBox( dlg ) end function SetLowCIOptions( dlg ) SetLowCI20Options( dlg ) SetLowCI50Options( dlg ) return true end function PutStab1OptionsInBox( dlg ) dlg.stepsperSt1 = dialog.AddSlider( "StepsStab1", SA_STEPSPERRUN_STAB1, 1, 3*SA_STEPSPERRUN_STAB1, 0 ) dlg.startsSt1 = dialog.AddSlider( "RunsStab1", SA_NUMSTARTS_STAB1, 1, 10*SA_NUMSTARTS_STAB1, 0 ) dlg.quitnogainSt1 = dialog.AddSlider( "Stop at N fails", SA_FAILIFNOGAIN_STAB1, 1, 5*SA_FAILIFNOGAIN_STAB1, 0 ) end function SetStab1Options( dlg ) SA_STEPSPERRUN_STAB1 = dlg.stepsperSt1.value SA_NUMSTARTS_STAB1 = dlg.startsSt1.value SA_FAILIFNOGAIN_STAB1 = dlg.quitnogainSt1.value DebugPrint("EarlyStab1 steps,starts,quit="..SA_STEPSPERRUN_STAB1..","..SA_NUMSTARTS_STAB1..","..SA_FAILIFNOGAIN_STAB1 ) return true end function PutStab2OptionsInBox( dlg ) dlg.stepsperSt2 = dialog.AddSlider( "StepsStab2", SA_STEPSPERRUN_STAB2, 1, 3*SA_STEPSPERRUN_STAB2, 0 ) dlg.startsSt2 = dialog.AddSlider( "RunsStab2", SA_NUMSTARTS_STAB2, 1, 10*SA_NUMSTARTS_STAB2, 0 ) dlg.quitnogainSt2 = dialog.AddSlider( "Stop at N fails", SA_FAILIFNOGAIN_STAB2, 1, 5*SA_FAILIFNOGAIN_STAB2, 0 ) end function SetStab2Options( dlg ) SA_STEPSPERRUN_STAB2 = dlg.stepsperSt2.value SA_NUMSTARTS_STAB2 = dlg.startsSt2.value SA_FAILIFNOGAIN_STAB2 = dlg.quitnogainSt2.value DebugPrint("EarlyStab2 steps,starts,quit="..SA_STEPSPERRUN_STAB2..","..SA_NUMSTARTS_STAB2..","..SA_FAILIFNOGAIN_STAB2 ) return true end function PutEarly1OptionsInBox( dlg ) dlg.stepsperEa1 = dialog.AddSlider( "StepsEarlyMove", SA_STEPSPERRUN_EARLY1, 1, 3*SA_STEPSPERRUN_EARLY1, 0 ) dlg.startsEa1 = dialog.AddSlider( "RunsEarlyMove", SA_NUMSTARTS_EARLY1, 1, 10*SA_NUMSTARTS_EARLY1, 0 ) dlg.quitnogainEa1 = dialog.AddSlider("Stop at N fails", SA_FAILIFNOGAIN_EARLY1, 1, 5*SA_FAILIFNOGAIN_EARLY1, 0 ) end function SetEarly1Options( dlg ) SA_STEPSPERRUN_EARLY1 = dlg.stepsperEa1.value SA_NUMSTARTS_EARLY1 = dlg.startsEa1.value SA_FAILIFNOGAIN_EARLY1 = dlg.quitnogainEa1.value DebugPrint("EarlyMove steps,starts,quit="..SA_STEPSPERRUN_EARLY1..","..SA_NUMSTARTS_EARLY1..","..SA_FAILIFNOGAIN_EARLY1 ) return true end function PutEarly2OptionsInBox( dlg ) dlg.stepsperEa2 = dialog.AddSlider( "StepsEarlyIdeal", SA_STEPSPERRUN_EARLY2, 1, 3*SA_STEPSPERRUN_EARLY2, 0 ) dlg.startsEa2 = dialog.AddSlider( "RunsEarlyIdeal", SA_NUMSTARTS_EARLY2, 1, 10*SA_NUMSTARTS_EARLY2, 0 ) dlg.quitnogainEa2 = dialog.AddSlider("Stop at N fails", SA_FAILIFNOGAIN_EARLY2, 1, 5*SA_FAILIFNOGAIN_EARLY2, 0 ) end function SetEarly2Options( dlg ) SA_STEPSPERRUN_EARLY2 = dlg.stepsperEa2.value SA_NUMSTARTS_EARLY2 = dlg.startsEa2.value SA_FAILIFNOGAIN_EARLY2 = dlg.quitnogainEa2.value DebugPrint("EarlyIdeal steps,starts,quit="..SA_STEPSPERRUN_EARLY2..","..SA_NUMSTARTS_EARLY2..","..SA_FAILIFNOGAIN_EARLY2 ) return true end function PutStabOptionsInBox( dlg ) PutStab1OptionsInBox( dlg ) PutStab2OptionsInBox( dlg ) end function SetStabOptions( dlg ) SetStab1Options( dlg ) SetStab2Options( dlg ) return true end function PutEarlyOptionsInBox( dlg ) PutEarly1OptionsInBox( dlg ) PutEarly2OptionsInBox( dlg ) dlg.minEarly = dialog.AddSlider("Min runs of Early", MIN_TRIES_EARLY_OP, 1, 2*MIN_TRIES_EARLY_OP, 0) dlg.maxEarly = dialog.AddSlider("Max runs of Early", MAX_TRIES_EARLY_OP, 1, 2*MAX_TRIES_EARLY_OP, 0) end function SetEarlyOptions( dlg ) SetEarly1Options( dlg ) SetEarly2Options( dlg ) MIN_TRIES_EARLY_OP = dlg.minEarly.value MAX_TRIES_EARLY_OP = dlg.maxEarly.value DebugPrint("MinTries, MaxTries = "..MIN_TRIES_EARLY_OP..","..MAX_TRIES_EARLY_OP) return true end function PutRebuild1OptionsInBox( dlg ) dlg.stepsperRb = dialog.AddSlider( "StepsRebuild1", SA_STEPSPERRUN_REBUILD, 1, 3*SA_STEPSPERRUN_REBUILD, 0 ) dlg.startsRb = dialog.AddSlider( "RunsRebuild1", SA_NUMSTARTS_REBUILD, 1, 10*SA_NUMSTARTS_REBUILD, 0 ) dlg.quitnogainRb = dialog.AddSlider( "Stop at N fails", SA_FAILIFNOGAIN_REBUILD, 1, 5*SA_FAILIFNOGAIN_REBUILD, 0 ) end function SetRebuild1Options( dlg ) SA_STEPSPERRUN_REBUILD = dlg.stepsperRb.value SA_NUMSTARTS_REBUILD = dlg.startsRb.value SA_FAILIFNOGAIN_REBUILD = dlg.quitnogainRb.value DebugPrint("RebuildBasic steps,starts,quit="..SA_STEPSPERRUN_REBUILD..","..SA_NUMSTARTS_REBUILD..","..SA_FAILIFNOGAIN_REBUILD ) return true end function PutRebuild2OptionsInBox( dlg ) dlg.stepsperRb2 = dialog.AddSlider( "StepsRebuild2", SA_STEPSPERRUN_DEEPREBUILD, 1, 3*SA_STEPSPERRUN_DEEPREBUILD, 0 ) dlg.startsRb2 = dialog.AddSlider( "RunsRebuild2", SA_NUMSTARTS_DEEPREBUILD, 1, 10*SA_NUMSTARTS_DEEPREBUILD, 0 ) dlg.quitnogainRb2 = dialog.AddSlider( "Stop at N fails", SA_FAILIFNOGAIN_DEEPREBUILD, 1, 5*SA_FAILIFNOGAIN_DEEPREBUILD, 0 ) end function SetRebuild2Options( dlg ) SA_STEPSPERRUN_DEEPREBUILD = dlg.stepsperRb2.value SA_NUMSTARTS_DEEPREBUILD = dlg.startsRb2.value SA_FAILIFNOGAIN_DEEPREBUILD = dlg.quitnogainRb2.value DebugPrint("RebuildDeep steps,starts,quit="..SA_STEPSPERRUN_DEEPREBUILD..","..SA_NUMSTARTS_DEEPREBUILD..","..SA_FAILIFNOGAIN_DEEPREBUILD ) return true end function PutRebuildOptionsInBox( dlg ) dlg.skipBasicRebuild = dialog.AddCheckbox( "Skip basic rebuild", false ) PutRebuild1OptionsInBox( dlg ) dlg.skipDeepRebuild = dialog.AddCheckbox( "Skip deep rebuild", false ) PutRebuild2OptionsInBox( dlg ) end function SetRebuildOptions( dlg ) SASEQ_SKIP_BASICREBUILD = dlg.skipBasicRebuild.value SASEQ_SKIP_DEEPREBUILD = dlg.skipDeepRebuild.value if not SASEQ_SKIP_BASICREBUILD then SetRebuild1Options( dlg ) end if not SASEQ_SKIP_DEEPREBUILD then SetRebuild2Options( dlg ) end return true end function PutMidOptionsInBox( dlg ) dlg.stepsperMid = dialog.AddSlider( "StepsMid", SA_STEPSPERRUN_MIDGAME, 1, 3*SA_STEPSPERRUN_MIDGAME, 0 ) dlg.startsMid = dialog.AddSlider( "RunsMid", SA_NUMSTARTS_MIDGAME, 1, 10*SA_NUMSTARTS_MIDGAME, 0 ) dlg.quitnogainMid = dialog.AddSlider( "Stop at N fails", SA_FAILIFNOGAIN_MIDGAME, 1, 5*SA_FAILIFNOGAIN_MIDGAME, 0 ) end function SetMidOptions( dlg ) SA_STEPSPERRUN_MIDGAME = dlg.stepsperMid.value SA_NUMSTARTS_MIDGAME = dlg.startsMid.value SA_FAILIFNOGAIN_MIDGAME = dlg.quitnogainMid.value DebugPrint("Mid steps,starts,quit="..SA_STEPSPERRUN_MIDGAME..","..SA_NUMSTARTS_MIDGAME..","..SA_FAILIFNOGAIN_MIDGAME ) return true end function PutLateOptionsInBox( dlg ) dlg.stepsperLt = dialog.AddSlider( "StepsFuser", SA_STEPSPERRUN_LATE, 1, 3*SA_STEPSPERRUN_LATE, 0 ) dlg.startsLt = dialog.AddSlider( "RunsFuser", SA_NUMSTARTS_LATE, 1, 10*SA_NUMSTARTS_LATE, 0 ) end function SetLateOptions( dlg ) SA_STEPSPERRUN_LATE = dlg.stepsperLt.value SA_NUMSTARTS_LATE = dlg.startsLt.value DebugPrint("Late steps,starts="..SA_STEPSPERRUN_LATE..","..SA_NUMSTARTS_LATE ) return true end function PutEndgameOptionsInBox( dlg ) dlg.endgameSkipCW = dialog.AddCheckbox( "Skip endgame CutAndWiggle start", SASEQ_ENDGAME_SKIP_CW ) dlg.minEnd = dialog.AddSlider("Min tries", MIN_TRIES_ENDGAME, 1, 3*MIN_TRIES_ENDGAME, 0) dlg.maxEnd = dialog.AddSlider("Max tries", MAX_TRIES_ENDGAME, 1, 4*MAX_TRIES_ENDGAME, 0) end function SetEndgameOptions( dlg ) SASEQ_ENDGAME_SKIP_CW = dlg.endgameSkipCW.value MIN_TRIES_ENDGAME = dlg.minEnd.value MAX_TRIES_ENDGAME = dlg.maxEnd.value DebugPrint("Skip CW fuse? "..BoolStr( SASEQ_ENDGAME_SKIP_CW )) DebugPrint("Min Tries Endgame"..MIN_TRIES_ENDGAME) DebugPrint("Max Tries Endgame"..MAX_TRIES_ENDGAME) return true end function PutContactMapOptionsInBox( dlg ) dlg.CmapLabel = dialog.AddLabel( "---------- ContactMap Run Options ----------") dlg.stepsperCMap = dialog.AddSlider( "StepsCMap", SA_STEPSPERRUN_CMAP, 1, 3*SA_STEPSPERRUN_CMAP, 0 ) dlg.startsCMap = dialog.AddSlider( "RunsLowCMap", SA_NUMSTARTS_CMAP, 1, 10*SA_NUMSTARTS_CMAP, 0 ) end function SetContactMapOptions( dlg ) SA_STEPSPERRUN_CMAP = dlg.stepsperCMap.value SA_NUMSTARTS_CMAP = dlg.startsCMap.value DebugPrint("CMap steps,starts="..SA_STEPSPERRUN_CMAP..","..SA_NUMSTARTS_CMAP ) return true end function PutLunchBuffetEconomyOptionsInBox( dlg ) dlg.actGentCom = dialog.AddCheckbox( "GentleComp", false ) dlg.actGentComLo = dialog.AddCheckbox( "GentleCompLowCI", false ) dlg.actInhExh = dialog.AddCheckbox( "InhaleAndExhale", false ) dlg.actTailG = dialog.AddCheckbox( "TailGrab", false ) dlg.actVoidC = dialog.AddCheckbox( "VoidCrusher", false ) dlg.actPushP = dialog.AddCheckbox( "PushPull", false ) dlg.actGenrHin = dialog.AddCheckbox( "GeneralHinge", false ) dlg.actIdealR = dialog.AddCheckbox( "IdealizeRegion", false ) dlg.actIdealX = dialog.AddCheckbox( "IdealizeXToY", false ) dlg.actIdealizePt = dialog.AddCheckbox( "IdealizePoint", false ) dlg.actRbBits = dialog.AddCheckbox( "RebuildBitspawn", false ) dlg.actRbBitsLo = dialog.AddCheckbox( "RebuildBitspawnLowCI", false ) dlg.actQuakeRb = dialog.AddCheckbox( "QuakingRebuild", false ) dlg.actRebSimpPt = dialog.AddCheckbox( "RebuildSimplePoint", false ) dlg.actBWP = dialog.AddCheckbox( "BandedWormPair", false ) dlg.actLocalWiggle = dialog.AddCheckbox( "LocalWiggle", false ) dlg.actATSide = dialog.AddCheckbox( "ATSidechainTweak", false ) dlg.actATSideAround = dialog.AddCheckbox( "ATSidechainTweakAround", false ) dlg.cmtBlankBuffet = dialog.AddLabel("") dlg.cmtBuffet = dialog.AddLabel("--- Expensive but useful ---") dlg.actRemix = dialog.AddCheckbox( "Remix", false ) dlg.actATSideManipulate = dialog.AddCheckbox( "ATSidechainManipulate", false ) end function SetLunchBuffetEconomyOptions( dlg ) if dlg.actGentCom.value then LunchBuffetActions[ #LunchBuffetActions + 1] = "GentleComp" end if dlg.actGentComLo.value then LunchBuffetActions[ #LunchBuffetActions + 1] = "GentleCompLowCI" end if dlg.actInhExh.value then LunchBuffetActions[ #LunchBuffetActions + 1] = "InhaleAndExhale" end if dlg.actTailG.value then LunchBuffetActions[ #LunchBuffetActions + 1] = "TailGrab" end if dlg.actVoidC.value then LunchBuffetActions[ #LunchBuffetActions + 1] = "VoidCrusher" end if dlg.actPushP.value then LunchBuffetActions[ #LunchBuffetActions + 1] = "PushPull" end if dlg.actGenrHin.value then LunchBuffetActions[ #LunchBuffetActions + 1] = "GeneralHinge" end if dlg.actIdealR.value then LunchBuffetActions[ #LunchBuffetActions + 1] = "IdealizeRegion" end if dlg.actIdealX.value then LunchBuffetActions[ #LunchBuffetActions + 1] = "IdealizeXToY" end if dlg.actIdealizePt.value then LunchBuffetActions[ #LunchBuffetActions + 1] = "IdealizePoint" end if dlg.actRbBits.value then LunchBuffetActions[ #LunchBuffetActions + 1] = "RebuildBitspawn" end if dlg.actRbBitsLo.value then LunchBuffetActions[ #LunchBuffetActions + 1] = "RebuildBitspawnLowCI" end if dlg.actQuakeRb.value then LunchBuffetActions[ #LunchBuffetActions + 1] = "QuakingRebuild" end if dlg.actRebSimpPt.value then LunchBuffetActions[ #LunchBuffetActions + 1] = "RebuildSimplePoint" end if dlg.actBWP.value then LunchBuffetActions[ #LunchBuffetActions + 1] = "BandedWormPair" end if dlg.actLocalWiggle.value then LunchBuffetActions[ #LunchBuffetActions + 1] = "LocalWiggle" end if dlg.actATSide.value then LunchBuffetActions[ #LunchBuffetActions + 1] = "ATSidechainTweak" end if dlg.actATSideAround.value then LunchBuffetActions[ #LunchBuffetActions + 1] = "ATSidechainTweakAround" end if dlg.actRemix.value then LunchBuffetActions[ #LunchBuffetActions + 1] = "Remix" end if dlg.actATSideManipulate.value then LunchBuffetActions[ #LunchBuffetActions + 1] = "ATSidechainManipulate" end end function PutLunchBuffetBanderOptionsInBox( dlg ) for i = 1, #AllActionsList do if AllActionsList[i].actionType == ACTION_TYPE_BANDER then dlg[ AllActionsList[i].nameStr ] = dialog.AddCheckbox( AllActionsList[i].nameStr, false ) end end end function SetLunchBuffetBanderOptions( dlg ) for i = 1, #AllActionsList do if AllActionsList[i].actionType == ACTION_TYPE_BANDER then if dlg[ AllActionsList[i].nameStr].value then LunchBuffetActions[ #LunchBuffetActions + 1] = AllActionsList[i].nameStr end end end end function PutLunchBuffetRebuilderOptionsInBox( dlg ) for i = 1, #AllActionsList do if AllActionsList[i].actionType == ACTION_TYPE_REBUILD or AllActionsList[i].actionType == ACTION_TYPE_REMIXIDEAL then dlg[ AllActionsList[i].nameStr ] = dialog.AddCheckbox( AllActionsList[i].nameStr, false ) end end end function SetLunchBuffetRebuilderOptions( dlg ) for i = 1, #AllActionsList do if AllActionsList[i].actionType == ACTION_TYPE_REBUILD or AllActionsList[i].actionType == ACTION_TYPE_REMIXIDEAL then if dlg[ AllActionsList[i].nameStr].value then LunchBuffetActions[ #LunchBuffetActions + 1] = AllActionsList[i].nameStr end end end end function PutLunchBuffetQuakerOptionsInBox( dlg ) for i = 1, #AllActionsList do if AllActionsList[i].actionType == ACTION_TYPE_QUAKER then dlg[ AllActionsList[i].nameStr ] = dialog.AddCheckbox( AllActionsList[i].nameStr, false ) end end end function SetLunchBuffetQuakerOptions( dlg ) for i = 1, #AllActionsList do if AllActionsList[i].actionType == ACTION_TYPE_QUAKER then if dlg[ AllActionsList[i].nameStr].value then LunchBuffetActions[ #LunchBuffetActions + 1] = AllActionsList[i].nameStr end end end end function PutLunchBuffetEndgameOptionsInBox( dlg ) for i = 1, #AllActionsList do if AllActionsList[i].actionType == ACTION_TYPE_ENDGAME then dlg[ AllActionsList[i].nameStr ] = dialog.AddCheckbox( AllActionsList[i].nameStr, false ) end end end function SetLunchBuffetEndgameOptions( dlg ) for i = 1, #AllActionsList do if AllActionsList[i].actionType == ACTION_TYPE_ENDGAME then if dlg[ AllActionsList[i].nameStr].value then LunchBuffetActions[ #LunchBuffetActions + 1] = AllActionsList[i].nameStr end end end end function PutLunchBuffetDubiousOptionsInBox( dlg ) for i = 1, #AllActionsList do if AllActionsList[i].actionType == ACTION_TYPE_DUBIOUS then dlg[ AllActionsList[i].nameStr ] = dialog.AddCheckbox( AllActionsList[i].nameStr, false ) end end end function SetLunchBuffetDubiousOptions( dlg ) for i = 1, #AllActionsList do if AllActionsList[i].actionType == ACTION_TYPE_DUBIOUS then if dlg[ AllActionsList[i].nameStr].value then LunchBuffetActions[ #LunchBuffetActions + 1] = AllActionsList[i].nameStr end end end end function PutLunchBuffetRunOptionsInBox( dlg ) dlg.wantWalker = dialog.AddCheckbox( "Walker instead of SA?", DO_WALKER_BUFFET ) dlg.LBblankWSA = dialog.AddLabel( "" ) dlg.sepWalkerRunOpt = dialog.AddLabel( "---------- Walker Options ------------") dlg.sepWalkerInfo = dialog.AddLabel( "For walker, pick order (topmost checked will be taken)") dlg.walkerSE = dialog.AddCheckbox( "Start to End", true ) dlg.walkerES = dialog.AddCheckbox( "End to Start", false ) dlg.walkerR = dialog.AddCheckbox( "Random order", false ) dlg.walkerWB = dialog.AddCheckbox( "Worst to best", false ) dlg.sepBuffetRunOpt = dialog.AddLabel( "---------- SA Run Options ------------") dlg.stepsperBuffet = dialog.AddSlider( "Steps", SA_STEPSPERRUN_BUFFET, 1, 3*SA_STEPSPERRUN_BUFFET, 0 ) dlg.startsBuffet = dialog.AddSlider( "Runs", SA_NUMSTARTS_BUFFET, 1, 10*SA_NUMSTARTS_BUFFET, 0 ) dlg.sepsaTempInfo = dialog.AddLabel( "For temp, slider is level of activity, 4=highest, 0=none") dlg.sepsaTempInfo2 = dialog.AddLabel( " (4=T_OneOverX 3=T_MiddlingX 2=T_LowX 1=T_ColdX 0=T_Zero)") dlg.tempControl = dialog.AddSlider( "Temp", 4, 0, 4, 0 ) end function SetLunchBuffetRunOptions( dlg ) if dlg.wantWalker.value then DO_WALKER_BUFFET = true if dlg.walkerSE.value then ACTION_ORDERPROTOCOL_BUFFET = ACTION_ORDERPROTOCOL_START_TO_END elseif dlg.walkerES.value then ACTION_ORDERPROTOCOL_BUFFET = ACTION_ORDERPROTOCOL_END_TO_START elseif dlg.walkerR.value then ACTION_ORDERPROTOCOL_BUFFET = ACTION_ORDERPROTOCOL_RANDOMIZE elseif dlg.walkerWB.value then ACTION_ORDERPROTOCOL_BUFFET = ACTION_ORDERPROTOCOL_WORST_TO_BEST else print("no order chosen: will default to Start-to-end") ACTION_ORDERPROTOCOL_BUFFET = ACTION_ORDERPROTOCOL_START_TO_END end DebugPrint("LunchBuffet walker: order="..ACTION_ORDERPROTOCOL_BUFFET) else DO_WALKER_BUFFET = false SA_STEPSPERRUN_BUFFET = dlg.stepsperBuffet.value SA_NUMSTARTS_BUFFET = dlg.startsBuffet.value TEMPFUNCNAME_BUFFET = PickTempStringByNumber( dlg.tempControl.value ) DebugPrint("LunchBuffet SA steps,starts="..SA_STEPSPERRUN_BUFFET..","..SA_NUMSTARTS_BUFFET ) DebugPrint("LunchBuffet SA temp="..TEMPFUNCNAME_BUFFET) end return true end function PutLunchBuffetOptionsInBox( dlg ) dlg.cmtLB1 = dialog.AddLabel( "-------- Lunch Buffet Actions --------" ) dlg.cmtLB11 = dialog.AddLabel( " Here be food: Please pick at least one" ) dlg.wantEconomyPlatter = dialog.AddCheckbox( "Pick Economy Platter", false ) dlg.wantBanders = dialog.AddCheckbox( "Pick banders", false ) dlg.wantQuakes = dialog.AddCheckbox( "Pick quakes", false ) dlg.wantRebuilders = dialog.AddCheckbox( "Pick rebuild/remix/idealize", false ) dlg.wantEndgameActs = dialog.AddCheckbox( "Pick endgame actions", false ) dlg.wantDubiousActs = dialog.AddCheckbox( "Pick dubious foods", false ) dlg.cmtLBSpacer1 = dialog.AddLabel( "" ) end function SetLunchBuffetOptions( dlg ) LunchBuffetActions = {} if dlg.wantEconomyPlatter.value then dlg2 = dialog.CreateDialog( "Economy Platter Actions" ) PutLunchBuffetEconomyOptionsInBox( dlg2 ) dlg2.ok = dialog.AddButton( "OK", 1 ) if dialog.Show( dlg2 ) == 0 then return false end SetLunchBuffetEconomyOptions( dlg2 ) end if dlg.wantBanders.value then dlg2 = dialog.CreateDialog( "Bander Actions" ) PutLunchBuffetBanderOptionsInBox( dlg2 ) dlg2.ok = dialog.AddButton( "OK", 1 ) if dialog.Show( dlg2 ) == 0 then return false end SetLunchBuffetBanderOptions( dlg2 ) end if dlg.wantQuakes.value then dlg2 = dialog.CreateDialog( "Quaker Actions" ) PutLunchBuffetQuakerOptionsInBox( dlg2 ) dlg2.ok = dialog.AddButton( "OK", 1 ) if dialog.Show( dlg2 ) == 0 then return false end SetLunchBuffetQuakerOptions( dlg2 ) end if dlg.wantRebuilders.value then dlg2 = dialog.CreateDialog( "Rebuilder Actions" ) PutLunchBuffetRebuilderOptionsInBox( dlg2 ) dlg2.ok = dialog.AddButton( "OK", 1 ) if dialog.Show( dlg2 ) == 0 then return false end SetLunchBuffetRebuilderOptions( dlg2 ) end if dlg.wantEndgameActs.value then dlg2 = dialog.CreateDialog( "Endgame Actions" ) PutLunchBuffetEndgameOptionsInBox( dlg2 ) dlg2.ok = dialog.AddButton( "OK", 1 ) if dialog.Show( dlg2 ) == 0 then return false end SetLunchBuffetEndgameOptions( dlg2 ) end if dlg.wantDubiousActs.value then dlg2 = dialog.CreateDialog( "Dubious Actions" ) PutLunchBuffetDubiousOptionsInBox( dlg2 ) dlg2.ok = dialog.AddButton( "OK", 1 ) if dialog.Show( dlg2 ) == 0 then return false end SetLunchBuffetDubiousOptions( dlg2 ) end for i=1, #LunchBuffetActions do DebugPrint("Will perform "..LunchBuffetActions[i]) end return #LunchBuffetActions >= 1 end function PutSASequenceOptionsInBox( dlg ) dlg.cmtSASeq = dialog.AddLabel( "------ SA Sequence Options -----" ) dlg.wantToChangeRuns = dialog.AddCheckbox( "SA run options", false ) dlg.skipStab = dialog.AddCheckbox( "Skip initial stabilizer runs", SASEQ_SKIP_STABILIZER ) dlg.skipRebuild = dialog.AddCheckbox( "Skip rebuild run", false ) dlg.wantFuses = dialog.AddCheckbox( "Add post-midgame fuse run", ALLOW_FUSE ) dlg.wantEndgame = dialog.AddCheckbox( "Add HWP endgame run", not SASEQ_SKIP_ENDGAME ) if InitialBandCount > 0 then dlg.cmtUserBandsBlank = dialog.AddLabel( "" ) dlg.cmtUserBands = dialog.AddLabel( "------ User Band options ------" ) dlg.nobandAfterStab = dialog.AddCheckbox( "Disable user bands after stabilizer", SASEQ_DISABLE_UBAND_AFTER_STAB ) dlg.nobandAfterEarly = dialog.AddCheckbox( "Disable user bands after early", SASEQ_DISABLE_UBAND_AFTER_EARLY ) end end function SetSASequenceOptions( dlg ) ALLOW_FUSE = dlg.wantFuses.value SASEQ_SKIP_STABILIZER = dlg.skipStab.value SASEQ_SKIP_DEEPREBUILD = dlg.skipRebuild.value SASEQ_SKIP_BASICREBUILD = dlg.skipRebuild.value SASEQ_SKIP_ENDGAME = not dlg.wantEndgame.value if InitialBandCount > 0 then SASEQ_DISABLE_UBAND_AFTER_STAB = dlg.nobandAfterStab.value SASEQ_DISABLE_UBAND_AFTER_EARLY = dlg.nobandAfterEarly.value DebugPrint("Disable user bands after Stab? "..BoolStr(SASEQ_DISABLE_UBAND_AFTER_STAB)) DebugPrint("Disable user bands after Early? "..BoolStr(SASEQ_DISABLE_UBAND_AFTER_EARLY)) end DebugPrint("skip Stab? "..BoolStr(SASEQ_SKIP_STABILIZER)) DebugPrint("skip DeepR? "..BoolStr(SASEQ_SKIP_DEEPREBUILD)) DebugPrint("skip BasicR? "..BoolStr(SASEQ_SKIP_BASICREBUILD)) DebugPrint("add Late/Fuse run? "..BoolStr(ALLOW_FUSE)) DebugPrint("skip End? "..BoolStr(SASEQ_SKIP_ENDGAME)) if dlg.wantToChangeRuns.value == true then local doStab,doEarly,doRebuild,doMidgame,doLate,doEnd = false, false, false, false, false, false dlg2 = dialog.CreateDialog( "SA Run Options" ) if not SASEQ_SKIP_STABILIZER then dlg2.SeeStabilizer = dialog.AddCheckbox( "Change Stabilizer?", false ) end dlg2.SeeEarly = dialog.AddCheckbox( "Change Early?", false ) if not (SASEQ_SKIP_DEEPREBUILD and SASEQ_SKIP_BASICREBUILD) then dlg2.SeeRebuild = dialog.AddCheckbox( "Change Rebuild?", false ) end dlg2.SeeMidgame = dialog.AddCheckbox( "Change Midgame?", false ) if ALLOW_FUSE then dlg2.SeeLate = dialog.AddCheckbox( "Change Fuse run?", false ) end if not SASEQ_SKIP_ENDGAME then dlg2.SeeEndgame = dialog.AddCheckbox( "Change Endgame?", false ) end dlg2.ok = dialog.AddButton( "OK", 1 ) dlg2.cancel = dialog.AddButton( "Cancel", 0 ) if dialog.Show( dlg2 ) == 0 then return false end if (not SASEQ_SKIP_STABILIZER) and dlg2.SeeStabilizer.value then local dlg3 = dialog.CreateDialog( "Stabilizer Run Options" ) PutStabOptionsInBox( dlg3 ) dlg3.ok = dialog.AddButton( "OK", 1 ) dlg3.cancel = dialog.AddButton( "Cancel", 0 ) if dialog.Show( dlg3 ) == 0 then return false end SetStabOptions( dlg3 ) end if dlg2.SeeEarly.value then local dlg3 = dialog.CreateDialog( "Early Run Options" ) PutEarlyOptionsInBox( dlg3 ) dlg3.ok = dialog.AddButton( "OK", 1 ) dlg3.cancel = dialog.AddButton( "Cancel", 0 ) if dialog.Show( dlg3 ) == 0 then return false end SetEarlyOptions( dlg3 ) end if (not (SASEQ_SKIP_DEEPREBUILD and SASEQ_SKIP_BASICREBUILD)) and dlg2.SeeRebuild.value then local dlg3 = dialog.CreateDialog( "Rebuild Run Options" ) PutRebuildOptionsInBox( dlg3 ) dlg3.ok = dialog.AddButton( "OK", 1 ) dlg3.cancel = dialog.AddButton( "Cancel", 0 ) if dialog.Show( dlg3 ) == 0 then return false end SetRebuildOptions( dlg3 ) end if dlg2.SeeMidgame.value then local dlg3 = dialog.CreateDialog( "Midgame Run Options" ) PutMidOptionsInBox( dlg3 ) dlg3.ok = dialog.AddButton( "OK", 1 ) dlg3.cancel = dialog.AddButton( "Cancel", 0 ) if dialog.Show( dlg3 ) == 0 then return false end SetMidOptions( dlg3 ) end if ALLOW_FUSE and dlg2.SeeLate.value then local dlg3 = dialog.CreateDialog( "Fuse Run Options" ) PutLateOptionsInBox( dlg3 ) dlg3.ok = dialog.AddButton( "OK", 1 ) dlg3.cancel = dialog.AddButton( "Cancel", 0 ) if dialog.Show( dlg3 ) == 0 then return false end SetLateOptions( dlg3 ) end if not SASEQ_SKIP_ENDGAME then local dlg3 = dialog.CreateDialog( "Endgame Run Options" ) PutEndgameOptionsInBox( dlg3 ) dlg3.ok = dialog.AddButton( "OK", 1 ) dlg3.cancel = dialog.AddButton( "Cancel", 0 ) if dialog.Show( dlg3 ) == 0 then return false end SetEndgameOptions( dlg3 ) end end return true end function PutCysteineOptionsInBox( dlg ) str = "" for i=1, #CysteineAaSegList do str = str..CysteineAaSegList[i] if i < #CysteineAaSegList then str = str.. "," end end dlg.cmtCy = dialog.AddLabel( "Cysteines: "..str ) str = "" for i=1, #CysteinePairList do local pair = CysteinePairList[i] str = str..pair[1]..","..pair[2] if i < #CysteinePairList then str = str .. "; " end end dlg.cmtCy2 = dialog.AddLabel( "Guessed pairs: "..str ) dlg.cyPairsWanted = dialog.AddSlider( "Pair count", #CysteinePairList, 0, #CysteinePairList, 0 ) dlg.cyPairings = dialog.AddTextbox( "Pairings", str) if InitialBandCount > 0 then dlg.cmtCy3 = dialog.AddLabel( "Cysteine-bander cannot honor user bands" ) end dlg.cyBandStrength = dialog.AddSlider( "Band strength", CYSTEINE_BAND_STRENGTH, 0.0, 8.0, 1 ) dlg.cyBandsPer = dialog.AddSlider( "Ct Bands", CYSTEINE_COUNT_BANDS_USED, 1, 4, 0 ) end function SetCysteineOptions( dlg ) ctCysPairs = dlg.cyPairsWanted.value if dlg.cyPairings.value ~= nil then parseCysteineStr( ctCysPairs, dlg.cyPairings.value) else -- this happens if user puts empty comment, -- but says they want a number of pairs smaller than expected -- we interpret this as request to truncate accepted list while ctCysPairs < #CysteinePairList do table.remove(CysteinePairList, #CysteinePairList) end end if ctCysPairs > 0 then str = "" for i=1, #CysteinePairList do pair = CysteinePairList[i] str = str..pair[1]..","..pair[2] if i < #CysteinePairList then str = str .. "; " end end DebugPrint( "CysteinePairList: "..str ) DebugPrint( "Try to add "..ctCysPairs.." cysteine band groups" ) else DebugPrint( "No cysteine bands wanted, none made" ) end CYSTEINE_BAND_STRENGTH = dlg.cyBandStrength.value CYSTEINE_COUNT_BANDS_USED = dlg.cyBandsPer.value DebugPrint( "Use cysteine band strength = "..CYSTEINE_BAND_STRENGTH ) DebugPrint( "Use "..CYSTEINE_COUNT_BANDS_USED.." bands per cysteine bond wanted" ) end -- THE BIG 2ND DIALOG AFTER TYPE OF RUN HAS BEEN CHOSEN function DoDialogParamChooser( opMsg, operationPutter, operationSetter, wantFuse, wantDecement, wantLunchPickers) local dlg = dialog.CreateDialog( opMsg ) -- Lunch Buffet if relevant (note: I might want a submenu putter and setter pair. SASequence might benefit) if wantLunchPickers then PutLunchBuffetOptionsInBox( dlg ) end -- Basic parameters dlg.cmtBO1 = dialog.AddLabel( "-------- Basic SA Parameters --------" ) dlg.cmtBO11 = dialog.AddLabel( " Here be baby dragons" ) dlg.preserveCuts = dialog.AddCheckbox( "Preserve user cuts", PRESERVE_USER_CUTS ) if InitialBandCount > 0 then dlg.preserveBands = dialog.AddCheckbox( "Preserve user bands", true ) end if #CysteineAaSegList >= 2 then dlg.playCysteineGames = dialog.AddCheckbox( "Bond cysteine pairs", false ) end dlg.forbidQstab = dialog.AddCheckbox( "Forbid qstab fuzing", FORBID_ALL_QSTAB_FUSE ) dlg.forbidWPChange = dialog.AddCheckbox( "Forbid wiggle power changes", FORBID_WIGGLE_POWER_CHANGE ) 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 PuzzleUsesFilters then dlg.cmKillFilters = dialog.AddCheckbox( "DisableFilters", KILLING_FILTERS ) end if PuzzleAllowsMutate then dlg.MutateCmt = dialog.AddLabel("Mutate: 0=never, 1=once, 2=always") dlg.whenToMutate = dialog.AddSlider( " Mutate", 1, 0, 2, 0 ) -- default to "once" end -- Advanced parameters dlg.cmtSpacer2 = dialog.AddLabel( "" ) dlg.cmtAO1 = dialog.AddLabel( "-------- Advanced SA Parameters --------" ) dlg.cmtAO11 = dialog.AddLabel( " Here be big dragons" ) dlg.wantRunParams = dialog.AddCheckbox( "Change run params", false ) if PuzzleAllowsMutate then dlg.setMutate = dialog.AddCheckbox( "Change Mutate options", false ) end dlg.IdRAdvancedPars= dialog.AddCheckbox( "Change Idealize/Rebuild/Remix", false ) --dlg.BanderPars= dialog.AddCheckbox( "Change Bander options", false ) if wantFuse then dlg.WigglerPars= dialog.AddCheckbox( "Change Fuser options", false ) end if wantDecement then dlg.DecementPars = dialog.AddCheckbox( "Change Decementing options", false ) end dlg.cmtSpacer3 = dialog.AddLabel( "" ) dlg.samingain = dialog.AddSlider( "MinGainForRuns", SA_MINGAIN, 0, 10*SA_MINGAIN, 1 ) dlg.maxCI = dialog.AddSlider( "MaxCI", CI_MAXSCALE, 0.0, 1.0, 2 ) dlg.rangeOfAction = dialog.AddTextbox( "Restrict to segs", "" ) dlg.ok = dialog.AddButton( "OK", 1 ) dlg.cancel = dialog.AddButton( "Cancel", 0 ) -- SHOW it to the user if dialog.Show( dlg ) == 0 then return false end if wantLunchPickers then SetLunchBuffetOptions( dlg ) end -- LEARN what the user wanted -- Basic params: PRESERVE_USER_CUTS = dlg.preserveCuts.value if PRESERVE_USER_CUTS then IDEALIZE_USE_CUTS = false PROB_FUSEWIGGLE_CUTFUSE = 0.00 -- don't use wigglers that put cuts PROB_FUSEWIGGLE_LOCAL = 0.00 -- this one's too useless PROB_FUSEWIGGLE_BLUEFUSE = 1.0 end DebugPrint( "Preserve user cuts? ".. BoolStr( PRESERVE_USER_CUTS ) ) if InitialBandCount > 0 then BANDS_PRESERVE_USER = dlg.preserveBands.value if not BANDS_PRESERVE_USER then InitialBandCount = 0 InitialBandStates = {} DelBands( ) end DebugPrint( "Preserve user bands? ".. BoolStr( PRESERVE_USER_BANDS ) ) end if dlg.playCysteineGames ~= nil and dlg.playCysteineGames.value == true then CYSTEINE_PERFORM_BANDING = true local dlg2 = dialog.CreateDialog("Cysteine Pairings") PutCysteineOptionsInBox( dlg2 ) dlg2.ok = dialog.AddButton( "OK", 1 ) dlg2.cancel = dialog.AddButton( "Cancel", 0 ) if dialog.Show( dlg2 ) == 0 then return false end if InitialBandCount > 0 then print("Cannot honor user bands if cysteine bands are added") InitialBandCount = 0 InitialBandStates = {} DelBands( ) end SetCysteineOptions( dlg2 ) PutCysteinePairBands( ) end FORBID_ALL_QSTAB_FUSE = dlg.forbidQstab.value FORBID_WIGGLE_POWER_CHANGE = dlg.forbidWPChange.value DebugPrint( "Forbid qstab fuzing? "..BoolStr( FORBID_WIGGLE_POWER_CHANGE )) DebugPrint( "Forbid wiggle power changes? "..BoolStr( FORBID_ALL_QSTAB_FUSE )) if PuzzleHasContactMap then CONTACTMAP_TAKEDROPS = dlg.cmForceContactBettering.value if CONTACTMAP_TAKEDROPS then DebugPrint( "Score drops of ".. CONTACTMAP_MAX_DROP .. " accepted if ContactMap improves" ) else DebugPrint( "No score drops permitted" ) end end if PuzzleUsesFilters then KILLING_FILTERS = dlg.cmKillFilters.value end if PuzzleAllowsMutate then if dlg.whenToMutate.value == 0 then MUTATE_NOT_SHAKE = false DebugPrint("Never mutate") elseif dlg.whenToMutate.value == 1 then MUTATE_NOT_SHAKE = true MUTATE_ONCE = true DebugPrint("Mutate once per action") else MUTATE_NOT_SHAKE = true MUTATE_ONCE = false DebugPrint("Always mutate") end end -- Advanced params CI_MAXSCALE = dlg.maxCI.value ExactSetCI( CI_MAXSCALE ) print( "Using MaxCI="..CI_MAXSCALE ) SA_MINGAIN = dlg.samingain.value DebugPrint("Run counts as fail if gain < "..SA_MINGAIN) if CI_MAXSCALE < 0.70 then USE_LOWCI_WIGGLES = true end if dlg.wantRunParams.value then -- this one gets its own dialog box, because it can get ugly local dlg2 = dialog.CreateDialog( "Run Parameters" ) operationPutter( dlg2 ) dlg2.ok = dialog.AddButton( "OK", 1 ) dlg2.cancel = dialog.AddButton( "Cancel", 0 ) if dialog.Show( dlg2 ) == 0 then return false end local r = operationSetter( dlg2 ) if r ~= nil and r == false then return false end end if dlg.rangeOfAction.value ~= nil and dlg.rangeOfAction.value ~= "" then AllowedActionIndices = parseRangesStr( dlg.rangeOfAction.value ) print("AllowedActionIndices has "..(#AllowedActionIndices).." segs" ) if #AllowedActionIndices > 0 then printVector( AllowedActionIndices, "ActOn", false ) else print("Error Parsing: No ranges selected") end end -- sub-dialogs based on Advanced Param choices if PuzzleAllowsMutate and dlg.setMutate.value then local dlg2 = dialog.CreateDialog( "Mutate Options" ) PutMutateOptionsInBox( dlg2 ) dlg2.ok = dialog.AddButton( "OK", 1 ) dlg2.cancel = dialog.AddButton( "Cancel", 0 ) if dialog.Show( dlg2 ) == 0 then return false end SetMutateOptions( dlg2 ) end if dlg.IdRAdvancedPars.value then local dlg2 = dialog.CreateDialog( "Idealize/Rebuild/Remix Options" ) PutIdealizeOptionsInBox( dlg2 ) PutlRebuildSubOptionsInBox( dlg2 ) PutRemixOptionsInBox( dlg2 ) dlg2.ok = dialog.AddButton( "OK", 1 ) dlg2.cancel = dialog.AddButton( "Cancel", 0 ) if dialog.Show( dlg2 ) == 0 then return false end SetIdealizeOptions( dlg2 ) SetRebuildSubOptions( dlg2 ) SetRemixOptions( dlg2 ) end --if dlg.BanderPars.value then -- local dlg2 = dialog.CreateDialog( "Bander Options" ) -- PutBanderOptionsInBox( dlg2 ) -- dlg2.ok = dialog.AddButton( "OK", 1 ) -- dlg2.cancel = dialog.AddButton( "Cancel", 0 ) -- if dialog.Show( dlg2 ) == 0 then return false end -- SetBanderOptions( dlg2 ) --end if wantFuse and dlg.WigglerPars.value then local dlg2 = dialog.CreateDialog( "Fuser Options" ) USE_FUSEWIGGLE = true PutSlowWiggleOptionsInBox( dlg2 ) dlg2.ok = dialog.AddButton( "OK", 1 ) dlg2.cancel = dialog.AddButton( "Cancel", 0 ) if dialog.Show( dlg2 ) == 0 then return false end SetSlowWiggleOptions( dlg2 ) end if wantDecement and dlg.DecementPars.value then local dlg2 = dialog.CreateDialog( "Decementing Options" ) PutDecementingOptionsInBox( dlg2 ) dlg2.ok = dialog.AddButton( "OK", 1 ) dlg2.cancel = dialog.AddButton( "Cancel", 0 ) if dialog.Show( dlg2 ) == 0 then return false end SetDecementingOptions( dlg2 ) end return true end function PutOtherSAOperationsInBox( dlg ) dlg.cmtSO = dialog.AddLabel( "-- Single Options" ) dlg.wantSALowCI = dialog.AddCheckbox( "LowCI", false ) dlg.wantSAStab1 = dialog.AddCheckbox( "Short Stabilizer", false ) dlg.wantSAStab2 = dialog.AddCheckbox( "Long Stabilizer", false ) dlg.wantSAEarlyMove = dialog.AddCheckbox( "Early Mover", false ) dlg.wantSAEarlyIdeal = dialog.AddCheckbox( "Early Ideal", false ) dlg.wantSARebuildBasic = dialog.AddCheckbox( "Basic Rebuild", false ) dlg.wantSARebuildDeep = dialog.AddCheckbox( "Deep Rebuild", false ) dlg.wantSAFuse = dialog.AddCheckbox( "Fuse", false ) if PuzzleHasContactMap then dlg.wantSAContact = dialog.AddCheckbox( "ContactMap", false ) end if DEBUGRUN then dlg.cmtSO2 = dialog.AddLabel( "-- Test Option" ) dlg.wantTest = dialog.AddCheckbox( "Test", false ) end end function SetOtherSAOperationOptions( dlg ) if dlg.wantSALowCI.value then return "SALowCI" elseif dlg.wantSAStab1.value then return "SAShortStab" elseif dlg.wantSAStab2.value then return "SALongStab" elseif dlg.wantSAEarlyMove.value then return "SAEarlyMove" elseif dlg.wantSAEarlyIdeal.value then return "SAEarlyIdeal" elseif dlg.wantSARebuildBasic.value then return "SARebuildBasic" elseif dlg.wantSARebuildDeep.value then return "SARebuildDeep" elseif dlg.wantSAFuse.value then return "SALate" elseif PuzzleHasContactMap and dlg.wantSAContact.value then return "SAContact" elseif DEBUGRUN and dlg.wantTest.value then return "SATest" else return nil -- something went wrong... end end function LetUserChooseParams( ) -- any condition that should not carry between different visits to -- dialog-box-land should be set to default values here. SetSAParamDefaults() DISABLE_ALL_USER_BANDS = false -- Do NOT put into SetSAParamDefaults local gotResultYet = false local operation while not gotResultYet do -- Welcome to the Netherworld! local dlg = dialog.CreateDialog( ReVersion ) dlg.cmt1 = dialog.AddLabel( "Pick one of following (topmost checked will be run)" ) dlg.modLabel1 = dialog.AddLabel( "---------- Press button get candy" ) dlg.wantSASeq = dialog.AddCheckbox( "Standard Sequence", true ) dlg.cmtBlank1 = dialog.AddLabel( "" ) dlg.modLabel2 = dialog.AddLabel( "---------- Individual Options" ) dlg.wantSAStab = dialog.AddCheckbox( "Stabilizer", false ) dlg.wantSAEarly = dialog.AddCheckbox( "Early", false ) dlg.wantSaRebuilder = dialog.AddCheckbox( "Rebuild", false ) dlg.wantSAMid = dialog.AddCheckbox( "Midgame", false ) dlg.wantSAEnd = dialog.AddCheckbox( "HWP Endgame", false ) dlg.cmtBlank2 = dialog.AddLabel( "" ) dlg.modLabel3 = dialog.AddLabel( "---------- Experimenter's Option" ) dlg.wantLunchBuffet = dialog.AddCheckbox( "LunchBuffet", false ) dlg.cmtBlank3 = dialog.AddLabel( "" ) dlg.modLabel4 = dialog.AddLabel( "---------- Specialty Options" ) dlg.wantOtherSAType = dialog.AddCheckbox( "Other Operation", false ) dlg.ok = dialog.AddButton( "OK", 1 ) dlg.cancel = dialog.AddButton( "Cancel", 0 ) if dialog.Show( dlg ) == 0 then return nil end -- PICK the Operation if dlg.wantSASeq.value then operation = "SASequence" elseif dlg.wantSAStab.value then operation = "SAStab" elseif dlg.wantSAEarly.value then operation = "SAEarly" elseif dlg.wantSaRebuilder.value then operation = "SARebuild" elseif dlg.wantSAMid.value then operation = "SAMidgame" elseif dlg.wantSAEnd.value then operation = "SAEndgame" elseif dlg.wantLunchBuffet.value then operation = "SALunchBuffet" elseif dlg.wantOtherSAType then local dlg2 = dialog.CreateDialog( "Other SA Operations" ) PutOtherSAOperationsInBox( dlg2 ) dlg2.ok = dialog.AddButton( "OK", 1 ) dlg2.cancel = dialog.AddButton( "Cancel", 0 ) if dialog.Show( dlg2 ) == 0 then return nil end operation = SetOtherSAOperationOptions( dlg2 ) if operation == nil then return nil end else return nil -- user didn't want anything! end -- ASK FOR MORE OPTIONS, offer as relevant to operation if operation == "SASequence" then gotResultYet = DoDialogParamChooser( "SASequence Options", PutSASequenceOptionsInBox, SetSASequenceOptions, true, true, false) elseif operation == "SAStab" then gotResultYet = DoDialogParamChooser( "Stabilizer SA Options", PutStabOptionsInBox, SetStabOptions, false, false, false) elseif operation == "SAEarly" then gotResultYet = DoDialogParamChooser( "Early SA Options", PutEarlyOptionsInBox, SetEarlyOptions, false, true, false) elseif operation == "SARebuild" then gotResultYet = DoDialogParamChooser( "Rebuild SA Options", PutRebuildOptionsInBox, SetRebuildOptions, false, false, false) elseif operation == "SAMidgame" then gotResultYet = DoDialogParamChooser( "Midgame SA Options", PutMidOptionsInBox, SetMidOptions, false, false, false) elseif operation == "SALate" then ALLOW_FUSE = true gotResultYet = DoDialogParamChooser( "Fuser SA Options", PutLateOptionsInBox, SetLateOptions, true, false, false) elseif operation == "SAEndgame" then gotResultYet = DoDialogParamChooser( "Endgame SA Options", PutEndgameOptionsInBox, SetEndgameOptions, false, false, false) elseif operation == "SALunchBuffet" then gotResultYet = DoDialogParamChooser( "LunchBuffet Options", PutLunchBuffetRunOptionsInBox, SetLunchBuffetRunOptions, false, false, true) elseif operation == "SAContact" then gotResultYet = DoDialogParamChooser( "ContactMap SA Options", PutContactMapOptionsInBox, SetContactMapOptions, false, false, false) elseif operation == "SALowCI" then gotResultYet = DoDialogParamChooser( "LowCI SA Options", PutLowCIOptionsInBox, SetLowCIOptions, false, false, false) elseif operation == "SAShortStab" then gotResultYet = DoDialogParamChooser( "ShortStabilizer SA Options", PutStab1OptionsInBox, SetStab1Options, false, false, false) elseif operation == "SALongStab" then gotResultYet = DoDialogParamChooser( "LongStabilizer SA Options", PutStab2OptionsInBox, SetStab2Options, false, false, false) elseif operation == "SAEarlyMove" then gotResultYet = DoDialogParamChooser( "EarlyMover SA Options", PutEarly1OptionsInBox, SetEarly1Options, false, true, false) elseif operation == "SAEarlyIdeal" then gotResultYet = DoDialogParamChooser( "EarlyIdealizer SA Options", PutEarly2OptionsInBox, SetEarly2Options, false, true, false) elseif operation == "SARebuildBasic" then gotResultYet = DoDialogParamChooser( "BasicRebuild SA Options", PutRebuild1OptionsInBox, SetRebuild1Options, false, false, false) elseif operation == "SARebuildDeep" then gotResultYet = DoDialogParamChooser( "DeepRebuild SA Options", PutRebuild2OptionsInBox, SetRebuild2Options, false, false, false) end end return operation end -------------------------------------------------------------------------- -- SETUP and CLEANUP -------------------------------------------------------------------------- function CleanPuzzleState( ) ExactSetCI( InitialClashImportance ) selection.DeselectAll( ) ResetFrozenness( ) ResetCuts( ) DelBands( true ) ResetSecondaryStructures( 1, SegCt ) ResetUserBands( true ) behavior.SetWigglePower( InitialWigglePower ) 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 if RESTORE_BEST_AT_END then LoadBest( ) end if PERFORM_CLEANUP_AT_END then CleanPuzzleState( ) end if KILLING_FILTERS then ResetFilterState( ) end if SHOW_STATS_REPORT then print("") reportStats( ) print( "EndDate: "..os.date() ) print( "TotalShakeTime="..TotalShakeTime ) -- because I want to know. print( "TotalMutateTime="..TotalMutateTime ) -- because I want to know. end PrintState( ) print( "" ) if errstr ~= nil then local start, stop, line, msg = errstr:find ( ":(%d+):%s()" ) if msg ~= nil then errstr = errstr:sub( msg, #errstr ) end if errstr:find ( "Cancelled" ) ~= nil then reason = "cancelled" else reason = "error" end if reason == "error" then print ( "Unexpected error detected" ) print ( "Error line: " .. line ) print ( "Error: \"" .. errstr .. "\"" ) end end end function InitializePuzzleState( ) -- some setup actions seedRandom( ) save.Quicksave( QS_Start ) save.Quicksave( QS_CmBest ) save.Quicksave( QS_Best ) GenerateAllActionsList( ) StartTime = os.time( ) -- learn a few things about the user and puzzle description Ident( ReVersion ) IdentPuzzleType( ) -- learn things the user did (StoreCuts would sure be nice to have) InitialBandCount = band.GetCount() StoreUserBands( ) StoreFrozenness( ) StoreSecondaryStructure( ) InitialClashImportance = behavior.GetClashImportance( ) CI_MAXSCALE = InitialClashImportance -- learn things about the protein in the puzzle InitialScore = getScore( ) GenerateNonLockedSegList( ) --StoreSecondaryStructure( ) FindAllMovableSegs( ) LocateHelices( ) LocateSheets( ) LocateLoops( ) LocateMissingHelices( ) -- places where a possible helix may be hiding if #PossibleHelices > 0 then print( "Treating some loops as helices: " ) for i=1, #PossibleHelices do local bounds = PossibleHelices[i] print(" "..i..". "..bounds.sIdx.."-"..bounds.eIdx ) end end setCysteineSegList( ) guessCysteinePairList( ) selection.DeselectAll( ) recentbest.Save( ) end -------------------------------------------------------------------------- -- MAIN -------------------------------------------------------------------------- function main( ) local operation = "" InitializePuzzleState() local didSomething = false print( "Start is in qs="..QS_Start.."; Best is in "..QS_Best ) if PuzzleHasContactMap then print( "CM-best is in "..QS_CmBest ) end while true do operation = LetUserChooseParams( ) if operation == nil then break end if KILLING_FILTERS then TurnOffFilters( ) end PerformOperation( operation ) didSomething = true LoadBest( ) ResetUserBands( ) PrintState( ) if SHOW_STATS_REPORT then reportStats() end resetStats() end if didSomething then print( " Done!" ) End( ) else print( "Come back again someday?" ) end end xpcall( main, End )

Comments


KarenCH Lv 1

Simply clicking OK to the first and second menu popups will cause it to perform a sequence of operations that should carry a provided pose to a good semi-final shape. (It will stop short of doing High Wiggle Power endgame actions, though it does provide a version of this as a separate set of actions).

It is a complex script that is capable of many many things. The first menu shows the "known-good" choices, but offers "Other actions" if you want to explore.

The second menu is the "dragons" menu - it uses "here be dragon" descriptions of the options to give a picture of how complicated the path will get.

INFO:

  1. It preserves user bands, cuts, and frozen sections, and accepts the current Clash Importance as a max value. For bands, if SASequence is requested, the "SA Run parameters" (under "big dragons") leads to an option of disabling the bands after the early phases. Its normal actions include qstab-fusing, but it can be disabled by choosing the correct option under the "baby dragons" header.
  2. It uses the simulated annealing algorithm to create sessions of 12-15 actions - score drops can happen during the session, but at the end of one, it takes the largest score it saw during that session.
  3. For a reasonably good computer, doing a full SASequence on a small protein will take a bit more than a day (28-30 hours). It goes faster if the original pose is closer to correct.