Icon representing a recipe

Recipe: CG303 GAB+EO V5.11

created by Crashguard303

Profile


Name
CG303 GAB+EO V5.11
ID
45465
Shared with
Public
Parent
None
Children
None
Created on
February 27, 2013 at 23:40 PM UTC
Updated on
February 27, 2013 at 23:40 PM UTC
Description

Adapted Version of Jeff's GAB V4.701+EO.
Since we have a small InputBox now for some of the many parameters, I did more code-documentation and moved the overriding of values via box into a separate function to keep the parameter initalizing block readable in one piece.
The variable intializing block also gives default values for the input box.
In the box, I changed the EOF-flag slider to a checkbox, as the flag can only be true or false.
Remember, when checking it, NO real genetic algorithm is executed anymore!
Extremal Optimization doesn't mean breeding two solutions (clusters), it is rather keeping or dropping them and creating random new ones (as the genetic algorithm also does, but not that much).
Moreover, I added a 2 sliders,
one for setting Herd size at start and one its maxium size.

Best for


Code


-- adapted 2/27/13 by Crashguard 303 from CG303 GAB V4.701+EO -- some minor changes like function positioning. -- changed EO slider to checkbox, as flag can be only true or false -- adapted 9/2/12 by jeff101 from CG303 GAB V4.70+EO --[[ Genetic Bands III by Crashguard303 Inspired by cartoon Villains Script, I created this one, including freezing. This script also works on not-very-best puzzle-states. Random Creating: It creates a set of clusters (herd). Each cluster has a random set of bands,freezes and a drift value. There is a random list, which segments have already been banded or frozen, so it is guaranteed that all are tried. If all have been tried, this list is shuffled, all segments are tried again. The drift shows, in which directions banding or freezing segments can move. (-1 will increase current segment number by, +1 will increase segment number by 1, 0 wont exist) Then, for this puzzle state, all clusters are tried. This means: Pulling: Bands and freezes are applied (plus constant bands, if you want), the puzzle is wiggled for one iteration. Releasing: Bands and freezes are removed. 4 different subroutines similar to blue fuse run. They test different clashing-importance shake/wiggle combinations. The best result of the fuse is stored to the cluster score. Sorting: If all clusters were tried, they are sorted by the scores they created, double score results are moved to the end of the list. The best cluster is on top, the worst or and equal cluster is on bottom at the list. Breeding: All clusters from BreedFirst to BreedLast are breeded, first best with other random clusters, preferring good ones The cluster with the most bands is mom, cluster with fewer bands is dad. Bands of mom and drift value are copied at first, then a random crossover point is generated within the length of dads bands. Bands from 1 to inclusive crossover point from the new cluster are replaced by bands of dad, rest of mom The same happens to freezes. Mutating: For each band or freeze: A random flag (Drift flag or multiplicator) (either 0 or 1) is created, depending on mutation probability. If this flag is 1, drift value (-1 or +1) is added to the segment index, in other case, the segment index stays the same. Band length and strength are randomly changed between an amount of -0.1 to 0.1 When mutating, all values are checked after they are changed, to guarantee that they dont leave a legal value range. Inverting: For each band or freeze: A random flag (inversion flag) (either o or 1) is created, depending on inverting probability. If this flag is 1, segment values are inverted, which means multiplying them by -1 Negative segment values results banding or freezing skip, they are deactivated. If a segment has a negative value and is inverted, the value is positive and activated again Filling: The rest of the herd (BreedLast+1 to HerdSize) is replaced by new random clusters, as described in Random Creating. Restart: When new clusters have been breeded or replaced, the recent best puzzle state is loaded. and pulling is performed again. END OF MAIN DESCRIPTION P.S.: If you find typos, you can keep them ;) ]]-- function math.frandom(m,n,e) -- float random, e is number of remaining decimal digits local e2=10^e return math.random(m*e2,n*e2)/e2 end -- math.frandom() function math.sgn(x) -- Signum function if x==nil then return nil elseif x>0 then return 1 elseif x<-0 then return -1 else return x end -- if end -- math.sgn() function CutOff(x,y) -- Keep only y digits after decimal point from x return math.floor(x*10^y)/10^y end -- CutOff() function UseSegIRange(UseList,A,B,StepSize,bool) -- In table "UseList", append or remove segment range A to B local UseList=UseList local A=A -- range start local B=B -- range end if A>B then A,B=B,A end -- Swap range start and end, if values are not okay local StepSize=StepSize local bool=bool -- True=append, false=remove local k=A repeat UseList=UseList_AR(UseList,k,bool) k=k+StepSize -- increase k by StepSize until k>B -- until k exceeds B return UseList end -- UseSegIRange() function UseSegIValues(UseList,field,bool) -- In table "UseList", append or remove segments listed in table "field" local UseList=UseList local field=field -- table to add local bool=bool -- True=append, false=remove local k if #field>0 then -- If table to add is not empty for k=1,#field do -- cycle through all elements from table UseList=UseList_AR(UseList,field[k],bool) end -- k loop end -- if #field return UseList end -- UseSegIValues() function Use_ss(UseList,SSLetter,bool) -- In table "UseList", append or remove segments with secondary structure "SSLetter" local UseList=UseList local SSLetter=SSLetter local bool=bool -- True=append, false=remove local k for k=1,NumSegs do -- Cycle through all segment indices if structure.GetSecondaryStructure(k)==SSLetter then -- If current segment index has same ss as given UseList=UseList_AR(UseList,k,bool) end -- if get_ss end -- k loop return UseList end -- Use_ss() function Use_aa(UseList,AALetters,bool) -- In table "UseList", append or remove segments with amino-acid in table "AALetters" local UseList=UseList local AALetters=AALetters local bool=bool -- add or remove if #AALetters>0 then -- Is there minimum one aa letter given? local k for k=1,NumSegs do -- Cycle through all segments local aa=get_aa(k) -- get current aa of segment index k local exit_condition=false local l=0 repeat l=l+1 -- Cycle through all given aa letters if aa==AALetters[l] then -- If current segment ks aa is equal to AALetters[l] UseList=UseList_AR(UseList,k,bool) exit_condition=true -- l loop can end here end -- if aa if l==#AALetters then exit_condition=true end until exit_condition==true end -- k loop end -- if AALetters return UseList end -- Use_aa() function Use_distance(UseList,MinDist,MaxDist,MinQuantity,MaxQuantity,bool) -- In table "UseList", append or remove segments which have -- MinQuantity to MaxQuantity neighbours within distance MinDist to MaxDist local MinDist=MinDist local MaxDist=MaxDist local MinQuantity=MinQuantity local MaxQuantity=MaxQuantity local bool=bool -- True=append, false=remove for k=1, NumSegs do -- Cycle through all segments local QCount=0 for l=1,NumSegs do -- compare index k with all around if l~=k then -- Dont count segment itself, only neighbours local Distance=structure.GetDistance(k,l) -- Measure distance from segment k to segment l if Distance>=MinDist then -- If equal or above min distance if Distance<=MaxDist then -- If equal or below max distance QCount=QCount+1 -- count this segment end -- if Distance end -- if Distance end -- if l end -- l loop if QCount<=MaxQuantity then -- If count is equal or below max quantity if QCount>=MinQuantity then -- If count is equal or above min quantity UseList=UseList_AR(UseList,k,bool) -- add or remove from list end -- if QCount end -- if QCount end -- k loop return UseList end -- Use_distance() function Use_close_ligand(UseList,MaxDist,bool) -- In table "UseList", append or remove segments which have -- a spatial distance of MaxDist or closer to ligand. local UseList=UseList local MaxDist=MaxDist local bool=bool -- True=append, false=remove local LigandIdx=NumSegs+1 -- Ligand Index local k for k=1,NumSegs do -- Cycle with k through all segments but not ligand local Distance=structure.GetDistance(k,LigandIdx) -- Check spatial distance of segment k to ligand if Distance<=MaxDist then -- If equal or below MaxDist UseList=UseList_AR(UseList,k,bool) -- add or remove from list end -- if end -- k loop return UseList end -- Use_close_ligand() function UseList_AR(UseList,value,bool) -- Append value "value" to UseList -- or remove all values out of UseList, depending on bool local UseList=UseList local value=value local bool=bool -- True=append, false=remove -- local OS=OS -- Temporary string for output if bool==true then UseList=UseList_Append(UseList,value) -- OS=OS.."In" else UseList=UseList_Remove(UseList,value) -- OS=OS.."Ex" end -- if bool -- OS=OS.."cluding segment index "..value -- print(OS) return UseList end -- UseList_AR() function UseList_Append(UseList,value) -- Adds content of "value" at end of UseList local UseList=UseList local value=value UseList[#UseList+1]=value return UseList end -- UseList_Append() function UseList_Remove(UseList,value) -- Creates new use list "UseList2" out of "UseList", but without all content of "value" local UseList=UseList local value=value local UseList2={} -- Initialize new uselist if #UseList>0 then -- if old for k=1,#UseList do -- Scan UseList if UseList[k]~=value then -- If "value" is not found UseList2[#UseList2+1]=UseList[k] -- append this content to new use list end -- if UseList end -- k loop end -- if UseList return UseList2 end -- UseList_Remove() function CompactContent(OS,E,AS) --[[ Adds string AS to temporary output string OS and counts number of added AS in E. If OS contents 10 elements, line is printed out I only had to write this sub because there Lua standard library is not included. We neither can do some string manipulation nor use a print command without linebreaks at the moment :/ ]]-- local OS=OS -- Temporary string for output local AS=AS -- String to add local E=E -- Element counter, how often AS was added E=E+1 if AS<10 then -- Sorry for this, but there are no string operations possible at the moment OS=OS.."00"..AS elseif AS<100 then OS=OS.."0"..AS else OS=OS..AS end -- if AS if E<10 then -- If there are not 10 elements per line OS=OS.." " -- add space else -- If there are 10 elements per line print(OS) -- print line out OS="" -- clear output string E=0 -- reset element counter end -- if E return OS,E end -- CompactContent() function CheckUselist(UseList) -- If there are fewer than 3 specific segments to work on given, take all local UseList=UseList if #UseList<=3 then print('No or too few specific segments to work on given.') print('Banding and freezing will now manipulate all puzzle segments.') UseList={} local k for k=1,NumSegs do -- Cycle through all segments UseList[#UseList+1]=k -- extend UseList by 1 and add segment index end -- k loop end -- if UseList print('Segment list is now:') local OS="" -- Initialize output string local E=0 -- Initialize element counter local k for k=1,#UseList do OS,E=CompactContent(OS,E,UseList[k]) end -- k if E>0 then print(OS) end return UseList end -- CheckUselist() function shuffle2(ShuffleProb) -- Scrambles segment use list depending on ShuffleProb print('Shuffling segment list') local kend=#UseList-1 local k for k=1,kend do -- Cycle through all UseList entries if math.random()<ShuffleProb then -- If random value<probability -- same as: if random_flag(ShuffleProb) then local l=math.random(k+1,#UseList) -- pick random list entry behind k UseList[k],UseList[l]=UseList[l],UseList[k] -- swap values of UseList index k with UseList index l end -- if random end -- k loop UsedSegments=0 -- After Shuffling, set list pointer to 0 end -- shuffle2() function random_segment() -- Gets a random segment index out of UseList which has not been used so far UsedSegments=UsedSegments+1 -- Increase UseList pointer local Seg_result=UseList[UsedSegments] -- fetch segment index if UsedSegments==#UseList then shuffle2(ShuffleProb) end -- If this was the last value of UseList, shuffle list and reset pointer return Seg_result -- return random segment number end -- random_segment() function FillHerd(StartAt,EndAt,TimeStamp) local StartAt=StartAt -- First cluster index to generate (not cluster slot) if StartAt<=HerdSize then local EndAt=EndAt -- Last cluster index to generate (not cluster slot) local TimeStamp=TimeStamp -- "birth date" print('Generating Herd from '..StartAt..' to '..EndAt) local k2 for k2=StartAt,EndAt do -- print('Cluster: '..k2) local k=ClusterPointer[k2] -- Fetch cluster slot by cluster index ClusterScore[k]=0 ClusterDrift[k]=random_direction() -- Create value -1 or 1 if (Mimic and k2==1) then -- If this is a Mimic band ClusterType[k]="mimic" -- set cluster information for Mimic else -- If this is not a Mimic band ClusterType[k]="random" -- set cluster information for random end -- if k2 ClusterType[k]=ClusterType[k].."-"..TimeStamp -- Show "birth date" if ClusterBands>0 then ClusterSegA[k]={} ClusterSegB[k]={} ClusterLength[k]={} ClusterStrength[k]={} local l for l=1,ClusterBands do if puzzle_is_ligand==false then -- If this is no ligand puzzle ClusterSegA[k][l]=random_segment() -- get random segment number else -- If this is a ligand puzzle ClusterSegA[k][l]=NumSegs+1 -- Segment A is always ligand end -- if puzzle_is_ligand if (Mimic==false or k2~=1) then -- If this is not a Mimic band if random_flag(InvBProb) then -- and random flag for inverting is given ClusterSegA[k][l]=-ClusterSegA[k][l] -- toggle cluster on/off by changing signum (+/-) end -- if random_flag end -- if k2 repeat ClusterSegB[k][l]=random_segment() local IDistance=index_distance(ClusterSegA[k][l],ClusterSegB[k][l]) -- fetch index distance local SDistance=structure.GetDistance(math.abs(ClusterSegA[k][l]),ClusterSegB[k][l]) -- fetch spatial distance until IDistance>=MID_Game and SDistance<=MaxBL_Game -- Segments must have a minimum index distance -- and maximum spatial distance if (Mimic and k2==1) then -- If this is a Mimic band ClusterLength[k][l]=FactorByLength(ClusterSegA[k][l],ClusterSegB[k][l]) ClusterStrength[k][l]=MaxBS else -- if k2 ClusterLength[k][l]=math.frandom(0,1,6) ClusterStrength[k][l]=math.frandom(MinBS,MaxBS,3) end -- if k2 end -- l loop end -- if ClusterBands if ClusterFreezes>0 then ClusterFreeze[k]={} local l for l=1,ClusterFreezes do ClusterFreeze[k][l]=random_segment() if (Mimic and k2==1) or random_flag(InvFProb) then -- If this is a Mimic band or random flag for inverting freeze information is given ClusterFreeze[k][l]=-ClusterFreeze[k][l] -- toggle freeze on/off by changing signum (+/-) end -- if random_flag end -- l loop end -- if end -- k loop end -- if StartAt end -- FillHerd() function ShowHerd() local k2 local l print('Clusters are:') for k2=1,HerdSize do local k=ClusterPointer[k2] print('Cluster:'..k2..' score:'..ClusterScore[k]..' drift:'..ClusterDrift[k]) if ClusterBands>0 then local l for l=1,ClusterBands do print('Band '..l..': '..ClusterSegA[k][l]..' to '..ClusterSegB[k][l]) end end -- if ClusterBands if ClusterFreezes>0 then local l for l=1,ClusterFreezes do print('Freeze '..l..': '..ClusterFreeze[k][l]) end -- l end -- if end -- k loop end -- ShowHerd() function ShowHerdShort() print('Clusters are:') local k2 for k2=1,HerdSize do local k=ClusterPointer[k2] print('Cluster:'..k2..'('..k..') score:'..ClusterScore[k]) print('Drift:'..ClusterDrift[k]) end -- k loop end -- ShowHerdShort() function ShowScoreList() local k2 for k2=1,HerdSize do local k=ClusterPointer[k2] print('Cluster:'..k2..'('..k..') delta:'..ClusterScore[k]) end -- k end -- ShowScoreList() function SortHerd() -- As we use pointers, we only have to swap the cluster "adresses" instead of copying all band/freeze values local Finish=HerdSize-1 local k for k=1,Finish do local start=k+1 local l for l=start,HerdSize do if ClusterScore[ClusterPointer[l]]>ClusterScore[ClusterPointer[k]] then -- print('Swapping cluster '..k..'('..ClusterPointer[k]..'):'..l..'('..ClusterPointer[l]..')') ClusterPointer[l],ClusterPointer[k]=ClusterPointer[k],ClusterPointer[l] end -- if end -- l end -- k end -- SortHerd() function CreateCrossoverPoint(x) -- create random crossover point if x==0 then return 0 else -- if x ~=0 -- return math.random(0,x) -- create random value between 0 and x return math.random(1,x-1) -- create random value between 1 and x-1 end -- if x end -- CreateCrossoverPoint() function Breed(TimeStamp) -- Copy all clusters to another bank, same name for all cluster tables but with 2 at end -- Breed two clusters from bank 2 back to old bank to prevent breeding collision. -- If this wouldnt be done, and (for example) cluster 1 and 2 would be breeded to cluster 3, -- cluster 3 couldnt be used as breeding source again, as it would be overwritten already. local TimeStamp=TimeStamp -- "birth date" ClusterScore2={} -- ClusterType2={} ClusterDrift2={} ClusterSegA2={} ClusterSegB2={} ClusterLength2={} ClusterStrength2={} ClusterFreeze2={} local k for k=1,HerdSize do ClusterScore2[k]=ClusterScore[k] ClusterDrift2[k]=ClusterDrift[k] if ClusterBands>0 then ClusterSegA2[k]={} ClusterSegB2[k]={} ClusterLength2[k]={} ClusterStrength2[k]={} local l for l=1,ClusterBands do ClusterSegA2[k][l]=ClusterSegA[k][l] ClusterSegB2[k][l]=ClusterSegB[k][l] ClusterLength2[k][l]=ClusterLength[k][l] ClusterStrength2[k][l]=ClusterStrength[k][l] end -- l loop end -- if ClusterBands if ClusterFreezes>0 then ClusterFreeze2[k]={} local l for l=1,ClusterFreezes do ClusterFreeze2[k][l]=ClusterFreeze[k][l] end -- l loop end -- if ClusterFreezes end -- k loop FitnessOffset=ClusterScore[ClusterPointer[HerdSize]] -- Take worst cluster score as fitness offset reference -- By subtracting this score offset from each cluster score and adding 1, -- it is guaranteed that worst cluster score is always 1, all other scores are better. -- This will shift all cluster scores up, if worst cluster score is below 1, so there will be no values<1 for fitness calculation. -- It will pull all scores down, if worst cluster score is above 1, to guarantee maximum privilege by fitness. -- If all clusters would have similar big score values, they would be choosen equally. -- By shifting the scores making the last score be 1, other scores are always x-times higher than 1. Fitness=0 local k for k=1,HerdSize do ClusterScore2[k]=ClusterScore2[k]-FitnessOffset+1 -- Shift cluster score copy by offset to met condition -- We can overwrite this table, because it is only needed for breeding, and it wont affect the original table. -- Original score will remain untouched. Fitness=Fitness+ClusterScore2[k] -- Calculate fitness by adding all scores (offset included) end -- k loop local k for k=BreedFirst,BreedLast do ClusterBreed(k,TimeStamp) end -- k loop end -- Breed() function Roulette() -- Returns a random cluster index (not slot), the better their score, the more often they will appear local TValue=math.random()*(Fitness+1) -- Target fitness value, which will stop the wheel local CValue=0 -- Current value, where single cluster points will be added local Wheel=math.random(1,HerdSize) -- Random initial wheel position repeat Wheel=Wheel+1 -- Spin Wheel if Wheel>HerdSize then Wheel=1 end -- If Wheel made a full turn, it starts at 1 again CValue=CValue+ClusterScore2[ClusterPointer[Wheel]] -- Increase current value by score of cluster at wheel position until CValue>TValue return Wheel end -- Roulette() function ClusterBreed(indexClusterB,TimeStamp) local indexClusterB=indexClusterB -- Target cluster local TimeStamp=TimeStamp -- "birth date" local indexClusterA1 -- Source cluster 1 if Parent1isRoulette==false then indexClusterA1=indexClusterB-BreedFirst+1 -- Choose best, starting with 1 else indexClusterA1=Roulette() -- Choose one by fitness roulette, the better the score, the more often it can be chosen end -- if Parent1isRoulette local indexClusterA2 -- Source cluster 2 if Parent2isRoulette==true then repeat indexClusterA2=Roulette() -- Choose one by fitness roulette, the better the score, the more often it can be chosen until indexClusterA2~=indexClusterA1 -- clusters must be different else indexClusterA2=indexClusterA1+1 -- Take next to Parent 1 if indexClusterA2>HerdSize then indexClusterA2=1 end end -- if Parent2isRoulette local ClusterB=ClusterPointer[indexClusterB] -- Fetch save slot for target cluster local ClusterA1=ClusterPointer[indexClusterA1] -- Fetch load slot for source cluster 1 (dad) local ClusterA2=ClusterPointer[indexClusterA2] -- Fetch load slot for source cluster 2 (mom) local OS="Breeding "..indexClusterA1.."("..ClusterA1..") and "..indexClusterA2.."("..ClusterA2..") to "..indexClusterB.."("..ClusterB..")" print(OS) ClusterType[ClusterB]="breeded".."-"..TimeStamp ClusterDrift[ClusterB]=ClusterDrift2[ClusterA1] -- Take drift information always from dad, preventing change in drift when breeding if ClusterBands>0 then -- We only need to copy if there are any bands local CrossoverEnd if MultiCrossOver== false then CrossoverEnd=CreateCrossoverPoint(ClusterBands) -- Create print('Band crossover point: '..CrossoverEnd) -- and show crossover point end -- if MultiCrossOver ClusterSegA[ClusterB]={} ClusterSegB[ClusterB]={} ClusterLength[ClusterB]={} ClusterStrength[ClusterB]={} local BandsChild local l for l=1,ClusterBands do -- Is crossover point reached? if CrossOverCheck(CrossoverEnd,l) then BandsChild=ClusterA2 -- Take mom after crossover point else BandsChild=ClusterA1 -- Take dad until crossover point end -- if CrossoverEnd ClusterSegA[ClusterB][l]=ClusterSegA2[BandsChild][l] ClusterSegB[ClusterB][l]=ClusterSegB2[BandsChild][l] ClusterLength[ClusterB][l]=ClusterLength2[BandsChild][l] ClusterStrength[ClusterB][l]=ClusterStrength2[BandsChild][l] end -- l loop end -- if ClusterBands if ClusterFreezes>0 then -- We only need to copy if there are any freezes local CrossoverEnd if MultiCrossOver== false then CrossoverEnd=CreateCrossoverPoint(ClusterFreezes) -- Create print('Freeze crossover point: '..CrossoverEnd) -- and show crossover point end -- if MultiCrossOver ClusterFreeze[ClusterB]={} local FreezesChild local l for l=1,ClusterFreezes do -- For all freezes if CrossOverCheck(CrossoverEnd,l) then -- Is crossover point reached? FreezesChild=ClusterA2 -- Take mom after crossover point else FreezesChild=ClusterA1 -- Take dad until crossover point end -- if CrossoverEnd ClusterFreeze[ClusterB][l]=ClusterFreeze2[FreezesChild][l] end -- l loop end -- if ClusterFreezes -- Cluster mutating starts here -- Secondary cluster set not needed anymore -- Mutation is directly performed on target cluster if ClusterBands>0 then local l for l=1,ClusterBands do if puzzle_is_ligand==false then -- only on non-ligand-puzzles mutate segment A if random_flag(DriftProb) then ClusterSegA[ClusterB][l]=drift_segment(ClusterSegA[ClusterB][l],ClusterDrift[ClusterB]) end -- if random_flag end -- if puzzle_is_ligand if random_flag(InvBProb) then ClusterSegA[ClusterB][l]=-ClusterSegA[ClusterB][l] -- invert end -- if random_flag repeat if random_flag(DriftProb) then ClusterSegB[ClusterB][l]=drift_segment(ClusterSegB[ClusterB][l],ClusterDrift[ClusterB]) end -- if random_flag local Distance=index_distance(ClusterSegA[ClusterB][l],ClusterSegB[ClusterB][l]) until Distance>=MID_Game -- Segments must have a minimum index distance if random_flag(DriftProb) then -- mutation allowed ClusterLength[ClusterB][l]=drift_band_attribute(ClusterLength[ClusterB][l],1,3,0,1,6) -- change bandlength by value + or - randomly 10e-[1 to 3 randomly] -- keep bandlength between 0 and 1 -- if error occurs, generate new bandstrength value with 6 decimal digits end -- if random_flag if random_flag(DriftProb) then -- mutation allowed ClusterStrength[ClusterB][l]=drift_band_attribute(ClusterStrength[ClusterB][l],1,3,MinBS,MaxBS,3) -- change bandstrength by value + or - randomly 10e-[1 to 3 randomly] -- keep bandstrength between MinBS and MaxBS -- if error occurs, generate new bandlength value with 3 decimal digits end -- if random_flag end -- l loop end -- if ClusterBands if ClusterFreezes>0 then local l for l=1,ClusterFreezes do if random_flag(DriftProb) then ClusterFreeze[ClusterB][l]=drift_segment(ClusterFreeze[ClusterB][l],ClusterDrift[ClusterB]) end -- if random_flag if random_flag(InvFProb) then ClusterFreeze[ClusterB][l]=-ClusterFreeze[ClusterB][l] -- invert end -- if random_flag end -- l loop end -- if end -- ClusterBreed() function drift_segment(Segment,Drift) local Drift=Drift local Seg2=Segment local Seg2sgn=math.sgn(Seg2) Seg2=math.abs(Seg2)+Drift if Seg2<1 then Seg2=NumSegs elseif Seg2>NumSegs then Seg2=1 end -- if Seg2 Seg2=Seg2*Seg2sgn return Seg2 end -- drift_segment() function drift_band_attribute(Target,RndE1,RndE2,Min,Max,RndE3) -- apply random drift on variable Target resulting Target2 (Target2=Target+random value) -- drift value can be positive or negative -- and is 10^-[RndE1 to RndE2 randomly] -- for example if RndE1 is 1 and RndE2 is 3, resulting value can be 10^-1,10-2 or 10^-3 -- If Min or Max is exceeded, value of Target2 is ring-wrapped (moebius transformation, no clamping): -- If maximum is exceeded, the amount of exceedment (Target2-Value) is applied to minimum -- If minimum is exceeded, the amount of exceedment (Target2-Value) is applied to maximum local Target2=Target local Target2=Target2+random_direction()*10^-math.random(RndE1,RndE2) if Target2>Max then Target2=Min+(Target2-Max) elseif Target2<Min then Target2=Max+(Target2-Min) end -- if Target2 if Target2>Max or Target2<Min then Target2=math.frandom(Min,Max,RndE3) end -- if Target2 return Target2 end -- drift_band_attribute() function CrossOverCheck(CrossoverEnd,Pos) if MultiCrossOver then if random_flag(0.5) then return true else return false end -- if random_flag else -- if MultiCrossOver is false if Pos>CrossoverEnd then return true else return false end -- if Pos end -- if end -- CrossOverCheck() function random_flag(Prob) -- Returns false or true randomly -- how often true appears depends on probability Prob local Prob=Prob if math.random()<Prob then return true else return false end -- if random end -- random_flag() function random_direction() -- returns either -1 or 1 return math.random(0,1)*2-1 end -- random_direction() function structure.WiggleBackbone(iter) structure.WiggleAll(iter,true,false) end -- structure.WiggleBackbone() function structure.WiggleSidechains(iter) structure.WiggleAll(iter,false,true) end -- structure.WiggleSidechains() function xtool(method,iter,tL2) -- unifies score-conditional shake and wiggle into one function local OS="" local iter=iter local tL2=tL2 if iter>0 then OS="max iter:"..iter end -- if -- print('Method:'..method..' '..OS..' threshold:'..tL2) local curr_iter=0 local exit_condition=false repeat curr_iter=curr_iter+1 -- print(' Testing with iterations: '..curr_iter) local tempScore=current.GetEnergyScore() if method=="s" then structure.ShakeSidechainsAll(curr_iter) elseif method=="wb" then structure.WiggleBackbone(curr_iter) elseif method=="ws" then structure.WiggleSidechains(curr_iter) else structure.WiggleAll(curr_iter) end -- if method local tempScore2=current.GetEnergyScore() local rDelta=(tempScore2-tempScore)/curr_iter -- print(' Rel. change: '..rDelta..' pts/iteration') if curr_iter==iter then exit_condition=true end if math.abs(rDelta)<tL2 then exit_condition=true end until exit_condition==true end -- xtool() -- Inspired by vertexs blue fuse script -- You may want to tweak this function function PinkFuse() save.Quicksave(3) -- store state before fuse print('Release 1') behavior.SetClashImportance(0.1) xtool("s",Shakes,ScoreThreshold) BestScoreCheck() behavior.SetClashImportance(0.7) xtool("wa",Wiggles,ScoreThreshold) BestScoreCheck() FuseEnd() save.Quickload(3) -- load state before fuse print('Release 2') behavior.SetClashImportance(0.3) xtool("s",Shakes,ScoreThreshold) BestScoreCheck() behavior.SetClashImportance(0.6) xtool("wa",Wiggles,ScoreThreshold) BestScoreCheck() FuseEnd() save.Quickload(3) -- load state before fuse print('Release 3') behavior.SetClashImportance(0.2) xtool("s",Shakes,ScoreThreshold) BestScoreCheck() behavior.SetClashImportance(0.5) xtool("wa",Wiggles,ScoreThreshold) BestScoreCheck() FuseEnd() save.Quickload(3) -- load state before fuse print('Release 4') behavior.SetClashImportance(0.4) xtool("s",Shakes,ScoreThreshold) BestScoreCheck() behavior.SetClashImportance(0.3) xtool("wa",Wiggles,ScoreThreshold) BestScoreCheck() FuseEnd() end -- PinkFuse() function FuseEnd() -- Fuse try finishing with CI=1 behavior.SetClashImportance(1) xtool("wa",Wiggles,ScoreThreshold) xtool("s",Shakes,ScoreThreshold) xtool("wa",Wiggles,ScoreThreshold) BestScoreCheck() end -- FuseEnd() function BestScoreCheck() local TempScore=current.GetEnergyScore() if LastBest then if TempScore>ACS5 then save.Quicksave(5) -- Set best cluster result for this generation ACS5=TempScore -- print('ACS5 is '..ACS5) end -- if TempScore end -- if LastBest if TempScore>ACS4 then save.Quicksave(4) -- Set best cluster result for current cluster ACS4=TempScore end -- if TempScore if TempScore>BestScore then -- recentbest.Save() BestScore=TempScore print('New best total score: '..BestScore) BSChange=true end -- if end -- BestScoreCheck() function PullDownEqualResults() print('Checking for double results') -- Compare all cluster points with next in list -- If next has the same score, move this cluster to end. local kEnd=HerdSize-1 local k for k=1,kEnd do while ClusterScore[ClusterPointer[k]]==ClusterScore[ClusterPointer[k+1]] do -- If next has the same score ClusterScore[ClusterPointer[k+1]]=ClusterScore[ClusterPointer[HerdSize]]-1 -- make its score more worse then the baddest cluster SortHerd() -- so it is placed at the end when sorting by score end -- while ClusterScore end -- k end -- PullDownEqualResults() function InitializeClusterData() ClusterScore={} ClusterType={} ClusterDrift={} ClusterSegA={} ClusterSegB={} ClusterLength={} ClusterStrength={} ClusterFreeze={} ClusterPointer={} local k for k=1,HerdSize do ClusterPointer[k]=k end -- k end -- InitializeClusterData() function PrintStartingTests() print() local OS=" " if Runs==1 then OS=OS.."1 run" else if Runs>1 then OS=OS..Runs else OS=OS.."infinite" end -- if OS=OS.." runs" end -- if OS="Starting cluster tests for "..OS.."." print(OS) end -- PrintStartingTests() function select_close_ligand() local LigandSegment=NumSegs+1 local k for k=1,NumSegs do if structure.GetDistance(k,LigandSegment)<=MutateLigandDistance then selection.Select(k) -- print(k," is close enough to ligand for mutating.") end -- if get_segment_distance end -- k loop end -- select_close_ligand() function SetRebuildWorst() -- Acitvate rebuild worst if forced or condidtions are met if RebuildForce==nil then --[[ if BSChange then RebuildWorst=false else RebuildWorst=true end -- if BSChange ]]-- RebuildWorst=BSValueCheck() else RebuildWorst=RebuildForce end -- if RebuildForce end -- SetRebuildWorst() function BSValueCheck() -- Returns true if current generations best cluster didnt do much local ChangeTooSmall=false if BSValue>=0 then -- If last generations best cluster score is better than at generation start if BSValue<SCPT then -- but below limit ChangeTooSmall=true end -- if BSValue else -- if BSValue<0 -- If last generations best cluster score is not better than at generation start if BSValue>SCNT then -- but above limit ChangeTooSmall=true end -- if BSValue end -- if BSValue return ChangeTooSmall end -- BSValueCheck() function SetBreedFirstCurrent(BreedFirstCurrent) -- Changes first cluster to test if forced or conditions are met local BreedFirstCurrent=BreedFirstCurrent if BreedFirstCurrentForce==nil then -- If we dont force BreedFirstCurrent do a special value if (LastBest==false) and (RecentUse==false) then -- if we load initial state BreedFirstCurrent=BreedFirst else -- If we dont load initial state if BSChange or BSValueCheck()==false then -- If there was a considerable change BreedFirstCurrent=1 -- check all clusters again in next generation else -- If there was no considerable change BreedFirstCurrent=BreedFirstCurrent+1 -- increase start cluster for this generation (dont test best again) if BreedFirstCurrent>BreedFirst then BreedFirstCurrent=BreedFirst end -- but not further than BreedFirst end -- if BSChange end -- if LastBest==false and RecentUse=false then else -- if BreedFirstCurrentForce not nil BreedFirstCurrent=BreedFirstCurrentForce end -- if BreedFirstCurrentForce return BreedFirstCurrent end -- SetBreedFirstCurrent() function GAB() -- save.Quickload(1): Puzzle state at GAB Start -- save.Quickload(2): Puzzle state at generation start -- save.Quickload(3): Puzzle state at fuse start -- save.Quickload(4): Best result for current cluster -- save.Quickload(5): Best result for current generation print('Starting GAB.') UseList=CheckUselist(UseList) shuffle2(ShuffleProb) -- Shuffle UseList and reset pointer InitializeClusterData() FillHerd(1,HerdSize,1) -- From 1 to HerdSize -- ShowHerd() band.DeleteAll() -- clean bands freeze.UnfreezeAll() -- and freezes behavior.SetClashImportance(1) selection.DeselectAll() recentbest.Save() save.Quicksave(1) -- Save initial puzzle state BestScore=current.GetEnergyScore() -- initialize best score (ACS1) PrintStartingTests(Runs) local BreedFirstCurrent=1 CRun=0 -- set CRun to 0, counting up after each cluster generation repeat -- seems start of main loop 9/2/12 CRun=CRun+1 -- Increase current run value if CRun>1 then -- If this is not the first run if RecentHybrid>0 then -- If RecentHybrid>0, tweak RecentUse if (CRun-1)%RecentHybrid==0 then -- Each RecentHybrid runs RecentUse=true -- use recent best else -- If not RecentUse=false -- dont use recent best end -- if CRun end -- if RecentHybrid if LastBest then print('Loaded last generations best.') save.Quickload(5) -- Load best cluster result of last generation else -- If Lastbest is false if RecentUse then print('Loaded recent best.') recentbest.Restore() -- Load best result so far else print('Loaded initial state.') save.Quickload(1) -- Load initial state end -- if RecentUse end -- if LastBest SetRebuildWorst() BreedFirstCurrent=SetBreedFirstCurrent(BreedFirstCurrent) end -- if CRun if RebuildWorstGen then -- If rebuild is requestet at geneartion start rebuild_worst() -- do it end BSChange=false -- Reset improvement information save.Quicksave(2) -- Set this state as start state for current generation ACS2=current.GetEnergyScore() -- Get score at start for this generation print() print('Score now: '..ACS2) local k2 -- Cluster counter (cluster number not in braces) for k2=BreedFirstCurrent,HerdSize do local k=ClusterPointer[k2] -- fetch slot number(adress) resulting from k2 (cluster number in braces) print() local OS='Gen.:'..CRun..' cluster:'..k2..'('..k..')/'..HerdSize..' drift:'..ClusterDrift[k]..' type:'..ClusterType[k]..' at '..(os.date()) print(OS) if k2>BreedFirstCurrent then -- print('Loaded Quicksave 1.') save.Quickload(2) end -- if k2 band.DeleteAll() -- remove all bands, because recent best can contain some freeze.UnfreezeAll() -- and freezing to apply others if ClusterBands>0 then local l -- Band counter for l=1,ClusterBands do if ClusterSegA[k][l]>0 then band.AddBetweenSegments(ClusterSegA[k][l],ClusterSegB[k][l]) local TempBandCount=band.GetCount() -- fetch current band number index to make setting its length and strength possible local Length=LengthWithFactor(ClusterSegA[k][l],ClusterSegB[k][l],ClusterLength[k][l]) if (Mimic==false or l~=1) then -- If this is not a Mimic band if Length>structure.GetDistance(ClusterSegA[k][l],ClusterSegB[k][l]) then -- and random generated target length is bigger than actual distance Length=Length+BLchangeUpPush -- add push up value -- print('Pushed up.') if Length>MaxBL_Game then Length=MaxBL_Game end -- if Length>MaxBL_Game else -- if random generated target length is smaller or equal than actual distance Length=Length+BLchangeDownPush -- add push down value -- print('Pushed down.') if Length<MinBL_Game then Length=MinBL_Game end -- if Length<MinBL_Game end -- if Length>structure.GetDistance end -- if (Mimic==false or l~=1) local Length1R=CutOff(ClusterLength[k][l],3) -- Cut after 3 decimal digits before displaying local Length2R=CutOff(Length,3) -- Cut after 3 decimal digits before displaying local OS="Band "..l..": "..ClusterSegA[k][l]..":"..ClusterSegB[k][l] OS=OS.." L:"..Length1R.."="..Length2R if ShowBF then OS=OS.." S:"..ClusterStrength[k][l] end -- if print(OS) band.SetGoalLength(TempBandCount,Length) -- Set current band length band.SetStrength(TempBandCount,ClusterStrength[k][l]) -- Set current band strength else -- if ClusterSegA[k][l] is <0, which means band is deactivated if ShowBF then local OS="Band "..l..": off" print(OS) end -- if end -- if ClusterSegA end -- l loop end -- if ClusterBands if RebuildWorstGen==false then rebuild_worst() end selection.DeselectAll() -- Before freezing, so we can select segments to freeze if ClusterFreezes>0 then -- if there are segments to freeze local l -- Freeze counter for l=1,ClusterFreezes do -- select all segments to freeze if ClusterFreeze[k][l]>0 then if ShowBF then local OS="Freeze "..l..": "..ClusterFreeze[k][l] print(OS) end -- if selection.Select(ClusterFreeze[k][l]) else if ShowBF then local OS="Freeze "..l..": off" print(OS) end -- if end -- if ClusterFreez end -- l loop end -- if ClusterFreezes if puzzle_is_ligand then -- if this is a ligand puzzle selection.Select(NumSegs+1) -- select ligand for freezing freeze.FreezeSelected(true,true) -- freeze backbone and sidechains else -- if this is not a ligand puzzle if ClusterFreezes>0 then -- but there are segments to freeze freeze.FreezeSelected(true,false) -- freeze backbone only end -- if ClusterFreezes end -- if puzzle_is_ligand if ConstantBands==true then add_constant_bands() -- You can add some bands or freezes in this routine, which should appear each try end -- if print('Pulling...') behavior.SetClashImportance(CI_pull) selection.SelectAll () -- Select all segments to wiggle structure.WiggleAll(PWiggles) -- Just a small pull band.DeleteAll() -- clean up bands before saving freeze.UnfreezeAll() -- clean up freezes before saving if LastBest then -- If LastBest Mode if k2==BreedFirstCurrent then -- and this is the first try of current generation ACS5=current.GetEnergyScore() -- initialize current generation best score end -- if k2 end -- if LastBest save.Quicksave(4) -- Initialize this state as reference for current cluster best score ACS4=current.GetEnergyScore() -- and initialize current cluster best score BestScoreCheck() -- raise BestScore ACS4, if result is better xMutate(Mutating1) -- including BestScoreCheck Release() -- including Fuse and BestScoreCheck xMutate(Mutating2) -- including BestScoreCheck ClusterScore[k]=ACS4-ACS2 -- Store best score minus start score for this try as cluster score print('Difference to start: '..ClusterScore[k]..' = '..(math.floor(ACS4*1000)/1000)..' - '..(math.floor(ACS2*1000)/1000)) end -- k loop, take next cluster print('\nSorting Cluster list by score') SortHerd() -- Sort herd by score difference ShowScoreList() BSValue=ClusterScore[ClusterPointer[1]] -- Fetch best score difference PullDownEqualResults() -- Move duplicate results to end of herd if EOflag==false then -- if EOflag is false (we do genetic and not extremal optimization) breed and replace some clusters -- if EOflag is true, breeding is skipped Breed(CRun+1) -- Range: BreedFirst to BreedLast end -- if EOflag if BSValueCheck() or BSValue<=0 then -- If generations best cluster has low or negative score difference print('No or few improvement for this generation.') if HerdSize<IncHerdSize then -- and herd size increasing is allowed print('Increasing herd size.') local k for k=1,2 do -- Increase herd size by 2 individuums HerdSize=HerdSize+1 -- Increase herd size ClusterPointer[HerdSize]=HerdSize -- and number of cluster save slots; set them to its own value end -- k loop BreedLast=BreedLast+1 -- Increase breed slots by 1 end -- if incHerdSize end -- if BSChange FillHerd(BreedLast+1,HerdSize,CRun+1) -- generate random clustes behind breeded ones -- ShowHerdShort() until CRun==Runs -- seems end of main loop 9/2/12 end -- GAB() function FactorByLength(SegA,SegB) -- As mimic doesnt use random band lengths (with random factor) but tries to imitate current puzzle state, -- we have not to generate but to calculate the factor value -- This is the opposite of function LengthWithFactor local Min=SpatLimit(SegA,SegB,BLchangeDown) local Max=SpatLimit(SegA,SegB,BLchangeUp) return (structure.GetDistance(SegA,SegB)-Min)/(Max-Min) end -- FactorByLength() function LengthWithFactor(SegA,SegB,Factor) -- Apply length factor to range between minimum allowed band length and maximum allowed band length -- Factor=0 results minimum allowed band length -- Factor=1 results maximum allowed band length local Min=SpatLimit(SegA,SegB,BLchangeDown) local Max=SpatLimit(SegA,SegB,BLchangeUp) -- local OS="Length range without push: "..CutOff(Min,3)..":"..CutOff(Max,3) -- print(OS) return Factor*(Max-Min)+Min end -- LengthWithFactor() function SpatLimit(SegA,SegB,Distance) local Distance2=structure.GetDistance(SegA,SegB)+Distance if Distance2<MinBL_Game then Distance2=MinBL_Game elseif Distance2>MaxBL_Game then Distance2=MaxBL_Game end -- if Distance2 return Distance2 end -- SpatLimit() function index_distance(SegA,SegB) -- Fetch segment index distance return math.abs(math.abs(SegA)-SegB) end -- index_distance() function Release() if Releasing then -- print('Score after pulling: '..ACS4) print('Releasing...') save.Quickload(4) -- load best cluster result so far selection.SelectAll () if Fuse then PinkFuse() -- save.Quicksave(4), raise BestScore and ACS4, if result is better else behavior.SetClashImportance(1) structure.ShakeSidechainsAll(1) structure.WiggleAll(12) BestScoreCheck() -- save.Quicksave(4), raise BestScore and ACS4, if result is better end -- if fuse end -- if Releasing end -- Release() function rebuild_worst() if RebuildWorst then print('Rebuilding worst...') selection.DeselectAll() local WorstScore=current.GetSegmentEnergyScore(1) local WorstIndex=1 local k for k=2,NumSegs do local SegmentScore=current.GetSegmentEnergyScore(k) if SegmentScore<WorstScore then WorstScore=SegmentScore WorstIndex=k end -- if SegmentScore end -- k if (WorstIndex-RebuildRange)<1 then WorstIndex=1+RebuildRange elseif (WorstIndex+RebuildRange)>NumSegs then WorstIndex=NumSegs-RebuildRange end -- if local SegA=WorstIndex-RebuildRange local SegB=WorstIndex+RebuildRange for k=SegA,SegB do selection.Select(k) end -- k loop structure.RebuildSelected(RebuildIter) selection.DeselectAll() end -- if RebuildWorst end -- rebuild_worst() function xMutate(Mutating) if Mutating then save.Quickload(4) -- load best result for this cluster so far print('Mutating...') if puzzle_is_ligand then selection.DeselectAll() -- clear selection select_close_ligand() -- select all segments close as MutateLigandDistance or less to ligand else selection.SelectAll () end -- if puzzle_is_ligand do_mutate(1) BestScoreCheck() -- Check if it made an improvement end -- if Mutating end -- xMutate() function detect_ligand(flag) --[[ ligand puzzle detection normally, segments have a secondary structure of "E", "H" or "L" and they always have a spatial distance of about 3.75 to 3.85 to their next index neighbour. a ligand is more far away. this function should respond true if this is a ligand puzzle, and false if it is not. if flag is nil, ligand auto-detection is enabled, distance of last two segments is checked if flag is not nil, ligand auto-detection is disabled, result is flag It also returns the last segment index which is no ligand ]]-- local flag=flag local LastPos=structure.GetCount() -- fetch very last segment index number if flag==nil then -- Only if flag is nil, detect if there is a ligand and change flag print('Detecting if there is a ligand.') local ss=structure.GetSecondaryStructure(LastPos) flag=not(ss=="L" or ss=="H" or ss=="E" ) -- if last segments ss is neither "l" nor "h" nor "e" flag=flag or (structure.GetDistance(LastPos-1,LastPos)>=3.9) -- or distance to second last segment is bigger or equal than 3.9 end -- if local OS="This should be " if flag then OS=OS.."a" LastPos=LastPos-1 else OS=OS.."no" end -- if flag OS=OS.." ligand puzzle." print(OS) return flag,LastPos end -- detect_ligand() function create_UseList(flag) -- Creates segment use list depending on which puzzle-type is there local flag=flag UseList={} -- Initialize list of segments to use -- UseList extensions (true) are applied to list, so multiple selected segments will appear more often if flag==false then -- If this is no ligand puzzle UseList=UseSegIRange(UseList,1,NumSegs,1,true) -- Set every segment index from 1 to puzzle size as bandable UseList=Use_distance(UseList,0,8,10,1200,false) -- Consider all segments which have min 10 to max 1200 neighbours -- over a distance of 0 to 8 as non-solitary and remove them from list UseList=UseSegIRange(UseList,1,NumSegs,1,true) -- Add a complete segment set again to make sure that distance check didnt erase all UseList=Use_ss(UseList,"L",true) -- Add segments with this secondary structure -- "L"=loop -- "H"=helix -- "E"=sheet -- UseList=UseSegIRange(UseList,1,NumSegs,2,false) -- Set every 2nd segment index between 1 to puzzle size as not bandable, example -- UseList=UseSegIValues(UseList,{1;3;9},true) -- Include these single segments as bandable, example -- UseList=UseSegIValues(UseList,{2;5;10},false) -- Exclude these single segments as bandable, example -- UseList=Use_aa(UseList,{"g";"a"},true) -- Set this amino acid as bandable, example else -- If this is a ligand puzzle UseList=Use_close_ligand(UseList,20,true) -- Set segments which have a maximum spatial distance of 20 to ligand as bandable end -- if flag end -- create_UseList() function LastBandLengthStrength(Length,Strength) -- sets length and strength of the very last band to default values local TempBandCount=band.GetCount() band.SetGoalLength(TempBandCount,Length) band.SetStrength(TempBandCount,Strength) end -- LastBandLengthStrength() function add_constant_bands() -- Add some constant bands to fix parts of the puzzle here -- and/or freeze some parts band.AddBetweenSegments(40,15) LastBandLengthStrength(5,0.1) --[[ selection.DeselectAll() for k=10,11 do selection.Select(k) end -- k freeze.FreezeSelected(true,false) ]]-- end -- add_constant_bands() function showss() -- below will show the sequence and secondary structure -- adapted 9/2/12 from randforce4d3.txt -- adapted 2/27/13 from randforce4d3.txt local j,aa,ss local aastr="AAs=" local ssstr="SSs=" local tot=structure.GetCount() print('Puzzle has '..tot..' residues with AAs and SSs as below:') for j=1,tot do aa=structure.GetAminoAcid(j) ss=structure.GetSecondaryStructure(j) aastr=(aastr..aa) ssstr=(ssstr..ss) if j==10*math.floor(j/10) and j<tot then aastr=(aastr..' ') -- add blank space after every 10th one ssstr=(ssstr..' ') end -- if j end -- for j print(aastr) print(ssstr) end -- showss() function altervalues() local qflag=0 while qflag==0 do local ask=dialog.CreateDialog('CG303 GAB V5') ask.Input1=dialog.AddCheckbox("EOflag",EOflag) ask.Label1a=dialog.AddLabel("\nChecked means use Extremal Optimization,\nunchecked means don't use Extremal Optimization.") ask.Label1b=dialog.AddLabel(" ") ask.Input2=dialog.AddTextbox("randstr ",randstr) ask.Label2a=dialog.AddLabel("\nLeave blank for best randomization or enter a number\nto always use the same sequence of random numbers.") ask.Label2b=dialog.AddLabel(" ") ask.Label2c=dialog.AddLabel(" ") ask.Input3=dialog.AddSlider("HerdSize ",HerdSize,8,14,0) ask.Label3a=dialog.AddLabel("Initial number of clusters for one generation") ask.Label3b=dialog.AddLabel(" ") ask.Input4=dialog.AddSlider("IncHerdSize ",IncHerdSize,16,32,0) ask.Label4a=dialog.AddLabel("Maximum herdsize - allow herd growing to this size") ask.Label4b=dialog.AddLabel(" ") ask.OK = dialog.AddButton("OK", 1) dialog.Show(ask) EOflag=ask.Input1.value randstr=ask.Input2.value HerdSize=ask.Input3.value IncHerdSize=ask.Input4.value qflag=1 end -- while for tmpval in string.gmatch(randstr,'[%s%a]*([%d%-%+]+)') do RNDseed=tmpval+0 -- force RNDseed to be a number end print('As randstr='..randstr..': set RNDseed to '..RNDseed..'.') math.randomseed(RNDseed) -- initialize random seed local OS='Use Extremal Optimization: ' if EOflag==false then OS=OS..'no' else OS=OS..'yes' end -- if EOflag print(OS) print ('Herdsize: '..HerdSize) print ('Herdsize increasable to: '..IncHerdSize) end -- altervalues() Runs=0 -- Number of runs (generations), integer value -- Set to <1 to run infinitely puzzle_is_ligand,NumSegs=detect_ligand() -- puzzle_is_ligand: Ligand flag, boolean value -- true for ligand puzzle -- false for non-ligand-puzzle -- NumSegs: Last segment index which is no ligand, integer value -- detect_ligand(): Ligand auto detection. -- If it fails, use detect_ligand(true) to declare that this is a ligand puzzle -- and detect_ligand(false) to declare that this is a no ligand puzzle create_UseList(puzzle_is_ligand) -- Initialize segment working list -- Depending on puzzle type -- Advanced Users: see function create_UseList for description of uselist creating features MID_Game=3 -- Minimum index distance of segment indices, integer value >=2 -- As the game doesnt allow banding the segments with themselves or the nearest neighbour, -- This value is needed to prevent game errors, -- but you can also use it to prevent sharp backbone turns. MinBL_Game=3.8 -- Minimum band length limiter, float value >=0 and <=MaxBL_Game -- Opposite of MaxBL_Game -- Prevents bands getting too short MaxBL_Game=10000 -- Maximum band length limiter, float value <=10000 and >=MinBL_Game -- In rough, values about 20 or lower tend to compress the puzzle, values above 20 allow decompressing (stretching) -- Maximum expedient value for a puzzle is about (number of segments-1)*3.8, -- which would stretch the region between connected segments completely out. BLchangeDown=-3.8*2 -- Maximum band change down, float value <=0 -- Generated bands have a minimum length of [current segment distance]+BLchangeDown+BLchangeDownPush BLchangeDownPush=-3.8/2 -- Value added to BLchangeDown, float value <=0 -- This value is added to non-mimic bands if they are shorter or equal current segment distance to guarantee a certain change in length BLchangeUp=3.8*1.5 -- Maximum band change up, float value >=0 -- Generated bands have a maximum length of [current segment distance]+BLchangeUp+BLchangeUpPush BLchangeUpPush=3.8/2 -- Value added to BLchangeUp, float value >=0 -- This value is added to non-mimic bands if they are longer than current segment distance to guarantee a certain change in length BreedFirst=3 -- First cluster to change by breeding, integer value -- All clusters before this index will be kept as good solution and as potential parents for breeding new solutions -- Setting this to 1 is not a good idea, because you will loose good clusters as breeding parents (some kind of incest), but should work, too BreedLast=5 -- Last cluster to change by breeding, integer value >=BreedFirst and <=HerdSize -- All clusters after this index to HerdSize will be generated randomly -- This value will be increased if no better solution was found HerdSize= 8 -- Number of clusters, integer value >=BreedLast (alterable by InputBox) -- This value will be increased if no better solution was found IncHerdSize= 16 -- Increase herdsize, integer value (alterable by InputBox) -- Allows increasing the herdsize if no better solution was found (will generate more clusters) -- if >HerdSize, allow increasing herdsize until this amount -- if <=HerdSize, no increasing EOflag=false -- Extremal Optimization flag, boolean value (alterable by InputBox) -- false (default) = script uses genetic algorithm with breeding -- true = breeding is skipped, clusters are left as they are, -- only those clusters with index behind BreedLast will be replaced by random ones ShowBF=true -- Shows band and freeze details, boolean value -- true (default) = segments which are banded or frozen are shown by text -- false = no text for these actions ClusterBands=4 -- Maximum Bands to create per cluster, integer value >=0 ClusterFreezes=3 -- Maximum segments to freeze by random, integer value >=0 MinBS=0.8 -- Minimum strength per (random chosen) band, float value -- Use decimal number between .1 and 10 MaxBS=1.2 -- Minimum strength per (random chosen) band, float value -- Use decimal number between .1 and 10 and >=MinBS Shakes=1 -- Number of iterations for fuse-shake, integer value Wiggles=4 -- Number of iterations for fuse-wiggle, integer value PWiggles=1 -- Number of iterations for pulling, integer value CI_pull=1 -- Clashing importance for pulling, float value >=0 and <=1 -- Default is 1 -- Reduce this to make pulling more drastic Releasing=true -- Release flag, boolean value -- true (default) = After pulling, releasing is performed. -- false = releasing is skipped (and Fuse, too) Fuse=true -- Fuse flag, boolean value -- true (default) = After pulling, Fuse (requires Releasing=true) is performed. -- false = after pulling, just a shake(1) and wiggle_all(12) with CI=1 is performed MutateLigandDistance=15 -- Radius length for selection sphere around ligand, where mutating is performed. -- Selects only segments which are this or more close to the ligand for mutating. ScoreThreshold=0.5 -- Threshold value for shake and wiggles, float value >=0 -- This wont repeat some w/s, if absolute score change per itertation is below this MultiCrossOver=true -- Multi crossover flag, boolean value -- false (default) = One crossover point for each breeding is generated. -- true = Each gene can be from mom or dad Parent1isRoulette=false -- Roulette flag for breeding parent 1, boolean value -- false (default) = parent is cluster with best score and downwards -- use this to force good clusters for breeding -- true = parent is chosen by fitness roulette Parent2isRoulette=true -- Roulette flag for breeding parent 2, boolean value -- true (default) = parent is chosen by fitness roulette -- false = parent is next to parent 1 -- use this to force good clusters for breeding DriftProb=0.3 -- band drift (cluster mutation) probability, float value >=0 and <1 -- Probability, if drift is added or not InvBProb=0.2 -- Inverting (deactivating/reactivating) probability for bands, float value >=0 and <1 -- Makes inversion happen depending on this probability value InvFProb=0.3 -- Inverting (deactivating/reactivating) probability for freezes, float value >=0 and <1 -- Makes inversion happen depending on this probability value ShuffleProb=0.9 -- Shuffle rate, float value >=0 and <=1 -- Used to scramble random segment list, where bands are applied -- 0 lets the list be as it is -- 1 swaps all list entries with a random one behind them in list RecentUse=true -- recent best flag, boolean value -- true = recent best puzzle state is used for each generation -- false = initial puzzle state is used for each generation -- prevents getting stuck on local maximum (recommended for endgame) -- If using RecentHybrid or LastBest, this value will be set automatically RecentHybrid=0 -- Hybrid behaviour between RecentUse=false/true, integer value >=0 -- ==0 = regular behaviour as set in RecentUse -- >0 = use intial puzzle state but recent best state each RecentHybrids generations -- (counting from generation 2) -- 1 would have the same effect as RecentUse=true -- I recommend values>=2 when using it LastBest=false -- Flag for using best cluster of current generation, boolean value -- false (default) = use recent best or initial puzzle state (as set in RecentUse/RecentHybrid) -- true = neither recent best nor initial puzzle state are loaded, but best result of current generation, -- allowing unimproving the puzzle to get out of local maximum -- Try this, you are really stuck on a puzzle. BreedFirstCurrentForce=nil -- Loop start cluster force flag, integer value -- nil (default) = best clusters will only be tested again -- if there was an improvement in last generation -- >0 = start at this cluster after first generation -- 1 = test all clusters again (also good ones) -- If BreedFirst, test only new generated clusters SCPT=1 -- Score change positive tolerance, float value >=0 -- Activates rebuild (if allowed) -- if current generation start score and best cluster score difference -- is below this positive value (not good enough) SCNT=-10 -- Score change negative tolerance, float value <=0 -- Activates rebuild (if allowed) -- if current generation start score and best cluster score difference -- is above this negative value (not bad enough) RebuildWorstGen=true -- Rebuild worst at generation start flag, boolean value -- true = rebuild worst is executed once for current generation -- false = rebuild worst is executed for each cluster (not recommended) -- nil = rebuild is never executed. RebuildWorst=false -- Rebuild flag at script start, boolean value -- true = rebuild is executed in first generation RebuildForce=nil -- Force RebuildWorst, boolean value -- Sets how RebuildWorst is changed. -- nil (default) = worst segment is only rebuilt -- if there was no improvement in last generation -- true = worst segment is always rebuilt before pulling -- false = worst segment is never rebuilt before pulling RebuildRange=2 -- Rebuild range, integer value>=1 -- For example, if 1 and worst segment is 3, segments from 2 to 4 are rebuilt. -- if 2 and worst segment is 3, segments from 1 to 5 are rebuilt. RebuildIter=1 -- Iterations for rebuild worst, integer value>0 Mutating1=puzzle_is_ligand -- if true, puzzle segment mutating after pulling is performed Mutating2=false -- if true, puzzle segment mutating after releasing is performed ConstantBands=false -- Add constant bands flag, boolean value -- if true, adds user-defined bands and freezes of add_constant_bands function above -- before regular test-cluster is applied Mimic=false -- Mimic flag, boolean value -- if true, first cluster tries to imitate initial puzzle state randstr=' ' -- Random Seed (input box), String value (alterable by InputBox) -- if not empty, it will change RNDseed RNDseed=os.time()+recipe.GetRandomSeed() -- Random Seed (resulting), integer value -- Here, the initial value is set to system time plus the games random seed, so we get different random numbers -- for each PC and each time the script is started. -- If you want the same numbers (for testing purposes/results), enter a value in randstr. altervalues() -- alter some of the default values given above via InputBox print('\nDoing puzzle '..puzzle.GetName()..' with ID '..puzzle.GetPuzzleID()..'.') -- show puzzle details showss() -- show AA and SS GAB() -- call main program

Comments