//  [python]
def _get_phi_function_and_derivative(self, S_hat, full_space):
        Del_S = self.del_k
        if self.method == 'trust-region':
            if S_hat.size > 0:
                Del_S = max(np.linalg.norm(S_hat-self.s_old, axis=1, ord=np.inf))
            def phi_function(s):
                s_tilde = np.divide((s - self.s_old), Del_S)
                try:
                    m,n = s_tilde.shape
                except:
                    m = 1
                    s_tilde = s_tilde.reshape(1,-1)
                phi = np.zeros((m, self.q))
                for k in range(self.q):
                    phi[:,k] = np.prod(np.divide(np.power(s_tilde, self.basis[k,:]), factorial(self.basis[k,:])), axis=1)
                if m == 1:
                    return phi.flatten()
                else:
                    return phi
            def phi_function_deriv(s):
                s_tilde = np.divide((s - self.s_old), Del_S)
                phi_deriv = np.zeros((self.n, self.q))
                for i in range(self.n):
                    for k in range(1, self.q):
                        if self.basis[k, i] != 0.0:
                            tmp = np.zeros(self.n)
                            tmp[i] = 1
                            phi_deriv[i,k] = self.basis[k, i] * np.prod(np.divide(np.power(s_tilde, self.basis[k,:]-tmp), \
                                    factorial(self.basis[k,:])))
                return np.divide(phi_deriv.T, Del_S).T
        elif self.method == 'omorf' and full_space:
            if S_hat.size > 0:
                Del_S = max(np.linalg.norm(S_hat-self.s_old, axis=1, ord=np.inf))
            def phi_function(s):
                s_tilde = np.divide((s - self.s_old), Del_S)
                try:
                    m,n = s_tilde.shape
                except:
                    m = 1
                    s_tilde = s_tilde.reshape(1,-1)
                phi = np.zeros((m, self.p))
                phi[:, 0] = 1.0
                phi[:, 1:] = s_tilde
                if m == 1:
                    return phi.flatten()
                else:
                    return phi
            phi_function_deriv = None
        elif self.method == 'omorf':
            if S_hat.size > 0:
                Del_S = max(np.linalg.norm(np.dot(S_hat-self.s_old,self.U), axis=1))
            def phi_function(s):
                u = np.divide(np.dot((s - self.s_old), self.U), Del_S)
                try:
                    m,n = u.shape
                except:
                    m = 1
                    u = u.reshape(1,-1)
                phi = np.zeros((m, self.q))
                for k in range(self.q):
                    phi[:,k] = np.prod(np.divide(np.power(u, self.basis[k,:]), factorial(self.basis[k,:])), axis=1)
                if m == 1:
                    return phi.flatten()
                else:
                    return phi
            def phi_function_deriv(s):
                u = np.divide(np.dot((s - self.s_old), self.U), Del_S)
                phi_deriv = np.zeros((self.d, self.q))
                for i in range(self.d):
                    for k in range(1, self.q):
                        if self.basis[k, i] != 0.0:
                            tmp = np.zeros(self.d)
                            tmp[i] = 1
                            phi_deriv[i,k] = self.basis[k, i] * np.prod(np.divide(np.power(u, self.basis[k,:]-tmp), \
                                    factorial(self.basis[k,:])))
                phi_deriv = np.divide(phi_deriv.T, Del_S).T
                return np.dot(self.U, phi_deriv)
        return phi_function, phi_function_deriv