How to re-order units based on their degree of desirable neighborhood ? (in Processing)











up vote
31
down vote

favorite
13












I would need help to implement an algorithm allowing the generation of building plans, that I've recently stumbled on while reading Professor Kostas Terzidis' latest publication: Permutation Design: Buildings, Texts and Contexts (2014).



CONTEXT




  • Consider a site (b) that is divided into a grid system (a).

  • Let's also consider a list of spaces to be placed within the limits of the site ( c ) and an adjacency matrix to determine the placement conditions and neighboring relations of these spaces (d)


enter image description here



Quoting Prof. Terzidis:




"A way of solving this problem is to stochastically place spaces within the grid until all spaces are fit and the constraints are satisfied"




The figure above shows such a problem and a sample solution (f).



ALGORITHM (as briefly described in the book)



1/ "Each space is associated with a list that contains all other spaces sorted according to their degree of desirable neighborhood."



2/ "Then each unit of each space is selected from the list and then one-by-one placed randomly in the site until they fit in the site and the neighboring conditions are met. (If it fails then the process is repeated)"



Example of nine randomly generated plans:



enter image description here



I should add that the author explains later that this algorithm doesn't rely on brute force techniques.



PROBLEMS



As you can see, the explanation is relatively vague and step 2 is rather unclear (in terms of coding). All I have so far are "pieces of a puzzle":




  • a "site" (list of selected integers)

  • an adjacency matrix (nestled lists)

  • "spaces" (dictionnary of lists)


for each unit:




  • a function that returns its direct neighbors

  • a list of its desirable neighbors with their indices in sorted order


  • a fitness score based on its actual neighbors



    from random import shuffle

    n_col, n_row = 7, 5
    to_skip = [0, 1, 21, 22, 23, 24, 28, 29, 30, 31]
    site = [i for i in range(n_col * n_row) if i not in to_skip]
    fitness, grid = [[None if i in to_skip else for i in range(n_col * n_row)] for e in range(2)]

    n = 2
    k = (n_col * n_row) - len(to_skip)
    rsize = 50

    #Adjacency matrix
    adm = [[0, 6, 1, 5, 2],
    [6, 0, 1, 4, 0],
    [1, 1, 0, 8, 0],
    [5, 4, 8, 0, 3],
    [2, 0, 0, 3, 0]]


    spaces = {"office1": [0 for i in range(4)],
    "office2": [1 for i in range(6)],
    "office3": [2 for i in range(6)],
    "passage": [3 for i in range(7)],
    "entry": [4 for i in range(2)]}


    def setup():
    global grid
    size(600, 400, P2D)
    rectMode(CENTER)
    strokeWeight(1.4)

    #Shuffle the order for the random placing to come
    shuffle(site)

    #Place units randomly within the limits of the site
    i = -1
    for space in spaces.items():
    for unit in space[1]:
    i+=1
    grid[site[i]] = unit


    #For each unit of each space...
    i = -1
    for space in spaces.items():
    for unit in space[1]:
    i+=1

    #Get the indices of the its DESIRABLE neighbors in sorted order
    ada = adm[unit]
    sorted_indices = sorted(range(len(ada)), key = ada.__getitem__)[::-1]

    #Select indices with positive weight (exluding 0-weight indices)
    pindices = [e for e in sorted_indices if ada[e] > 0]

    #Stores its fitness score (sum of the weight of its REAL neighbors)
    fitness[site[i]] = sum([ada[n] for n in getNeighbors(i) if n in pindices])

    print 'Fitness Score:', fitness

    def draw():
    background(255)

    #Grid's background
    fill(170)
    noStroke()
    rect(width/2 - (rsize/2) , height/2 + rsize/2 + n_row , rsize*n_col, rsize*n_row)


    #Displaying site (grid cells of all selected units) + units placed randomly
    for i, e in enumerate(grid):
    if isinstance(e, list): pass
    elif e == None: pass
    else:
    fill(50 + (e * 50), 255 - (e * 80), 255 - (e * 50), 180)
    rect(width/2 - (rsize*n_col/2) + (i%n_col * rsize), height/2 + (rsize*n_row/2) + (n_row - ((k+len(to_skip))-(i+1))/n_col * rsize), rsize, rsize)
    fill(0)
    text(e+1, width/2 - (rsize*n_col/2) + (i%n_col * rsize), height/2 + (rsize*n_row/2) + (n_row - ((k+len(to_skip))-(i+1))/n_col * rsize))




    def getNeighbors(i):
    neighbors =

    if site[i] > n_col and site[i] < len(grid) - n_col:
    if site[i]%n_col > 0 and site[i]%n_col < n_col - 1:
    if grid[site[i]-1] != None: neighbors.append(grid[site[i]-1])
    if grid[site[i]+1] != None: neighbors.append(grid[site[i]+1])
    if grid[site[i]-n_col] != None: neighbors.append(grid[site[i]-n_col])
    if grid[site[i]+n_col] != None: neighbors.append(grid[site[i]+n_col])

    if site[i] <= n_col:
    if site[i]%n_col > 0 and site[i]%n_col < n_col - 1:
    if grid[site[i]-1] != None: neighbors.append(grid[site[i]-1])
    if grid[site[i]+1] != None: neighbors.append(grid[site[i]+1])
    if grid[site[i]+n_col] != None: neighbors.append(grid[site[i]+n_col])

    if site[i]%n_col == 0:
    if grid[site[i]+1] != None: neighbors.append(grid[site[i]+1])
    if grid[site[i]+n_col] != None: neighbors.append(grid[site[i]+n_col])

    if site[i] == n_col-1:
    if grid[site[i]-1] != None: neighbors.append(grid[site[i]-1])
    if grid[site[i]+n_col] != None: neighbors.append(grid[site[i]+n_col])

    if site[i] >= len(grid) - n_col:
    if site[i]%n_col > 0 and site[i]%n_col < n_col - 1:
    if grid[site[i]-1] != None: neighbors.append(grid[site[i]-1])
    if grid[site[i]+1] != None: neighbors.append(grid[site[i]+1])
    if grid[site[i]-n_col] != None: neighbors.append(grid[site[i]-n_col])

    if site[i]%n_col == 0:
    if grid[site[i]+1] != None: neighbors.append(grid[site[i]+1])
    if grid[site[i]-n_col] != None: neighbors.append(grid[site[i]-n_col])

    if site[i]%n_col == n_col-1:
    if grid[site[i]-1] != None: neighbors.append(grid[site[i]-1])
    if grid[site[i]-n_col] != None: neighbors.append(grid[site[i]-n_col])

    if site[i]%n_col == 0:
    if site[i] > n_col and site[i] < len(grid) - n_col:
    if grid[site[i]+1] != None: neighbors.append(grid[site[i]+1])
    if grid[site[i]+n_col] != None: neighbors.append(grid[site[i]+n_col])
    if grid[site[i]-n_col] != None: neighbors.append(grid[site[i]-n_col])

    if site[i]%n_col == n_col - 1:
    if site[i] > n_col and site[i] < len(grid) - n_col:
    if grid[site[i]-1] != None: neighbors.append(grid[site[i]-1])
    if grid[site[i]+n_col] != None: neighbors.append(grid[site[i]+n_col])
    if grid[site[i]-n_col] != None: neighbors.append(grid[site[i]-n_col])

    return neighbors



enter image description here



I would really appreciate if someone could help connect the dots and explain me:




  • how to re-order the units based on their degree of desirable neighborhood ?


EDIT



As some of you have noticed the algorithm is based on the likelihood that certain spaces (composed of units) are adjacent. The logic would have it then that for each unit to place randomly within the limits of the site:




  • we check its direct neighbors (up, down, left right) beforehand

  • compute a fitness score if at least 2 neighbors. (=sum of the weights of these 2+ neighbors)

  • and finally place that unit if the adjacency probability is high


Roughly, it would translate into this:



    i = -1   
for space in spaces.items():
for unit in space[1]:
i+=1

#Get the indices of the its DESIRABLE neighbors (from the adjacency matrix 'adm') in sorted order
weights = adm[unit]
sorted_indices = sorted(range(len(weights)), key = weights.__getitem__)[::-1]

#Select indices with positive weight (exluding 0-weight indices)
pindices = [e for e in sorted_indices if weights[e] > 0]


#If random grid cell is empty
if not grid[site[i]]:

#List of neighbors
neighbors = [n for n in getNeighbors(i) if isinstance(n, int)]

#If no neighbors -> place unit
if len(neighbors) == 0:
grid[site[i]] = unit

#If at least 1 of the neighbors == unit: -> place unit (facilitate grouping)
if len(neighbors) > 0 and unit in neighbors:
grid[site[i]] = unit

#If 2 or 3 neighbors, compute fitness score and place unit if probability is high
if len(neighbors) >= 2 and len(neighbors) < 4:

fscore = sum([weights[n] for n in neighbors if n in pindices]) #cumulative weight of its ACTUAL neighbors
count = [1 for t in range(10) if random(sum(weights)) < fscore] #add 1 if fscore higher than a number taken at random between 0 and the cumulative weight of its DESIRABLE neighbors

if len(count) > 5:
grid[site[i]] = unit

#If 4 neighbors and high probability, 1 of them must belong to the same space
if len(neighbors) > 3:

fscore = sum([weights[n] for n in neighbors if n in pindices]) #cumulative weight of its ACTUAL neighbors
count = [1 for t in range(10) if random(sum(weights)) < fscore] #add 1 if fscore higher than a number taken at random between 0 and the cumulative weight of its DESIRABLE neighbors

if len(count) > 5 and unit in neighbors:
grid[site[i]] = unit


#if random grid cell not empty -> pass
else: pass


Given that a significant part of the units won't be placed on the first run (because of low adjacency probability), we need to iterate over and over until a random distribution where all units can be fitted is found.



enter image description here



After a few thousand iterations a fit is found and all the neighboring requirements are met.



Notice however how this algorithm produces separated groups instead of non-divided and uniform stacks like in the example provided. I should also add that nearly 5000 iterations is a lot more than the 274 iterations mentioned by Mr. Terzidis in his book.



Questions:




  • Is there something wrong with the way I'm approaching this algorithm ?

  • If no then what implicit condition am I missing ?










