def optimize(lattice,
             positions,
             numbers,
             displacements,
             forces,
             alm_options=None,
             p2s_map=None,
             p2p_map=None,
             log_level=0):
    """Calculate force constants

    lattice : array_like
        Basis vectors. a, b, c are given as column vectors.
        shape=(3, 3), dtype='double'
    positions : array_like
        Fractional coordinates of atomic points.
        shape=(num_atoms, 3), dtype='double'
    numbers : array_like
        Atomic numbers.
        shape=(num_atoms,), dtype='intc'
    displacements : array_like
        Atomic displacement patterns in supercells in Cartesian.
        dtype='double', shape=(supercells, num_atoms, 3)
    forces : array_like
        Forces in supercells.
        dtype='double', shape=(supercells, num_atoms, 3)
    alm_options : dict, optional
        Default is None.
        List of keys
            cutoff_distance : float
            solver : str
                Either 'SimplicialLDLT' or 'dense'. Default is
                'SimplicialLDLT'.

    """

    from alm import ALM
    with ALM(lattice, positions, numbers) as alm:
        natom = len(numbers)
        alm.set_verbosity(log_level)
        nkd = len(np.unique(numbers))
        if 'cutoff_distance' not in alm_options:
            rcs = -np.ones((2, nkd, nkd), dtype='double')
        elif type(alm_options['cutoff_distance']) is float:
            rcs = np.ones((2, nkd, nkd), dtype='double')
            rcs[0] *= -1
            rcs[1] *= alm_options['cutoff_distance']
        alm.define(2, rcs)
        alm.set_displacement_and_force(displacements, forces)

        if 'solver' in alm_options:
            solver = alm_options['solver']
        else:
            solver = 'SimplicialLDLT'
        info = alm.optimize(solver=solver)
        fc2 = extract_fc2_from_alm(alm,
                                   natom,
                                   atom_list=p2s_map,
                                   p2s_map=p2s_map,
                                   p2p_map=p2p_map)
        fc3 = _extract_fc3_from_alm(alm,
                                    natom,
                                    p2s_map=p2s_map,
                                    p2p_map=p2p_map)
        return fc2, fc3
Calculate force constants

    lattice : array_like
        Basis vectors. a, b, c are given as column vectors.
        shape=(3, 3), dtype='double'
    positions : array_like
        Fractional coordinates of atomic points.
        shape=(num_atoms, 3), dtype='double'
    numbers : array_like
        Atomic numbers.
        shape=(num_atoms,), dtype='intc'
    displacements : array_like
        Atomic displacement patterns in supercells in Cartesian.
        dtype='double', shape=(supercells, num_atoms, 3)
    forces : array_like
        Forces in supercells.
        dtype='double', shape=(supercells, num_atoms, 3)
    alm_options : dict, optional
        Default is None.
        List of keys
            cutoff_distance : float
            solver : str
                Either 'SimplicialLDLT' or 'dense'. Default is
                'SimplicialLDLT'.