Icon representing a recipe

Recipe: Banded Worm Pairs Inf Filt 1.4.7

created by Bruno Kestemont

Profile


Name
Banded Worm Pairs Inf Filt 1.4.7
ID
100682
Shared with
Public
Parent
BandedWormPairs
Children
Created on
December 01, 2021 at 20:44 PM UTC
Updated on
December 01, 2021 at 20:44 PM UTC
Description

Banded worm, with pairs of bands and more random action, including user bands - Filter optimization and infinite run

Best for


Code


--Banded Worm Pairs Infinite (& Filter) ------------------------------------------------------------------------------ -- Banded Worm ------------------------------------------------------------------------------ -- Modifies Worm LWS v2 by rav3n_pl -- -- by KarenCH ------------------------------------------------------------------------------ -- Made infinite and filters optimized by Bruno Kestemont 15/2/2015 -- v 1.1 corrected random contact map 20/9/2015 -- v 1.2 added random use of user bands (and random multiplier of their strength) -- v 1.2.1 undo.SetUndo -- v 1.3.0 BAND_TO_SIDECHAINS allowed -- v 1.3.1 Fixed unideal loop bug (thanks to gitwut) (band= true) -- v 1.3.2 Second attempt to fix it (added save.Quickload) -- v 1.4 Dialog for filters -- v 1.4.1 and tried again to fix GENERICFILTER on recentbest (see feedback discussion, Foldit Bug) -- replaced by FakeRecentBestSave() and FakeRecentBestRestore() 29/8/2017 -- v 1.4.2 added Ligand dialog -- v 1.4.3 systematic display of current score (Greg's suggestion), again fixing filter bug -- v 1.4.4 fixed detect bonusses -- v 1.4.5 fixed segMeanScore=(scoreboard.GetGroupScore()-8000)/segCnt -- v 1.4.5b fixed firstligand bug (thanks LociOiling) -- v 1.4.7 fixing quickload bug by initializing the slots and restoring recentbest.save in BandedWorm function --TO DO = probability otions in advanced dialog recipename= "Banded Worm Pairs Inf Filter 1.4.7" undo.SetUndo(false) -- interesting global variables that users might want to modify PROB_CHOOSE_USERBANDS = 0.10 -- don't put it too high PROB_CHOOSE_CONTACTMAP = 0.60 PROB_PUTBAND = 1.0 -- how often do we put bands in our wiggle steps? PROB_BIS_NOT_BETWEEN = 0.25 -- do we prefer BIS or bands between segs PROB_2ND_IS_BIS = 0.50 PROB_BETWEEN_USES_ATOM = 0.50 -- between: should wiggled seg have band from non-default atom BAND_STRENGTH_DEFAULT = 1.0 PROB_BAND_TO_LIGAND= 0 -- prob band to ligand if ligand -- less interesting global variables that users might consider modifying BIS_LENGTH = 5.0 -- max length of a BIS SCALE_MAXCI = 1.0 CONTACTMAP_THRESHOLD = 0.25 -- min heat of contacts USENORMALSCORE = true -- exploration puzzles would set false DEBUGRUN = false -- mostly goes with DebugPrint, but could get more use later -- atoms in an amino acid BETA_CARBON = 5 TERMINAL_BETA = 6 -- not used CENTER_CARBON = 2 --this is the default atom for bands to attach to BAND_TO_SIDECHAINS = true -- New BK, some bands to sidechains as well -- variables users probably don't want to play with (SLOTS) QS_Start = 1 QS_Best = 3 Qs_Recent = 5 -- for debugging recentbest bug Qs_Current = 6 -- for debugging recentbest score -- variables users really shouldn't play with PuzzleHasContactMap = false PuzzleHasLockedSegs = false EndCalled = false InitialScore = 0.0 -- not important: will be reinitialized in InitializePuzzleState( ) StartTime = 0 -- not important: will be reinitialized in InitializePuzzleState( ) CurrentBestScore = 0 -- not important: will be reinitialized in InitializePuzzleState( ) InitialClashImportance = behavior.GetClashImportance() NonLockedSegList = {} segCt = structure.GetCount() MinUnlockedSeg = 1 MaxUnlockedSeg = segCt segCnt2=segCt while structure.GetSecondaryStructure(segCnt2)=="M" do segCnt2=segCnt2-1 end FirstLigand= segCnt2 -- 0 if no ligand LastLigand= segCt InitialBandCount = 0 ubcount = 0 -- user bands ubandlist={} -- {band number, band strength, goal_length} USERBANDS=false PROBABLEFILTER=false --FILTERMANAGE=false -- default yes during wiggle (will always be activate when scoring) GENERICFILTER=false PROBABLELIGAND=false GENERICLIGAND=false --init of the slots save.SaveSolution ("Autosaved Current Solution")-- to debug the return to other recipe's solution save.Quicksave( QS_Start ) --to debug the return to other recipe's solution save.Quicksave( QS_Best ) -- to debug the return to other recipe's solution save.Quicksave( Qs_Recent ) -- to debug the return to other recipe's solutios save.Quicksave( Qs_Current ) -- to debug the return to other recipe's solution save.SaveSolution ("Autosaved Credit Best Soloist Solution")-- to debug the return to other recipe's solution save.SaveSolution ("Autosaved Recent Best Soloist Solution")-- to debug the return to other recipe's solution save.SaveSolution ("Autosaved Very Best Soloist Solution")-- to debug the return to other recipe's solution save.SaveSolution ("Autosaved Recent Best Evolver Solution")-- to debug the return to other recipe's solution --identifying explicitly (heavy) filtered puzzles (Contact with remain filter enabled, what is good) --START extraction of information from puzzle metadata --Extrait des infos function detectfilterandmut() -- Bruno Kestemont 10/10/2013; 13/2/2015; 5/1/2019 local descrTxt=puzzle.GetDescription() local puzzletitle=puzzle.GetName() local function SymetryFinder() -- by Bruno Kestemont 7/2/2013, 25/8/2013 local segMeanScore=(scoreboard.GetGroupScore()-8000)/segCnt2 -- top score pour eviter les debuts de puzzle --p("Score moyen par segment= "..segMeanScore) if PROBABLESYM then if segMeanScore<33.39 then sym=1 PROBABLESYM=false elseif segMeanScore<85 then sym=2 elseif segMeanScore<132 then sym=3 elseif segMeanScore<197 then sym=4 else sym=5 end else sym=1 end return end if #descrTxt>0 and (descrTxt:find("filter") or descrTxt:find("filters") or descrTxt:find("bonus") or descrTxt:find("bonuses") and not descrTxt:find("disabled"))then PROBABLEFILTER=true FILTERMANAGE=true -- default yes during wiggle (will always be activate when scoring) GENERICFILTER=false -- to be evaluated end if #descrTxt>0 and (descrTxt:find("H-bond networks") or descrTxt:find("Hydrogen Bond Networks") or descrTxt:find("H-bond Networks") or descrTxt:find("H-bond Network") and not descrTxt:find("disabled"))then PROBABLEFILTER=true FILTERMANAGE=false -- default no GENERICFILTER=false -- to be evaluated end if #descrTxt>0 and (descrTxt:find("design") or descrTxt:find("designs")) then HASMUTABLE=true IDEALCHECK=true HANDFOLD=true end if #descrTxt>0 and (descrTxt:find("De-novo") or descrTxt:find("de-novo") or descrTxt:find("freestyle") or descrTxt:find("prediction") or descrTxt:find("predictions")) then IDEALCHECK=true HANDFOLD=true end 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 PROBABLESYM=true if puzzletitle:find("Dimer") and not puzzletitle:find("Dimer of Dimers") then sym=2 elseif puzzletitle:find("Trimer") or puzzletitle:find("trimer") then sym=3 elseif puzzletitle:find("Dimer of Dimers") or puzzletitle:find("Tetramer") then sym=4 elseif puzzletitle:find("Pentamer") then sym=5 else SymetryFinder() end end end 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 PROBABLESYM=true if (descrTxt:find("Dimer") or descrTxt:find("dimer") or descrTxt:find("C2 symmetry") or descrTxt:find("twoo symmetric")) and not (descrTxt:find("Dimer of Dimers") or descrTxt:find("dimer of dimers")) then sym=2 elseif descrTxt:find("Trimer") or descrTxt:find("trimer") or descrTxt:find("C3 symmetry") or descrTxt:find("three symmetric") then sym=3 elseif (descrTxt:find("Dimer of Dimers") or descrTxt:find("Tetramer") or descrTxt:find("C4 symmetry") or descrTxt:find("four symmetric")) and not (descrTxt:find("dimer of dimers") or descrTxt:find("tetramer"))then sym=4 elseif descrTxt:find("Pentamer") or descrTxt:find("pentamer") or descrTxt:find("C5 symmetry") or descrTxt:find("five symmetric") then sym=5 else SymetryFinder() end end --print resulting sym info if PROBABLESYM then print("Symmetric") if sym==2 then print("Dimer") elseif sym==3 then print("Trimer") elseif sym==4 then print("Tetramer") elseif sym==5 then print("Pentamer") elseif sym>5 then print("Terrible polymer") end else print("Monomer") end if #puzzletitle>0 and puzzletitle:find("Sepsis") then -- new BK 17/6/2013 SEPSIS=true HANDFOLD=true --p(true,"-Sepsis") print("Sepsis") end if #puzzletitle>0 and puzzletitle:find("Electron Density") then -- for Electron Density --p(true,"-Electron Density") ELECTRON=true HANDFOLD=true print("Electron density") end if #puzzletitle>0 and puzzletitle:find("Centroid") then -- New BK 20/10/2013 --p(true,"-Centroid") CENTROID=true print("Centroid") end if #puzzletitle>0 and puzzletitle:find("Hotspot") then -- New BK 21/01/2014 HOTSPOT=true print("Hotspot") end return end detectfilterandmut() --END extraction of information from puzzle metadata --Extrait des infos function DialogForFilters() ask = dialog.CreateDialog(recipename) ask.l6 = dialog.AddLabel("Fast = filters off unless for score") ask.l8 = dialog.AddLabel("Slow = filters always on") ask.Fast = dialog.AddButton("Fast",1) ask.Slow = dialog.AddButton("Slow",2) askresult=dialog.Show(ask) if askresult < 2 then GENERICFILTER=true end end function DialogForLigand() ask = dialog.CreateDialog(recipename) ask.l6 = dialog.AddLabel("Ligand = move ligand") ask.l8 = dialog.AddLabel("All = move all") ask.Fast = dialog.AddButton("Ligand",1) ask.Slow = dialog.AddButton("All",2) askresult=dialog.Show(ask) if askresult> 1 then GENERICLIGAND=false else GENERICLIGAND=true end end if PROBABLEFILTER then DialogForFilters() end if PROBABLELIGAND then DialogForLigand() end if GENERICLIGAND and not FirstLigand == 0 then --there should be a ligand but who knows PROB_BAND_TO_LIGAND=1 end --START Generic Filter Management by BitSpawn 21/12/2014, updated by Bruno Kestemont 4/1/2019 --Source: http://fold.it/portal/node/1998917 --Note: GENERICFILTER must be defined elsewhere (otherwise, it will not do anything) -- GENERICFILTER=true -- function to copy class/table function CopyTable(orig) local copy = {} for orig_key, orig_value in pairs(orig) do copy[orig_key] = orig_value end return copy end -- functions for filters function FiltersOn() if filter.AreAllEnabled()==false then filter.EnableAll() end end function FiltersOff() if filter.AreAllEnabled() then filter.DisableAll() end end -- function to overload a function function mutFunction(func) local currentfunc = func local function mutate(func, newfunc) local lastfunc = currentfunc currentfunc = function(...) return newfunc(lastfunc, ...) end end local wrapper = function(...) return currentfunc(...) end return wrapper, mutate end -- function to overload a class -- to do: set the name of function classes_copied = 0 myclcp = {} function MutClass(cl, filters) classes_copied = classes_copied+1 myclcp[classes_copied] = CopyTable(cl) local mycl =myclcp[classes_copied] for orig_key, orig_value in pairs(cl) do myfunc, mutate = mutFunction(mycl[orig_key]) if filters==true then mutate(myfunc, function(...) FiltersOn() if table.getn(arg)>1 then -- first arg is self (function pointer), we pack from second argument local arguments = {} for i=2,table.getn(arg) do arguments[i-1]=arg[i] end return mycl[orig_key](unpack(arguments)) else --print("No arguments") return mycl[orig_key]() end end) cl[orig_key] = myfunc else mutate(myfunc, function(...) FiltersOff() if table.getn(arg)>1 then local arguments = {} for i=2, table.getn(arg) do arguments[i-1]=arg[i] end return mycl[orig_key](unpack(arguments)) else return mycl[orig_key]() end end) cl[orig_key] = myfunc end end end -- how to use: --setting default options if filters BK 4/2/2015 --MutClass(structure, false) --MutClass(band, false) --MutClass(current, true) if GENERICFILTER then -- WARNING: TO VERIFY !! (may be it's irreversible for several funtions bellow) MutClass(structure, false) MutClass(band, true) -- if false, you have to enable filter just afterwards (otherwise unideal filter bug) MutClass(current, true) MutClass(recentbest, true) -- otherwise, it remembers cut solutions MutClass(save, true) -- better to save with full score end --STOP Generic Filter Management ------------------------------------------------------------------------------ -- FUNCTIONS ------------------------------------------------------------------------------ function BandedWorm( pattern ) recentbest.Save( ) -- new still trying to debug the recentbest bug 1/12/2021 FakeRecentBestSave() SetCI( 1.0 ) SaveBest( ) local ss = getScore() local idx=1 for w = 1, #pattern do save.Quickload( QS_Best ) -- new for DEBUG len = pattern[ w ] local sw = getScore() local swCurr = sw print( "Starting BandedWormPairs of len " .. len .. ", score: ".. TrimNum( getScore() ) ) for s=MinUnlockedSeg, MaxUnlockedSeg - len + 1 do selection.DeselectAll() selection.SelectRange( s, s + len - 1 ) if random( ) < PROB_PUTBAND then if random( ) < PROB_BAND_TO_LIGAND then idx= random( FirstLigand, LastLigand) else idx = random( s, s + len - 1 ) end PutSingleRandomBandToSeg( idx, PROB_BIS_NOT_BETWEEN ) if random( ) < 0.25 then local idx2 = random( s, s + len - 1 ) PutSingleRandomBandToSeg( idx2, PROB_2ND_IS_BIS ) end uBandEnabel() -- new v1.2 random adding one of the user bands structure.LocalWiggleSelected( random(2,4) ) ManageBands( ) structure.WiggleAll( 2 ) end structure.LocalWiggleSelected( 5 ) local swNew = getScore( ) local gain = swNew - swCurr if gain > 0 then structure.LocalWiggleSelected( 20 ) --recentbest.Restore( ) FakeRecentBestRestore() ManageBands( ) swNew = getScore( ) gain = swNew - swCurr if TrimNum( gain ) > 0 then print( ">>>> At " .. s .. ": Gained ".. TrimNum( gain ).." Score: "..TrimNum( swNew )) end SaveBest( ) swCurr = swNew else --recentbest.Restore( ) FakeRecentBestRestore() structure.LocalWiggleSelected( 4 ) end --recentbest.Restore( ) FakeRecentBestRestore() ManageBands( ) end print( "Pattern gain: ".. getScore( ) - sw ) SaveBest( ) end selection.DeselectAll() print( "Total BandedWormPairs gain: " .. TrimNum( getScore( ) - ss ) ) end function PutSingleRandomBandToSeg( idx, probBis ) changeSucceeded = false local strength = random( 0.5 * BAND_STRENGTH_DEFAULT, 1.5 * BAND_STRENGTH_DEFAULT, true ) local doBIS = random( ) < probBis if doBIS then changeSucceeded = PutBandInSpace( idx, BIS_LENGTH, strength ) else if SegHasContactData( idx, CONTACTMAP_THRESHOLD ) and random( ) < PROB_CHOOSE_CONTACTMAP -- changed > to < BK then local doSidechain = random( ) < PROB_BETWEEN_USES_ATOM changeSucceeded = PutSomeContactMapBands( CONTACTMAP_THRESHOLD, strength, 1, doSidechain ) else local atom = PickAtomNumberForBand( idx ) changeSucceeded = PutBandToRandomSeg( idx, 5, strength, atom ) end end return changeSucceeded end ---------------------------------------------------------------- -- ---------------- BOILERPLATE --------------------- -- ---------------------------------------------------------------- ---------------------------------------------------------------- -- BASIC FUNCTIONALITY ---------------------------------------------------------------- function DebugPrint( str ) if DEBUGRUN then print( str ) end end function TrimNum( val ) return val - val % 0.001 end -- Not for "external" use - call getScore. This could change if customers want -- something besides current or recentbest. function internalGetScore( wantRB ) if wantRB == nil then wantRB = false end local s=0.0 if not USENORMALSCORE then if wantRB then --s = recentbest.GetEnergyScore( ) s= FakeRecentBestGetEnergyScore() else s=current.GetEnergyScore( ) end else if wantRB then --s = recentbest.GetScore( ) s = FakeRecentBestGetScore() else s=current.GetScore( ) end end return s end function getScore( ) return internalGetScore( false ) end function getRBScore( ) return internalGetScore( true ) end function SaveBest( ) local score = getScore( ) if score > CurrentBestScore then save.Quicksave( QS_Best ) CurrentBestScore = score end -- CheckFullScore() -- for DEBUG only end --START Debugging Recentbest Foldit Bug Temporary solution of Foldit bug (BK 29/8/2017) function Score() -- for BWPIF only return current.GetScore() end function FakeRecentBestSave() if PROBABLEFILTER then -- trying to solve the Foldit bug save.Quicksave(Qs_Recent) else recentbest.Save() end end function FakeRecentBestRestore() if PROBABLEFILTER then -- trying to solve the Foldit bug local ss=Score() recentbest.Restore() -- filter disabled (bug) local se=Score() -- now with the filter if se > ss then save.Quicksave(Qs_Recent) end save.Quickload(Qs_Recent) else recentbest.Restore() end end function FakeRecentBestGetScore() if PROBABLEFILTER then -- trying to solve the Foldit bug save.Quicksave(Qs_Current) recentbest.Restore() -- filter disabled (bug) local se=Score() -- now with the filter save.Quickload(Qs_Current) return se else recentbest.GetScore( ) end end function FakeRecentBestGetEnergyScore() if PROBABLEFILTER then -- trying to solve the Foldit bug save.Quicksave(Qs_Current) recentbest.Restore() -- filter disabled (bug) local se=current.GetEnergyScore( ) -- now with the filter save.Quickload(Qs_Current) return se else recentbest.GetEnergyScore( ) end end --END Debugging Recentbest Foldit Bug --[[ function CheckFullScore() -- check without filter (only for DEBUG) if filter.AreAllEnabled()==false then DebugPrint ("DEBUG: filter is off, turning on") FiltersOn() end end ]]-- function SetCI( ci ) behavior.SetClashImportance( SCALE_MAXCI * ci ) end ------------- CONTACTMAP FUNCTIONS ------------ function CheckForContactMap( ) PuzzleHasContactMap = false local saveval = 0.0 for i=1, segCt-1 do for j=i+1, segCt do val = contactmap.GetHeat( i, j ) if saveval ~= 0.0 and val ~= saveval then PuzzleHasContactMap = true ContactMapScore = GetContactScore( ) return -- all we wanted to know was whether scores exist end if saveval == 0.0 then saveval = val end end end return end function SegHasContactData( segIn, heatThreshold ) for i = 1, segCt do if i < segIn - 1 or i > segIn + 1 then if contactmap.GetHeat( segIn, i ) >= heatThreshold then return true end end end return false end function InitializeContactMapSegList( heatThreshold ) HasContactMapSegList = {} for i = 1, segCt do if SegHasContactData( i, heatThreshold ) then HasContactMapSegList[ #HasContactMapSegList + 1 ] = i end end end function GetContactScore( ) if not PuzzleHasContactMap then return 0 end local sum = 0.0 local segCt = structure.GetCount( ) for i = 1,segCt-1 do for j = i + 1, segCt do if contactmap.IsContact( i, j ) then sum = sum + contactmap.GetHeat( i, j ) end end end return sum end ----------------------- MATHY STUFF ----------------------- function seedRandom() seed=os.time( )/math.abs( getScore( ) ) seed=seed%0.001 seed=1/seed while seed<10000000 do seed=seed*1000 end seed=seed-seed%1 DebugPrint( "Seed is: "..seed ) math.randomseed( seed ) -- throw away a couple of randoms math.random( ) math.random( ) end function random( n1,n2, forceFloat ) --random function returns int or float depends on input vars if forceFloat == nil then forceFloat = false end if n1==nil then return math.random() else if n2==nil then if n1 == 0 then return 0 end -- a random number between 0 and 0 is 0 if n1%1==0 then -- can't test for "forceFloat", so caller must beware return math.random( n1) --integer else return math.random( ) * n1 --float end else if n1%1==0 and n2%1==0 and not forceFloat then return math.random( n1, n2 ) --integer between else return math.random( ) * (n2 - n1) + n1 --float between end end end end function randomSeg( ) return random( segCt ) end function randomThetaPhi() return math.acos( random( -1.0, 1.0, true ) ), random( 2 * math.pi ) end function randomizeIndexList( idxList ) for i=1, #idxList do j = random( #idxList ) if j ~= i then idxList[i], idxList[j] = idxList[j], idxList[i] end end end -- for branched aas, simply picks one (longer, one with donor/acceptor tip, or if no difference then either) function GetAtomOfTip( aa ) if aa == "a" then return 10 elseif aa == "c" then return 10 elseif aa == "d" then return 8 elseif aa == "e" then return 9 elseif aa == "f" then return 20 elseif aa == "g" then return 0 -- glycine has no tip. just use a backbone atom elseif aa == "h" then return 17 elseif aa == "i" then return 18 elseif aa == "k" then return 9 elseif aa == "l" then return 16 elseif aa == "m" then return 17 elseif aa == "n" then return 14 elseif aa == "p" then return 13 elseif aa == "q" then return 9 elseif aa == "r" then return 22 elseif aa == "s" then return 11 elseif aa == "t" then return 6 elseif aa == "v" then return 13 elseif aa == "w" then return 24 elseif aa == "y" then return 12 else return 0 end end function GetTipAtomOfSeg( idx ) return GetAtomOfTip( structure.GetAminoAcid( idx )) end function PickAtomNumberForBand( idx ) if not BAND_TO_SIDECHAINS then return CENTER_CARBON end local r = random( 1, 4 ) -- consider adjusting probability? if r == 1 then return BETA_CARBON elseif r == 2 then return CENTER_CARBON else return GetTipAtomOfSeg( idx ) -- 50% of the cases end end function IsUnlockedSeg( seg1 ) return not structure.IsLocked( seg1 ) end function FindAllMovableSegs( ) for i=1, segCt do if structure.IsLocked( i ) then PuzzleHasLockedSegs = true else NonLockedSegList[ #NonLockedSegList + 1] = i end end if PuzzleHasLockedSegs then for i=1, segCt do if IsUnlockedSeg( i ) then MinUnlockedSeg = i break end end for i=segCt, 1, -1 do if IsUnlockedSeg( i ) then MaxUnlockedSeg = i break end end end return false end ----------------------- BANDY STUFF ----------------------- function uMakeBands() -- list of existing user bands, strength, goal length ubcount=band.GetCount() for i=1, ubcount do ubandlist[i]={i, band.GetStrength(i), band.GetGoalLength(i)} -- {band number, band strength, goal_length} end if #ubandlist==0 then USERBANDS=false else USERBANDS=true end return ubandlist end function uBandEnabel() -- random enable a user band if USERBANDS and PROB_CHOOSE_USERBANDS >= random(0.0,1.0) then local maxstrength= 5 local minstrength=0.1 local bandIndex= random(1,ubcount) local multiplier = random( 0.5,2) local bandstrength=band.GetStrength(bandIndex) bandstrength=ubandlist[bandIndex][2]*multiplier if bandstrength>maxstrength then bandstrength=maxstrength elseif bandstrength<minstrength then bandstrength=minstrength end band.SetStrength(bandIndex, bandstrength) -- to do: random length? band.Enable(bandIndex) end end function ManageBands() --delete recipe bands, disable user bands if ubcount==0 or ubcount==nil then band.DeleteAll() else local bands=band.GetCount() if bands>ubcount then for i=bands, ubcount+1, -1 do band.Delete(i) end -- TO DO: il reste peut etre une bande ici end end band.DisableAll() end function BandBetweenSegsWithParameters( seg1, seg2, strength, goalLength, atom1, atom2 ) if not ( IsUnlockedSeg( seg1 ) or IsUnlockedSeg( seg2 ) ) then return false end if atom1 == nil then atom1 = CENTER_CARBON end if atom2 == nil then atom2 = CENTER_CARBON end local bIdx = band.AddBetweenSegments( seg1, seg2, atom1, atom2 ) if bIdx ~= band.GetCount( ) then DebugPrint( "failed to add band from "..seg1.." to "..seg2) return false end if bIdx <= InitialBandCount then return true end -- don't change user-supplied bands if goalLength ~= nil then band.SetGoalLength( bIdx, goalLength ) end if strength ~= nil and strength > 0.0 then band.SetStrength( bIdx, strength ) end return true end function BandInSpaceWithParameters( seg, segFini, segInit, rho, theta, phi, strength, goalLength, atomIndexOrigin, atomIndexXAxis, atomIndexYAxis) if not ( IsUnlockedSeg( seg) ) then return false end local atomIndexOrigin, atomIndexXAxis, atomIndexYAxis = atomIndexOrigin or CENTER_CARBON, atomIndexXAxis or 0, atomIndexYAxis or 0 local bIdx = band.Add( seg, segFini, segInit, rho, theta, phi, atomIndexOrigin, atomIndexXAxis, atomIndexYAxis ) if bIdx ~= band.GetCount( ) then return false end if bIdx <= InitialBandCount then return true end -- don't change user-supplied bands if goalLength ~= nil then band.SetGoalLength( bIdx, goalLength ) end if strength ~= nil and strength ~= 0.0 then band.SetStrength( bIdx, strength ) end return true end function PutBandInSpace( idx, maxRho, strength ) local atomIndexOrigin, atomIndexXAxis, atomIndexYAxis = 0,0,0 -- x and y not used actually 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 -- random atom for the banded (BIS) segment local MaxatomIndexOrigin = PickAtomNumberForBand( idx ) -- it's the end of the sidechain atomIndexOrigin = random( 0 , MaxatomIndexOrigin ) return BandInSpaceWithParameters( idx, idx2, idx3, rho, theta, phi, strength, atomIndexOrigin, atomIndexXAxis, atomIndexYAxis ) end function PutBandToRandomSeg( idx, minGap, strength, atom ) needNew = true local failedTries = 0 while ( needNew and failedTries < 30 ) do idx2 = randomSeg( ) -- ok if this one isn't movable (we assume idx is movable) if idx2 > idx + minGap or idx2 < idx - minGap then needNew = false break else failedTries = failedTries + 1 end end if not needNew then return BandBetweenSegsWithParameters( idx, idx2, strength, nil, atom, nil ) end return false end function PutSomeContactMapBands( heatThreshold, strength, ctBands, doSidechains ) changeSucceeded = false local hotList = {} for i = 1, segCt-2 do for j = i+2, segCt do local heat = contactmap.GetHeat(i, j) if heat >= heatThreshold and not contactmap.IsContact( i , j ) then hotList[ #hotList + 1] = { i, j, heat } end end end randomizeIndexList( hotList ) for i=1, math.min( ctBands, #hotList ) do local atom1 = nil local atom2 = nil if BAND_TO_SIDECHAINS and doSidechains then atom1 = PickAtomNumberForBand( hotList[i][1] ) atom2 = PickAtomNumberForBand( hotList[i][2] ) end local ch = BandBetweenSegsWithParameters( hotList[i][1], hotList[i][2], strength, nil, doTip1, doTip2 ) changeSucceeded = ch or changeSucceeded end return changeSucceeded end -------------------------------------------------------------------------- -- SETUP, CLEANUP, and MAIN -------------------------------------------------------------------------- function CleanPuzzleState( ) SetCI( 1.0 ) selection.DeselectAll() ManageBands() 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 ) undo.SetUndo(true) if EndCalled then return end -- no infinite recursion please EndCalled = true print( "" ) if errstr ~= nil then if string.find( errstr, "Cancelled" ) then print( "User cancel" ) else print( errstr ) end end save.Quickload( QS_Best ) PrintState( ) CleanPuzzleState( ) end function InitializePuzzleState( ) seedRandom( ) InitialScore = getScore( ) CurrentBestScore = InitialScore StartTime = os.time() save.Quicksave( QS_Start ) save.Quicksave( QS_Best ) InitialClashImportance = behavior.GetClashImportance() SCALE_MAXCI = InitialClashImportance uMakeBands() -- new v1.2 FindAllMovableSegs( ) CheckForContactMap() if PuzzleHasContactMap then InitializeContactMapSegList( CONTACTMAP_THRESHOLD ) end end function main( ) for i= 1, 1000 do InitializePuzzleState( ) local gain = 0.0 repeat local score = getScore( ) pattern={ 2,5,11,3,13,4,7,1,6 } BandedWorm( pattern ) gain = getScore( ) - score until gain < 0.01 InitializePuzzleState( ) local gain = 0.0 repeat local score = getScore( ) pattern={ 14,8,6,7,13,12,2,10,11 } BandedWorm( pattern ) gain = getScore( ) - score until gain < 0.01 InitializePuzzleState( ) local gain = 0.0 repeat local score = getScore( ) pattern={ 5,7,1,3,9,6,2,4,8 } BandedWorm( pattern ) gain = getScore( ) - score until gain < 0.01 InitializePuzzleState( ) local gain = 0.0 repeat local score = getScore( ) pattern={ 3,6,12,4,14,5,8,2,7 } BandedWorm( pattern ) gain = getScore( ) - score until gain < 0.01 InitializePuzzleState( ) local gain = 0.0 repeat local score = getScore( ) pattern={ 3,8,4,5,12,6,10,2,7} BandedWorm( pattern ) gain = getScore( ) - score until gain < 0.01 end End( ) end xpcall( main, End )