share|improve this question
























  • What is the exactly meaning of matrix (d)? e.g what is the meaning of m[2][4] = 4 or m[3][4] = 8, what does the values 4 and 8 mean?
    – Rabbid76
    Nov 3 at 16:17












  • It's a weight, the higher that value is, the higher the probability that the two spaces are adjecent is. Here the probability that 'Office3' (3) and 'Passage' (4) are neighbors is high (8).
    – solub
    Nov 3 at 17:02










  • I'm interested in working this problem, but I don't know what your gui library is. Could you include it so I can run the code?
    – David Culbreth
    Nov 6 at 19:36










  • @DavidCulbreth The code needs to be run from the Processing IDE with Python mode.
    – solub
    Nov 6 at 21:43






  • 1




    "Then each unit of each space is selected from the list and then one-by-one placed randomly in the site until they fit in the site and the neighboring conditions are met." Until what conditions are met? The adjacency matrix doesn't look like it's a count of adjacent buildings, it's more of a heuristic (higher means more likely to be adjacent). So how do you verify that "the neighboring conditions are met" and that a given output is correct? I feel like this problem statement is clear as mud, and some more precise definitions would be useful
    – Matt Messersmith
    Nov 7 at 23:47















up vote
31
down vote

favorite
13












I would need help to implement an algorithm allowing the generation of building plans, that I've recently stumbled on while reading Professor Kostas Terzidis' latest publication: Permutation Design: Buildings, Texts and Contexts (2014).



CONTEXT




  • Consider a site (b) that is divided into a grid system (a).

  • Let's also consider a list of spaces to be placed within the limits of the site ( c ) and an adjacency matrix to determine the placement conditions and neighboring relations of these spaces (d)


enter image description here



Quoting Prof. Terzidis:




"A way of solving this problem is to stochastically place spaces within the grid until all spaces are fit and the constraints are satisfied"




The figure above shows such a problem and a sample solution (f).



ALGORITHM (as briefly described in the book)



1/ "Each space is associated with a list that contains all other spaces sorted according to their degree of desirable neighborhood."



2/ "Then each unit of each space is selected from the list and then one-by-one placed randomly in the site until they fit in the site and the neighboring conditions are met. (If it fails then the process is repeated)"



Example of nine randomly generated plans:



enter image description here



I should add that the author explains later that this algorithm doesn't rely on brute force techniques.



PROBLEMS



As you can see, the explanation is relatively vague and step 2 is rather unclear (in terms of coding). All I have so far are "pieces of a puzzle":




  • a "site" (list of selected integers)

  • an adjacency matrix (nestled lists)

  • "spaces" (dictionnary of lists)


for each unit:




  • a function that returns its direct neighbors

  • a list of its desirable neighbors with their indices in sorted order


  • a fitness score based on its actual neighbors



    from random import shuffle

    n_col, n_row = 7, 5
    to_skip = [0, 1, 21, 22, 23, 24, 28, 29, 30, 31]
    site = [i for i in range(n_col * n_row) if i not in to_skip]
    fitness, grid = [[None if i in to_skip else for i in range(n_col * n_row)] for e in range(2)]

    n = 2
    k = (n_col * n_row) - len(to_skip)
    rsize = 50

    #Adjacency matrix
    adm = [[0, 6, 1, 5, 2],
    [6, 0, 1, 4, 0],
    [1, 1, 0, 8, 0],
    [5, 4, 8, 0, 3],
    [2, 0, 0, 3, 0]]


    spaces = {"office1": [0 for i in range(4)],
    "office2": [1 for i in range(6)],
    "office3": [2 for i in range(6)],
    "passage": [3 for i in range(7)],
    "entry": [4 for i in range(2)]}


    def setup():
    global grid
    size(600, 400, P2D)
    rectMode(CENTER)
    strokeWeight(1.4)

    #Shuffle the order for the random placing to come
    shuffle(site)

    #Place units randomly within the limits of the site
    i = -1
    for space in spaces.items():
    for unit in space[1]:
    i+=1
    grid[site[i]] = unit


    #For each unit of each space...
    i = -1
    for space in spaces.items():
    for unit in space[1]:
    i+=1

    #Get the indices of the its DESIRABLE neighbors in sorted order
    ada = adm[unit]
    sorted_indices = sorted(range(len(ada)), key = ada.__getitem__)[::-1]

    #Select indices with positive weight (exluding 0-weight indices)
    pindices = [e for e in sorted_indices if ada[e] > 0]

    #Stores its fitness score (sum of the weight of its REAL neighbors)
    fitness[site[i]] = sum([ada[n] for n in getNeighbors(i) if n in pindices])

    print 'Fitness Score:', fitness

    def draw():
    background(255)

    #Grid's background
    fill(170)
    noStroke()
    rect(width/2 - (rsize/2) , height/2 + rsize/2 + n_row , rsize*n_col, rsize*n_row)


    #Displaying site (grid cells of all selected units) + units placed randomly
    for i, e in enumerate(grid):
    if isinstance(e, list): pass
    elif e == None: pass
    else:
    fill(50 + (e * 50), 255 - (e * 80), 255 - (e * 50), 180)
    rect(width/2 - (rsize*n_col/2) + (i%n_col * rsize), height/2 + (rsize*n_row/2) + (n_row - ((k+len(to_skip))-(i+1))/n_col * rsize), rsize, rsize)
    fill(0)
    text(e+1, width/2 - (rsize*n_col/2) + (i%n_col * rsize), height/2 + (rsize*n_row/2) + (n_row - ((k+len(to_skip))-(i+1))/n_col * rsize))




    def getNeighbors(i):
    neighbors =

    if site[i] > n_col and site[i] < len(grid) - n_col:
    if site[i]%n_col > 0 and site[i]%n_col < n_col - 1:
    if grid[site[i]-1] != None: neighbors.append(grid[site[i]-1])
    if grid[site[i]+1] != None: neighbors.append(grid[site[i]+1])
    if grid[site[i]-n_col] != None: neighbors.append(grid[site[i]-n_col])
    if grid[site[i]+n_col] != None: neighbors.append(grid[site[i]+n_col])

    if site[i] <= n_col:
    if site[i]%n_col > 0 and site[i]%n_col < n_col - 1:
    if grid[site[i]-1] != None: neighbors.append(grid[site[i]-1])
    if grid[site[i]+1] != None: neighbors.append(grid[site[i]+1])
    if grid[site[i]+n_col] != None: neighbors.append(grid[site[i]+n_col])

    if site[i]%n_col == 0:
    if grid[site[i]+1] != None: neighbors.append(grid[site[i]+1])
    if grid[site[i]+n_col] != None: neighbors.append(grid[site[i]+n_col])

    if site[i] == n_col-1:
    if grid[site[i]-1] != None: neighbors.append(grid[site[i]-1])
    if grid[site[i]+n_col] != None: neighbors.append(grid[site[i]+n_col])

    if site[i] >= len(grid) - n_col:
    if site[i]%n_col > 0 and site[i]%n_col < n_col - 1:
    if grid[site[i]-1] != None: neighbors.append(grid[site[i]-1])
    if grid[site[i]+1] != None: neighbors.append(grid[site[i]+1])
    if grid[site[i]-n_col] != None: neighbors.append(grid[site[i]-n_col])

    if site[i]%n_col == 0:
    if grid[site[i]+1] != None: neighbors.append(grid[site[i]+1])
    if grid[site[i]-n_col] != None: neighbors.append(grid[site[i]-n_col])

    if site[i]%n_col == n_col-1:
    if grid[site[i]-1] != None: neighbors.append(grid[site[i]-1])
    if grid[site[i]-n_col] != None: neighbors.append(grid[site[i]-n_col])

    if site[i]%n_col == 0:
    if site[i] > n_col and site[i] < len(grid) - n_col:
    if grid[site[i]+1] != None: neighbors.append(grid[site[i]+1])
    if grid[site[i]+n_col] != None: neighbors.append(grid[site[i]+n_col])
    if grid[site[i]-n_col] != None: neighbors.append(grid[site[i]-n_col])

    if site[i]%n_col == n_col - 1:
    if site[i] > n_col and site[i] < len(grid) - n_col:
    if grid[site[i]-1] != None: neighbors.append(grid[site[i]-1])
    if grid[site[i]+n_col] != None: neighbors.append(grid[site[i]+n_col])
    if grid[site[i]-n_col] != None: neighbors.append(grid[site[i]-n_col])

    return neighbors



enter image description here



I would really appreciate if someone could help connect the dots and explain me:




  • how to re-order the units based on their degree of desirable neighborhood ?


EDIT



As some of you have noticed the algorithm is based on the likelihood that certain spaces (composed of units) are adjacent. The logic would have it then that for each unit to place randomly within the limits of the site:




  • we check its direct neighbors (up, down, left right) beforehand

  • compute a fitness score if at least 2 neighbors. (=sum of the weights of these 2+ neighbors)

  • and finally place that unit if the adjacency probability is high


Roughly, it would translate into this:



    i = -1   
for space in spaces.items():
for unit in space[1]:
i+=1

#Get the indices of the its DESIRABLE neighbors (from the adjacency matrix 'adm') in sorted order
weights = adm[unit]
sorted_indices = sorted(range(len(weights)), key = weights.__getitem__)[::-1]

#Select indices with positive weight (exluding 0-weight indices)
pindices = [e for e in sorted_indices if weights[e] > 0]


#If random grid cell is empty
if not grid[site[i]]:

#List of neighbors
neighbors = [n for n in getNeighbors(i) if isinstance(n, int)]

#If no neighbors -> place unit
if len(neighbors) == 0:
grid[site[i]] = unit

#If at least 1 of the neighbors == unit: -> place unit (facilitate grouping)
if len(neighbors) > 0 and unit in neighbors:
grid[site[i]] = unit

#If 2 or 3 neighbors, compute fitness score and place unit if probability is high
if len(neighbors) >= 2 and len(neighbors) < 4:

fscore = sum([weights[n] for n in neighbors if n in pindices]) #cumulative weight of its ACTUAL neighbors
count = [1 for t in range(10) if random(sum(weights)) < fscore] #add 1 if fscore higher than a number taken at random between 0 and the cumulative weight of its DESIRABLE neighbors

if len(count) > 5:
grid[site[i]] = unit

#If 4 neighbors and high probability, 1 of them must belong to the same space
if len(neighbors) > 3:

fscore = sum([weights[n] for n in neighbors if n in pindices]) #cumulative weight of its ACTUAL neighbors
count = [1 for t in range(10) if random(sum(weights)) < fscore] #add 1 if fscore higher than a number taken at random between 0 and the cumulative weight of its DESIRABLE neighbors

if len(count) > 5 and unit in neighbors:
grid[site[i]] = unit


#if random grid cell not empty -> pass
else: pass


Given that a significant part of the units won't be placed on the first run (because of low adjacency probability), we need to iterate over and over until a random distribution where all units can be fitted is found.



enter image description here



After a few thousand iterations a fit is found and all the neighboring requirements are met.



Notice however how this algorithm produces separated groups instead of non-divided and uniform stacks like in the example provided. I should also add that nearly 5000 iterations is a lot more than the 274 iterations mentioned by Mr. Terzidis in his book.



