Code
--[[------------------------------------------------------------------------------------------------
NBL_hinge
Author: Nicobul2 - april 2014
Contributors: Ch Garnier, Yoyo, Bruno Kestemont
Original recipe: Glycine hinge by Tlaloc (LUA v1)
Converted from v1 lua by Rav3n_pl v1 to v2 converter
Copyright (C) 2011 tlaloc <http://fold.it/portal/user/57765>
Copyright (C) 2011 rav3n_pl <http://fold.it/portal/user/174969>
Copyright (C) 2011 Seagat2011 <http://fold.it/port/user/1992490>
Copyright (C) 2011 thom001 <http://fold.it/port/user/172510>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
--]]
local _options = {
--- User Options Begin ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
wiggle_count = 1, -- #iters (flex)
wiggle_out_count = 30, -- #iters (unflex)
band_strength = 0.25, -- band strength
allow_float_wiggle_count = false, -- allows "floating" via random number generation of wiggle_count
wiggle_count_upper = wiggle_count, -- max possible #iters. iff allow_float_wiggle_count, then this value must be defined. (disabled by default)
wiggle_count_lower = wiggle_count, -- min possible #iters. iff allow_float_wiggle_count, then this value must be defined. (disabled by default)
wiggle_count_bounds = wiggle_count, -- allowed variance for #iters. iff allow_float_wiggle_count, then this value must be defined. (disabled by default)
global_wiggle = true, -- perform wa. iff false, then perform lws (local_wiggle)
freeze_backbone = true, -- freeze bb
freeze_sidechains = false, -- freeze sc (disabled by default)
ci = 0.30, -- clashing importance
allow_ci_float = false, -- allows "floating" via random number generation of ci. Iff true, ci_upper and ci_lower must be defined. (disabled by default)
ci_upper = ci, -- U_ci_value. iff allow_ci_float == true, then this value must be defined. (disabled by default)
ci_lower = ci, -- L_ci_value. iff allow_ci_float == true, then this value must be defined. (disabled by default)
ci_bounds = ci, -- allowed variance for ci. ff allow_ci_float == true, then this value must be defined. (disabled by default)
qs_recent_best = 3, -- iff exploratory == true, then recent best is saved into this saveslot
freeze_hinge_instead = false, -- allows for the hinge to be frozen instead of the rods. (disabled by default)
--- User Options End ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
score = 0,
ranked_score = 0,
multiplier = 0,
}
flag = {selected = false, mutate = false}
uo = {mutateAlways = false}
function SegmentListToSet(list) -- retirer doublons
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) -- faire une liste a partir d'une zone
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) -- verifier si segment est dans la liste
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) --verifie si segment est dans la zone
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) -- fusionner 2 listes de segments
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) --fusionner (ajouter) 2 zones
return SegmentListToSet(SegmentJoinList(SegmentSetToList(set1),SegmentSetToList(set2)))
end
function SegmentCommList(list1,list2) -- chercher intersection de 2 listes
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) -- intersection de 2 zones
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 SegmentPrintListToSet(list) -- NEW BK 14/04/2014 prints a list in a set format
SegmentPrintSet(SegmentListToSet(list))
end
function SegmentSetToString(set) -- pour pouvoir imprimer
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)--verifier si zone est dans suite
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) -- vrai ou faux pour chaque segment utilisable ou non
local result={}
for i=1,structure.GetCount() do
result[i]=SegmentInSet(set,i)
end
return result
end
--- End of Segment Set module
function InitWORKONbool()
WORKONbool=SegmentSetToBool(WORKON)
end
function Zone(zStart, zEnd, hw, prot, options) -- seg start & segend are not necesserally first and last segments
for i=zStart, zEnd do
j=WORKONBIS[i] -- NEW 24/9/2013 to be able to treat segments in any order defined in WORKON
nbl_hinge(j, hw, prot, options)
--SaveBestMaaa()
end
end
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
local function _floor ( n )
return n - n%0.01
end
local function _floor2 ( n,c )
return n - n%c
end
local _math = {
_random = random,
_random2 = random,
_floor = _floor,
_floor2 = _floor2,
}
local _saveslots = {
max = 10, --#savelots available
}
local function get_value ( m, l, u ) --> mean, lower, upper
local upper
local lower
upper = m+u
lower = m-l
return math._random (lower,upper)
end
local function get_value2 ( m, b ) --> mean, bounds (symmetrical)
local upper
local lower
upper = m+b
lower = m-b
return math._random (lower,upper)
end
local _prot = { -- READ ONLY
L_idx = 1, -- end of left-hand side rod
L_idx2 = 1, -- beginning of left-hand side rod
R_idx = 1, -- beginning of right-hand side rod
R_idx2 = 1, -- end of right-hand side rod
n = 1, -- local index (SS temp)
k = 1, -- segment_count
next_group = 0, -- local index
rebuild_forward = true, -- direction indicator. true = right-side; false = left-side
bands_enabled = true,
}
local function get_ss_group(r)
local tmp
while ( 1 ) do
if r.rebuild_forward == true then
tmp = structure.GetSecondaryStructure(r.R_idx2)
else
tmp = structure.GetSecondaryStructure(r.L_idx)
end
if tmp == r.n then
if r.rebuild_forward == true then
if r.R_idx2 < r.k then
r.R_idx2 = r.R_idx2 + 1
else
r.R_idx2 = r.k
break
end
else
if r.L_idx > 1 then
r.L_idx = r.L_idx - 1
else
r.L_idx = 1
break
end
end
else
if r.rebuild_forward == true then
r.next_group = r.R_idx2
r.R_idx2 = r.R_idx2 - 1
else
r.next_group = r.L_idx
r.L_idx = r.L_idx + 1
end
break
end
end -- while ( 1 )
return r
end
local function build_hinge(prot,options,i,hw)
local glycine_idx
prot.k = structure.GetCount()
glycine_idx = i
-- (internally) focus on the right side..
prot.R_idx2 = glycine_idx + 1 + hw
prot.R_idx = glycine_idx + hw
prot.rebuild_forward = true
prot.n = structure.GetSecondaryStructure(glycine_idx + 1 )
prot = get_ss_group(prot )
-- (internally) focus on the left side..
prot.L_idx = glycine_idx - 2
prot.L_idx2 = glycine_idx - 1
prot.rebuild_forward = false
prot.n = structure.GetSecondaryStructure(glycine_idx - 1 )
prot = get_ss_group(prot )
return prot
end
local function save_recent_best(options )
-- if ( options.exploratory == true ) then
-- save.Quicksave(options.qs_recent_best )
-- else
recentbest.Save()
-- end
end
local function recall_recent_best(options )
-- if ( options.exploratory == true ) then
-- save.Quickload(options.qs_recent_best )
-- else
recentbest.Restore()
-- end
end
function ncWiggle(zone, iters, iter)
how = "wa"
iters = iters or 1
iter = iter or 1
local step = .001
local ws = 0
--if flag.selected then ws = ws+1 end
if uo.mutateAlways or flag.mutate then ws = ws+10 end
function wShake()
if ws==0 then structure.ShakeSidechainsAll(1)
--elseif ws==1 then structure.ShakeSidechainsSelected(1)
elseif ws==10 then structure.MutateSidechainsAll(1)
--elseif ws==11 then structure.MutateSidechainsSelected(1)
end
end
function wWiggle()
local b, s = true, true
if how=='wb' then s = false end
--if ws==1 then
--structure.WiggleSelected(iters, b, s)
--else
if zone=='a' then
structure.WiggleAll(iters, b, s)
else
structure.LocalWiggleAll(iters, b, s)
end
--end
end
if how=='s' then
local sp = current.GetScore()
wShake()
if (current.GetScore()-sp)>(step*(1+iter)) then
wShake()
end
else
local sp = current.GetScore()
wWiggle()
if (current.GetScore()-sp)>(step*(1+iter)) then
ncWiggle(how, iters+1, iter+1)
end
end
end
local function wiggle(prot,options )
local do_wiggle
local iter
-- establish if this is a global or local operation
if ( options.global_wiggle == true ) then
do_wiggle = ncWiggle('a')
else
do_wiggle = ncWiggle('l')
end
-- establish how to execute wiggle
if ( options.allow_float_wiggle_count == true ) then
local mean
local upper
local lower
local bounds
mean = options.wiggle_count
upper = options.wiggle_count_upper
lower = options.wiggle_count_lower
bounds = options.wiggle_count_bounds
iter = get_value2(mean,bounds )
--iter = get_value ( mean, lower, upper )
else
if ( prot.bands_enabled ) then -- are we flexing ?
iter = options.wiggle_count
else
iter = options.wiggle_out_count
end
end
if ( options.verbose == true ) then
-- print ( "Performing Wiggle | iters = ", iter )
end
ncWiggle('a', iters, iter)
end
local function show_score(options )
local s
local gn
gn = ""
if ( options.exploratory == true ) then
s = current.GetScore()
local n = {
[true] = "Yes",
[false] = "No",
}
print ( "Stabilization Score = ", current.GetEnergyScore())
print ( "Ranking score = ", current.GetScore())
print ( "Multiplier: ", current.GetExplorationMultiplier() )
print ( "Conditions met: ", n [current.AreConditionsMet()] )
if ( s > options.ranked_score ) then
save.Quicksave(options.qs_recent_best )
if ( options.ranked_score ~= 0 ) then
local gain = s-options.ranked_score
gn = " + "..gain
end
options.score = current.GetEnergyScore()
options.ranked_score = s
options.multiplier = current.GetExplorationMultiplier()
end
print ( "Ranking Score = ", s..gn )
print ("")
else
s = current.GetEnergyScore()
if ( s > options.score ) then
if ( options.score ~= 0 ) then
local gain = s-options.score
gn = " + "..gain
end
options.score = s
end
print ( "Score = ", s..gn )
--print ("")
end
return options
end
local function freeze_rods(prot,options )
local r_idx
local r_idx2
local l_idx
local l_idx2
local freeze_sc
local freeze_bb
selection.DeselectAll()
r_idx = prot.R_idx
r_idx2 = prot.R_idx2
l_idx = prot.L_idx
l_idx2 = prot.L_idx2
freeze_sc = options.freeze_sidechains
freeze_bb = options.freeze_backbone
selection.SelectRange(r_idx,r_idx2 )
selection.SelectRange(l_idx,l_idx2 )
if ( options.verbose == true ) then
local _s = {
[true] = "true",
[false] = "false",
}
-- print ( "Freezing backbone.." )
-- print ( "backbone = ", _s [freeze_bb] )
-- print ( "sidechains = ", _s [freeze_sc] )
end
freeze.FreezeSelected(freeze_bb, freeze_sc )
selection.SelectAll()
end
local function rod_add_bands(prot,options )
local idx
local idx2
local str
local k
idx = prot.R_idx
idx2 = prot.L_idx2
k = structure.GetCount() + 1
str = options.band_strength
if ( options.verbose == true ) then
-- print ( "Placing bands.." )
-- print ( "Setting band strength: ", str )
end
for i = 0,3 do
local n
local n2
n = idx + i
n2 = idx2 - i
if (( n < k ) and ( n2 > 0 )) then
band.AddBetweenSegments(n,n2 )
band.SetStrength(i+1,str )
end
end
end
local function set_clash_importance(options )
local ci
if ( options.allow_ci_float == true ) then
local mean
local upper
local lower
local bounds
mean = options.ci
upper = options.ci_upper
lower = options.ci_lower
bounds = options.ci_bounds
ci = get_value2(mean,bounds )
--ci = get_value(mean, lower, upper )
else
ci = options.ci
end
if ( options.verbose == true ) then
--print ( "Setting clash importance: ", ci )
end
behavior.SetClashImportance(ci )
end
local function reset_clash_importance(options )
if ( options.verbose == true ) then
-- print ( "Resetting clash importance: ", 1 )
end
behavior.SetClashImportance(1)
end
local function turn_bands_on(prot, options )
if ( options.verbose == true ) then
--print ( "Enabling bands.." )
end
band.EnableAll()
prot.bands_enabled = true
set_clash_importance(options )
return prot
end
local function turn_bands_off(prot, options )
if ( options.verbose == true ) then
--print ( "Disabling bands.." )
end
band.DisableAll()
prot.bands_enabled = false
reset_clash_importance ( options )
return prot
end
local function unfreeze_rods(prot,options )
freeze.UnfreezeAll()
end
local function freeze_hinge(prot,options )
local glycine_idx
local freeze_bb
local freeze_sc
selection.DeselectAll()
glycine_idx = glycine_locator(prot,options )
freeze_sc = options.freeze_sidechains
freeze_bb = options.freeze_backbone
selection.Select(glycine_idx )
freeze.FreezeSelected(freeze_bb,freeze_sc )
selection.SelectAll()
end
local function unfreeze_hinge(prot,options )
freeze.UnfreezeAll()
end
local function check_preconditions(prot, options )
if options.freeze_hinge_instead == true then
turn_bands_on(options )
wiggle(prot,options )
turn_bands_off(options )
unfreeze_rods(prot,options )
freeze_hinge(prot,options )
end
end
function nbl_hinge(seg, hw, prot, options)
if (hw==1) then
print ("Segment: " .. seg)
else
print ("Segments: " .. seg .. "-" .. seg+hw-1)
end
prot = build_hinge(prot, options, seg, hw)
freeze_rods(prot, options )
rod_add_bands(prot, options )
save_recent_best(options )
check_preconditions(prot, options )
prot = turn_bands_on(prot, options )
wiggle(prot, options )
prot = turn_bands_off(prot, options )
wiggle(prot, options )
recall_recent_best(options )
options = show_score(options )
freeze.UnfreezeAll()
band.DeleteAll()
end
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
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
function bkh(hinge_width, prot, options)
--print ("Segs aleatoires")
print ("Random segs")
compteur=0 -- intialise le compteur de WORKONBIS
p=print --"quicker" print
segCnt=structure.GetCount()
--segCnt=segCnt-1 -- for lingard puzzles only! sera initialise par seglock
flagligand=false
segCnt2=segCnt -- cas de ligands
segStart = range_min
segEnd = range_max
while structure.GetSecondaryStructure(segCnt2)=="M" do segCnt2=segCnt2-1 flagligand=true end
WORKON={{1,segCnt2}} --BK16/04/2014
WORKONBIS={}
for i = segStart, segEnd do
compteur=compteur+1
WORKONBIS[compteur]=i
end
ShuffleTable(WORKONBIS) -- NEW 24/9/2013 mix the segment table randomly
si=current.GetScore()
--print ("Score initial: " .. si)
print ("Starting score: " .. si)
for run = 1, nbrun do
print()
--print ("Boucle " .. run .. " sur " .. nbrun)
print ("Loop " .. run .. " of " .. nbrun)
Zone(1, #WORKONBIS, hinge_width, prot, options)
end
end
function nblh(hinge_width, prot, options)
for run = 1, nbrun do
if (run > 1) then
rci = math.random() / 5
options.ci = ici + rci - 0.1
rbs = math.random() / 10
options.band_strength = ibs + rbs - 0.05
end
print()
--print ("Boucle " .. run .. " sur " .. nbrun)
print ("Loop " .. run .. " of " .. nbrun)
print ("CI " .. options.ci)
print ("Band strength " .. options.band_strength)
si=current.GetScore()
--print ("Score initial: " .. si)
print ("Starting score: " .. si)
for i=range_min, range_max do
nbl_hinge(i, hinge_width, prot, options)
end
print ("Gain: " .. current.GetScore()-si)
--print ("Gain total: " .. current.GetScore()-startscore)
print ("Total gain: " .. current.GetScore()-startscore)
end
end
do
local prot
local options
print ( "NBL_hinge v1.1" )
options = _options
prot = _prot
ici = options.ci
ibs = options.band_strength
math.randomseed(os.time()%1000000)
math.random(100)
freeze.UnfreezeAll()
band.DeleteAll()
startscore=current.GetScore()
sc = structure.GetCount()
range_min = 3
range_max = sc-3
local ask = dialog.CreateDialog("nbl_hinge")
--ask.hinge_width = dialog.AddSlider("Taille charnieres: ",1,1,2,0)
ask.hinge_width = dialog.AddSlider("Hinges size: ",1,1,2,0)
--ask.keep_trying = dialog.AddCheckbox("Toute la nuit ", true)
ask.keep_trying = dialog.AddCheckbox("Keep trying ", true)
--ask.random = dialog.AddCheckbox("Segs aleatoires ", false)
ask.random = dialog.AddCheckbox("Random ", false)
--ask.range = dialog.AddTextbox("Zone forcee", "")
ask.range = dialog.AddTextbox("Range ", "")
ask.OK = dialog.AddButton("OK",1)
ask.Cancel = dialog.AddButton("Cancel",0)
if (dialog.Show(ask) > 0) then
hinge_width = ask.hinge_width.value
keep_trying = ask.keep_trying.value
random = ask.random.value
if (ask.range.value ~= "") then
local rangetext=ask.range.value
local rangelist=ReadSegmentSet(rangetext)
if not Errfound then
range_min = rangelist[1][1]
if (range_min<3) then range_min = 3 end
range_max = rangelist[1][2]
if (range_max > sc-3) then range_max = sc-3 end
else
print ("Error in range, using default")
end
end
else
Exit()
end
if keep_trying then
nbrun = 100
else
nbrun=1
end
if random then
bkh(hinge_width, prot, options)
else
nblh(hinge_width, prot, options)
end
end