Icon representing a recipe

Recipe: Loop Remix/Rebuild 12.6

created by LociOiling

Profile


Name
Loop Remix/Rebuild 12.6
ID
109122
Shared with
Public
Parent
Loop Remix/Rebuild 12.5
Children
Created on
August 10, 2025 at 21:51 PM UTC
Updated on
August 21, 2025 at 18:19 PM UTC
Description

Fix crash if "use remix" option is unchecked. Eliminate some obsolete features. Clarify and simplify scriptlog output.

Best for


Code


--[[ Loop Remix/Rebuild Copyright notice. You may copy and paste at will. Plagiarize shamelessly! End copyright notice Adapted by jeff101 11/13/17 from spvincent's public 11/04/16 "Loop rebuild 8.0" recipe: 8.0a.txt = Original "Loop rebuild 8.0" code copy/pasted by 848am 10/05/17 from Foldit client 10b. Should be <Foldit:MacroID>102235</Foldit:MacroID> and <Foldit:MacroRevisionID>203034</Foldit:MacroRevisionID> code as used for scriptlog1445h14.txt. 8.0b.txt = Remove blank lines, replace some tabs w/spaces, make indenting & comments more uniform. Ideally all changes are superficial not functional. 9.0a.txt = Let user specify residues to rebuild & mutate. Last updated 11/17/17 303pm 12.0.txt = + added rebuild worst segments + settings in the gui and how many worst segments to rebuild Last updated 06/23/25 530am 12.5.txt = changed max_residue = structure.GetCount() -- max segments/residues like the current puzzle has! "for the next very large Puzzles" 12.6 - LociOiling 20250809 - see first comment ]]-- -- Below sets the globals prog_name='Loop Remix/Rebuild 12.6' -- Mostly user-configurable globals number_of_rebuilds = 8 -- It'll look for the best score from this number of rebuilds. ss_criterion = 4 -- Controls whether to rebuild a section based on secondary structure convert_to_loop = false -- If true, any non-loop residues will be temporarily converted to loops keep_bands = true min_residue = 1 max_residue = structure.GetCount() -- max segments/residues like the current puzzle has! kInvalidScore = -99999 rebuild_worst = true -- Rebuild Worst Segments = true -- How many Worst segments to remix/rebuild (default value 30% from the number of residues of the entire Protein) howmany = (structure.GetCount() / 100) * 30 run_remix = true fidealize = false -- Final Idealize = false (default) inner_sphere = {} outer_sphere = {} kInnerSphereRadius = 10 kOuterSphereRadius = 18 kDefaultWiggleDuration = 12 kLowCiWiggle = 0.2 pw_threshold_value = 80 score_type = 1 ST_NORMAL = 1 ST_HIDING = 2 ST_BONDING = 3 ST_FILTERS = 4 ST_SLOWFILT = 5 rebuild_str="" rebuild_list={} -- will be a list of 1's & 0's for each residue. 1 means can rebuild. 0 means don't rebuild. -- Use of quicksave slots kOriginalStructureOrNewBest = 1 kBestPostRebuild_a = 2 kBestPostRebuild_b = 3 kBestPostRebuild_a_post_wiggle = 4 kTemp = 5 kRemixQuicksaveStart = 30 -- Globals original_secondary_structure = {} fixed_residues = {} original_slow_filters_setting = 0 n_bands = 0 orig_enabled_bands = {} n_residues = 0 best_score = 0 start_score = 0 score_after_bc_wiggle = 0 rx = 0 -- Controls whether we should do a mini-fuze -- (Shake at Low CI, Wiggle at CI of 1) after -- completion of the Rebuild sequence. -- A value of 0 means do it iff there's an overall improvement: -- a high negative value would mean do it always: -- a high positive value would mean do it always. post_rebuild_threshold = 2 -- For monitoring loss_from_low_ci_wiggle = {} DEBUGRUN = false n_loop_residues = 0 n_helix_residues = 0 n_sheet_residues = 0 start_time = os.time() rx_worst = 0 rx_all = 0 best_post_rxs_a = kInvalidScore -- best after rebuild and shake, slot A best_post_rxs_b = kInvalidScore -- best after rebuild and shake, slot B CIfactor=behavior.GetClashImportance() maxCI = true -- for future use -- Above sets the globals -- ========================================================================================= -- Below defines the functions function DebugPrint ( str ) if DEBUGRUN then print ( str ) end end function setCI(CInr) if CInr > 0.99 then maxCI=true else maxCI=false end behavior.SetClashImportance(CInr*CIfactor) end function r0 ( x ) -- Round to 0 decimal places return math.floor ( x + 0.5 ) -- x = -2.5 to -1.5001 becomes -2.0 -- x = -1.5 to -0.5001 becomes -1.0 -- x = -0.5 to 0.4999 becomes 0.0 -- x = 0.5 to 1.4999 becomes 1.0 -- x = 1.5 to 2.4999 becomes 2.0 -- x = 2.5 to 3.4999 becomes 3.0 end function r3 ( x ) -- Round to 3 decimal places t = 10 ^ 3 return math.floor ( x*t + 0.5 ) / t end function trunc3 (x) -- truncates to 3 decimal places -- as for the scores listed in Foldit GUI return math.floor(x*1000)/1000 end function GetScore () local score = 0 if score_type == ST_NORMAL then score = current.GetEnergyScore () elseif score_type == ST_HIDING then score = 0 for i = 1 , n_residues do score = score + current.GetSegmentEnergySubscore ( i , "hiding" ) end elseif score_type == ST_BONDING then score = 0 for i = 1 , n_residues do score = score + current.GetSegmentEnergySubscore ( i , "bonding" ) end elseif score_type == ST_FILTERS then behavior.SetSlowFiltersDisabled ( false ) score_with_filters = current.GetEnergyScore () behavior.SetSlowFiltersDisabled ( true ) score_without_filters = current.GetEnergyScore () score = score_with_filters - score_without_filters elseif score_type == ST_SLOWFILT then behavior.SetSlowFiltersDisabled ( false ) score = current.GetEnergyScore () behavior.SetSlowFiltersDisabled ( true ) end return score end function DoesPuzzleHaveSlowFilters () local init_setting = behavior.GetSlowFiltersDisabled () if init_setting == false then score_without_sf = current.GetEnergyScore () behavior.SetSlowFiltersDisabled ( true ) score_with_sf = current.GetEnergyScore () else score_with_sf = current.GetEnergyScore () behavior.SetSlowFiltersDisabled ( false ) score_without_sf = current.GetEnergyScore () end behavior.SetSlowFiltersDisabled ( init_setting ) if math.abs ( score_without_sf - score_with_sf ) > 1e-3 then return true else return false end end function Coprime ( n ) -- 11/15/17 http://primes.utm.edu/lists/small/1000.txt -- lists the following plus many more prime numbers: 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, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997,1009,1013} local i = #primes -- find the highest prime < 70% of the residue count -- and which is coprime with the number of residues while i >= 1 do if primes [ i ] < n*0.7 and n % primes [ i ] ~= 0 then return primes [ i ] end i = i - 1 end return 1 end function SegmentComposition ( first, last ) -- Returns number of residues of each secondary structure type local n_loop_residues = 0 local n_helix_residues = 0 local n_sheet_residues = 0 for i = first, last do ss = structure.GetSecondaryStructure ( i ) if ss == "L" then n_loop_residues = n_loop_residues + 1 elseif ss == "H" then n_helix_residues = n_helix_residues + 1 elseif ss == "E" then n_sheet_residues = n_sheet_residues + 1 end end return n_loop_residues, n_helix_residues, n_sheet_residues end function IsSegmentRebuildable ( first, last ) local tot = 0 for i = first, last do tot = tot + rebuild_list[i] end if tot < rebuild_length then return false end -- Above checks if enough residues in the segment are in the rebuild_list. -- Below checks if the segment is rebuildable in the sense that its -- secondary structure satisfies the specified criteria. n_loop_residues,n_helix_residues,n_sheet_residues=SegmentComposition(first,last) if ss_criterion == 1 then -- Loops only if n_helix_residues > 0 or n_sheet_residues > 0 then return false else return true end elseif ss_criterion == 2 then -- Loops with one non-loop residue if n_helix_residues + n_sheet_residues > 1 then return false else return true end elseif ss_criterion == 3 then -- Loops or sheets if n_helix_residues > 0 then return false else return true end elseif ss_criterion == 4 then return true end end function ConvertToLoop ( first , last ) -- Slightly inefficient to call SegmentComposition twice n_loop_residues,n_helix_residues,n_sheet_residues=SegmentComposition(first,last) if n_helix_residues + n_sheet_residues > 0 then selection.DeselectAll ( ) selection.SelectRange ( first , last ) structure.SetSecondaryStructureSelected ( "L" ) end end function pseudorandom ( score ) -- Returns a pseudorandom number >= 0 and < 1. -- Based on the fractional part of the score if score >= 0 then return score % 1 else return ( -score ) % 1 end end function GetListOfFixedResidues () for i = 1 , n_residues do fixed_residues [ i ] = false end for i = 1 , n_residues do seg_backbone_frozen, seg_sidechain_frozen = freeze.IsFrozen ( i ) -- what to do if just the sidechains are frozen? if seg_backbone_frozen then fixed_residues [ i ] = true end s = structure.IsLocked ( i ) if s then fixed_residues [ i ] = true end end end function DoesSectionContainFixedResidues ( start_idx , end_idx ) for i = start_idx , end_idx do if fixed_residues [ i ] then return true end end return false end function ShakeLowCIWiggle ( c_score ) save.Quicksave ( kTemp ) setCI ( 0.10 ) structure.ShakeSidechainsSelected ( 1 ) setCI ( 1 ) structure.WiggleSelected ( kDefaultWiggleDuration ) local score = GetScore () if score < c_score then save.Quickload ( kTemp ) score = c_score end end function FinalIdealize ( c_score , start_idx , end_idx ) kFallApartThreshold = 1000 save.Quicksave ( kTemp ) selection.DeselectAll () selection.SelectRange ( start_idx , end_idx ) structure.IdealizeSelected () local score_after_idealize = GetScore () selection.SelectAll () if c_score - score_after_idealize > kFallApartThreshold then structure.WiggleAll ( 1, false , true ) -- wiggle sidechains end if math.abs ( score - c_score ) > 1e-3 then structure.WiggleSelected ( 12 ) score = GetScore () if score < c_score then save.Quickload ( kTemp ) score = c_score end end end function WiggleNudge ( c_score ) save.Quicksave ( kTemp ) structure.WiggleSelected ( kDefaultWiggleDuration ) local aa_score = GetScore () if aa_score < c_score then save.Quickload ( kTemp ) aa_score = c_score -- Cater to filter-induced score decrease end save.Quicksave ( kTemp ) setCI ( kLowCiWiggle ) structure.WiggleSelected ( 1 ) table.insert ( loss_from_low_ci_wiggle , aa_score - GetScore () ) setCI ( 1 ) structure.WiggleSelected ( kDefaultWiggleDuration ) score = GetScore () if score < aa_score then save.Quickload ( kTemp ) end end function WiggleTwoBestCandidatesAndSelectBest () save.Quickload ( kBestPostRebuild_a ) structure.WiggleSelected ( kDefaultWiggleDuration ) local score_a = GetScore () save.Quicksave ( kBestPostRebuild_a_post_wiggle ) if best_post_rxs_b > kInvalidScore then -- To cater for single rebuild save.Quickload ( kBestPostRebuild_b ) structure.WiggleSelected ( kDefaultWiggleDuration ) local score_b = GetScore () if score_a > score_b then save.Quickload ( kBestPostRebuild_a_post_wiggle ) end end end function PostWiggle () local init_score = GetScore () save.Quicksave ( kTemp ) if score_type == ST_HIDING or score_type == ST_BONDING or score_type == ST_FILTERS then return true -- Hiding or bonding elseif best_score - init_score < pw_threshold_value then structure.ShakeSidechainsSelected ( 1 ) score = GetScore () if score < init_score then save.Quickload ( kTemp ) -- Cater for filters causing a decrease score = init_score end WiggleNudge ( score ) return true else return false end end function FinalFuse ( start_x , end_x ) -- After rebuilding, if we've got a new best score -- (tweakable by adjusting post_rebuild_threshold), -- do a shake at low CI followed by a wiggle local init_score = GetScore () local score_below_best = best_score - init_score if score_type == ST_HIDING or score_type == ST_BONDING or score_type == ST_FILTERS then return -- Hiding or bonding elseif score_below_best < post_rebuild_threshold then if fidealize then FinalIdealize ( init_score , start_x , end_x ) else ShakeLowCIWiggle ( init_score ) end return else return end end function RecordImprovement () local curr_score = GetScore () local new_gain = curr_score - best_score local all_gain = curr_score - start_score best_score = curr_score save.LoadSecondaryStructure () save.Quicksave ( kOriginalStructureOrNewBest ) print ( "+" .. r3( new_gain ) .. " to " .. trunc3 ( best_score ) .. string.format ( " (%d%% of total gain)", r0 ( 100 * new_gain / all_gain ) ) ) return end function ConstructListOfResiduesWithinInnerSphere ( start_idx , end_idx ) for i = 1 , n_residues do inner_sphere [ i ] = false end for i = 1 , n_residues do for j = start_idx , end_idx do if structure.GetDistance ( i , j ) < kInnerSphereRadius then inner_sphere [ i ] = true end end end end function SelectInnerSphere () selection.DeselectAll () for i = 1 , n_residues do if inner_sphere [ i ] then selection.Select ( i ) end end end function ConstructListOfResiduesWithinOuterSphere ( start_idx , end_idx ) for i = 1 , n_residues do outer_sphere [ i ] = false end for i = 1 , n_residues do for j = start_idx , end_idx do if structure.GetDistance ( i , j ) < kOuterSphereRadius then outer_sphere [ i ] = true end end end end function SelectOuterSphere () selection.DeselectAll () for i = 1 , n_residues do if outer_sphere [ i ] then selection.Select ( i ) end end end function RebuildPreamble ( start_idx , end_idx ) save.Quickload ( kOriginalStructureOrNewBest ) if convert_to_loop then ConvertToLoop ( start_idx , end_idx ) end selection.DeselectAll () selection.SelectRange ( start_idx , end_idx ) end function RebuildSeg ( start_idx , end_idx, ndx, tot ) local action = "remix" if not run_remix then action = "rebuild" end print ( action .. " " .. start_idx .. "-" .. end_idx .. " (" .. ndx .. "/" .. tot .. ")" ) local n_remix = 0 local n_rebuilds = 0 local n_good_rebuilds = 0 local rb = 0 local rx = 0 local rb1 = 0 -- rebuild position number local rx1 = 0 -- remix position number best_post_rxs_a = kInvalidScore best_post_rxs_b = kInvalidScore ConstructListOfResiduesWithinInnerSphere ( start_idx , end_idx ) ConstructListOfResiduesWithinOuterSphere ( start_idx , end_idx ) local use_remix = run_remix if use_remix then DebugPrint ( "trying remix" ) RebuildPreamble ( start_idx , end_idx ) n_remix = structure.RemixSelected ( kRemixQuicksaveStart , number_of_rebuilds ) DebugPrint ( "remixes found = " .. n_remix ) if n_remix == 0 then print ( "remix failed, trying rebuild" ) n_rebuilds = number_of_rebuilds use_remix = false action = "rebuild" rx = 0 else use_remix = true rx = 1 end else DebugPrint ( "doing rebuild" ) action = "rebuild" n_rebuilds = number_of_rebuilds end if rx >= 1 then rx=n_remix else rx=n_rebuilds end for i = 1 , rx do DebugPrint ( "RebuildSeg main loop, run " .. i .. "/" .. rx ) if use_remix then DebugPrint ( "loading remix " .. i .. " from slot " .. kRemixQuicksaveStart - 1 + i ) save.Quickload ( kRemixQuicksaveStart -1 + i ) rx = n_remix else DebugPrint ( "doing rebuild" ) RebuildPreamble ( start_idx , end_idx ) structure.RebuildSelected ( 1 ) rb = n_rebuilds end score_after_rebuild = GetScore () DebugPrint ( "score after " .. action .. " = " .. r3 ( score_after_rebuild ) ) if math.abs ( score_after_rebuild - best_score ) >= 1e-5 then n_good_rebuilds = n_good_rebuilds + 1 SelectInnerSphere () structure.ShakeSidechainsSelected ( 1 ) local score_after_shake_wiggle = GetScore () DebugPrint ( "score after shake, wiggle = " .. r3 ( score_after_shake_wiggle ) ) if score_after_shake_wiggle > math.min ( best_post_rxs_a, best_post_rxs_b ) then if best_post_rxs_b < best_post_rxs_a then best_post_rxs_b = score_after_shake_wiggle save.Quicksave ( kBestPostRebuild_b ) DebugPrint ( "saved post-rebuild slot b, score = " .. r3 ( best_post_rxs_b ) ) else best_post_rxs_a = score_after_shake_wiggle save.Quicksave ( kBestPostRebuild_a ) DebugPrint ( "saved post-rebuild slot a, score = " .. r3 ( best_post_rxs_a ) ) end end end end -- for i if n_good_rebuilds == 0 then print ( "no valid remixes or rebuilds found" ) end return n_good_rebuilds end function RebuildAllAtSpecifiedLength ( rebuild_length ) local inc local max_possible_residue = max_residue - rebuild_length + 1 local n_possible_segs = max_possible_residue - min_residue + 1 local r = pseudorandom ( best_score ) local start_idx = min_residue + n_possible_segs * r start_idx = start_idx - start_idx % 1 inc = Coprime ( n_possible_segs ) -- increment used for start_idx -- The point of this Coprime, start_idx business is so we go through the protein in a -- nonuniform way. Rather than rebuilding 1-4, 2-5 , 3-6 for example, we might do 21-24, 53-57, 3-6 -- or something like that candidate_section_found = false rx_all = rx_all + 1 print("== Remix/rebuild all run " .. rx_all .. ": "..os.date( "%x %X" ).." ==") for i = 1 , n_possible_segs do local end_idx = start_idx + rebuild_length - 1 assert ( start_idx >= min_residue and end_idx <= max_residue , "Range error" ) save.LoadSecondaryStructure () if DoesSectionContainFixedResidues ( start_idx , end_idx ) == false and IsSegmentRebuildable ( start_idx , end_idx ) then candidate_section_found = true DebugPrint("("..i.."/"..n_possible_segs..")") DebugPrint(n_possible_segs+1-i .. " segments left to do") if RebuildSeg ( start_idx , end_idx, i, n_possible_segs ) > 0 then SelectOuterSphere () WiggleTwoBestCandidatesAndSelectBest () score_after_bc_wiggle = GetScore () if PostWiggle () then score_after_post_wiggle = GetScore () FinalFuse ( start_idx , end_idx ) score_after_final_fuse = GetScore () if score_after_final_fuse > best_score then DebugPrint ( " " .. r3 ( score_after_bc_wiggle - best_score ) .. " " .. r3 ( score_after_post_wiggle - score_after_bc_wiggle ) .. " " .. r3 ( score_after_final_fuse - score_after_post_wiggle ) ) RecordImprovement () -- prints new score else DebugPrint ( " " .. r3 ( score_after_bc_wiggle - best_score ) .. " " .. r3 ( score_after_post_wiggle - score_after_bc_wiggle ) ) end -- if score else DebugPrint ( " " .. r3 ( score_after_bc_wiggle - best_score ) ) end -- if PostWiggle else print ( "skipped " .. start_idx .. "-" .. end_idx .. " (" .. i .. "/" .. n_possible_segs .. ")" ) end -- if RebuildSeg end -- if DoesSectionContainFixedResidues start_idx = start_idx + inc if start_idx > max_possible_residue then start_idx = start_idx - n_possible_segs end end -- for i if candidate_section_found == false then print ( "No rebuildable sections found" ) exit (0) end end -- -- the function Sort is taken from http://fold.it/portal/recipe/49233 -- "Tvdl enhanced DRW 3.0.1" by Timo van der Laan -- function Sort ( tab, items ) --BACKWARD bubble sorting - lowest on top, only needed items for xx = 1, items do --items do for yy = xx + 1, #tab do if tab [ xx ] [ 1 ] > tab [ yy ] [ 1 ] then tab [ xx ], tab [ yy ] = tab [ yy ], tab [ xx ] end end end return tab end function Rebuild_Worst(howmany, rebuild_length) local segCnt = structure.GetCount() -- -- get the score of each segment, store it in a table -- local scoreTab = {} -- a new, empty table for ii = 1, segCnt do scoreTab [ #scoreTab + 1 ] = current.GetSegmentEnergyScore ( ii ) end -- -- now get the worst sections of the specified length -- local worstTab = {} -- another new empty table for ii = 1, segCnt - rebuild_length + 1 do local partScore = 0 for jj = ii, ii + rebuild_length - 1 do partScore = partScore + scoreTab [ jj ] end worstTab [ #worstTab + 1 ] = { partScore, ii, ii + rebuild_length - 1 } end local buildWorst = howmany worstTab = Sort ( worstTab, buildWorst ) local max_possible_residue = max_residue local n_possible_segs = max_possible_residue - min_residue + 1 candidate_section_found = false rx_worst = rx_worst + 1 print( "== Remix/rebuild worst run " .. rx_worst .. ": "..os.date( "%x %X" ).." ==") for i = 1 , howmany do DebugPrint(howmany+1-i .. " segments left to do") local seg = worstTab [ i ] [ 2 ] local end_idx = worstTab [ i ] [ 3 ] save.LoadSecondaryStructure () if DoesSectionContainFixedResidues ( seg , end_idx ) == false and IsSegmentRebuildable ( seg , end_idx ) then candidate_section_found = true if RebuildSeg ( seg , end_idx, i, howmany ) > 0 then SelectOuterSphere () WiggleTwoBestCandidatesAndSelectBest () score_after_bc_wiggle = GetScore () if PostWiggle () then score_after_post_wiggle = GetScore () FinalFuse ( seg , end_idx ) score_after_final_fuse = GetScore () if score_after_final_fuse > best_score then DebugPrint ( "best candidate wiggle gain = " .. r3 ( score_after_bc_wiggle - best_score ) .. ", post wiggle gain = " .. r3 ( score_after_post_wiggle - score_after_bc_wiggle ) .. ", final fuze gain = " .. r3 ( score_after_final_fuse - score_after_post_wiggle ) ) RecordImprovement () -- prints new score else DebugPrint ( "best candidate wiggle loss = " .. r3 ( score_after_bc_wiggle - best_score ) .. ", post wiggle loss = " .. r3 ( score_after_post_wiggle - score_after_bc_wiggle ) ) end -- if score else DebugPrint ( " " .. r3 ( score_after_bc_wiggle - best_score ) ) end -- if PostWiggle else print ( "skipped " .. seg .. "-" .. end_idx .. " (" .. i .. "/" .. n_possible_segs .. ")" ) end -- if RebuildSeg end -- if DoesSectionContainFixedResidues end -- for i if candidate_section_found == false then print ( "No rebuildable sections found" ) exit (0) end end function PrintParameters () print ( "options:" ) if score_type == ST_NORMAL then print ( "Score type: Normal" ) elseif score_type == ST_HIDING then print ( "Score type: Hiding" ) elseif score_type == ST_BONDING then print ( "Score type: Bonding" ) elseif score_type == ST_FILTERS then print ( "Score type: Filters" ) elseif score_type == ST_SLOWFILT then print ( "Score type: Normal/Slow Filters" ) end -- if score_type print(string.format("Start score: %.3f",trunc3(best_score))) print ( "Remix/rebuild length: " .. rebuild_length ) if ss_criterion == 1 then print ( "Remix/rebuild loops only" ) elseif ss_criterion == 2 then print ( "Remix/rebuild loops + 1" ) elseif ss_criterion == 3 then print ( "Remix/rebuild loops + sheets" ) elseif ss_criterion == 4 then print ( "Remix/rebuild any" ) end -- ss_criterion if convert_to_loop then print ( "Converting to loops" ) end if run_remix then print ( "Using remix" ) end if rebuild_worst then print ( "Remix/rebuild worst segments" ) end if fidealize then print ( "Run final idealize in final fuze" ) else print ( "Run ShakeLowCIWiggle in final fuze" ) end print ('Remix/rebuild = \"'..rebuild_str..'\" = \"'..printlist(rebuild_list)..'\"') print ( "Remix/rebuild range " .. min_residue .. " to " .. max_residue ) print ( "N of remixes/rebuilds " .. number_of_rebuilds ) if keep_bands then print('Won\'t disable bands') end print ('CI factor = ' .. CIfactor ) print ( "--" ) end -- http://www.lua.org/manual/5.2/manual.html#6.4 -- helped make this function 11/16/17 function getlist(liststr) local newlist={} local ilo,ihi,idir,substr for i=1,n_residues do newlist[i]=0 end -- for i -- below reads from liststr a series of substr's -- where each substr contains an integer -- followed by one or more '-' signs -- followed by an integer for substr in string.gmatch(liststr,"(%d+%-+%d+)") do -- substr includes one or more '-' characters in a row -- below gets ilo & ihi from substr ilo=string.gsub(substr,"(%d+)%-+(%d+)","%1")+0 ihi=string.gsub(substr,"(%d+)%-+(%d+)","%2")+0 -- above gets ilo & ihi from substr idir=1 -- the increment to use from ilo to ihi if ilo>ihi then idir= -1 end -- if ilo for i=ilo,ihi,idir do -- for i=ilo to ihi step idir if i>=1 and i<=n_residues then newlist[i]=1 end -- if i end -- for i end -- for substr -- below reads from liststr a series of substr's -- where each substr contains an integer for substr in string.gmatch(liststr,"(%d+)") do i=substr+0 -- converts substr into the number i if i>=1 and i<=n_residues then newlist[i]=1 end -- if i end -- for substr return newlist end function checklist() local resinrow = 0 local maxresinrow = 0 local min_residue=0 local max_residue=0 for i=1,n_residues do if rebuild_list[i]==1 then resinrow=resinrow+1 max_residue=i if min_residue==0 then min_residue=i end else if resinrow>maxresinrow then maxresinrow=resinrow end resinrow=0 end -- if rebuild_list end -- for i if resinrow>maxresinrow then maxresinrow=resinrow end if maxresinrow<rebuild_length then print("Rebuild range error.") print("The list of residues to rebuild (\""..rebuild_str.."\" input above)") print("has at most "..maxresinrow.." of the desired "..rebuild_length.." residues in a row.") return false else return true end -- if maxresinrow end -- http://www.lua.org/manual/5.2/manual.html#6.4 -- helped make this function 11/16/17 function printlist(templist) local outstr='' local gotone,strlen gotone=0 for i=1,n_residues do if templist[i]==1 then gotone=gotone+1 if gotone==1 then outstr=(outstr..i) end -- if gotone else -- templist[i]==0 if gotone>1 then outstr=(outstr..'-'..(i-1)..' ') elseif gotone==1 then outstr=(outstr..' ') end -- if gotone gotone=0 end -- if templist end -- for i if gotone>1 then outstr=(outstr..'-'..n_residues) end -- if gotone strlen=string.len(outstr) if string.sub(outstr,strlen,strlen)==' ' then -- if outstr ends with a blank space, -- then remove that blank space outstr=string.sub(outstr,1,strlen-1) end return outstr end function GetOptionalParameters () local dlog = dialog.CreateDialog("Options") dlog.pw_threshold = dialog.AddSlider("Post sw threshold", pw_threshold_value, 0, 200, 0) dlog.cnvt_loops = dialog.AddCheckbox("Convert to loops", convert_to_loop) dlog.keep_bands = dialog.AddCheckbox("Keep bands", keep_bands) dlog.ok = dialog.AddButton ( "OK" , 1 ) dlog.cancel = dialog.AddButton ( "Cancel" , 0 ) if dialog.Show ( dlog ) > 0 then pw_threshold_value = dlog.pw_threshold.value convert_to_loop = dlog.cnvt_loops.value keep_bands = dlog.keep_bands.value return true else return false end end function GetParameters () local rc repeat local dlog = dialog.CreateDialog (prog_name) dlog.label_rxx = dialog.AddLabel("RXX = remix or rebuild") dlog.run_remix = dialog.AddCheckbox ( "Use remix (else rebuild)" , run_remix ) dlog.f_idealize = dialog.AddCheckbox ("Idealize instead of fuse" , fidealize) dlog.rb_worst = dialog.AddCheckbox ( "RXX worst segments (else RXX all)" , rebuild_worst ) dlog.rb_worst_howmany = dialog.AddSlider ( "How many worst" , howmany , 3 , structure.GetCount() , 0 ) dlog.rb_length = dialog.AddSlider ( "RXX length" , 6 , 3 , 9 , 0 ) dlog.rlabel_list = dialog.AddLabel("RXX Segments:") dlog.rebuild_list = dialog.AddTextbox ( "RXX segs" , rebuild_str ) dlog.rlabela = dialog.AddLabel('List segs to RXX like 1-3,6,19-30,45-62') dlog.rebuild_criterion = dialog.AddSlider ( "RXX criterion" , ss_criterion , 1 , 4 , 0 ) dlog.rc = dialog.AddLabel ( "1 = L only, 2 = L only + 1, 3 = L + E, 4 = Any" ) dlog.n_rebuilds = dialog.AddSlider ( "# of RXX" , number_of_rebuilds , 1 , 40 , 0 ) dlog.CIfactor = dialog.AddSlider ( "CI factor", CIfactor, 0.1, 1, 2 ) dlog.div_1 = dialog.AddLabel ( "__________________________________________" ) if DoesPuzzleHaveSlowFilters () then score_type = ST_SLOWFILT end dlog.score_type = dialog.AddSlider ( "Score type" , score_type , 1 , 5 , 0 ) dlog.tp = dialog.AddLabel ( "1 = Normal, 2 = Hiding, 3 = Bonding" ) dlog.tp_2 = dialog.AddLabel ( "4 = Filters, 5 = Normal for Slow Filters" ) dlog.DEBUGRUN = dialog.AddCheckbox ( "Debug", DEBUGRUN ) dlog.ok = dialog.AddButton ( "OK" , 1 ) dlog.cancel = dialog.AddButton ( "Cancel" , 0 ) dlog.other_options = dialog.AddButton ( "Other options" , 2 ) rc = dialog.Show ( dlog ) if rc > 0 then fidealize = dlog.f_idealize.value howmany = dlog.rb_worst_howmany.value rebuild_worst = dlog.rb_worst.value rebuild_length = dlog.rb_length.value rebuild_list = getlist(dlog.rebuild_list.value) rebuild_str = printlist(rebuild_list) ss_criterion = dlog.rebuild_criterion.value number_of_rebuilds = dlog.n_rebuilds.value run_remix = dlog.run_remix.value CIfactor = dlog.CIfactor.value score_type = dlog.score_type.value DEBUGRUN = dlog.DEBUGRUN.value if rc == 2 then GetOptionalParameters () end end until rc <= 1 return rc > 0 end function main() local n_enabled, n_disabled, templist n_bands = band.GetCount () n_enabled = 0 n_disabled = 0 for i = 1, n_bands do orig_enabled_bands [i] = false if band.IsEnabled(i) then orig_enabled_bands [i] = true n_enabled = n_enabled + 1 else n_disabled = n_disabled + 1 end end n_residues = structure.GetCount () for i = 1, n_residues do original_secondary_structure [ i ] = structure.GetSecondaryStructure ( i ) end save.SaveSecondaryStructure () templist = string.format('1-%d',n_residues) rebuild_str=templist rebuild_list=getlist(templist) save.Quicksave ( kOriginalStructureOrNewBest ) setCI ( 1 ) original_slow_filters_setting = behavior.GetSlowFiltersDisabled () if not GetParameters () then return end best_score = GetScore () start_score = best_score print(string.format('%s (%s)\nPuzzle %s (%s)', prog_name, ui.GetPlatform(), puzzle.GetName(), puzzle.GetPuzzleID())) print(string.format('%d residues, %d bands (%d enabled, %d disabled)', n_residues, n_bands, n_enabled, n_disabled)) if not checklist() then return end PrintParameters () start_time = os.time () if keep_bands == false then band.DisableAll () -- turns all bands gray end GetListOfFixedResidues () -- the main loop is endless... while true do if rebuild_worst then Rebuild_Worst(howmany,rebuild_length) end RebuildAllAtSpecifiedLength ( rebuild_length ) end print('This line should never be reached') cleanup() end function cleanup (errmsg) if CLEANUPENTRY ~= nil then return end CLEANUPENTRY = true print ( "---" ) local reason local start, stop, line, msg if errmsg == nil then reason = "complete" else start, stop, line, msg = errmsg:find ( ":(%d+):%s()" ) if msg ~= nil then errmsg = errmsg:sub ( msg, #errmsg ) end if errmsg:find ( "Cancelled" ) ~= nil then reason = "cancelled" else reason = "error" end end print ( prog_name .. " " .. reason .. " " .. os.date ( "%x %X" )) if reason == "error" then print ( "Unexpected error detected" ) print ( "Error line: " .. line ) print ( "Error: \"" .. errmsg .. "\"" ) end local tot setCI ( 1.0 ) save.Quickload ( kOriginalStructureOrNewBest ) best_score = GetScore() if convert_to_loop then save.LoadSecondaryStructure () end selection.SelectAll () if keep_bands == false then for i=1,n_bands do -- turn certain bands purple again if orig_enabled_bands[i] then band.Enable(i) end end -- for i end -- if keep_bands behavior.SetSlowFiltersDisabled ( original_slow_filters_setting ) end_time = os.time () print("Elapsed time: "..os.difftime(end_time,start_time).." secs") print("Final score: "..trunc3(best_score)) print("Start score: "..trunc3(start_score)) print("Gain: "..trunc3(best_score - start_score)) if #loss_from_low_ci_wiggle > 1 then table.sort ( loss_from_low_ci_wiggle ) mid_pt = math.ceil ( #loss_from_low_ci_wiggle / 2 ) print("Median loss from low ci ("..kLowCiWiggle..") wiggle "..r3(loss_from_low_ci_wiggle[mid_pt])) end end xpcall ( main , cleanup )

Comments


LociOiling Lv 1

Thanks to ZeroLeak7 for Loop Remix/Rebuild 12.0 and 12.5. The original Loop Rebuild was created by spvincent, then extended by jeff101. Later, spvincent shifted to Loop Remix, which dropped the rebuild capability.

In ZeroLeak7's version, both remix and rebuild are supported.

This version of Loop Remix/Rebuild rearranges and simplifies the main menu. It also reformats much of the scriptlog output to help clarify what the recipe is doing.

Some points to note:

  • Loop Remix/Rebuild by default does remix. If no remixes are found for a given segment range, it tries rebuilding the range instead.

  • If "use remix" isn't checked, Loop Remix/Rebuild uses rebuild only. It does not try remixing ranges where no rebuild is found.

  • Loop Remix/Rebuild has two modes of operation. The first is to remix or rebuild the worst segments first. This mode is engaged when the "RXX worst segments" option is checked. ("RXX" is short for "remix/rebuild".) The number of worst segments is remix or rebuild is an option for this mode.

  • The second mode is to remix or rebuild everything. Loop Remix/Rebuild enters this mode after the "worst" mode completes, or if "worst" isn't selected.

  • Loop Remix/Rebuild runs until cancelled.

  • Loop Rebuild/Remix 12.6 shows the initial clashing importance as "CI factor" in the main dialog. CI factor is to scale all CI changes in the rest of the recipe, then restored at the end. This is similar to how TvdL Enhanced DRW and other recipes handle CI

Loop Remix/Rebuild 12.6 includes the following changes:
+ fix a crash if "use remix" isn't selected
+ trim some obsolete features (exploration mode, design puzzle, "are conditions met", …)
+ condense score types
+ move some messages to debug status, rework others
+ adjust the scope of some variables
+ simplify "if", "elseif", "while", and "until" statements ala Lua
+ minor code reformatting here and there
+ print gain at end
+ honor initial CI ala gmn, new "CI factor" slider

Internally, the goal is to minimize changes to the code. Everything should be in the same relative position as in the original. There has been only limited reformatting.

LociOiling Lv 1

Differences between Loop Remix/Rebuild and and DRemixW/Enhanced DRW

In a number of ways, Loop Remix/Rebuild (LRR) takes a different approach than the classic Timo van der Laan remix and rebuild recipes.

The differences include:

  • LRR only rebuilds one length, ranging from 3 to 9 segments, in a given run
  • LRR does not evaluate a given remix or rebuild according to multiple subscores
  • LRR compares each remix/rebuild at a given position, keeping track of the best two
  • LRR does not offer a option to customize which subscores count in determining the "worst" segments
  • LRR does terminate after a fixed number of runs, and instead must be cancelled
  • when remixing/rebuilding all segments, LRR does not randomize the possible segments in a standard way
  • LRR uses "coprime" logic to determine the order when working on all segments
  • LRR has smaller defaults for the number of remix/rebuild operations at a given point

The net effect of these differences is that LRR may be faster than classic remix/rebuild recipes, especially on large puzzles. LRR doesn't maintain large tables in the way the classic recipes do. For example, the classic recipes have a table containing all subscores for every segment in the puzzle. The classic recipes also maintain lots of lists, such as a list of segments already worked on.

The tables and lists may tend to slow down the classic recipes on large puzzles, due to what's known as "quadratic behavior". By keeping things simple, LRR may reduce the performance impact of a very large puzzle.

bravosk8erboy Lv 1

i am a little out of the "loop" on these recipes. does it rebuild across terminal gaps? or does it do one side then the other side?

bravosk8erboy Lv 1

Recipe Crash Report
remix 73-76 (98/101)

Loop Remix/Rebuild 12.6 error 10/02/25 08:43:42
Error line: 678
Error: "attempt to index field '?' (a nil value)"

with rebuild length 4 i think that there are not 101 possible selections with only 101 segments.
howmany for 675 should probably have a max value of segment count minus selection length
—— Or it should not exceed #worstTab