Questions:




  • Is there something wrong with the way I'm approaching this algorithm ?

  • If no then what implicit condition am I missing ?










share|improve this question
























  • What is the exactly meaning of matrix (d)? e.g what is the meaning of m[2][4] = 4 or m[3][4] = 8, what does the values 4 and 8 mean?
    – Rabbid76
    Nov 3 at 16:17












  • It's a weight, the higher that value is, the higher the probability that the two spaces are adjecent is. Here the probability that 'Office3' (3) and 'Passage' (4) are neighbors is high (8).
    – solub
    Nov 3 at 17:02










  • I'm interested in working this problem, but I don't know what your gui library is. Could you include it so I can run the code?
    – David Culbreth
    Nov 6 at 19:36










  • @DavidCulbreth The code needs to be run from the Processing IDE with Python mode.
    – solub
    Nov 6 at 21:43






  • 1




    "Then each unit of each space is selected from the list and then one-by-one placed randomly in the site until they fit in the site and the neighboring conditions are met." Until what conditions are met? The adjacency matrix doesn't look like it's a count of adjacent buildings, it's more of a heuristic (higher means more likely to be adjacent). So how do you verify that "the neighboring conditions are met" and that a given output is correct? I feel like this problem statement is clear as mud, and some more precise definitions would be useful
    – Matt Messersmith
    Nov 7 at 23:47













up vote
31
down vote

favorite
13









up vote
31
down vote

favorite
13






13





I would need help to implement an algorithm allowing the generation of building plans, that I've recently stumbled on while reading Professor Kostas Terzidis' latest publication: Permutation Design: Buildings, Texts and Contexts (2014).



CONTEXT




  • Consider a site (b) that is divided into a grid system (a).

  • Let's also consider a list of spaces to be placed within the limits of the site ( c ) and an adjacency matrix to determine the placement conditions and neighboring relations of these spaces (d)


enter image description here



Quoting Prof. Terzidis:




"A way of solving this problem is to stochastically place spaces within the grid until all spaces are fit and the constraints are satisfied"




The figure above shows such a problem and a sample solution (f).



ALGORITHM (as briefly described in the book)



1/ "Each space is associated with a list that contains all other spaces sorted according to their degree of desirable neighborhood."



2/ "Then each unit of each space is selected from the list and then one-by-one placed randomly in the site until they fit in the site and the neighboring conditions are met. (If it fails then the process is repeated)"



Example of nine randomly generated plans:



enter image description here



I should add that the author explains later that this algorithm doesn't rely on brute force techniques.



PROBLEMS



As you can see, the explanation is relatively vague and step 2 is rather unclear (in terms of coding). All I have so far are "pieces of a puzzle":




  • a "site" (list of selected integers)

  • an adjacency matrix (nestled lists)

  • "spaces" (dictionnary of lists)


for each unit:




  • a function that returns its direct neighbors

  • a list of its desirable neighbors with their indices in sorted order


  • a fitness score based on its actual neighbors



    from random import shuffle

    n_col, n_row = 7, 5
    to_skip = [0, 1, 21, 22, 23, 24, 28, 29, 30, 31]
    site = [i for i in range(n_col * n_row) if i not in to_skip]
    fitness, grid = [[None if i in to_skip else for i in range(n_col * n_row)] for e in range(2)]

    n = 2
    k = (n_col * n_row) - len(to_skip)
    rsize = 50

    #Adjacency matrix
    adm = [[0, 6, 1, 5, 2],
    [6, 0, 1, 4, 0],
    [1, 1, 0, 8, 0],
    [5, 4, 8, 0, 3],
    [2, 0, 0, 3, 0]]


    spaces = {"office1": [0 for i in range(4)],
    "office2": [1 for i in range(6)],
    "office3": [2 for i in range(6)],
    "passage": [3 for i in range(7)],
    "entry": [4 for i in range(2)]}


    def setup():
    global grid
    size(600, 400, P2D)
    rectMode(CENTER)
    strokeWeight(1.4)

    #Shuffle the order for the random placing to come
    shuffle(site)

    #Place units randomly within the limits of the site
    i = -1
    for space in spaces.items():
    for unit in space[1]:
    i+=1
    grid[site[i]] = unit


    #For each unit of each space...
    i = -1
    for space in spaces.items():
    for unit in space[1]:
    i+=1

    #Get the indices of the its DESIRABLE neighbors in sorted order
    ada = adm[unit]
    sorted_indices = sorted(range(len(ada)), key = ada.__getitem__)[::-1]

    #Select indices with positive weight (exluding 0-weight indices)
    pindices = [e for e in sorted_indices if ada[e] > 0]

    #Stores its fitness score (sum of the weight of its REAL neighbors)
    fitness[site[i]] = sum([ada[n] for n in getNeighbors(i) if n in pindices])

    print 'Fitness Score:', fitness

    def draw():
    background(255)

    #Grid's background
    fill(170)
    noStroke()
    rect(width/2 - (rsize/2) , height/2 + rsize/2 + n_row , rsize*n_col, rsize*n_row)


    #Displaying site (grid cells of all selected units) + units placed randomly
    for i, e in enumerate(grid):
    if isinstance(e, list): pass
    elif e == None: pass
    else:
    fill(50 + (e * 50), 255 - (e * 80), 255 - (e * 50), 180)
    rect(width/2 - (rsize*n_col/2) + (i%n_col * rsize), height/2 + (rsize*n_row/2) + (n_row - ((k+len(to_skip))-(i+1))/n_col * rsize), rsize, rsize)
    fill(0)
    text(e+1, width/2 - (rsize*n_col/2) + (i%n_col * rsize), height/2 + (rsize*n_row/2) + (n_row - ((k+len(to_skip))-(i+1))/n_col * rsize))




    def getNeighbors(i):
    neighbors =

    if site[i] > n_col and site[i] < len(grid) - n_col:
    if site[i]%n_col > 0 and site[i]%n_col < n_col - 1:
    if grid[site[i]-1] != None: neighbors.append(grid[site[i]-1])
    if grid[site[i]+1] != None: neighbors.append(grid[site[i]+1])
    if grid[site[i]-n_col] != None: neighbors.append(grid[site[i]-n_col])
    if grid[site[i]+n_col] != None: neighbors.append(grid[site[i]+n_col])

    if site[i] <= n_col:
    if site[i]%n_col > 0 and site[i]%n_col < n_col - 1:
    if grid[site[i]-1] != None: neighbors.append(grid[site[i]-1])
    if grid[site[i]+1] != None: neighbors.append(grid[site[i]+1])
    if grid[site[i]+n_col] != None: neighbors.append(grid[site[i]+n_col])

    if site[i]%n_col == 0:
    if grid[site[i]+1] != None: neighbors.append(grid[site[i]+1])
    if grid[site[i]+n_col] != None: neighbors.append(grid[site[i]+n_col])

    if site[i] == n_col-1:
    if grid[site[i]-1] != None: neighbors.append(grid[site[i]-1])
    if grid[site[i]+n_col] != None: neighbors.append(grid[site[i]+n_col])

    if site[i] >= len(grid) - n_col:
    if site[i]%n_col > 0 and site[i]%n_col < n_col - 1:
    if grid[site[i]-1] != None: neighbors.append(grid[site[i]-1])
    if grid[site[i]+1] != None: neighbors.append(grid[site[i]+1])
    if grid[site[i]-n_col] != None: neighbors.append(grid[site[i]-n_col])

    if site[i]%n_col == 0:
    if grid[site[i]+1] != None: neighbors.append(grid[site[i]+1])
    if grid[site[i]-n_col] != None: neighbors.append(grid[site[i]-n_col])

    if site[i]%n_col == n_col-1:
    if grid[site[i]-1] != None: neighbors.append(grid[site[i]-1])
    if grid[site[i]-n_col] != None: neighbors.append(grid[site[i]-n_col])

    if site[i]%n_col == 0:
    if site[i] > n_col and site[i] < len(grid) - n_col:
    if grid[site[i]+1] != None: neighbors.append(grid[site[i]+1])
    if grid[site[i]+n_col] != None: neighbors.append(grid[site[i]+n_col])
    if grid[site[i]-n_col] != None: neighbors.append(grid[site[i]-n_col])

    if site[i]%n_col == n_col - 1:
    if site[i] > n_col and site[i] < len(grid) - n_col:
    if grid[site[i]-1] != None: neighbors.append(grid[site[i]-1])
    if grid[site[i]+n_col] != None: neighbors.append(grid[site[i]+n_col])
    if grid[site[i]-n_col] != None: neighbors.append(grid[site[i]-n_col])

    return neighbors



enter image description here



I would really appreciate if someone could help connect the dots and explain me:




  • how to re-order the units based on their degree of desirable neighborhood ?


EDIT



As some of you have noticed the algorithm is based on the likelihood that certain spaces (composed of units) are adjacent. The logic would have it then that for each unit to place randomly within the limits of the site:




  • we check its direct neighbors (up, down, left right) beforehand

  • compute a fitness score if at least 2 neighbors. (=sum of the weights of these 2+ neighbors)

  • and finally place that unit if the adjacency probability is high


Roughly, it would translate into this:



    i = -1   
for space in spaces.items():
for unit in space[1]:
i+=1

#Get the indices of the its DESIRABLE neighbors (from the adjacency matrix 'adm') in sorted order
weights = adm[unit]
sorted_indices = sorted(range(len(weights)), key = weights.__getitem__)[::-1]

#Select indices with positive weight (exluding 0-weight indices)
pindices = [e for e in sorted_indices if weights[e] > 0]


#If random grid cell is empty
if not grid[site[i]]:

#List of neighbors
neighbors = [n for n in getNeighbors(i) if isinstance(n, int)]

#If no neighbors -> place unit
if len(neighbors) == 0:
grid[site[i]] = unit

#If at least 1 of the neighbors == unit: -> place unit (facilitate grouping)
if len(neighbors) > 0 and unit in neighbors:
grid[site[i]] = unit

#If 2 or 3 neighbors, compute fitness score and place unit if probability is high
if len(neighbors) >= 2 and len(neighbors) < 4:

fscore = sum([weights[n] for n in neighbors if n in pindices]) #cumulative weight of its ACTUAL neighbors
count = [1 for t in range(10) if random(sum(weights)) < fscore] #add 1 if fscore higher than a number taken at random between 0 and the cumulative weight of its DESIRABLE neighbors

if len(count) > 5:
grid[site[i]] = unit

#If 4 neighbors and high probability, 1 of them must belong to the same space
if len(neighbors) > 3:

fscore = sum([weights[n] for n in neighbors if n in pindices]) #cumulative weight of its ACTUAL neighbors
count = [1 for t in range(10) if random(sum(weights)) < fscore] #add 1 if fscore higher than a number taken at random between 0 and the cumulative weight of its DESIRABLE neighbors

