Icon representing a recipe

Recipe: BiS Wiggle 1.2 - Brow42

created by brow42

Profile


Name
BiS Wiggle 1.2 - Brow42
ID
37466
Shared with
Public
Parent
None
Children
Created on
September 15, 2012 at 21:37 PM UTC
Updated on
September 15, 2012 at 21:37 PM UTC
Description

Wiggle with random bands to space. New defaults from 1.0. Now ignores locked segs. Removes bands on cancel.

Best for


Code


--[[ =================================== * BiS Wiggle nee ZLB Wiggle * Original Author: Brow42 * Version 1.0 Jan. 15 2012 * This does random small bands and then wiggles * restoring best periodically. This may find a few * 0.001s of a point in the end game. * Version 1.0.1 * New defaults, fixed random sphere to be correct (not hemisphere) * Version 1.0.2 * Added option to reverse bands and wiggle * Version 1.1 Apr. 27 2012 Brow42 * Now checks for locked segments and skips them * Now bands terminal segments correctly * Removes bands on cancel * Version 1.1.1 Sep 14 2012 Brow42 * Checkbox to allow banding to locked segments * Name changed to BiS Wiggle to avoid confusion with Zero Length Bands * WiggleAll changed to 2 iterations as per jflat advice * Version 1.2 Sept. 15 2012 Brow42 * Added slider for # of wiggles * Added unbanded wiggle before score check * Band removal on cancel actually works * Auto detects all-locked puzzles --]] NSeg = structure.GetCount() -- Will be recomputed later options = { band_str = 2.5, max_len = 0.3, do_bb = true, do_sc = false, nbands = 1, restore_every=1, flip = false, lockedok = false, nwiggle = 1, unbanded = false } title = 'BiS WIggle' version='1.1.2' update_every = 10 -- ================================== Begin New Dialog Library Functions --[[ Throws up a dialog containing just text, provided as a string or table of strings in the first argument. Title and buttons are optional. Return value is 1 if the first button is clicked and 0 if the second button is clicked or the window is closed. --]] function dialog.MessageBox(msg,title,buttontext1, buttontext0) title = title or '' local d = dialog.CreateDialog(title) if type(msg) == 'string' then d['1'] = dialog.AddLabel(msg) else for i = 1,#msg do d[tostring(i)] = dialog.AddLabel(msg[i]) end end buttontext1 = buttontext1 or 'Ok' d.button = dialog.AddButton(buttontext1,1) if buttontext0 then d.button0 = dialog.AddButton(buttontext0,0) end return dialog.Show(d) end --[[ Add items to the dialog from a table in the order given. The each table entry is the dialog control function, the control label, the data key name, and the control options. If this function fails, it gives an error saying which table item it failed on. d = a created dialog, fields = table of dialog controls as described, object = data table --]] function dialog.AddFromTable(d,fields,object) local func, label, id, value -- renamed field parameters for clarity -- function wrappers to catch errors, explicitly named for clarity function _AddLabel(args) d[id] = dialog.AddLabel(label) end function _AddCheckbox(args) d[id] = dialog.AddCheckbox(label,value) end function _AddSlider(args) d[id] = dialog.AddSlider(label,value,args[4],args[5],args[6]) end function _AddTextbox(args) d[id] = dialog.AddTextbox(label,value) end for i = 1, #fields do local rc = true local err rc,err = pcall( function() func,label,id = fields[i][1],fields[i][2],fields[i][3] end) value = object[id] if func == dialog.AddLabel then id='_AL'..tostring(i) rc,err = pcall(_AddLabel,fields[i]) else -- this is a crasher for AddTextbox but not an error for AddLabel! if value == nil then error('Missing data field for field #'..tostring(i)..'\n(Did you forget to pass a string?)') end if func == dialog.AddCheckbox then rc,err = pcall(_AddCheckbox,fields[i]) elseif func == dialog.AddSlider then rc,err = pcall(_AddSlider,fields[i]) elseif func == dialog.AddTextbox then rc,err = pcall(_AddTextbox,fields[i]) else error('Unknown control in dialog field #'..tostring(i)) end end -- if AddLabel if rc == false then error('Error setting dialog field #'..tostring(i)..(err and ('\n'..err) or '')) end end end --[[ This just copies the data from the dialog to the data table. --]] function dialog.ReadFields(d,fields,object) for i = 1,#fields do if fields[i][1]~= dialog.AddLabel then object[fields[i][3]] = d[fields[i][3]].value end end end -- ================================== End New Dialog Library Functions function DoInfoDialog() dialog.MessageBox( {'This does random small bands and then wiggles', 'restoring best periodically. This may find a few', ' 0.001s of a point in the end game.'},'About '..title,'Okay') end function DoOptionsDialog() fields = { { dialog.AddSlider,'Band Str:', 'band_str', 0.1,10,1 }, { dialog.AddSlider,'Max Len:', 'max_len', 0.01,1.,2 }, { dialog.AddSlider, '# Bands:', 'nbands', 1,NSeg, 0 }, { dialog.AddSlider, 'Restore Every', 'restore_every', 1,20, 0 }, { dialog.AddSlider, '# Wiggle', 'nwiggle', 1, 10, 0}, { dialog.AddCheckbox, 'Band Backbone', 'do_bb' }, { dialog.AddCheckbox, 'Band Sidechain C-b', 'do_sc'}, { dialog.AddCheckbox, 'Wiggle then Reverse and Wiggle again','flip'}, { dialog.AddCheckbox, 'Locked/Froze Okay','lockedok'}, { dialog.AddCheckbox, 'Unbanded wiggle before restore','unbanded'} } d = dialog.CreateDialog(title..' v'..version) dialog.AddFromTable(d,fields,options) d.okay = dialog.AddButton('Start',1) d.cancel = dialog.AddButton('Cancel',0) d.about = dialog.AddButton('About',-1) rc = dialog.Show(d) dialog.ReadFields(d,fields,options) return rc end fsl = fsl or {} fsl.atom = fsl.atom or {} fsl.atom.atomcount = { -- shorter table just for identifying terminals a=10, c=11, d=12, e=15, f=20, g=7, h=17, i=19, k=22, l=19, m=17, n=14, p=15, q=17, r=24, s=11, t=14, v=16, w=24, y=21 } function fsl.atom._IsDisulfideBonded(iSeg) local s = current.GetSegmentEnergySubscore(iSeg,'disulfides') return tostring(s) ~= '-0' end function fsl.atom._IsTerminalTest(aa,count,disulfide) local diff = count - fsl.atom.atomcount[aa] if disulfide then diff = diff + 1 end -- because count is one less because a H was removed if diff == 0 then return false, false, disulfide elseif diff == 1 then return false, true, disulfide elseif diff == 2 then return true, false, disulfide elseif diff == 3 then return true, true, disulfide end error('Strange atom count, report this!') end function band.SetParams(iBand, goal, str) band.SetGoalLength(iBand, goal) band.SetStrength(iBand, str) end -- Pick a random combination from 1 - N function math.Pick(k,n) local l = {} local m = {} for i=1,n do l[i] = i end for i = 1,k do local j = math.random(n) m[i] = l[j] l[j] = l[n] n = n - 1 end table.sort(m) return m end ValidSegments = {} function DoBanding(seglist, do_bb,bandlist) local nseg = structure.GetCount() bandlist = bandlist or {} for i = 1,#seglist do local phi,rho,theta,s1,s2,s3 s1 = ValidSegments[seglist[i]] if s1 == 1 then s2,s3 = 2,3 elseif s1 == nseg then s2,s3 = nseg-1,nseg-2 else s2,s3 = s1-1,s1+1 end if do_bb then phi,theta,rho = RandomSphere() iBand = band.Add(s1,s2,s3,rho,theta,phi,0) band.SetParams(iBand,0.0,options.band_str) bandlist[#bandlist+1] = {s1,s2,s3,rho,theta,phi,0,0.0,options.band_str} elseif structure.GetSecondaryStructure(s1) ~= 'M' and structure.GetAminoAcid(s1) ~= 'g' then local first,last,disulfide = fsl.atom._IsTerminalTest( structure.GetAminoAcid(s1), structure.GetAtomCount(s1), fsl.atom._IsDisulfideBonded(s1)) phi,theta,rho = RandomSphere() iBand = band.Add(s1,s2,s3,rho,theta,phi,last and 6 or 5) band.SetParams(iBand,0.0,options.band_str) bandlist[#bandlist+1] = {s1,s2,s3,rho,theta,phi,5,0.0,options.band_str} end end return bandlist end function ReverseBands(bandlist) unpack = unpack or table.unpack local s1,s2,s3,rho,theta,phi,atom,len,str for i = 1,#bandlist do s1,s2,s3,rho,theta,phi,atom,len,str = unpack(bandlist[i]) theta = math.pi - theta phi = (phi + math.pi) % (2 * math.pi) iBand = band.Add(s1,s2,s3,rho,theta,phi,atom) band.SetParams(iBand,len,str) end end function RandomSphere() return 2 * math.pi * math.random(), math.acos(2*math.random()-1), math.random()^(1/3) * options.max_len +0.01 end function PrintTable(tab,indent) indent = indent or '' for i,v in pairs(tab) do if type(v) == 'table' then print(i) PrintTable(v,indent..' - ') else print(i,v) end end end function round(x,n) return math.floor(0.5 + x * 10^n) / 10^n end function IsValidSegment(iSeg) return options.lockedok or not structure.IsLocked(iSeg) end NBands = band.GetCount() function ResetBands() while band.GetCount() > NBands do band.Delete(band.GetCount()) end end -- ===================== Begin Main ===================== print(puzzle.GetName(), os.date()) seed = (os.time() * 5779) % 10000 math.randomseed(seed) if options.lockedok == false then print ('Checking for all-locked puzzle') options.lockedok = true for i = 1,NSeg do if structure.IsLocked(i) == false then options.lockedok = false break end end end repeat local rc = DoOptionsDialog() if rc == 0 then print('Canceled.') return end if rc == -1 then DoInfoDialog() end until rc == 1 for i=1,NSeg do if IsValidSegment(i) then table.insert(ValidSegments,i) end end NSeg = #ValidSegments if NSeg == 0 then print('Couldn\'t find any wiggle-able segments.') dialog.MessageBox('No segments to wiggle! (all are locked maybe?)','Can\'t Wiggle!','Quit') return end print('seed =',seed) print('Options:') PrintTable(options) recentbest.Save() score = current.GetScore() print('Start Score:',score) print(' Round Change Energy') function Main() -- wrapper for cancel catch iLoop = 0 repeat ResetBands() bandlist = {} if options.do_bb then bandlist = DoBanding(math.Pick(options.nbands, NSeg),true, bandlist) end if options.do_sc then bandlist = DoBanding(math.Pick(options.nbands, NSeg),false, bandlist) end structure.WiggleAll(2 * options.nwiggle) if options.flip then ResetBands() ReverseBands(bandlist) structure.WiggleAll(2 * options.nwiggle) end if options.unbanded then ResetBands() structure.WiggleAll(2 * options.nwiggle) end local current_score = recentbest.GetScore() iLoop = iLoop + 1 if iLoop % options.restore_every == 0 then recentbest.Restore() end if iLoop % update_every == 0 then print('Round #',iLoop,round(current_score-score,5),round(current_score,3)) end until false end function OnError(err) -- Thanks to Tlaloc for example if err:find('Cancel') then print('User Cancel -- Removing bands') ResetBands() return false end print('ERROR',err) return err end xpcall(Main, OnError)

Comments


brow42 Lv 1

When I can't get any more points, I would take one band to space and pull it around with the mouse while wiggling and seeing if the score would go up. This will maybe do sort of the same thing, with small random bands followed by a wiggle and restore recent best. You can set the band strength, the band length, how many bands to make, and how often to restore. You can band to the backbone or the sidechain or both.

brow42 Lv 1

  • Version 1.0.1 Jan. 17 2012 Brow42
  • New defaults, fixed random sphere to be correct (not hemisphere)

  • Version 1.0.2 Mar. 6 2012 Brow42
  • Added option to reverse bands and wiggle

  • Version 1.1 Apr. 27 2012 Brow42

  • Now checks for locked segments and skips them
  • Now bands terminal segments correctly
  • Removes bands on cancel

1.1 posting pending server certificate working resolution.

brow42 Lv 1

Version 1.1.1 Sep 14 2012 Brow42

Checkbox to allow banding to locked segments
Name changed to BiS Wiggle to avoid confusion with Zero Length Bands http://fold.it/portal/recipe/37147
WiggleAll changed to 2 iterations as per jflat advice

Wiggle should always be an even number because step 1 of wiggle minimizes energy and step 2 of wiggle restores constraints.

Vredeman Lv 1

Brow. I found that stopping this script with every minor gain and then starting it again with the same settings seems benificial. If I was proficient at programming I would mske it do this automatically. Then I would let it up the ci and start again.