0

At the moment, I managed to code, successfully, a simulation for a work that I need to do. However, I'm fairly new to python. And so, I'm now in the process of making the simulation more efficient. For instance:

if random.random() < mm:
    z = numpy.random.choice(pat)

    if random.random() < 0.5:
        if random.random() < mut:
            if maleadult[z][0] == 0:
                malejuv[y][x][0] = 1
            elif maleadult[z][0] == 1:
                malejuv[y][x][0] = 0
        else:
            malejuv[y][x][0] = maleadult[z][0]
    else:
        if random.random() < mut:
            if femaleadult[z][0] == 0:
                malejuv[y][x][0] = 1
            elif femaleadult[z][0] == 1:
                malejuv[y][x][0] = 0
        else:
            malejuv[y][x][0] = femaleadult[z][0]

    if random.random() < 0.5:
        if random.random() < mut:
            if maleadult[z][1] == 0:
                malejuv[y][x][1] = 1
            elif maleadult[z][1] == 1:
                malejuv[y][x][1] = 0
        else:
            malejuv[y][x][1] = maleadult[z][1]
    else:
        if random.random() < mut:
            if femaleadult[z][1] == 0:
                malejuv[y][x][1] = 1
            elif femaleadult[z][1] == 1:
                malejuv[y][x][1] = 0
        else:
            malejuv[y][x][1] = femaleadult[z][0]

where:

 mm - male dispersal, 
 mf - female dispersal, 
 mut - mutations, 
 pat - patch, 
 maleadult - adult male, 
 femaleadult - adult female, 
 malejuv - juvenile male, 
 femalejuv - juvenile female. 

As you can see, the code is big. And this is only for males and when they disperse. The rest of the code is very similar. These are standard genetic and demographic processes - but I feel like this can be improved. I feel like these processes are simple enough, so maybe code as big as this is not necessary.

Does anyone have any ideas to shorten this and, by consequence, making it more efficient?

Gabriel
  • 40,504
  • 73
  • 230
  • 404
GWasp
  • 51
  • 6
  • 1
    If you code works, but just needs improvement, it would be more appropriate for it to be on Code Review; this site is primarily for broken code. Note though that they require full, complete, runnable code over there. – Carcigenicate May 07 '17 at 16:57
  • 1
    There is no loop in your code. Have a look at the [List (sequence) documentation](https://docs.python.org/3/library/stdtypes.html#sequence-types-list-tuple-range) to see if any methods could help simplify your code. – handle May 07 '17 at 16:58

1 Answers1

1

Your example does not have any loops but it looks like it could be simplified by one:

if random.random() < mm:
    z = numpy.random.choice(pat)

    for i in range(2):

        if random.random() < 0.5:
            if random.random() < mut:
                if maleadult[z][i] == 0:
                    malejuv[y][x][i] = 1
                elif maleadult[z][i] == 1:
                    malejuv[y][x][i] = 0
            else:
                malejuv[y][x][i] = maleadult[z][i]
        else:
            if random.random() < mut:
                if femaleadult[z][i] == 0:
                    malejuv[y][x][i] = 1
                elif femaleadult[z][i] == 1:
                    malejuv[y][x][i] = 0
            else:
                malejuv[y][x][i] = femaleadult[z][i]


It is also possible to pass a mutable object as reference to a function which can modify it, which allows further reduction of almost redundant code. I've added some data to test it:
#!python3
#coding=utf-8

import random

maleadult = [[["male adult"], ["another male adult"], ]]
femaleadult = [[["female adult"], ["another female adult"], ]]
malejuv =   [[[["male juv"],["another male juv"]]]]

mut = 0.5
mm = 1.0
x = 0
y = 0
z = 0


def some_logic(a, j):
    """ does something """
    if random.random() < mut:
        if a[z][i] == 0:
            j[y][x][i] = 1
        elif a[z][i] == 1:
            j[y][x][i] = 0
        # added!
        else:
            j[y][x][i] = 0
    else:
        j[y][x][i] = a[z][i]


if random.random() < mm:
    z = 0 #numpy.random.choice(pat)
    for i in range(2):
        print(i)
        if random.random() < 0.5:
            some_logic(maleadult, malejuv)
        else:
            some_logic(femaleadult, malejuv)

print(maleadult)
print(malejuv)
print(femaleadult)
Community
  • 1
  • 1
handle
  • 5,859
  • 3
  • 54
  • 82