if len(count) > 5 and unit in neighbors:
grid[site[i]] = unit


#if random grid cell not empty -> pass
else: pass


Given that a significant part of the units won't be placed on the first run (because of low adjacency probability), we need to iterate over and over until a random distribution where all units can be fitted is found.



enter image description here



After a few thousand iterations a fit is found and all the neighboring requirements are met.



Notice however how this algorithm produces separated groups instead of non-divided and uniform stacks like in the example provided. I should also add that nearly 5000 iterations is a lot more than the 274 iterations mentioned by Mr. Terzidis in his book.



Questions:




  • Is there something wrong with the way I'm approaching this algorithm ?

  • If no then what implicit condition am I missing ?










share|improve this question















I would need help to implement an algorithm allowing the generation of building plans, that I've recently stumbled on while reading Professor Kostas Terzidis' latest publication: Permutation Design: Buildings, Texts and Contexts (2014).



CONTEXT




  • Consider a site (b) that is divided into a grid system (a).

  • Let's also consider a list of spaces to be placed within the limits of the site ( c ) and an adjacency matrix to determine the placement conditions and neighboring relations of these spaces (d)


enter image description here



Quoting Prof. Terzidis:




"A way of solving this problem is to stochastically place spaces within the grid until all spaces are fit and the constraints are satisfied"




The figure above shows such a problem and a sample solution (f).



ALGORITHM (as briefly described in the book)



1/ "Each space is associated with a list that contains all other spaces sorted according to their degree of desirable neighborhood."



2/ "Then each unit of each space is selected from the list and then one-by-one placed randomly in the site until they fit in the site and the neighboring conditions are met. (If it fails then the process is repeated)"



Example of nine randomly generated plans:



enter image description here



I should add that the author explains later that this algorithm doesn't rely on brute force techniques.



PROBLEMS



As you can see, the explanation is relatively vague and step 2 is rather unclear (in terms of coding). All I have so far are "pieces of a puzzle":




  • a "site" (list of selected integers)

  • an adjacency matrix (nestled lists)

  • "spaces" (dictionnary of lists)


for each unit:




  • a function that returns its direct neighbors

  • a list of its desirable neighbors with their indices in sorted order


  • a fitness score based on its actual neighbors



    from random import shuffle

    n_col, n_row = 7, 5
    to_skip = [0, 1, 21, 22, 23, 24, 28, 29, 30, 31]
    site = [i for i in range(n_col * n_row) if i not in to_skip]
    fitness, grid = [[None if i in to_skip else for i in range(n_col * n_row)] for e in range(2)]

    n = 2
    k = (n_col * n_row) - len(to_skip)
    rsize = 50

    #Adjacency matrix
    adm = [[0, 6, 1, 5, 2],
    [6, 0, 1, 4, 0],
    [1, 1, 0, 8, 0],
    [5, 4, 8, 0, 3],
    [2, 0, 0, 3, 0]]


    spaces = {"office1": [0 for i in range(4)],
    "office2": [1 for i in range(6)],
    "office3": [2 for i in range(6)],
    "passage": [3 for i in range(7)],
    "entry": [4 for i in range(2)]}


    def setup():
    global grid
    size(600, 400, P2D)
    rectMode(CENTER)
    strokeWeight(1.4)

    #Shuffle the order for the random placing to come
    shuffle(site)

    #Place units randomly within the limits of the site
    i = -1
    for space in spaces.items():
    for unit in space[1]:
    i+=1
    grid[site[i]] = unit


    #For each unit of each space...
    i = -1
    for space in spaces.items():
    for unit in space[1]:
    i+=1

    #Get the indices of the its DESIRABLE neighbors in sorted order
    ada = adm[unit]
    sorted_indices = sorted(range(len(ada)), key = ada.__getitem__)[::-1]

    #Select indices with positive weight (exluding 0-weight indices)
    pindices = [e for e in sorted_indices if ada[e] > 0]

    #Stores its fitness score (sum of the weight of its REAL neighbors)
    fitness[site[i]] = sum([ada[n] for n in getNeighbors(i) if n in pindices])

    print 'Fitness Score:', fitness

    def draw():
    background(255)

    #Grid's background
    fill(170)
    noStroke()
    rect(width/2 - (rsize/2) , height/2 + rsize/2 + n_row , rsize*n_col, rsize*n_row)


    #Displaying site (grid cells of all selected units) + units placed randomly
    for i, e in enumerate(grid):
    if isinstance(e, list): pass
    elif e == None: pass
    else:
    fill(50 + (e * 50), 255 - (e * 80), 255 - (e * 50), 180)
    rect(width/2 - (rsize*n_col/2) + (i%n_col * rsize), height/2 + (rsize*n_row/2) + (n_row - ((k+len(to_skip))-(i+1))/n_col * rsize), rsize, rsize)
    fill(0)
    text(e+1, width/2 - (rsize*n_col/2) + (i%n_col * rsize), height/2 + (rsize*n_row/2) + (n_row - ((k+len(to_skip))-(i+1))/n_col * rsize))




    def getNeighbors(i):
    neighbors =

    if site[i] > n_col and site[i] < len(grid) - n_col:
    if site[i]%n_col > 0 and site[i]%n_col < n_col - 1:
    if grid[site[i]-1] != None: neighbors.append(grid[site[i]-1])
    if grid[site[i]+1] != None: neighbors.append(grid[site[i]+1])
    if grid[site[i]-n_col] != None: neighbors.append(grid[site[i]-n_col])
    if grid[site[i]+n_col] != None: neighbors.append(grid[site[i]+n_col])

    if site[i] <= n_col:
    if site[i]%n_col > 0 and site[i]%n_col < n_col - 1:
    if grid[site[i]-1] != None: neighbors.append(grid[site[i]-1])
    if grid[site[i]+1] != None: neighbors.append(grid[site[i]+1])
    if grid[site[i]+n_col] != None: neighbors.append(grid[site[i]+n_col])

    if site[i]%n_col == 0:
    if grid[site[i]+1] != None: neighbors.append(grid[site[i]+1])
    if grid[site[i]+n_col] != None: neighbors.append(grid[site[i]+n_col])

    if site[i] == n_col-1:
    if grid[site[i]-1] != None: neighbors.append(grid[site[i]-1])
    if grid[site[i]+n_col] != None: neighbors.append(grid[site[i]+n_col])

    if site[i] >= len(grid) - n_col:
    if site[i]%n_col > 0 and site[i]%n_col < n_col - 1:
    if grid[site[i]-1] != None: neighbors.append(grid[site[i]-1])
    if grid[site[i]+1] != None: neighbors.append(grid[site[i]+1])
    if grid[site[i]-n_col] != None: neighbors.append(grid[site[i]-n_col])

    if site[i]%n_col == 0:
    if grid[site[i]+1] != None: neighbors.append(grid[site[i]+1])
    if grid[site[i]-n_col] != None: neighbors.append(grid[site[i]-n_col])

    if site[i]%n_col == n_col-1:
    if grid[site[i]-1] != None: neighbors.append(grid[site[i]-1])
    if grid[site[i]-n_col] != None: neighbors.append(grid[site[i]-n_col])

    if site[i]%n_col == 0:
    if site[i] > n_col and site[i] < len(grid) - n_col:
    if grid[site[i]+1] != None: neighbors.append(grid[site[i]+1])
    if grid[site[i]+n_col] != None: neighbors.append(grid[site[i]+n_col])
    if grid[site[i]-n_col] != None: neighbors.append(grid[site[i]-n_col])

    if site[i]%n_col == n_col - 1:
    if site[i] > n_col and site[i] < len(grid) - n_col:
    if grid[site[i]-1] != None: neighbors.append(grid[site[i]-1])
    if grid[site[i]+n_col] != None: neighbors.append(grid[site[i]+n_col])
    if grid[site[i]-n_col] != None: neighbors.append(grid[site[i]-n_col])

    return neighbors



enter image description here



I would really appreciate if someone could help connect the dots and explain me:




  • how to re-order the units based on their degree of desirable neighborhood ?


EDIT



As some of you have noticed the algorithm is based on the likelihood that certain spaces (composed of units) are adjacent. The logic would have it then that for each unit to place randomly within the limits of the site:




  • we check its direct neighbors (up, down, left right) beforehand

  • compute a fitness score if at least 2 neighbors. (=sum of the weights of these 2+ neighbors)

  • and finally place that unit if the adjacency probability is high


Roughly, it would translate into this:



    i = -1   
for space in spaces.items():
for unit in space[1]:
i+=1

#Get the indices of the its DESIRABLE neighbors (from the adjacency matrix 'adm') in sorted order
weights = adm[unit]
sorted_indices = sorted(range(len(weights)), key = weights.__getitem__)[::-1]

#Select indices with positive weight (exluding 0-weight indices)
pindices = [e for e in sorted_indices if weights[e] > 0]


#If random grid cell is empty
if not grid[site[i]]:

#List of neighbors
neighbors = [n for n in getNeighbors(i) if isinstance(n, int)]

#If no neighbors -> place unit
if len(neighbors) == 0:
grid[site[i]] = unit

#If at least 1 of the neighbors == unit: -> place unit (facilitate grouping)
if len(neighbors) > 0 and unit in neighbors:
grid[site[i]] = unit

#If 2 or 3 neighbors, compute fitness score and place unit if probability is high
if len(neighbors) >= 2 and len(neighbors) < 4:

fscore = sum([weights[n] for n in neighbors if n in pindices]) #cumulative weight of its ACTUAL neighbors
count = [1 for t in range(10) if random(sum(weights)) < fscore] #add 1 if fscore higher than a number taken at random between 0 and the cumulative weight of its DESIRABLE neighbors

if len(count) > 5:
grid[site[i]] = unit

#If 4 neighbors and high probability, 1 of them must belong to the same space
if len(neighbors) > 3:

fscore = sum([weights[n] for n in neighbors if n in pindices]) #cumulative weight of its ACTUAL neighbors
count = [1 for t in range(10) if random(sum(weights)) < fscore] #add 1 if fscore higher than a number taken at random between 0 and the cumulative weight of its DESIRABLE neighbors

if len(count) > 5 and unit in neighbors:
grid[site[i]] = unit


#if random grid cell not empty -> pass
else: pass


Given that a significant part of the units won't be placed on the first run (because of low adjacency probability), we need to iterate over and over until a random distribution where all units can be fitted is found.



enter image description here



After a few thousand iterations a fit is found and all the neighboring requirements are met.



Notice however how this algorithm produces separated groups instead of non-divided and uniform stacks like in the example provided. I should also add that nearly 5000 iterations is a lot more than the 274 iterations mentioned by Mr. Terzidis in his book.



Questions:




  • Is there something wrong with the way I'm approaching this algorithm ?

  • If no then what implicit condition am I missing ?







python processing permutation






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 9 at 20:13

























asked Nov 3 at 0:56









solub

345317




345317












  • What is the exactly meaning of matrix (d)? e.g what is the meaning of m[2][4] = 4 or m[3][4] = 8, what does the values 4 and 8 mean?
    – Rabbid76
    Nov 3 at 16:17












  • It's a weight, the higher that value is, the higher the probability that the two spaces are adjecent is. Here the probability that 'Office3' (3) and 'Passage' (4) are neighbors is high (8).
    – solub
    Nov 3 at 17:02










  • I'm interested in working this problem, but I don't know what your gui library is. Could you include it so I can run the code?
    – David Culbreth
    Nov 6 at 19:36










  • @DavidCulbreth The code needs to be run from the Processing IDE with Python mode.
    – solub
    Nov 6 at 21:43






  • 1




    "Then each unit of each space is selected from the list and then one-by-one placed randomly in the site until they fit in the site and the neighboring conditions are met." Until what conditions are met? The adjacency matrix doesn't look like it's a count of adjacent buildings, it's more of a heuristic (higher means more likely to be adjacent). So how do you verify that "the neighboring conditions are met" and that a given output is correct? I feel like this problem statement is clear as mud, and some more precise definitions would be useful
    – Matt Messersmith
    Nov 7 at 23:47


















  • What is the exactly meaning of matrix (d)? e.g what is the meaning of m[2][4] = 4 or m[3][4] = 8, what does the values 4 and 8 mean?
    – Rabbid76
    Nov 3 at 16:17












  • It's a weight, the higher that value is, the higher the probability that the two spaces are adjecent is. Here the probability that 'Office3' (3) and 'Passage' (4) are neighbors is high (8).
    – solub
    Nov 3 at 17:02










  • I'm interested in working this problem, but I don't know what your gui library is. Could you include it so I can run the code?
    – David Culbreth
    Nov 6 at 19:36










  • @DavidCulbreth The code needs to be run from the Processing IDE with Python mode.
    – solub
    Nov 6 at 21:43






  • 1




    "Then each unit of each space is selected from the list and then one-by-one placed randomly in the site until they fit in the site and the neighboring conditions are met." Until what conditions are met? The adjacency matrix doesn't look like it's a count of adjacent buildings, it's more of a heuristic (higher means more likely to be adjacent). So how do you verify that "the neighboring conditions are met" and that a given output is correct? I feel like this problem statement is clear as mud, and some more precise definitions would be useful
    – Matt Messersmith
    Nov 7 at 23:47
















What is the exactly meaning of matrix (d)? e.g what is the meaning of m[2][4] = 4 or m[3][4] = 8, what does the values 4 and 8 mean?
– Rabbid76
Nov 3 at 16:17






What is the exactly meaning of matrix (d)? e.g what is the meaning of m[2][4] = 4 or m[3][4] = 8, what does the values 4 and 8 mean?
– Rabbid76
Nov 3 at 16:17














It's a weight, the higher that value is, the higher the probability that the two spaces are adjecent is. Here the probability that 'Office3' (3) and 'Passage' (4) are neighbors is high (8).
– solub
Nov 3 at 17:02




It's a weight, the higher that value is, the higher the probability that the two spaces are adjecent is. Here the probability that 'Office3' (3) and 'Passage' (4) are neighbors is high (8).
– solub
Nov 3 at 17:02












I'm interested in working this problem, but I don't know what your gui library is. Could you include it so I can run the code?
– David Culbreth
Nov 6 at 19:36




I'm interested in working this problem, but I don't know what your gui library is. Could you include it so I can run the code?
– David Culbreth
Nov 6 at 19:36












@DavidCulbreth The code needs to be run from the Processing IDE with Python mode.
– solub
Nov 6 at 21:43




@DavidCulbreth The code needs to be run from the Processing IDE with Python mode.
– solub
Nov 6 at 21:43




1




1




"Then each unit of each space is selected from the list and then one-by-one placed randomly in the site until they fit in the site and the neighboring conditions are met." Until what conditions are met? The adjacency matrix doesn't look like it's a count of adjacent buildings, it's more of a heuristic (higher means more likely to be adjacent). So how do you verify that "the neighboring conditions are met" and that a given output is correct? I feel like this problem statement is clear as mud, and some more precise definitions would be useful
– Matt Messersmith
Nov 7 at 23:47




"Then each unit of each space is selected from the list and then one-by-one placed randomly in the site until they fit in the site and the neighboring conditions are met." Until what conditions are met? The adjacency matrix doesn't look like it's a count of adjacent buildings, it's more of a heuristic (higher means more likely to be adjacent). So how do you verify that "the neighboring conditions are met" and that a given output is correct? I feel like this problem statement is clear as mud, and some more precise definitions would be useful
– Matt Messersmith
Nov 7 at 23:47












2 Answers
2






active

oldest

votes

















up vote
3
down vote



accepted
+50










The solution I propose to solve this challenge is based on repeating the algorithm several times while recordig valid solutions. As solution is not unique, I expect the algorithm to throw more than 1 solution. Each of them will have a score based on neighbours affinity.



I'll call an 'attempt' to a complete run trying to find a valid plant distribution. Full script run will consist in N attempts.



Each attempt starts with 2 random (uniform) choices:




  • Starting point in grid

  • Starting office


Once defined a point and an office, it comes an 'expansion process' trying to fit all the office blocks into the grid.



Each new block is set according to his procedure:




  • 1st. Compute affinity for each adjacent cell to the office.

  • 2nd. Randomly select one site. Choices should be weighted by the affinity.


After every office block is placed, another uniform random choice is needed: next office to be placed.



Once picked, you should compute again affinitty for each site, and randomly (weigthed) select the starting point for the new office.




0 affinity offices don't add. Probability factor should be 0 for
that point in the grid. Affinity function selection is an iteresting
part of this problem. You could try with the addition or even the
multiplication of adjacent cells factor.




Expansion process takes part again until every block of the office is placed.



So basically, office picking follows a uniform distribution and, after that, the weighted expansion process happens for selected office.



When does an attempt end?,
If:




  • There's no point in grid to place a new office (all have affinity = 0)

  • Office can't expand because all affinity weights equal 0


Then the attempt is not valid and should be descarded moving to a fully new random attempt.



Otherwise, if all blocks are fit: it's valid.



The point is that offices should stick together. That's the key point of the algorithm, which randomly tries to fit every new office according to affinity but still a random process. If conditions are not met (not valid), the random process starts again choosing a newly random gridpoint and office.



enter image description here



Sorry there's just an algorithm but nothing of code here.



Note: I'm sure the affinity compute process could be improved or even you could try with some different methods. This is just an idea to help you get your solution.



Hope it helps.






share|improve this answer





















  • Before any further investigation I'd like to say how much I appreciate the effort you put in your answer (clear explanations and neat graphic).
    – solub
    Nov 10 at 14:33












  • I wish I had a little more time to implement your suggestion and be sure of its feasibility and correctness. Nevertheless, I'm accepting this answer for 3 reasons. It's the most helpful in finding a solution that best fit Prof. Terzidis's original algorithm (I believe the adjacency matrix should remain unchanged), it's also the oldest and neatest answer. I have contacted Prof. Terzidis for further details, if he ever replies be assured I'll update this topic with his answer.
    – solub
    Nov 12 at 17:37












  • @solub Please let us know what Prof. Terzidis answer is!!. I found this question really interesting.
    – Cheche
    Nov 12 at 17:54


















up vote
0
down vote













I'm sure the Professor Kostas Terzidis would be an excellent computer theory researcher, but his algorithm explanations don't help at all.



First, the adjacency matrix has no sense. In the questions comments you said:




"the higher that value is, the higher the probability that the two spaces are adjecent is"




but m[i][i] = 0, so that means people in the same "office" prefer other offices as neighbor. That's exactly the opposite that you'd expect, isn't it? I suggest to use this matrix instead:



With 1 <= i, j <= 5:

+----------------+
| 10 6 1 5 2 |
| 10 1 4 0 |
m[i][j] = | 10 8 0 |
| 10 3 |
| 10 |
+----------------+


