Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --[[
- Genetic Bands III by Crashguard303
- Inspired by cartoon Villain's 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 won't 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 dad's 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 don't 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 -- function
- 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 -- function
- function CutOff(x,y)
- -- Keep only y digits after decimal point from x
- return math.floor(x*10^y)/10^y
- end -- function
- BoolString={}
- BoolString[true]="In"
- BoolString[false]="Ex"
- 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 -- function
- 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 -- function
- 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 -- function
- 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 k's 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 -- function
- 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 -- Don't 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 -- function
- 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 -- function
- function UseList_AR(UseList,value,bool)
- -- Append value "value" to UseList
- -- or remove all value's out of UseList, depending on bool
- local UseList=UseList
- local value=value
- local bool=bool -- True=append, false=remove
- -- print(BoolString[bool],"cluding segment index ",value)
- if bool==true then
- UseList=UseList_Append(UseList,value)
- else
- UseList=UseList_Remove(UseList,value)
- end -- if bool
- return UseList
- end -- function
- 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 -- function
- 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 -- function
- 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 -- function
- 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 -- function
- 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
- 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 -- function
- 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 -- function
- 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 -- function
- 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 -- function
- function ShowScoreList()
- local k2
- for k2=1,HerdSize do
- local k=ClusterPointer[k2]
- print("Cluster:",k2,"(",k,") delta:",ClusterScore[k])
- end -- k
- end -- function
- 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 -- function
- 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 -- function
- 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 wouldn't be done, and (for example) cluster 1 and 2 would be breeded to cluster 3,
- -- cluster 3 couldn't 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 won't 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 -- function
- 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 -- function
- 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 -- function
- 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 -- function
- 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 -- function
- 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 -- function
- 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 -- function
- function random_direction()
- -- returns either -1 or 1
- return math.random(0,1)*2-1
- end -- function
- function structure.WiggleBackbone(iter)
- structure.WiggleAll(iter,true,false)
- end -- function
- function structure.WiggleSidechains(iter)
- structure.WiggleAll(iter,false,true)
- end -- function
- 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 -- function
- -- Inspired by vertex's 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
- 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 -- function
- 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 -- function
- 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 -- function
- function InitializeClusterData()
- ClusterScore={}
- ClusterType={}
- ClusterDrift={}
- ClusterSegA={}
- ClusterSegB={}
- ClusterLength={}
- ClusterStrength={}
- ClusterFreeze={}
- ClusterPointer={}
- local k
- for k=1,HerdSize do
- ClusterPointer[k]=k
- end -- k
- end -- function
- 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 -- function
- 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 -- function
- 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 -- function
- function BSValueCheck()
- -- Returns true if current generation's best cluster didn't do much
- local ChangeTooSmall=false
- if BSValue>=0 then -- If last generation's 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 generation's 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 -- function
- function SetBreedFirstCurrent(BreedFirstCurrent)
- -- Changes first cluster to test if forced or conditions are met
- local BreedFirstCurrent=BreedFirstCurrent
- if BreedFirstCurrentForce==nil then -- If we don't force BreedFirstCurrent do a special value
- if (LastBest==false) and (RecentUse==false) then -- if we load initial state
- BreedFirstCurrent=BreedFirst
- else -- If we don't 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 (don't 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 -- function
- 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-III.")
- print ("Minimum allowed bandlength: ",MinBL_Game)
- print ("Maximum allowed bandlength: ",MaxBL_Game)
- print ("Random seed is: ",RNDseed)
- math.randomseed(RNDseed) -- initialize random seed
- 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
- 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 -- don't use recent best
- end -- if CRun
- end -- if RecentHybrid
- if LastBest then
- print("Loaded last generation's 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]
- 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])
- end -- k loop, take next cluster
- print()
- print("Sorting 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 ExtremalOptimization==false then -- if we do genetic and not extremal optimization
- Breed(CRun+1) -- Range: BreedFirst to BreedLast
- end -- if ExtremalOptimization
- if BSValueCheck() or BSValue<=0 then -- If generation's 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
- end -- function GAB
- function FactorByLength(SegA,SegB)
- -- As mimic doesn't 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 -- function
- 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 -- function
- 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 -- funtction
- function index_distance(SegA,SegB)
- -- Fetch segment index distance
- return math.abs(math.abs(SegA)-SegB)
- end -- function
- 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 -- function
- 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 -- function
- 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 -- function
- 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 segment's 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 -- function
- 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 didn't 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 -- function
- 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 -- function
- 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 -- function
- 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 doesn't 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
- -- This value will be increased if no better solution was found
- IncHerdSize=16
- -- Increase herdsize, integer value
- -- 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
- ExtremalOptimization=false
- -- ExtremalOptimization flag, boolean value
- -- false (default) = script uses genetic algorithm with breeding
- -- true = breeding is skipped, cluster are left as they are,
- -- only those clusters with index behind BreedLast to 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 won't 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 RecentHybrid's 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
- RNDseed=os.time()+recipe.GetRandomSeed()
- -- Random Seed
- -- Here, the initial value is set to system time plus the game's 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), take an arbitrary constant value.
- GAB()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement