Code
--MicroRemix v2.0 --working version v207. RG 04/03/2019
--[[Based on spvincent microIdealize March 2014
changed to remix BK 05/03/2014
1.2 Added more dialog and options 20/03/2014
12/04/2014 better log + added restore
2.0 04/03/2019 fixed and adapted to new remix tool by robgee
2.1 06/03/2019 added UseCuts: not cutting, by default now
]]--
recipename= "MicroRemix 2.1"
kOriginalStructureOrNewBest = 1 -- the starting structure, or any subsequent improvement, will be stored in this quicksave slot
OriginalStructure = 2 --the starting structure held here, just in case
best_score = 0
remix_length = 3
remix_lengthFrom=3-- works from 3 to 9 only
remix_lengthTo=9 -- works from 3 to 9 only
min_residue = 1
max_residue = 999
sphere = {}
kSphereRadius = 10
kbestremixslot1=15 -- temp remix slots are 30-100
original_secondary_structure = {}
number_of_remix=8 -- max number of remix per zone (break if no replacement found). 8 is a good number for some puzzles
n_residues = 0
curr_score = 0
MoreInfo=false -- true only if you want to check the options
skipShake=false -- shake is not very useful here, you might skip it to save time
UseCuts=false -- cuts is not necessarilly usefull for remix; to be evaluated
WiggleThreshold=-1 -- do wiggle if loss is less than
NoProposals= true -- remix does not propose anything yet
failingsLimit=100 -- if the remix does not propose anything after this rounds, suggests to stop the script
failings=0 --init
--[[ SLOTS
quicksave_start = 30 -- Start of quicksave slots for returned remixes
so we have maximum 70 remixe slots
]]--
Debugrun = false
function debugprint(str)
if Debugrun then
print(str)
end
end--KarenCH
function r3 ( i )
-- printing convenience
return i - i % 0.001
end
function r1(i)
return i - i % 1
end
function GetScore ()
score = current.GetEnergyScore ()
return score
end
function SphereSelect ( start_idx , end_idx )
for i = 1 , n_residues do
sphere [ i ] = false
end
for i = 1 , n_residues do
for j = start_idx , end_idx do
if ( structure.GetDistance ( i , j ) < kSphereRadius ) then
sphere [ i ] = true
end
end
end
selection.DeselectAll ()
for i = 1 , n_residues do
if ( sphere [ i ] == true ) then
selection.Select ( i )
end
end
end
function Do_Remix()
--print("Zone length", remix_length)
if remix_length > 2 and remix_length < 10 then -- 22/02/2014
recentbest.Save () --19/02/2014
save.Quicksave(kbestremixslot1)
CutScoreBeforeRemix = GetScore ()
bestremixscore = GetScore () - 900000 -- threshold to be adapted
local replacement = true -- was 'local replacements = true'
local quicksave_start = 30 -- Start of quicksave slots for returned remixes
local rmx_found = structure.RemixSelected(quicksave_start, number_of_remix) --get remixes; default = 6
debugprint('rmx_found '..rmx_found)
for i = 0, rmx_found - 1 do --iterate thru returned remixes
--print('quicksave:',30+i)
if rmx_found == 0 then
print ('No remix found')
--replacements = false --what does this do ??
replacement = false --should it be this ??
break
end
save.Quickload(quicksave_start + i)--load next remix
curr_score = GetScore ()--no threshold value here ???
-------------------------------------------------------------
if MoreInfo then
print("Temp score after remix:",curr_score," in Qsave:",quicksave_start + i)
end
---------------------------------------------------------------------------------------
if curr_score>bestremixscore then -- local best only for this remix attempt
bestremixscore=curr_score
save.Quicksave(kbestremixslot1)--this is saved with cuts in !!!
end
------------------------------------------------------------------------------------------------------
if replacement==true then NoProposals= false end -- finally, we can trust remix here !
end
-- ================================================================================
--print('rmx_found',rmx_found ,' replacement',replacement,' NoProposals',NoProposals)--dbg
if replacement then
save.Quickload(kbestremixslot1) -- take the best attempt for this zone
curr_score = GetScore ()
debugprint('best scoring of '..rmx_found..' remixes',curr_score)--dbg
if curr_score ~= CutScoreBeforeRemix and not skipShake then
behavior.SetClashImportance(0.05)
structure.ShakeSidechainsSelected(1)
behavior.SetClashImportance(1)
end
curr_score = GetScore ()
if MoreInfo then
if UseCuts then
print("Best cut score after remix round:",curr_score)
else
print("Best temp score after remix round:",curr_score)
end
end
end
end
end
function Go ( remix_length )
for i = min_residue, max_residue - ( remix_length ) do --; -1 here ???
save.Quickload ( kOriginalStructureOrNewBest )
local ScoreBeforeRemix=GetScore ()
local validcut1 = false
local validcut2 = false
local selectseg_start = i --3 rm=3
local selectseg_stop = i + remix_length - 1 --3+3-1=5; 3,4,5=3segs
local cutpoint1 = selectseg_start -2 -- if cutpoint is negative, there will be no cut
local cutpoint2 = selectseg_stop +2
if cutpoint1 > 0 and UseCuts then -- added UseCuts 6/3/2019
validcut1 = true
end
if cutpoint2 > 0 and cutpoint2 < n_residues and UseCuts then -- added UseCuts 6/3/2019
validcut2 = true
end
if ( validcut1 ) then
structure.InsertCut ( cutpoint1 )
end
if ( validcut2 ) then
structure.InsertCut ( cutpoint2 )
end
selection.DeselectAll ()
selection.SelectRange ( selectseg_start, selectseg_stop )
if MoreInfo then
print('====================================')
print("How many remixes:", number_of_remix)
print("Remix length:", remix_length)
print('cut segments values:', cutpoint1, cutpoint2 )
print("selected segs:", selectseg_start..'-'..selectseg_stop )
end
Do_Remix()
------------------------------------------------------------------------------------------------
if NoProposals then failings = failings+1--Once set to false it will never become true again !!
debugprint('failings '..failings)
if failings>failingsLimit then
print("REMIX FAILED TO PROPOSE ANYTHING YET")
print("Please consider stopping the script")
failingsLimit=failingsLimit*2
end
end
---------------------------------------------------------------
if ( validcut1 ) then
structure.DeleteCut ( cutpoint1 ) --deleting cuts here means remix stuff is saved with cuts.
end
if ( validcut2 ) then
structure.DeleteCut ( cutpoint2 )
end
---------------------------------------------------------------------------------------------------
if not NoProposals then --if nothing proposed: saves time in the beginning !!
score = GetScore ()
if MoreInfo and math.abs(score-ScoreBeforeRemix) > 2 then print("Score after remix=" .. score) end
---------------------------------------------------------------------
if score > ScoreBeforeRemix - WiggleThreshold then
debugprint('Wiggling')---dbg
SphereSelect ( i + 1 , i + remix_length )
structure.WiggleSelected ( 6 ) -- not too much, we concentrate here mostly on remix gains (was 10 now 6)
end
---------------------------------------------------------------------------------
score = GetScore ()
if ( score > best_score ) then
best_score = score
print ( "+++ Improvement to ".. best_score )
if not MoreInfo then print ( "Zone " .. "Score ".."Start ".."Best ".."Total gain") end
save.Quicksave ( kOriginalStructureOrNewBest )
end
if MoreInfo then
print("Wiggled remix score:",r3(score))
print ( "Zone " .. "Score ".."Start ".."Best ".."Total gain") -- this prints however if not more info, only for gains (see above)
end
--this always prints !!
print ( i + 1 .."-".. i + remix_length.." "..r1(score).." "..r1(startScore).." "..r1(best_score).." "..best_score-startScore)
end
end
end
function GetParameters ()
local dlog = dialog.CreateDialog ( "Micro Remix 2.0" )
dlog.remix_lengthFrom = dialog.AddSlider ( "From remix length" , remix_lengthFrom , 3 , 9 , 0 )
dlog.remix_lengthTo = dialog.AddSlider ( "To remix length" , remix_lengthTo , 3 , 9 , 0 )
dlog.number_of_remix = dialog.AddSlider ( "Remix per zone" , number_of_remix , 1 , 69 , 0 )-- 06/03/2019
dlog.label3=dialog.AddLabel("(Small is fast. Long remix length is very slow)")
dlog.min_residue = dialog.AddSlider ( "Min residue" , 1 , 1 , n_residues-9 , 0 )
dlog.max_residue = dialog.AddSlider ( "Max residue" , n_residues , 9, n_residues , 0 )
dlog.WiggleThreshold = dialog.AddSlider ( "Wiggle Threshold" , WiggleThreshold , -5, 1000 , 0 )-- 20/03/2014
dlog.label2=dialog.AddLabel("Small is fast. Negative = after gain only")
dlog.skipShake=dialog.AddCheckbox("Skip shake (fast)",skipShake)-- 20/03/2014
dlog.UseCuts=dialog.AddCheckbox("Use cuts",UseCuts)-- 6/3/2019 not sure cutting is usefull for remix
dlog.MoreInfo=dialog.AddCheckbox("Display more info",MoreInfo)-- 20/03/2014
dlog.ok = dialog.AddButton ( "OK" , 1 )
dlog.cancel = dialog.AddButton ( "Cancel" , 0 )
if ( dialog.Show ( dlog ) > 0 ) then
--remix_length = dlog.remix_length.value
remix_lengthFrom= dlog.remix_lengthFrom.value
remix_lengthTo= dlog.remix_lengthTo.value
min_residue = dlog.min_residue.value
max_residue = dlog.max_residue.value
skipShake=dlog.skipShake.value
WiggleThreshold=dlog.WiggleThreshold.value
MoreInfo=dlog.MoreInfo.value
number_of_remix=dlog.number_of_remix.value
UseCuts=dlog.UseCuts.value
return true
else
return false
end
end
function main ()
print ( recipename )
band.DisableAll ()
save.Quicksave ( kOriginalStructureOrNewBest )
save.Quicksave ( OriginalStructure )--keeps OG structure as a backup
best_score = GetScore ()
startScore=GetScore ()
print ( "Start score " .. r3 ( best_score ) )
n_residues = structure.GetCount ()
if ( GetParameters () == false ) then
return -- graceful exit
end
local optionshake="Shake."
if skipShake then optionshake="Skip shake." end
print(number_of_remix,"remix per zone.",optionshake,"Wiggle threshold=",WiggleThreshold)
for i = remix_lengthFrom, remix_lengthTo do
remix_length = i--The for-loop iterator is always locally-scoped to loop body
print('')
print("Starting zones of "..remix_length.." segments")
if not MoreInfo then print ( "Zone " .. "Score ".."Start ".."Best ".."Total gain") end
Go ( remix_length )
save.Quickload ( kOriginalStructureOrNewBest )
end
print ( "Ending recipe.." )
behavior.SetClashImportance ( 1.0 )
save.Quickload ( kOriginalStructureOrNewBest )
--recentbest.Restore()) -- this can still have cuts in
band.EnableAll ()
print("Total remix gain=", r3(GetScore() -startScore))
end
function cleanup (err)
start,stop,line,msg=err:find(":(%d+):%s()")
err=err:sub(msg,#err)
print('---')
if err:find('Cancelled')~=nil then
print("User stop.")
else
print("unexpected error detected.")
print("Error line:", line)
print("Error :", err)
end
print ( "Cleaning up" )
behavior.SetClashImportance ( 1.0 )
save.Quickload ( kOriginalStructureOrNewBest )
--recentbest.Restore() -- this can still have cuts in
band.EnableAll ()
print("Total remix gain=", r3(GetScore() -startScore))
end
--main ()
xpcall ( main , cleanup )