Comments


gitwut Lv 1

Hi Bruno. Thanks for the scripts–we appreciate your hard work!

A question about the scoring though. I've encountered scoring problems where the score dips (probably due to a filter) but the script appears to continue running from the lowered score instead of restoring the credit best and then continuing. I'm guessing that this is not the intended behavior. Here is a sample of the script output:

Seed is: 1310003941
Starting BandedWormPairs of len 2, score: 10689.316
>>>> At 4: Gained 0.083
>>>> At 8: Gained 0.033
>>>> At 9: Gained 0.003
>>>> At 10: Gained 0.004
>>>> At 12: Gained 0.015
>>>> At 20: Gained 0.028
>>>> At 24: Gained 0.036
>>>> At 27: Gained 0.002
>>>> At 34: Gained 0.005
>>>> At 38: Gained 0.001
>>>> At 39: Gained 0.005
>>>> At 43: Gained 0.14
>>>> At 45: Gained 0.004
>>>> At 46: Gained 0.178
>>>> At 54: Gained 0.073
>>>> At 57: Gained 0.151
>>>> At 59: Gained 0.017
>>>> At 62: Gained 0.049
>>>> At 65: Gained 0.025
Pattern gain: -98.577704773403
Starting BandedWormPairs of len 5, score: 10590.738
>>>> At 4: Gained 0.022
>>>> At 13: Gained 0.126
>>>> At 17: Gained 0.171
>>>> At 25: Gained 0.089
>>>> At 39: Gained 0.01
>>>> At 40: Gained 0.166
>>>> At 41: Gained 0.002
>>>> At 43: Gained 0.143
>>>> At 47: Gained 0.368
>>>> At 48: Gained 0.973
>>>> At 54: Gained 0.445
>>>> At 56: Gained 0.004
>>>> At 60: Gained 0.018
>>>> At 67: Gained 0.04
>>>> At 70: Gained 0.397
>>>> At 73: Gained 0.178
>>>> At 74: Gained 0.111
>>>> At 76: Gained 0.176
>>>> At 81: Gained 0.197
>>>> At 83: Gained 0.003
>>>> At 84: Gained 0.109
>>>> At 85: Gained 0.023
>>>> At 87: Gained 0.038

User cancel
Startscore: 10689.316
Score: 10690.177
Total gain: 0.861
Run time: 1545

Thanks!

gitwut Lv 1

The ideal loops filter is what causes the -100 penalty. It also occurs with Acid Tweeker v2.6.1 Filter.

Bruno Kestemont Lv 1

– v 1.4 Dialog for filters
– v 1.4.1 and tried again to fix GENERICFILTER on recentbest (see feedback discussion, Foldit Bug)
– replaced by FakeRecentBestSave() and FakeRecentBestRestore()
– v 1.4.2 added Ligand dialog
– v 1.4.3 systematic display of current score (Greg's suggestion), again fixing filter bug