Code
--
-- Tvdl Mutate
-- Can be run in several ways:
-- 1. Fast hunt for gains
-- 2. Same but with a fuze after each gain
-- 3. Slow because of qstab after each try
-- Module Mutate.lua
-- Written because the Lua mutate function does not find the best
-- when filters are around
-- Added: possible to do afterprocessing after each win or each mutation
-- 13-03-2013 Timo van der Laan.
-- Handy shorts module
normal= (current.GetExplorationMultiplier() == 0)
segCnt=structure.GetCount()
segCnt2=segCnt
while structure.GetSecondaryStructure(segCnt2)=="M" do segCnt2=segCnt2-1 end
-- On request of gmn
CIfactor=1
function CI(CInr)
behavior.SetClashImportance(CInr*CIfactor)
end
function CheckCI()
local ask=dialog.CreateDialog("Clash importance is not 1")
ask.l1=dialog.AddLabel("Last change to change it")
ask.l2=dialog.AddLabel("CI settings will be multiplied by set CI")
ask.continue=dialog.AddButton("Continue",1)
dialog.Show(ask)
end
if behavior.GetClashImportance() < 0.99 then CheckCI() end
CIfactor=behavior.GetClashImportance()
-- Score functions
function Score(pose)
if pose==nil then pose=current end
local total= pose.GetEnergyScore()
-- FIX for big negatives
if normal then
return total
else
return total*pose.GetExplorationMultiplier()
end
end
function SegScore(pose)
if pose==nil then pose=current end
local total=8000
for i=1,segCnt2 do
total=total+pose.GetSegmentEnergyScore(i)
end
return total
end
function RBScore()
return Score(recentbest)
end
function round3(x)--cut all afer 3-rd place
return x-x%0.001
end
bestScore=Score()
function SaveBest()
local g=Score()-bestScore
if g>0 then
if g>0.01 then print("Gained another "..round3(g).." pts.") end
bestScore=Score()
save.Quicksave(3)
end
end
-- Wiggle function
-- Note the extra parameter to be used if only selected parts must be done
function Wiggle(how, iters, minppi,onlyselected)
--score conditioned recursive wiggle/shake
--fixed a bug, absolute difference is the threshold now
if how==nil then how="wa" end
if iters==nil then iters=6 end
if minppi==nil then minppi=0.1 end
if onlyselected==nil then onlyselected=false end
if iters>0 then
iters=iters-1
local sp=Score()
if onlyselected then
if how == "s" then
-- Shake is not considered to do much in second or more rounds
structure.ShakeSidechainsSelected(1)
return
elseif how == "wb" then structure.WiggleSelected(2,true,false)
elseif how == "ws" then structure.WiggleSelected(2,false,true)
elseif how == "wa" then structure.WiggleSelected(2,true,true)
end
else
if how == "s" then
-- Shake is not considered to do much in second or more rounds
structure.ShakeSidechainsAll(1)
return
elseif how == "wb" then structure.WiggleAll(2,true,false)
elseif how == "ws" then structure.WiggleAll(2,false,true)
elseif how == "wa" then structure.WiggleAll(2,true,true)
end
end
if math.abs(Score()-sp) > minppi then return Wiggle(how, iters, minppi,onlyselected) end
end
end
-- end of handy shorts module
-- Segment set and list module
-- Notice that most functions assume that the sets are well formed
-- (=ordered and no overlaps)
-- 02-05-2012 TvdL Free to use for non commercial purposes
function SegmentListToSet(list)
local result={}
local f=0
local l=-1
table.sort(list)
for i=1,#list do
if list[i] ~= l+1 and list[i] ~= l then
-- note: duplicates are removed
if l>0 then result[#result+1]={f,l} end
f=list[i]
end
l=list[i]
end
if l>0 then result[#result+1]={f,l} end
--print("list to set")
--SegmentPrintSet(result)
return result
end
function SegmentSetToList(set)
local result={}
for i=1,#set do
--print(set[i][1],set[i][2])
for k=set[i][1],set[i][2] do
result[#result+1]=k
end
end
return result
end
function SegmentCleanSet(set)
-- Makes it well formed
return SegmentListToSet(SegmentSetToList(set))
end
function SegmentInvertSet(set,maxseg)
-- Gives back all segments not in the set
-- maxseg is added for ligand
local result={}
if maxseg==nil then maxseg=structure.GetCount() end
if #set==0 then return {{1,maxseg}} end
if set[1][1] ~= 1 then result[1]={1,set[1][1]-1} end
for i=2,#set do
result[#result+1]={set[i-1][2]+1,set[i][1]-1}
end
if set[#set][2] ~= maxseg then result[#result+1]={set[#set][2]+1,maxseg} end
return result
end
function SegmentInList(s,list)
table.sort(list)
for i=1,#list do
if list[i]==s then return true
elseif list[i]>s then return false
end
end
return false
end
function SegmentInSet(set,s)
for i=1,#set do
if s>=set[i][1] and s<=set[i][2] then return true
elseif s<set[i][1] then return false
end
end
return false
end
function SegmentJoinList(list1,list2)
local result=list1
if result == nil then return list2 end
for i=1,#list2 do result[#result+1]=list2[i] end
table.sort(result)
return result
end
function SegmentJoinSet(set1,set2)
return SegmentListToSet(SegmentJoinList(SegmentSetToList(set1),SegmentSetToList(set2)))
end
function SegmentCommList(list1,list2)
local result={}
table.sort(list1)
table.sort(list2)
if #list2==0 then return result end
local j=1
for i=1,#list1 do
while list2[j]<list1[i] do
j=j+1
if j>#list2 then return result end
end
if list1[i]==list2[j] then result[#result+1]=list1[i] end
end
return result
end
function SegmentCommSet(set1,set2)
return SegmentListToSet(SegmentCommList(SegmentSetToList(set1),SegmentSetToList(set2)))
end
function SegmentSetMinus(set1,set2)
return SegmentCommSet(set1,SegmentInvertSet(set2))
end
function SegmentPrintSet(set)
print(SegmentSetToString(set))
end
function SegmentSetToString(set)
local line = ""
for i=1,#set do
if i~=1 then line=line..", " end
line=line..set[i][1].."-"..set[i][2]
end
return line
end
function SegmentSetInSet(set,sub)
if sub==nil then return true end
-- Checks if sub is a proper subset of set
for i=1,#sub do
if not SegmentRangeInSet(set,sub[i]) then return false end
end
return true
end
function SegmentRangeInSet(set,range)
if range==nil or #range==0 then return true end
local b=range[1]
local e=range[2]
for i=1,#set do
if b>=set[i][1] and b<=set[i][2] then
return (e<=set[i][2])
elseif e<=set[i][1] then return false end
end
return false
end
function SegmentSetToBool(set)
local result={}
for i=1,structure.GetCount() do
result[i]=SegmentInSet(set,i)
end
return result
end
--- End of Segment Set module
-- Module Find Segment Types
function FindMutablesList()
local result={}
for i=1,segCnt2 do if structure.IsMutable(i) then result[#result+1]=i end end
return result
end
function FindMutables()
return SegmentListToSet(FindMutablesList())
end
function FindFrozenList()
local result={}
for i=1,segCnt2 do if freeze.IsFrozen(i) then result[#result+1]=i end end
return result
end
function FindFrozen()
return SegmentListToSet(FindFrozenList())
end
function FindLockedList()
local result={}
for i=1,segCnt2 do if structure.IsLocked(i) then result[#result+1]=i end end
return result
end
function FindLocked()
return SegmentListToSet(FindLockedList())
end
function FindSelectedList()
local result={}
for i=1,segCnt do if selection.IsSelected(i) then result[#result+1]=i end end
return result
end
function FindSelected()
return SegmentListToSet(FindSelectedList())
end
function FindAAtypeList(aa)
local result={}
for i=1,segCnt2 do
if structure.GetSecondaryStructure(i)== aa then result[#result+1]=i end
end
return result
end
function FindAAtype(aa)
return SegmentListToSet(FindAAtypeList(aa))
end
function FindAminotype(at) --NOTE: only this one gives a list not a set
local result={}
for i=1,segCnt2 do
if structure.GetAminoAcid(i) == at then result[#result+1]=i end
end
return result
end
-- end Module Find Segment Types
-- Module Random
-- Tvdl, 01-11-2012
Randomseed=os.time()%1000000
function Seedrandom()
math.randomseed(Randomseed)
math.random(100) -- Because the first is not random
end
Seedrandom()
-- Thanks too Rav4pl
function ShuffleTable(tab) --randomize order of elements
local cnt=#tab
for i=1,cnt do
local r=math.random(cnt)
tab[i],tab[r]=tab[r],tab[i]
end
return tab
end
function MutateSeg(segnr,winextra,allextra)
local aatypes= {"e","m","a","l","k","f","q","w","i","v","d","h","r","t","s","c","n","y","p","g"}
local basescore=Score()
local highscore=basescore-100000
local curtype=structure.GetAminoAcid(segnr)
local highletter=curtype
for i=1,#aatypes do
structure.SetAminoAcid(segnr,aatypes[i])
if allextra ~= nil then allextra(segnr,bestScore) end
local s=Score()
if s>=highscore then highscore=s highletter=aatypes[i] end
end
structure.SetAminoAcid(segnr,highletter)
SaveBest()
save.Quickload(3)
if recentbest.GetEnergyScore() > Score()+0.001 then
print("Unexpected gain found in recentbest")
recentbest.Restore()
SaveBest()
end
if structure.GetAminoAcid(segnr) ~= curtype then
print("Gain from changing "..curtype.." to "..structure.GetAminoAcid(segnr))
if winextra ~= nil then winextra() end
end
end
function MutateList(list,n,winextra,allextra)
local i=1
local max=n
if n==nil then max=100 end
recentbest.Save()
repeat
local ss=Score()
print("Loop "..i.." Startscore: "..round3(ss))
ShuffleTable(list)
for j=1,#list do
print("Trying seg "..list[j].." "..j.." from "..#list..". Score: "..round3(Score()))
MutateSeg(list[j],winextra,allextra)
end
i=i+1
print("Loop gained "..round3(Score()-ss).." pts. Current score: "..round3(Score()))
until i>max or Score()-ss < 0.1
end
function MutateAll(n,winextra,allextra)
local Mutables=FindMutablesList()
MutateList(Mutables,n,winextra,allextra)
end
function MutateSelection(n,winextra,allextra)
local selection=FindSelectedList()
local Mutables=FindMutablesList()
local WorkOn=SegmentCommList(selection,Mutables)
MutateList(WorkOn,n,winextra,allextra)
end
-- Standard Fuze module
-- Picks up all gains by using recentbest
function GetRB(prefun,postfun)
if RBScore()> Score() then
if prefun ~= nil then prefun() end
recentbest.Restore()
if postfun ~= nil then postfun() end
end
end
function FuzeEnd(prefun,postfun)
if prefun ~= nil then prefun() end
CI(1)
Wiggle("wa",1)
Wiggle("s",1)
Wiggle()
GetRB(prefun,postfun)
if postfun ~= nil then postfun() end
SaveBest()
end
function Fuze1(ci1,ci2,prefun,postfun)
if prefun ~=nil then prefun() end
CI(ci1)
Wiggle("s",1)
CI(ci2)
Wiggle("wa",1)
if postfun ~= nil then postfun() end
end
function Fuze2(ci1,ci2,prefun,postfun)
if prefun ~= nil then prefun() end
CI(ci1)
Wiggle("wa",1)
CI(1)
Wiggle("wa",1)
CI(ci2)
Wiggle("wa",1)
if postfun ~= nil then postfun() end
end
function reFuze(scr,slot)
local s=Score()
if s<scr then
save.Quickload(slot)
else
scr=s
save.Quicksave(slot)
end
return scr
end
function Fuze(slot,prefun,postfun)
local scr=Score()
if slot == nil then slot=4 save.Quicksave(slot) end
recentbest.Save()
Fuze1(0.3,0.6,prefun,postfun) FuzeEnd(prefun,postfun)
scr=reFuze(scr,slot)
Fuze2(0.3,1,prefun,postfun)
GetRB(prefun,postfun)
SaveBest()
scr=reFuze(scr,slot)
Fuze1(0.05,1,prefun,postfun)
GetRB(prefun,postfun)
SaveBest()
scr=reFuze(scr,slot)
Fuze2(0.7,0.5,prefun,postfun) FuzeEnd()
scr=reFuze(scr,slot)
Fuze1(0.07,1,prefun,postfun)
GetRB(prefun,postfun)
SaveBest()
reFuze(scr,slot)
GetRB(prefun,postfun)
SaveBest()
end
-- end standard Fuze module
-- Module AskSelections
-- 02-05-2012 Timo van der Laan, Free to use for non commercial purposes
function AskForSelections(title,mode)
local result={{1,structure.GetCount()}} -- All segments
if mode == nil then mode={} end
if mode.askloops==nil then mode.askloops=true end
if mode.asksheets==nil then mode.asksheets=true end
if mode.askhelixes==nil then mode.askhelixes=true end
if mode.askligands==nil then mode.askligands=false end
if mode.askselected==nil then mode.askselected=true end
if mode.asknonselected==nil then mode.asknonselected=true end
if mode.askmutateonly==nil then mode.askmutateonly=true end
if mode.askignorelocks==nil then mode.askignorelocks=true end
if mode.askignorefrozen==nil then mode.askignorefrozen=true end
if mode.askranges==nil then mode.askranges=true end
if mode.defloops==nil then mode.defloops=true end
if mode.defsheets==nil then mode.defsheets=true end
if mode.defhelixes==nil then mode.defhelixes=true end
if mode.defligands==nil then mode.defligands=false end
if mode.defselected==nil then mode.defselected=false end
if mode.defnonselected==nil then mode.defnonselected=false end
if mode.defmutateonly==nil then mode.defmutateonly=false end
if mode.defignorelocks==nil then mode.defignorelocks=false end
if mode.defignorefrozen==nil then mode.defignorefrozen=false end
local Errfound=false
repeat
local ask = dialog.CreateDialog(title)
if Errfound then
ask.E1=dialog.AddLabel("Try again, ERRORS found, check output box")
result={{1,structure.GetCount()}} --reset start
Errfound=false
end
if mode.askloops then
ask.loops = dialog.AddCheckbox("Work on loops",mode.defloops)
elseif not mode.defloops then
ask.noloops= dialog.AddLabel("Loops will be auto excluded")
end
if mode.askhelixes then
ask.helixes = dialog.AddCheckbox("Work on helixes",mode.defhelixes)
elseif not mode.defhelixes then
ask.nohelixes= dialog.AddLabel("Helixes will be auto excluded")
end
if mode.asksheets then
ask.sheets = dialog.AddCheckbox("Work on sheets",mode.defsheets)
elseif not mode.defsheets then
ask.nosheets= dialog.AddLabel("Sheets will be auto excluded")
end
if mode.askligands then
ask.ligands = dialog.AddCheckbox("Work on ligands",mode.defligands)
elseif not mode.defligands then
ask.noligands= dialog.AddLabel("Ligands will be auto excluded")
end
if mode.askselected then ask.selected = dialog.AddCheckbox("Work only on selected",mode.defselected) end
if mode.asknonselected then ask.nonselected = dialog.AddCheckbox("Work only on nonselected",mode.defnonselected) end
if mode.askmutateonly then ask.mutateonly = dialog.AddCheckbox("Work only on mutateonly",mode.defmutateonly) end
if mode.askignorelocks then
ask.ignorelocks =dialog.AddCheckbox("Dont work on locked ones",true)
elseif mode.defignorelocks then
ask.nolocks=dialog.AddLabel("Locked ones will be auto excluded")
end
if mode.askignorefrozen then
ask.ignorefrozen = dialog.AddCheckbox("Dont work on frozen",true)
elseif mode.defignorefrozen then
ask.nofrozen=dialog.AddLabel("Frozen ones will be auto excluded")
end
if mode.askranges then
ask.R1=dialog.AddLabel("Or put in segmentranges. Above selections also count")
ask.ranges=dialog.AddTextbox("Ranges","")
end
ask.OK = dialog.AddButton("OK",1) ask.Cancel = dialog.AddButton("Cancel",0)
if dialog.Show(ask) > 0 then
-- We start with all the segments including ligands
if mode.askloops then mode.defloops=ask.loops.value end
if not mode.defloops then
result=SegmentSetMinus(result,FindAAtype("L"))
end
if mode.asksheets then mode.defsheets=ask.sheets.value end
if not mode.defsheets then
result=SegmentSetMinus(result,FindAAtype("E"))
end
if mode.askhelixes then mode.defhelixes=ask.helixes.value end
if not mode.defhelixes then
result=SegmentSetMinus(result,FindAAtype("H"))
end
if mode.askligands then mode.defligands=ask.ligands.value end
if not mode.defligands then
result=SegmentSetMinus(result,FindAAtype("M"))
end
if mode.askignorelocks then mode.defignorelocks=ask.ignorelocks.value end
if mode.defignorelocks then
result=SegmentSetMinus(result,FindLocked())
end
if mode.askignorefrozen then mode.defignorefrozen=ask.ignorefrozen.value end
if mode.defignorefrozen then
result=SegmentSetMinus(result,FindFrozen())
end
if mode.askselected then mode.defselected=ask.selected.value end
if mode.defselected then
result=SegmentCommSet(result,FindSelected())
end
if mode.asknonselected then mode.defnonselected=ask.nonselected.value end
if mode.defnonselected then
result=SegmentCommSet(result,SegmentInvertSet(FindSelected()))
end
if mode.askranges and ask.ranges.value ~= "" then
local rangetext=ask.ranges.value
local function Checknums(nums)
-- Now checking
if #nums%2 ~= 0 then
print("Not an even number of segments found")
return false
end
for i=1,#nums do
if nums[i]==0 or nums[i]>structure.GetCount() then
print("Number "..nums[i].." is not a segment")
return false
end
end
return true
end
local function ReadSegmentSet(data)
local nums = {}
local NoNegatives='%d+' -- - is not part of a number
local result={}
for v in string.gfind(data,NoNegatives) do
table.insert(nums, tonumber(v))
end
if Checknums(nums) then
for i=1,#nums/2 do
result[i]={nums[2*i-1],nums[2*i]}
end
result=SegmentCleanSet(result)
else Errfound=true result={} end
return result
end
local rangelist=ReadSegmentSet(rangetext)
if not Errfound then
result=SegmentCommSet(result,rangelist)
end
end
end
until not Errfound
return result
end
-- end of module AskSelections
-- Module setsegmentset
-- Tvdl, 11-05-2012 Free to use for noncommercial purposes
function SetSelection(set)
selection.DeselectAll()
for i=1,#set do
selection.SelectRange(set[i][1],set[i][2])
end
end
function SelectAround(ss,se,radius,nodeselect)
if nodeselect~=true then selection.DeselectAll() end
for i=1, segCnt2 do
for x=ss,se do
if structure.GetDistance(x,i)<radius then selection.Select(i) break end
end
end
end
function SetAAtype(set,aa)
local saveselected=FindSelected()
SetSelection(set)
structure.SetSecondaryStructureSelected(aa)
SetSelection(saveselected)
end
Version="1.6.0"
function qStab(seg,curbest)
SelectAround(seg,seg,12)
-- Do not accept qstab losses
recentbest.Save()
CI(0.1)
Wiggle("s",1,nil,true) --shake only selected part
if fastQstab==false then
CI(0.4)
Wiggle("wa",1)
CI(1)
Wiggle("s",1)
end
CI(1)
Wiggle()
recentbest.Restore()
end
fastQstab=true
deltafuze= -1
function QstabFuze(seg,curbest)
qStab(seg,curbest)
if Score()-bestScore > deltafuze then Fuze() end
end
function AskMutParams()
local ask=dialog.CreateDialog("Tvdl Mutate "..Version)
local winfuze=nil
local extra=nil
save.Quicksave(3)
ask.fuze=dialog.AddCheckbox("Fuze best try if a win",false)
ask.nogain=dialog.AddCheckbox("Run until no gain",false)
ask.nrloop=dialog.AddSlider("Or loopnr",1,1,10,0)
ask.qstab=dialog.AddCheckbox("Qstab after each try",false)
ask.fastq=dialog.AddCheckbox("If qstab then fast",fastQstab)
ask.qfuze=dialog.AddCheckbox("If qstab then fuze if close",false)
ask.diff=dialog.AddSlider("Fuze if loss <",deltafuze,-5,5,0)
ask.sel=dialog.AddCheckbox("Select where to work",false)
ask.OK = dialog.AddButton("OK",1) ask.Cancel = dialog.AddButton("Cancel",0)
if dialog.Show(ask) > 0 then
if ask.fuze.value then winfuze=Fuze end
if ask.qstab.value then
if ask.qfuze.value then extra=QstabFuze
else extra=qStab
end
end
print("Tvdl Mutate "..Version)
local loopnr=ask.nrloop.value
if ask.nogain.value then loopnr=nil end
fastQstab=ask.fastq.value
deltafuze=ask.diff.value
if ask.sel.value then
SetSelection(AskForSelections("Select where to work on"))
MutateSelection(loopnr,winfuze,extra)
else MutateAll(loopnr,winfuze,extra)
end
end
end
function CleanUp()
CI(1)
save.Quickload(3)
end
xpcall(AskMutParams,CleanUp)