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 )