With this matrix,




  • The highest value is 10. So m[i][i] = 10 means exactly what you want: People in the same office should be together.

  • The lowest value is 0. (People who shouldn't have any contact at all)


The algorithm



Step 1: Start putting all places randomly



(So sorry for 1-based matrix indexing, but it's to be consistent with adjacency matrix.)



With 1 <= x <= 5 and 1 <= y <= 7:

+---------------------+
| - - 1 2 1 4 3 |
| 1 2 4 5 1 4 3 |
p[x][y] = | 2 4 2 4 3 2 4 |
| - - - - 3 2 4 |
| - - - - 5 3 3 |
+---------------------+


Step 2: Score the solution



For all places p[x][y], calculate the score using the adjacency matrix. For example, the first place 1 has 2 and 4 as neighbors, so the score is 11:



score(p[1][3]) = m[1][2] + m[1][4] = 11


The sum of all individual scores would be the solution score.



Step 3: Refine the current solution by swapping places



For each pair of places p[x1][y1], p[x2][y2], swap them and evaluate the solution again, if the score is better, keep the new solution. In any case repeat the step 3 till no permutation is able to improve the solution.



For example, if you swap p[1][4] with p[2][1]:



            +---------------------+
| - - 1 1 1 4 3 |
| 2 2 4 5 1 4 3 |
p[x][y] = | 2 4 2 4 3 2 4 |
| - - - - 3 2 4 |
| - - - - 5 3 3 |
+---------------------+


you'll find a solution with a better score:



before swap



score(p[1][3]) = m[1][2] + m[1][4] = 11
score(p[2][1]) = m[1][2] + m[1][2] = 12


after swap



score(p[1][3]) = m[1][1] + m[1][4] = 15
score(p[2][1]) = m[2][2] + m[2][2] = 20


So keep it and continue swapping places.



Some notes




  • Notice the algorithm will always finalize given that at some point of the iteration you won't be able to swap 2 places and have a better score.

  • In a matrix with N places there are N x (N-1) possible swaps, and that can be done in a efficient way (so, no brute force is needed).


Hope it helps!






share|improve this answer























  • You miss here ~amount of iterations required or some speed comparison.
    – PascalVKooten
    Nov 10 at 17:07










  • @PascalVKooten You are right, I never mentioned the amount of iterations, but that was never asked. I was just trying to answer the question and help this guy.
    – Cartucho
    Nov 10 at 17:14










  • @Cartucho According to your algorithm a swapping occurs only when both units benefit from a better solution score. The problem is that sometimes a unit will have a lower score (because less neighbors) and that will prevent a swapping that is yet necessary --> imgur.com/a/qgRyp6N
    – solub
    Nov 12 at 1:14










  • @solub No, swap should always be done if the overall score in the whole matrix improves. What I proposed is to calculate the score(p1) + score(p2) + score(neighbors) before and after the swap. In you example, score(p1) + score(p2) = 18+26 before and 18+28 after (score of all neighbors of p1 and p2 should be calculated as well), so the algorithm DO the swap.
    – Cartucho
    Nov 12 at 12:54












  • @Cartucho Your comment is unclear whether it's the "solution score" (sum of individual scores of the whole grid) OR score(p1) + score(p2) + score(neighbors) that has to be computed before and after the swap. I tried the first option ( "solution score") and even if the overall score improves the final output doesn't always display perfectly separated spaces.
    – solub
    Nov 12 at 16:04













Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53127467%2fhow-to-re-order-units-based-on-their-degree-of-desirable-neighborhood-in-proc%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























2 Answers
2






active

oldest

votes








2 Answers
2






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
3
down vote



accepted
+50










The solution I propose to solve this challenge is based on repeating the algorithm several times while recordig valid solutions. As solution is not unique, I expect the algorithm to throw more than 1 solution. Each of them will have a score based on neighbours affinity.



I'll call an 'attempt' to a complete run trying to find a valid plant distribution. Full script run will consist in N attempts.



Each attempt starts with 2 random (uniform) choices:




  • Starting point in grid

  • Starting office


Once defined a point and an office, it comes an 'expansion process' trying to fit all the office blocks into the grid.



Each new block is set according to his procedure:




  • 1st. Compute affinity for each adjacent cell to the office.

  • 2nd. Randomly select one site. Choices should be weighted by the affinity.


After every office block is placed, another uniform random choice is needed: next office to be placed.



Once picked, you should compute again affinitty for each site, and randomly (weigthed) select the starting point for the new office.




0 affinity offices don't add. Probability factor should be 0 for
that point in the grid. Affinity function selection is an iteresting
part of this problem. You could try with the addition or even the
multiplication of adjacent cells factor.




Expansion process takes part again until every block of the office is placed.



So basically, office picking follows a uniform distribution and, after that, the weighted expansion process happens for selected office.



When does an attempt end?,
If:




  • There's no point in grid to place a new office (all have affinity = 0)

  • Office can't expand because all affinity weights equal 0


Then the attempt is not valid and should be descarded moving to a fully new random attempt.



Otherwise, if all blocks are fit: it's valid.



The point is that offices should stick together. That's the key point of the algorithm, which randomly tries to fit every new office according to affinity but still a random process. If conditions are not met (not valid), the random process starts again choosing a newly random gridpoint and office.



enter image description here



Sorry there's just an algorithm but nothing of code here.



Note: I'm sure the affinity compute process could be improved or even you could try with some different methods. This is just an idea to help you get your solution.



Hope it helps.






share|improve this answer





















  • Before any further investigation I'd like to say how much I appreciate the effort you put in your answer (clear explanations and neat graphic).
    – solub
    Nov 10 at 14:33












  • I wish I had a little more time to implement your suggestion and be sure of its feasibility and correctness. Nevertheless, I'm accepting this answer for 3 reasons. It's the most helpful in finding a solution that best fit Prof. Terzidis's original algorithm (I believe the adjacency matrix should remain unchanged), it's also the oldest and neatest answer. I have contacted Prof. Terzidis for further details, if he ever replies be assured I'll update this topic with his answer.
    – solub
    Nov 12 at 17:37












  • @solub Please let us know what Prof. Terzidis answer is!!. I found this question really interesting.
    – Cheche
    Nov 12 at 17:54















up vote
3
down vote



accepted
+50










The solution I propose to solve this challenge is based on repeating the algorithm several times while recordig valid solutions. As solution is not unique, I expect the algorithm to throw more than 1 solution. Each of them will have a score based on neighbours affinity.



I'll call an 'attempt' to a complete run trying to find a valid plant distribution. Full script run will consist in N attempts.



Each attempt starts with 2 random (uniform) choices:




  • Starting point in grid

  • Starting office


Once defined a point and an office, it comes an 'expansion process' trying to fit all the office blocks into the grid.



Each new block is set according to his procedure:




  • 1st. Compute affinity for each adjacent cell to the office.

  • 2nd. Randomly select one site. Choices should be weighted by the affinity.


After every office block is placed, another uniform random choice is needed: next office to be placed.



Once picked, you should compute again affinitty for each site, and randomly (weigthed) select the starting point for the new office.




0 affinity offices don't add. Probability factor should be 0 for
that point in the grid. Affinity function selection is an iteresting
part of this problem. You could try with the addition or even the
multiplication of adjacent cells factor.




Expansion process takes part again until every block of the office is placed.



So basically, office picking follows a uniform distribution and, after that, the weighted expansion process happens for selected office.



When does an attempt end?,
If:




  • There's no point in grid to place a new office (all have affinity = 0)

  • Office can't expand because all affinity weights equal 0


Then the attempt is not valid and should be descarded moving to a fully new random attempt.



Otherwise, if all blocks are fit: it's valid.



The point is that offices should stick together. That's the key point of the algorithm, which randomly tries to fit every new office according to affinity but still a random process. If conditions are not met (not valid), the random process starts again choosing a newly random gridpoint and office.



enter image description here



Sorry there's just an algorithm but nothing of code here.



Note: I'm sure the affinity compute process could be improved or even you could try with some different methods. This is just an idea to help you get your solution.



Hope it helps.






share|improve this answer





















  • Before any further investigation I'd like to say how much I appreciate the effort you put in your answer (clear explanations and neat graphic).
    – solub
    Nov 10 at 14:33












  • I wish I had a little more time to implement your suggestion and be sure of its feasibility and correctness. Nevertheless, I'm accepting this answer for 3 reasons. It's the most helpful in finding a solution that best fit Prof. Terzidis's original algorithm (I believe the adjacency matrix should remain unchanged), it's also the oldest and neatest answer. I have contacted Prof. Terzidis for further details, if he ever replies be assured I'll update this topic with his answer.
    – solub
    Nov 12 at 17:37












  • @solub Please let us know what Prof. Terzidis answer is!!. I found this question really interesting.
    – Cheche
    Nov 12 at 17:54













up vote
3
down vote



accepted
+50







up vote
3
down vote



accepted
+50




+50




The solution I propose to solve this challenge is based on repeating the algorithm several times while recordig valid solutions. As solution is not unique, I expect the algorithm to throw more than 1 solution. Each of them will have a score based on neighbours affinity.



I'll call an 'attempt' to a complete run trying to find a valid plant distribution. Full script run will consist in N attempts.



Each attempt starts with 2 random (uniform) choices:




  • Starting point in grid

  • Starting office


Once defined a point and an office, it comes an 'expansion process' trying to fit all the office blocks into the grid.



Each new block is set according to his procedure:




  • 1st. Compute affinity for each adjacent cell to the office.

  • 2nd. Randomly select one site. Choices should be weighted by the affinity.


After every office block is placed, another uniform random choice is needed: next office to be placed.



Once picked, you should compute again affinitty for each site, and randomly (weigthed) select the starting point for the new office.




0 affinity offices don't add. Probability factor should be 0 for
that point in the grid. Affinity function selection is an iteresting
part of this problem. You could try with the addition or even the
multiplication of adjacent cells factor.




Expansion process takes part again until every block of the office is placed.



So basically, office picking follows a uniform distribution and, after that, the weighted expansion process happens for selected office.



When does an attempt end?,
If:




  • There's no point in grid to place a new office (all have affinity = 0)

  • Office can't expand because all affinity weights equal 0


Then the attempt is not valid and should be descarded moving to a fully new random attempt.



Otherwise, if all blocks are fit: it's valid.



The point is that offices should stick together. That's the key point of the algorithm, which randomly tries to fit every new office according to affinity but still a random process. If conditions are not met (not valid), the random process starts again choosing a newly random gridpoint and office.



enter image description here



Sorry there's just an algorithm but nothing of code here.



Note: I'm sure the affinity compute process could be improved or even you could try with some different methods. This is just an idea to help you get your solution.



Hope it helps.






share|improve this answer












The solution I propose to solve this challenge is based on repeating the algorithm several times while recordig valid solutions. As solution is not unique, I expect the algorithm to throw more than 1 solution. Each of them will have a score based on neighbours affinity.



I'll call an 'attempt' to a complete run trying to find a valid plant distribution. Full script run will consist in N attempts.



Each attempt starts with 2 random (uniform) choices:




  • Starting point in grid

  • Starting office


Once defined a point and an office, it comes an 'expansion process' trying to fit all the office blocks into the grid.



Each new block is set according to his procedure:




  • 1st. Compute affinity for each adjacent cell to the office.

  • 2nd. Randomly select one site. Choices should be weighted by the affinity.


After every office block is placed, another uniform random choice is needed: next office to be placed.



Once picked, you should compute again affinitty for each site, and randomly (weigthed) select the starting point for the new office.




0 affinity offices don't add. Probability factor should be 0 for
that point in the grid. Affinity function selection is an iteresting
part of this problem. You could try with the addition or even the
multiplication of adjacent cells factor.




Expansion process takes part again until every block of the office is placed.



So basically, office picking follows a uniform distribution and, after that, the weighted expansion process happens for selected office.



When does an attempt end?,
If:




  • There's no point in grid to place a new office (all have affinity = 0)

  • Office can't expand because all affinity weights equal 0


Then the attempt is not valid and should be descarded moving to a fully new random attempt.



Otherwise, if all blocks are fit: it's valid.



The point is that offices should stick together. That's the key point of the algorithm, which randomly tries to fit every new office according to affinity but still a random process. If conditions are not met (not valid), the random process starts again choosing a newly random gridpoint and office.



enter image description here



Sorry there's just an algorithm but nothing of code here.



Note: I'm sure the affinity compute process could be improved or even you could try with some different methods. This is just an idea to help you get your solution.



Hope it helps.







share|improve this answer












share|improve this answer



share|improve this answer










answered Nov 10 at 13:30









Cheche

798218




798218












  • Before any further investigation I'd like to say how much I appreciate the effort you put in your answer (clear explanations and neat graphic).
    – solub
    Nov 10 at 14:33












  • I wish I had a little more time to implement your suggestion and be sure of its feasibility and correctness. Nevertheless, I'm accepting this answer for 3 reasons. It's the most helpful in finding a solution that best fit Prof. Terzidis's original algorithm (I believe the adjacency matrix should remain unchanged), it's also the oldest and neatest answer. I have contacted Prof. Terzidis for further details, if he ever replies be assured I'll update this topic with his answer.
    – solub
    Nov 12 at 17:37












  • @solub Please let us know what Prof. Terzidis answer is!!. I found this question really interesting.
    – Cheche
    Nov 12 at 17:54


















  • Before any further investigation I'd like to say how much I appreciate the effort you put in your answer (clear explanations and neat graphic).
    – solub
    Nov 10 at 14:33












  • I wish I had a little more time to implement your suggestion and be sure of its feasibility and correctness. Nevertheless, I'm accepting this answer for 3 reasons. It's the most helpful in finding a solution that best fit Prof. Terzidis's original algorithm (I believe the adjacency matrix should remain unchanged), it's also the oldest and neatest answer. I have contacted Prof. Terzidis for further details, if he ever replies be assured I'll update this topic with his answer.
    – solub
    Nov 12 at 17:37












  • @solub Please let us know what Prof. Terzidis answer is!!. I found this question really interesting.
    – Cheche
    Nov 12 at 17:54
















Before any further investigation I'd like to say how much I appreciate the effort you put in your answer (clear explanations and neat graphic).
– solub
Nov 10 at 14:33






Before any further investigation I'd like to say how much I appreciate the effort you put in your answer (clear explanations and neat graphic).
– solub
Nov 10 at 14:33














I wish I had a little more time to implement your suggestion and be sure of its feasibility and correctness. Nevertheless, I'm accepting this answer for 3 reasons. It's the most helpful in finding a solution that best fit Prof. Terzidis's original algorithm (I believe the adjacency matrix should remain unchanged), it's also the oldest and neatest answer. I have contacted Prof. Terzidis for further details, if he ever replies be assured I'll update this topic with his answer.
– solub
Nov 12 at 17:37






I wish I had a little more time to implement your suggestion and be sure of its feasibility and correctness. Nevertheless, I'm accepting this answer for 3 reasons. It's the most helpful in finding a solution that best fit Prof. Terzidis's original algorithm (I believe the adjacency matrix should remain unchanged), it's also the oldest and neatest answer. I have contacted Prof. Terzidis for further details, if he ever replies be assured I'll update this topic with his answer.
– solub
Nov 12 at 17:37














@solub Please let us know what Prof. Terzidis answer is!!. I found this question really interesting.
– Cheche
Nov 12 at 17:54




@solub Please let us know what Prof. Terzidis answer is!!. I found this question really interesting.
– Cheche
Nov 12 at 17:54












up vote
0
down vote













I'm sure the Professor Kostas Terzidis would be an excellent computer theory researcher, but his algorithm explanations don't help at all.



First, the adjacency matrix has no sense. In the questions comments you said:




"the higher that value is, the higher the probability that the two spaces are adjecent is"




but m[i][i] = 0, so that means people in the same "office" prefer other offices as neighbor. That's exactly the opposite that you'd expect, isn't it? I suggest to use this matrix instead:



With 1 <= i, j <= 5:

+----------------+
| 10 6 1 5 2 |
| 10 1 4 0 |
m[i][j] = | 10 8 0 |
| 10 3 |
| 10 |
+----------------+


With this matrix,




  • The highest value is 10. So m[i][i] = 10 means exactly what you want: People in the same office should be together.

  • The lowest value is 0. (People who shouldn't have any contact at all)


The algorithm



Step 1: Start putting all places randomly



(So sorry for 1-based matrix indexing, but it's to be consistent with adjacency matrix.)



With 1 <= x <= 5 and 1 <= y <= 7:

+---------------------+
| - - 1 2 1 4 3 |
| 1 2 4 5 1 4 3 |
p[x][y] = | 2 4 2 4 3 2 4 |
| - - - - 3 2 4 |
| - - - - 5 3 3 |
+---------------------+


Step 2: Score the solution



For all places p[x][y], calculate the score using the adjacency matrix. For example, the first place 1 has 2 and 4 as neighbors, so the score is 11:



score(p[1][3]) = m[1][2] + m[1][4] = 11


The sum of all individual scores would be the solution score.



Step 3: Refine the current solution by swapping places



For each pair of places p[x1][y1], p[x2][y2], swap them and evaluate the solution again, if the score is better, keep the new solution. In any case repeat the step 3 till no permutation is able to improve the solution.



For example, if you swap p[1][4] with p[2][1]:



            +---------------------+
| - - 1 1 1 4 3 |
| 2 2 4 5 1 4 3 |
p[x][y] = | 2 4 2 4 3 2 4 |
| - - - - 3 2 4 |
| - - - - 5 3 3 |
+---------------------+


you'll find a solution with a better score:



before swap



score(p[1][3]) = m[1][2] + m[1][4] = 11
score(p[2][1]) = m[1][2] + m[1][2] = 12


after swap



score(p[1][3]) = m[1][1] + m[1][4] = 15
score(p[2][1]) = m[2][2] + m[2][2] = 20


So keep it and continue swapping places.



Some notes




  • Notice the algorithm will always finalize given that at some point of the iteration you won't be able to swap 2 places and have a better score.

  • In a matrix with N places there are N x (N-1) possible swaps, and that can be done in a efficient way (so, no brute force is needed).


Hope it helps!






share|improve this answer























  • You miss here ~amount of iterations required or some speed comparison.
    – PascalVKooten
    Nov 10 at 17:07










  • @PascalVKooten You are right, I never mentioned the amount of iterations, but that was never asked. I was just trying to answer the question and help this guy.
    – Cartucho
    Nov 10 at 17:14










  • @Cartucho According to your algorithm a swapping occurs only when both units benefit from a better solution score. The problem is that sometimes a unit will have a lower score (because less neighbors) and that will prevent a swapping that is yet necessary --> imgur.com/a/qgRyp6N
    – solub
    Nov 12 at 1:14










  • @solub No, swap should always be done if the overall score in the whole matrix improves. What I proposed is to calculate the score(p1) + score(p2) + score(neighbors) before and after the swap. In you example, score(p1) + score(p2) = 18+26 before and 18+28 after (score of all neighbors of p1 and p2 should be calculated as well), so the algorithm DO the swap.
    – Cartucho
    Nov 12 at 12:54












  • @Cartucho Your comment is unclear whether it's the "solution score" (sum of individual scores of the whole grid) OR score(p1) + score(p2) + score(neighbors) that has to be computed before and after the swap. I tried the first option ( "solution score") and even if the overall score improves the final output doesn't always display perfectly separated spaces.
    – solub
    Nov 12 at 16:04

















up vote
0
down vote













I'm sure the Professor Kostas Terzidis would be an excellent computer theory researcher, but his algorithm explanations don't help at all.



First, the adjacency matrix has no sense. In the questions comments you said:




"the higher that value is, the higher the probability that the two spaces are adjecent is"




but m[i][i] = 0, so that means people in the same "office" prefer other offices as neighbor. That's exactly the opposite that you'd expect, isn't it? I suggest to use this matrix instead:



With 1 <= i, j <= 5:

+----------------+
| 10 6 1 5 2 |
| 10 1 4 0 |
m[i][j] = | 10 8 0 |
| 10 3 |
| 10 |
+----------------+


With this matrix,




  • The highest value is 10. So m[i][i] = 10 means exactly what you want: People in the same office should be together.

  • The lowest value is 0. (People who shouldn't have any contact at all)


The algorithm



Step 1: Start putting all places randomly



(So sorry for 1-based matrix indexing, but it's to be consistent with adjacency matrix.)



With 1 <= x <= 5 and 1 <= y <= 7:

+---------------------+
| - - 1 2 1 4 3 |
| 1 2 4 5 1 4 3 |
p[x][y] = | 2 4 2 4 3 2 4 |
| - - - - 3 2 4 |
| - - - - 5 3 3 |
+---------------------+


Step 2: Score the solution



For all places p[x][y], calculate the score using the adjacency matrix. For example, the first place 1 has 2 and 4 as neighbors, so the score is 11:



score(p[1][3]) = m[1][2] + m[1][4] = 11


The sum of all individual scores would be the solution score.



Step 3: Refine the current solution by swapping places



For each pair of places p[x1][y1], p[x2][y2], swap them and evaluate the solution again, if the score is better, keep the new solution. In any case repeat the step 3 till no permutation is able to improve the solution.



For example, if you swap p[1][4] with p[2][1]:



            +---------------------+
| - - 1 1 1 4 3 |
| 2 2 4 5 1 4 3 |
p[x][y] = | 2 4 2 4 3 2 4 |
| - - - - 3 2 4 |
| - - - - 5 3 3 |
+---------------------+


you'll find a solution with a better score:



before swap



score(p[1][3]) = m[1][2] + m[1][4] = 11
score(p[2][1]) = m[1][2] + m[1][2] = 12


after swap



score(p[1][3]) = m[1][1] + m[1][4] = 15
score(p[2][1]) = m[2][2] + m[2][2] = 20


So keep it and continue swapping places.



Some notes




  • Notice the algorithm will always finalize given that at some point of the iteration you won't be able to swap 2 places and have a better score.

  • In a matrix with N places there are N x (N-1) possible swaps, and that can be done in a efficient way (so, no brute force is needed).


Hope it helps!






share|improve this answer























  • You miss here ~amount of iterations required or some speed comparison.
    – PascalVKooten
    Nov 10 at 17:07










  • @PascalVKooten You are right, I never mentioned the amount of iterations, but that was never asked. I was just trying to answer the question and help this guy.
    – Cartucho
    Nov 10 at 17:14










  • @Cartucho According to your algorithm a swapping occurs only when both units benefit from a better solution score. The problem is that sometimes a unit will have a lower score (because less neighbors) and that will prevent a swapping that is yet necessary --> imgur.com/a/qgRyp6N
    – solub
    Nov 12 at 1:14










  • @solub No, swap should always be done if the overall score in the whole matrix improves. What I proposed is to calculate the score(p1) + score(p2) + score(neighbors) before and after the swap. In you example, score(p1) + score(p2) = 18+26 before and 18+28 after (score of all neighbors of p1 and p2 should be calculated as well), so the algorithm DO the swap.
    – Cartucho
    Nov 12 at 12:54












  • @Cartucho Your comment is unclear whether it's the "solution score" (sum of individual scores of the whole grid) OR score(p1) + score(p2) + score(neighbors) that has to be computed before and after the swap. I tried the first option ( "solution score") and even if the overall score improves the final output doesn't always display perfectly separated spaces.
    – solub
    Nov 12 at 16:04















up vote
0
down vote










up vote
0
down vote









I'm sure the Professor Kostas Terzidis would be an excellent computer theory researcher, but his algorithm explanations don't help at all.



First, the adjacency matrix has no sense. In the questions comments you said:




"the higher that value is, the higher the probability that the two spaces are adjecent is"




but m[i][i] = 0, so that means people in the same "office" prefer other offices as neighbor. That's exactly the opposite that you'd expect, isn't it? I suggest to use this matrix instead:



With 1 <= i, j <= 5:

+----------------+
| 10 6 1 5 2 |
| 10 1 4 0 |
m[i][j] = | 10 8 0 |
| 10 3 |
| 10 |
+----------------+


With this matrix,




  • The highest value is 10. So m[i][i] = 10 means exactly what you want: People in the same office should be together.

  • The lowest value is 0. (People who shouldn't have any contact at all)


The algorithm



Step 1: Start putting all places randomly



(So sorry for 1-based matrix indexing, but it's to be consistent with adjacency matrix.)



With 1 <= x <= 5 and 1 <= y <= 7:

+---------------------+
| - - 1 2 1 4 3 |
| 1 2 4 5 1 4 3 |
p[x][y] = | 2 4 2 4 3 2 4 |
| - - - - 3 2 4 |
| - - - - 5 3 3 |
+---------------------+


Step 2: Score the solution



For all places p[x][y], calculate the score using the adjacency matrix. For example, the first place 1 has 2 and 4 as neighbors, so the score is 11:



score(p[1][3]) = m[1][2] + m[1][4] = 11


The sum of all individual scores would be the solution score.



Step 3: Refine the current solution by swapping places



For each pair of places p[x1][y1], p[x2][y2], swap them and evaluate the solution again, if the score is better, keep the new solution. In any case repeat the step 3 till no permutation is able to improve the solution.



For example, if you swap p[1][4] with p[2][1]:



            +---------------------+
| - - 1 1 1 4 3 |
| 2 2 4 5 1 4 3 |
p[x][y] = | 2 4 2 4 3 2 4 |
| - - - - 3 2 4 |
| - - - - 5 3 3 |
+---------------------+


you'll find a solution with a better score:



before swap



score(p[1][3]) = m[1][2] + m[1][4] = 11
score(p[2][1]) = m[1][2] + m[1][2] = 12


after swap



score(p[1][3]) = m[1][1] + m[1][4] = 15
score(p[2][1]) = m[2][2] + m[2][2] = 20


So keep it and continue swapping places.



Some notes




  • Notice the algorithm will always finalize given that at some point of the iteration you won't be able to swap 2 places and have a better score.

  • In a matrix with N places there are N x (N-1) possible swaps, and that can be done in a efficient way (so, no brute force is needed).


Hope it helps!






share|improve this answer














I'm sure the Professor Kostas Terzidis would be an excellent computer theory researcher, but his algorithm explanations don't help at all.



First, the adjacency matrix has no sense. In the questions comments you said:




"the higher that value is, the higher the probability that the two spaces are adjecent is"




but m[i][i] = 0, so that means people in the same "office" prefer other offices as neighbor. That's exactly the opposite that you'd expect, isn't it? I suggest to use this matrix instead:



With 1 <= i, j <= 5:

+----------------+
| 10 6 1 5 2 |
| 10 1 4 0 |
m[i][j] = | 10 8 0 |
| 10 3 |
| 10 |
+----------------+


With this matrix,




  • The highest value is 10. So m[i][i] = 10 means exactly what you want: People in the same office should be together.

  • The lowest value is 0. (People who shouldn't have any contact at all)


The algorithm



Step 1: Start putting all places randomly



(So sorry for 1-based matrix indexing, but it's to be consistent with adjacency matrix.)



With 1 <= x <= 5 and 1 <= y <= 7:

+---------------------+
| - - 1 2 1 4 3 |
| 1 2 4 5 1 4 3 |
p[x][y] = | 2 4 2 4 3 2 4 |
| - - - - 3 2 4 |
| - - - - 5 3 3 |
+---------------------+


Step 2: Score the solution



For all places p[x][y], calculate the score using the adjacency matrix. For example, the first place 1 has 2 and 4 as neighbors, so the score is 11:



score(p[1][3]) = m[1][2] + m[1][4] = 11


The sum of all individual scores would be the solution score.



Step 3: Refine the current solution by swapping places



For each pair of places p[x1][y1], p[x2][y2], swap them and evaluate the solution again, if the score is better, keep the new solution. In any case repeat the step 3 till no permutation is able to improve the solution.



For example, if you swap p[1][4] with p[2][1]:



            +---------------------+
| - - 1 1 1 4 3 |
| 2 2 4 5 1 4 3 |
p[x][y] = | 2 4 2 4 3 2 4 |
| - - - - 3 2 4 |
| - - - - 5 3 3 |
+---------------------+


you'll find a solution with a better score:



before swap



score(p[1][3]) = m[1][2] + m[1][4] = 11
score(p[2][1]) = m[1][2] + m[1][2] = 12


after swap



score(p[1][3]) = m[1][1] + m[1][4] = 15
score(p[2][1]) = m[2][2] + m[2][2] = 20


So keep it and continue swapping places.



Some notes




  • Notice the algorithm will always finalize given that at some point of the iteration you won't be able to swap 2 places and have a better score.

  • In a matrix with N places there are N x (N-1) possible swaps, and that can be done in a efficient way (so, no brute force is needed).


Hope it helps!







share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 10 at 16:58

























answered Nov 10 at 16:18









Cartucho

2,14611736




2,14611736












  • You miss here ~amount of iterations required or some speed comparison.
    – PascalVKooten
    Nov 10 at 17:07










  • @PascalVKooten You are right, I never mentioned the amount of iterations, but that was never asked. I was just trying to answer the question and help this guy.
    – Cartucho
    Nov 10 at 17:14










  • @Cartucho According to your algorithm a swapping occurs only when both units benefit from a better solution score. The problem is that sometimes a unit will have a lower score (because less neighbors) and that will prevent a swapping that is yet necessary --> imgur.com/a/qgRyp6N
    – solub
    Nov 12 at 1:14










  • @solub No, swap should always be done if the overall score in the whole matrix improves. What I proposed is to calculate the score(p1) + score(p2) + score(neighbors) before and after the swap. In you example, score(p1) + score(p2) = 18+26 before and 18+28 after (score of all neighbors of p1 and p2 should be calculated as well), so the algorithm DO the swap.
    – Cartucho
    Nov 12 at 12:54












  • @Cartucho Your comment is unclear whether it's the "solution score" (sum of individual scores of the whole grid) OR score(p1) + score(p2) + score(neighbors) that has to be computed before and after the swap. I tried the first option ( "solution score") and even if the overall score improves the final output doesn't always display perfectly separated spaces.
    – solub
    Nov 12 at 16:04




















  • You miss here ~amount of iterations required or some speed comparison.
    – PascalVKooten
    Nov 10 at 17:07










  • @PascalVKooten You are right, I never mentioned the amount of iterations, but that was never asked. I was just trying to answer the question and help this guy.
    – Cartucho
    Nov 10 at 17:14










  • @Cartucho According to your algorithm a swapping occurs only when both units benefit from a better solution score. The problem is that sometimes a unit will have a lower score (because less neighbors) and that will prevent a swapping that is yet necessary --> imgur.com/a/qgRyp6N
    – solub
    Nov 12 at 1:14










  • @solub No, swap should always be done if the overall score in the whole matrix improves. What I proposed is to calculate the score(p1) + score(p2) + score(neighbors) before and after the swap. In you example, score(p1) + score(p2) = 18+26 before and 18+28 after (score of all neighbors of p1 and p2 should be calculated as well), so the algorithm DO the swap.
    – Cartucho
    Nov 12 at 12:54












  • @Cartucho Your comment is unclear whether it's the "solution score" (sum of individual scores of the whole grid) OR score(p1) + score(p2) + score(neighbors) that has to be computed before and after the swap. I tried the first option ( "solution score") and even if the overall score improves the final output doesn't always display perfectly separated spaces.
    – solub
    Nov 12 at 16:04


















You miss here ~amount of iterations required or some speed comparison.
– PascalVKooten
Nov 10 at 17:07




You miss here ~amount of iterations required or some speed comparison.
– PascalVKooten
Nov 10 at 17:07












@PascalVKooten You are right, I never mentioned the amount of iterations, but that was never asked. I was just trying to answer the question and help this guy.
– Cartucho
Nov 10 at 17:14




@PascalVKooten You are right, I never mentioned the amount of iterations, but that was never asked. I was just trying to answer the question and help this guy.
– Cartucho
Nov 10 at 17:14












@Cartucho According to your algorithm a swapping occurs only when both units benefit from a better solution score. The problem is that sometimes a unit will have a lower score (because less neighbors) and that will prevent a swapping that is yet necessary --> imgur.com/a/qgRyp6N
– solub
Nov 12 at 1:14




@Cartucho According to your algorithm a swapping occurs only when both units benefit from a better solution score. The problem is that sometimes a unit will have a lower score (because less neighbors) and that will prevent a swapping that is yet necessary --> imgur.com/a/qgRyp6N
– solub
Nov 12 at 1:14












@solub No, swap should always be done if the overall score in the whole matrix improves. What I proposed is to calculate the score(p1) + score(p2) + score(neighbors) before and after the swap. In you example, score(p1) + score(p2) = 18+26 before and 18+28 after (score of all neighbors of p1 and p2 should be calculated as well), so the algorithm DO the swap.
– Cartucho
Nov 12 at 12:54






@solub No, swap should always be done if the overall score in the whole matrix improves. What I proposed is to calculate the score(p1) + score(p2) + score(neighbors) before and after the swap. In you example, score(p1) + score(p2) = 18+26 before and 18+28 after (score of all neighbors of p1 and p2 should be calculated as well), so the algorithm DO the swap.
– Cartucho
Nov 12 at 12:54














@Cartucho Your comment is unclear whether it's the "solution score" (sum of individual scores of the whole grid) OR score(p1) + score(p2) + score(neighbors) that has to be computed before and after the swap. I tried the first option ( "solution score") and even if the overall score improves the final output doesn't always display perfectly separated spaces.
– solub
Nov 12 at 16:04






@Cartucho Your comment is unclear whether it's the "solution score" (sum of individual scores of the whole grid) OR score(p1) + score(p2) + score(neighbors) that has to be computed before and after the swap. I tried the first option ( "solution score") and even if the overall score improves the final output doesn't always display perfectly separated spaces.
– solub
Nov 12 at 16:04




















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.





Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


Please pay close attention to the following guidance:


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53127467%2fhow-to-re-order-units-based-on-their-degree-of-desirable-neighborhood-in-proc%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







這個網誌中的熱門文章

Xamarin.form Move up view when keyboard appear

Post-Redirect-Get with Spring WebFlux and Thymeleaf

Anylogic : not able to use stopDelay()