make a faster permutation matrix init

From issue #108 (closed) there was a bottleneck in the permutation matrix constructor regarding the function find_lattice_site_by_position. See here:

This is the current profile output with cutoff at 15

5417280 function calls (5367174 primitive calls) in 12.218 seconds

   Ordered by: cumulative time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
    736/1    0.052    0.000   12.219   12.219 {built-in method builtins.exec}
        1    0.019    0.019   12.219   12.219 profile_permutation_matrix.py:1(<module>)
        1    0.000    0.000   10.773   10.773 profile_permutation_matrix.py:11(init_permutation_matrix_python)
        1    0.000    0.000   10.773   10.773 permutation_matrix.py:54(__init__)
        1    0.010    0.010    7.251    7.251 permutation_matrix.py:112(_build_lattice_site_permutation_matrix)
      887    0.120    0.000    7.184    0.008 permutation_matrix.py:127(<listcomp>)
    42576    1.115    0.000    7.063    0.000 geometry.py:175(find_lattice_site_by_position)
        1    0.435    0.435    2.744    2.744 permutation_matrix.py:145(_prune_permutation_matrix)
    42534    0.750    0.000    2.339    0.000 linalg.py:300(solve)
   393853    1.434    0.000    2.318    0.000 lattice_site.py:52(__eq__)
       23    0.001    0.000    2.064    0.090 __init__.py:1(<module>)
    664/1    0.007    0.000    1.427    1.427 <frozen importlib._bootstrap>:966(_find_and_load)
    664/1    0.005    0.000    1.427    1.427 <frozen importlib._bootstrap>:939(_find_and_load_unlocked)
    818/2    0.002    0.000    1.426    0.713 <frozen importlib._bootstrap>:214(_call_with_frames_removed)
    594/2    0.006    0.000    1.426    0.713 <frozen importlib._bootstrap>:659(_load_unlocked)
    491/2    0.003    0.000    1.426    0.713 <frozen importlib._bootstrap_external>:659(exec_module)
        2    0.000    0.000    1.426    0.713 __init__.py:2(<module>)
    416/1    0.001    0.000    1.426    1.426 {built-in method builtins.__import__}
    85104    0.699    0.000    1.415    0.000 linalg.py:2014(norm)
    42528    0.477    0.000    0.820    0.000 geometry.py:191(<listcomp>)
2944/1962    0.007    0.000    0.820    0.000 <frozen importlib._bootstrap>:996(_handle_fromlist)

Exploring points

  • position - > lattice_site lookup (dict)
  • inline __eq__
  • don't use norm to find closest position in atoms.position (other algorithm available?)
  • Get rid of for loops if possible and make more use of array expressions
  • inline functions or copy to local name space
Edited by Mattias Ångqvist