Example #1
0
    def run_laplacian_debug(self, x):
        """Compute the trained derivative (debug version)."""
        n = len(x)
        m = len(self.eq.bc)
        H = len(self.v)
        w = self.w
        u = self.u
        v = self.v

        z = np.zeros((n, H))
        for i in range(n):
            for k in range(H):
                z[i, k] = u[k]
                for j in range(m):
                    z[i, k] += w[j, k] * x[i, j]

        s = np.zeros((n, H))
        for i in range(n):
            for k in range(H):
                s[i, k] = sigma.s(z[i, k])

        s1 = np.zeros((n, H))
        for i in range(n):
            for k in range(H):
                s1[i, k] = sigma.s1(s[i, k])

        s2 = np.zeros((n, H))
        for i in range(n):
            for k in range(H):
                s2[i, k] = sigma.s2(s[i, k])

        N = np.zeros(n)
        for i in range(n):
            for k in range(H):
                N[i] += s[i, k] * v[k]

        delN = np.zeros((n, m))
        for i in range(n):
            for j in range(m):
                for k in range(H):
                    delN[i, j] += v[k] * s1[i, k] * w[j, k]

        del2N = np.zeros((n, m))
        for i in range(n):
            for j in range(m):
                for k in range(H):
                    del2N[i, j] += v[k] * s2[i, k] * w[j, k]**2

        del2Yt = np.zeros((n, m))
        for i in range(n):
            del2Yt[i] = self.tf.del2Yt(x[i], N[i], delN[i], del2N[i])

        return del2Yt
Example #2
0
    def _train_delta_debug(self, x, opts=DEFAULT_OPTS):
        """Train using the delta method (debug version). """

        my_opts = dict(DEFAULT_OPTS)
        my_opts.update(opts)

        # Sanity-check arguments.
        assert len(x) > 0
        assert opts['maxepochs'] > 0
        assert opts['eta'] > 0
        assert opts['vmin'] < opts['vmax']
        assert opts['wmin'] < opts['wmax']
        assert opts['umin'] < opts['umax']

        # Determine the number of training points, independent variables, and
        # hidden nodes.
        n = len(x)  # Number of training points
        m = len(self.eq.bc)
        H = len(self.v)   # Number of hidden nodes

        # Change notation for convenience.
        debug = my_opts['debug']
        verbose = my_opts['verbose']
        eta = my_opts['eta']  # Learning rate
        maxepochs = my_opts['maxepochs']  # Number of training epochs
        wmin = my_opts['wmin']  # Network parameter limits
        wmax = my_opts['wmax']
        umin = my_opts['umin']
        umax = my_opts['umax']
        vmin = my_opts['vmin']
        vmax = my_opts['vmax']

        # Create the hidden node weights, biases, and output node weights.
        w = np.random.uniform(wmin, wmax, (m, H))
        u = np.random.uniform(umin, umax, H)
        v = np.random.uniform(vmin, vmax, H)

        # Initial parameter deltas are 0.
        dE_dw = np.zeros((m, H))
        dE_du = np.zeros(H)
        dE_dv = np.zeros(H)

        # Train the network.
        for epoch in range(maxepochs):
            if debug:
                print('Starting epoch %d.' % epoch)

            # Compute the new values of the network parameters.
            for j in range(m):
                for k in range(H):
                    w[j, k] -= eta*dE_dw[j, k]

            for k in range(H):
                u[k] -= eta*dE_du[k]

            for k in range(H):
                v[k] -= eta*dE_dv[k]

            # Compute the input, the sigmoid function, and its derivatives,
            # for each hidden node and each training point.
            z = np.zeros((n, H))
            for i in range(n):
                for k in range(H):
                    z[i, k] = u[k]
                    for j in range(m):
                        z[i, k] += w[j, k]*x[i, j]

            s = np.zeros((n, H))
            for i in range(n):
                for k in range(H):
                    s[i, k] = sigma.s(z[i, k])

            s1 = np.zeros((n, H))
            for i in range(n):
                for k in range(H):
                    s1[i, k] = sigma.s1(s[i, k])

            s2 = np.zeros((n, H))
            for i in range(n):
                for k in range(H):
                    s2[i, k] = sigma.s2(s[i, k])

            # Compute the network output and its derivatives, for each
            # training point.
            N = np.zeros(n)
            for i in range(n):
                for k in range(H):
                    N[i] += v[k]*s[i, k]

            P = np.zeros(n)
            for i in range(n):
                P[i] = self._P(x[i])

            delP = np.zeros((n, m))
            for i in range(n):
                for j in range(m):
                    delP[i, j] = self._delP[j](self, x[i])

            delN = np.zeros((n, m))
            for i in range(n):
                for j in range(m):
                    for k in range(H):
                        delN[i, j] += v[k]*s1[i, k]*w[j, k]

            dN_dw = np.zeros((n, m, H))
            for i in range(n):
                for j in range(m):
                    for k in range(H):
                        dN_dw[i, j, k] = v[k]*s1[i, k]*x[i, j]

            dN_du = np.zeros((n, H))
            for i in range(n):
                for k in range(H):
                    dN_du[i, k] = v[k]*s1[i, k]

            dN_dv = np.zeros((n, H))
            for i in range(n):
                for k in range(H):
                    dN_dv[i, k] = s[i, k]

            d2N_dwdx = np.zeros((n, m, m, H))
            for i in range(n):
                for j in range(m):
                    for jj in range(m):
                        for k in range(H):
                            d2N_dwdx[i, j, jj, k] = (
                                v[k]*(s1[i, k]*kdelta(j, jj)
                                      + s2[i, k]*w[jj, k]*x[i, j])
                            )

            d2N_dudx = np.zeros((n, m, H))
            for i in range(n):
                for j in range(m):
                    for k in range(H):
                        d2N_dudx[i, j, k] = v[k]*s2[i, k]*w[j, k]

            d2N_dvdx = np.zeros((n, m, H))
            for i in range(n):
                for j in range(m):
                    for k in range(H):
                        d2N_dvdx[i, j, k] = s1[i, k]*w[j, k]

            # Compute the value of the trial solution and its derivatives,
            # for each training point.
            Yt = np.zeros(n)
            for i in range(n):
                Yt[i] = self._Yt(x[i], N[i])

            delYt = np.zeros((n, m))
            for i in range(n):
                for j in range(m):
                    delYt[i, j] = self._delYt[j](self, x[i], N[i], delN[i])

            dYt_dw = np.zeros((n, m, H))
            for i in range(n):
                for j in range(m):
                    for k in range(H):
                        dYt_dw[i, j, k] = P[i]*dN_dw[i, j, k]

            dYt_du = np.zeros((n, H))
            for i in range(n):
                for k in range(H):
                    dYt_du[i, k] = P[i]*dN_du[i, k]

            dYt_dv = np.zeros((n, H))
            for i in range(n):
                for k in range(H):
                    dYt_dv[i, k] = P[i]*dN_dv[i, k]

            d2Yt_dwdx = np.zeros((n, m, m, H))
            for i in range(n):
                for j in range(m):
                    for jj in range(m):
                        for k in range(H):
                            d2Yt_dwdx[i, j, jj, k] = (
                                P[i]*d2N_dwdx[i, j, jj, k]
                                + delP[i, jj]*dN_dw[i, j, k]
                            )

            d2Yt_dudx = np.zeros((n, m, H))
            for i in range(n):
                for j in range(m):
                    for k in range(H):
                        d2Yt_dudx[i, j, k] = (
                            P[i]*d2N_dudx[i, j, k]
                            + delP[i, j]*dN_du[i, k]
                        )

            d2Yt_dvdx = np.zeros((n, m, H))
            for i in range(n):
                for j in range(m):
                    for k in range(H):
                        d2Yt_dvdx[i, j, k] = (
                            P[i]*d2N_dvdx[i, j, k]
                            + delP[i, j]*dN_dv[i, k]
                        )

            # Compute the value of the original differential equation for
            # each training point, and its derivatives.
            G = np.zeros(n)
            for i in range(n):
                G[i] = self.eq.G(x[i], Yt[i], delYt[i])

            dG_dYt = np.zeros(n)
            for i in range(n):
                dG_dYt[i] = self.eq.dG_dY(x[i], Yt[i], delYt[i])

            dG_ddelYt = np.zeros((n, m))
            for i in range(n):
                for j in range(m):
                    dG_ddelYt[i, j] = (
                        self.eq.dG_ddelY[j](x[i], Yt[i], delYt[i])
                    )

            dG_dw = np.zeros((n, m, H))
            for i in range(n):
                for j in range(m):
                    for k in range(H):
                        dG_dw[i, j, k] = dG_dYt[i]*dYt_dw[i, j, k]
                        for jj in range(m):
                            dG_dw[i, j, k] += (
                                dG_ddelYt[i, jj]*d2Yt_dwdx[i, j, jj, k]
                            )

            dG_du = np.zeros((n, H))
            for i in range(n):
                for k in range(H):
                    dG_du[i, k] = dG_dYt[i]*dYt_du[i, k]
                    for j in range(m):
                        dG_du[i, k] += dG_ddelYt[i, j]*d2Yt_dudx[i, j, k]

            dG_dv = np.zeros((n, H))
            for i in range(n):
                for k in range(H):
                    dG_dv[i, k] = dG_dYt[i]*dYt_dv[i, k]
                    for j in range(m):
                        dG_dv[i, k] += dG_ddelYt[i, j]*d2Yt_dvdx[i, j, k]

            # Compute the error function for this epoch.
            E = 0
            for i in range(n):
                E += G[i]**2

            # Compute the partial derivatives of the error with respect to
            # the network parameters.
            dE_dw = np.zeros((m, H))
            for j in range(m):
                for k in range(H):
                    for i in range(n):
                        dE_dw[j, k] += 2*G[i]*dG_dw[i, j, k]

            dE_du = np.zeros(H)
            for k in range(H):
                for i in range(n):
                    dE_du[k] += 2*G[i]*dG_du[i, k]

            dE_dv = np.zeros(H)
            for k in range(H):
                for i in range(n):
                    dE_dv[k] += 2*G[i]*dG_dv[i, k]

            # Compute the RMS error for this epoch.
            rmse = sqrt(E/n)
            if verbose:
                print(epoch, rmse)

        # Save the optimized parameters.
        self.w = w
        self.u = u
        self.v = v
Example #3
0
    def _compute_error_debug(self, p, x):
        """Compute the error function using the current parameter values
           (debug version)."""

        # Determine the number of training points, independent variables, and
        # hidden nodes.
        n = len(x)
        m = len(self.eq.bc)
        H = len(self.v)

        # Unpack the network parameters.
        w = np.zeros((m, H))
        for j in range(m):
            w[j] = p[j * H:(j + 1) * H]
        u = p[m * H:(m + 1) * H]
        v = p[(m + 1) * H:(m + 2) * H]

        # Compute the forward pass through the network.
        z = np.zeros((n, H))
        for i in range(n):
            for k in range(H):
                z[i, k] = u[k]
                for j in range(m):
                    z[i, k] += w[j, k] * x[i, j]

        s = np.zeros((n, H))
        for i in range(n):
            for k in range(H):
                s[i, k] = sigma.s(z[i, k])

        s1 = np.zeros((n, H))
        for i in range(n):
            for k in range(H):
                s1[i, k] = sigma.s1(s[i, k])

        s2 = np.zeros((n, H))
        for i in range(n):
            for k in range(H):
                s2[i, k] = sigma.s2(s[i, k])

        N = np.zeros(n)
        for i in range(n):
            for k in range(H):
                N[i] += v[k] * s[i, k]

        delN = np.zeros((n, m))
        for i in range(n):
            for j in range(m):
                for k in range(H):
                    delN[i, j] += v[k] * s1[i, k] * w[j, k]

        del2N = np.zeros((n, m))
        for i in range(n):
            for j in range(m):
                for k in range(H):
                    del2N[i, j] += v[k] * s2[i, k] * w[j, k]**2

        Yt = np.zeros(n)
        for i in range(n):
            Yt[i] = self.tf.Yt(x[i], N[i])

        delYt = np.zeros((n, m))
        for i in range(n):
            delYt[i] = self.tf.delYt(x[i], N[i], delN[i])

        del2Yt = np.zeros((n, m))
        for i in range(n):
            del2Yt[i] = self.tf.del2Yt(x[i], N[i], delN[i], del2N[i])

        G = np.zeros(n)
        for i in range(n):
            G[i] = self.eq.G(x[i], Yt[i], delYt[i], del2Yt[i])

        E2 = 0
        for i in range(n):
            E2 += G[i]**2

        return E2
Example #4
0
    def _train_delta_debug(self, x, opts=DEFAULT_OPTS):
        """Train using the delta method (debug version)."""

        my_opts = dict(DEFAULT_OPTS)
        my_opts.update(opts)

        # Determine the number of training points, independent variables, and
        # hidden nodes.
        n = len(x)
        m = len(self.eq.bc)
        H = len(self.v)

        # Change notation for convenience.
        debug = my_opts["debug"]
        verbose = my_opts["verbose"]
        eta = my_opts["eta"]  # Learning rate
        maxepochs = my_opts["maxepochs"]  # Number of training epochs
        wmin = my_opts["wmin"]  # Network parameter limits
        wmax = my_opts["wmax"]
        umin = my_opts["umin"]
        umax = my_opts["umax"]
        vmin = my_opts["vmin"]
        vmax = my_opts["vmax"]

        # Create the hidden node weights, biases, and output node weights.
        w = np.random.uniform(wmin, wmax, (m, H))
        u = np.random.uniform(umin, umax, H)
        v = np.random.uniform(vmin, vmax, H)
        # w = np.zeros((m, H))
        # u = np.zeros(H)
        # v = np.zeros(H)

        # Initial parameter deltas are 0.
        dE_dw = np.zeros((m, H))
        dE_du = np.zeros(H)
        dE_dv = np.zeros(H)

        # Train the network.
        for epoch in range(maxepochs):
            if debug:
                print("Starting epoch %d." % epoch)

            # Compute the new values of the network parameters.
            for j in range(m):
                for k in range(H):
                    w[j, k] -= eta * dE_dw[j, k]

            for k in range(H):
                u[k] -= eta * dE_du[k]

            for k in range(H):
                v[k] -= eta * dE_dv[k]

            # Compute the input, the sigmoid function, and its derivatives,
            # for each hidden node and each training point.
            z = np.zeros((n, H))
            for i in range(n):
                for k in range(H):
                    z[i, k] = u[k]
                    for j in range(m):
                        z[i, k] += w[j, k] * x[i, j]

            s = np.zeros((n, H))
            for i in range(n):
                for k in range(H):
                    s[i, k] = sigma.s(z[i, k])

            s1 = np.zeros((n, H))
            for i in range(n):
                for k in range(H):
                    s1[i, k] = sigma.s1(s[i, k])

            s2 = np.zeros((n, H))
            for i in range(n):
                for k in range(H):
                    s2[i, k] = sigma.s2(s[i, k])

            s3 = np.zeros((n, H))
            for i in range(n):
                for k in range(H):
                    s3[i, k] = sigma.s3(s[i, k])

            # Compute the network output and its derivatives, for each
            # training point.
            N = np.zeros(n)
            for i in range(n):
                for k in range(H):
                    N[i] += v[k] * s[i, k]

            delN = np.zeros((n, m))
            for i in range(n):
                for j in range(m):
                    for k in range(H):
                        delN[i, j] += v[k] * s1[i, k] * w[j, k]

            del2N = np.zeros((n, m))
            for i in range(n):
                for j in range(m):
                    for k in range(H):
                        del2N[i, j] += v[k] * s2[i, k] * w[j, k]**2

            dN_dw = np.zeros((n, m, H))
            for i in range(n):
                for j in range(m):
                    for k in range(H):
                        dN_dw[i, j, k] = v[k] * s1[i, k] * x[i, j]

            dN_du = np.zeros((n, H))
            for i in range(n):
                for k in range(H):
                    dN_du[i, k] = v[k] * s1[i, k]

            dN_dv = np.zeros((n, H))
            for i in range(n):
                for k in range(H):
                    dN_dv[i, k] = s[i, k]

            d2N_dwdx = np.zeros((n, m, m, H))
            for i in range(n):
                for j in range(m):
                    for jj in range(m):
                        for k in range(H):
                            d2N_dwdx[i, j, jj,
                                     k] = (v[k] *
                                           (s1[i, k] * kdelta(j, jj) +
                                            s2[i, k] * w[jj, k] * x[i, j]))

            d2N_dudx = np.zeros((n, m, H))
            for i in range(n):
                for j in range(m):
                    for k in range(H):
                        d2N_dudx[i, j, k] = v[k] * s2[i, k] * w[j, k]

            d2N_dvdx = np.zeros((n, m, H))
            for i in range(n):
                for j in range(m):
                    for k in range(H):
                        d2N_dvdx[i, j, k] = s1[i, k] * w[j, k]

            d3N_dwdx2 = np.zeros((n, m, m, H))
            for i in range(n):
                for j in range(m):
                    for jj in range(m):
                        for k in range(H):
                            d3N_dwdx2[i, j, jj, k] = (
                                v[k] *
                                (2 * s2[i, k] * w[jj, k] * kdelta(j, jj) +
                                 s3[i, k] * w[j, k]**2 * x[i, j]))

            d3N_dudx2 = np.zeros((n, m, H))
            for i in range(n):
                for j in range(m):
                    for k in range(H):
                        d3N_dudx2[i, j, k] = v[k] * s3[i, k] * w[j, k]**2

            d3N_dvdx2 = np.zeros((n, m, H))
            for i in range(n):
                for j in range(m):
                    for k in range(H):
                        d3N_dvdx2[i, j, k] = s2[i, k] * w[j, k]**2

            # Compute the value of the trial solution and its derivatives,
            # for each training point.
            P = np.zeros(n)
            for i in range(n):
                P[i] = self.tf.P(x[i])

            delP = np.zeros((n, m))
            for i in range(n):
                delP[i] = self.tf.delP(x[i])

            del2P = np.zeros((n, m))
            for i in range(n):
                del2P[i] = self.tf.del2P(x[i])

            Yt = np.zeros(n)
            for i in range(n):
                Yt[i] = self.tf.Yt(x[i], N[i])

            delYt = np.zeros((n, m))
            for i in range(n):
                delYt[i] = self.tf.delYt(x[i], N[i], delN[i])

            del2Yt = np.zeros((n, m))
            for i in range(n):
                del2Yt[i] = self.tf.del2Yt(x[i], N[i], delN[i], del2N[i])

            dYt_dw = np.zeros((n, m, H))
            for i in range(n):
                for j in range(m):
                    for k in range(H):
                        dYt_dw[i, j, k] = P[i] * dN_dw[i, j, k]

            dYt_du = np.zeros((n, H))
            for i in range(n):
                for k in range(H):
                    dYt_du[i, k] = P[i] * dN_du[i, k]

            dYt_dv = np.zeros((n, H))
            for i in range(n):
                for k in range(H):
                    dYt_dv[i, k] = P[i] * dN_dv[i, k]

            d2Yt_dwdx = np.zeros((n, m, m, H))
            for i in range(n):
                for j in range(m):
                    for jj in range(m):
                        for k in range(H):
                            d2Yt_dwdx[i, j, jj,
                                      k] = (P[i] * d2N_dwdx[i, j, jj, k] +
                                            delP[i, jj] * dN_dw[i, j, k])

            d2Yt_dudx = np.zeros((n, m, H))
            for i in range(n):
                for j in range(m):
                    for k in range(H):
                        d2Yt_dudx[i, j, k] = (P[i] * d2N_dudx[i, j, k] +
                                              delP[i, j] * dN_du[i, k])

            d2Yt_dvdx = np.zeros((n, m, H))
            for i in range(n):
                for j in range(m):
                    for k in range(H):
                        d2Yt_dvdx[i, j, k] = (P[i] * d2N_dvdx[i, j, k] +
                                              delP[i, j] * dN_dv[i, k])

            d3Yt_dwdx2 = np.zeros((n, m, m, H))
            for i in range(n):
                for j in range(m):
                    for jj in range(m):
                        for k in range(H):
                            d3Yt_dwdx2[i, j, jj, k] = (
                                P[i] * d3N_dwdx2[i, j, jj, k] +
                                2 * delP[i, jj] * d2N_dwdx[i, j, jj, k] +
                                del2P[i, jj] * dN_dw[i, j, k])

            d3Yt_dudx2 = np.zeros((n, m, H))
            for i in range(n):
                for j in range(m):
                    for k in range(H):
                        d3Yt_dudx2[i, j,
                                   k] = (P[i] * d3N_dudx2[i, j, k] +
                                         2 * delP[i, j] * d2N_dudx[i, j, k] +
                                         del2P[i, j] * dN_du[i, k])

            d3Yt_dvdx2 = np.zeros((n, m, H))
            for i in range(n):
                for j in range(m):
                    for k in range(H):
                        d3Yt_dvdx2[i, j,
                                   k] = (P[i] * d3N_dvdx2[i, j, k] +
                                         2 * delP[i, j] * d2N_dvdx[i, j, k] +
                                         del2P[i, j] * dN_dv[i, k])

            # Compute the value of the original differential equation
            # for each training point, and its derivatives.
            G = np.zeros(n)
            for i in range(n):
                G[i] = self.eq.G(x[i], Yt[i], delYt[i], del2Yt[i])

            dG_dYt = np.zeros(n)
            for i in range(n):
                dG_dYt[i] = self.eq.dG_dY(x[i], Yt[i], delYt[i], del2Yt[i])

            dG_ddelYt = np.zeros((n, m))
            for i in range(n):
                for j in range(m):
                    dG_ddelYt[i,
                              j] = (self.eq.dG_ddelY[j](x[i], Yt[i], delYt[i],
                                                        del2Yt[i]))

            dG_ddel2Yt = np.zeros((n, m))
            for i in range(n):
                for j in range(m):
                    dG_ddel2Yt[i,
                               j] = (self.eq.dG_ddel2Y[j](x[i], Yt[i],
                                                          delYt[i], del2Yt[i]))

            dG_dw = np.zeros((n, m, H))
            for i in range(n):
                for j in range(m):
                    for k in range(H):
                        dG_dw[i, j, k] = dG_dYt[i] * dYt_dw[i, j, k]
                        for jj in range(m):
                            dG_dw[i, j, k] += (
                                dG_ddelYt[i, jj] * d2Yt_dwdx[i, j, jj, k] +
                                dG_ddel2Yt[i, jj] * d3Yt_dwdx2[i, j, jj, k])

            dG_du = np.zeros((n, H))
            for i in range(n):
                for k in range(H):
                    dG_du[i, k] = dG_dYt[i] * dYt_du[i, k]
                    for j in range(m):
                        dG_du[i, k] += (dG_ddelYt[i, j] * d2Yt_dudx[i, j, k] +
                                        dG_ddel2Yt[i, j] * d3Yt_dudx2[i, j, k])

            dG_dv = np.zeros((n, H))
            for i in range(n):
                for k in range(H):
                    dG_dv[i, k] = dG_dYt[i] * dYt_dv[i, k]
                    for j in range(m):
                        dG_dv[i, k] += (dG_ddelYt[i, j] * d2Yt_dvdx[i, j, k] +
                                        dG_ddel2Yt[i, j] * d3Yt_dvdx2[i, j, k])

            # Compute the error function for this epoch.
            E2 = 0
            for i in range(n):
                E2 += G[i]**2
            if verbose:
                rmse = sqrt(E2 / n)
                print(epoch, rmse)

            # Compute the partial derivatives of the error with respect to the
            # network parameters.
            dE_dw = np.zeros((m, H))
            for j in range(m):
                for k in range(H):
                    for i in range(n):
                        dE_dw[j, k] += 2 * G[i] * dG_dw[i, j, k]

            dE_du = np.zeros(H)
            for k in range(H):
                for i in range(n):
                    dE_du[k] += 2 * G[i] * dG_du[i, k]

            dE_dv = np.zeros(H)
            for k in range(H):
                for i in range(n):
                    dE_dv[k] += 2 * G[i] * dG_dv[i, k]

        # Save the optimized parameters.
        self.w = w
        self.u = u
        self.v = v
Example #5
0
    def _compute_error_jacobian_debug(self, p, x):
        """Compute the Jacobian of the error function (debug version)."""

        # Determine the number of training points, independent variables, and
        # hidden nodes.
        n = len(x)
        m = len(self.eq.bc)
        H = len(self.v)

        # Unpack the network parameters.
        w = np.zeros((m, H))
        for j in range(m):
            w[j] = p[j * H:(j + 1) * H]
        u = p[m * H:(m + 1) * H]
        v = p[(m + 1) * H:(m + 2) * H]

        # Compute the forward pass through the network.
        z = np.zeros((n, H))
        for i in range(n):
            for k in range(H):
                z[i, k] = u[k]
                for j in range(m):
                    z[i, k] += w[j, k] * x[i, j]

        s = np.zeros((n, H))
        for i in range(n):
            for k in range(H):
                s[i, k] = sigma.s(z[i, k])

        s1 = np.zeros((n, H))
        for i in range(n):
            for k in range(H):
                s1[i, k] = sigma.s1(s[i, k])

        s2 = np.zeros((n, H))
        for i in range(n):
            for k in range(H):
                s2[i, k] = sigma.s2(s[i, k])

        s3 = np.zeros((n, H))
        for i in range(n):
            for k in range(H):
                s3[i, k] = sigma.s3(s[i, k])

        N = np.zeros(n)
        for i in range(n):
            for k in range(H):
                N[i] += v[k] * s[i, k]

        delN = np.zeros((n, m))
        for i in range(n):
            for j in range(m):
                for k in range(H):
                    delN[i, j] += v[k] * s1[i, k] * w[j, k]

        del2N = np.zeros((n, m))
        for i in range(n):
            for j in range(m):
                for k in range(H):
                    del2N[i, j] += v[k] * s2[i, k] * w[j, k]**2

        dN_dw = np.zeros((n, m, H))
        for i in range(n):
            for j in range(m):
                for k in range(H):
                    dN_dw[i, j, k] = v[k] * s1[i, k] * x[i, j]

        dN_du = np.zeros((n, H))
        for i in range(n):
            for k in range(H):
                dN_du[i, k] = v[k] * s1[i, k]

        dN_dv = np.zeros((n, H))
        for i in range(n):
            for k in range(H):
                dN_dv[i, k] = s[i, k]

        d2N_dwdx = np.zeros((n, m, m, H))
        for i in range(n):
            for j in range(m):
                for jj in range(m):
                    for k in range(H):
                        d2N_dwdx[i, j, jj,
                                 k] = (v[k] * (s1[i, k] * kdelta(j, jj) +
                                               s2[i, k] * w[jj, k] * x[i, j]))

        d2N_dudx = np.zeros((n, m, H))
        for i in range(n):
            for j in range(m):
                for k in range(H):
                    d2N_dudx[i, j, k] = v[k] * s2[i, k] * w[j, k]

        d2N_dvdx = np.zeros((n, m, H))
        for i in range(n):
            for j in range(m):
                for k in range(H):
                    d2N_dvdx[i, j, k] = s1[i, k] * w[j, k]

        d3N_dwdx2 = np.zeros((n, m, m, H))
        for i in range(n):
            for j in range(m):
                for jj in range(m):
                    for k in range(H):
                        d3N_dwdx2[i, j, jj, k] = (
                            v[k] * (2 * s2[i, k] * w[jj, k] * kdelta(j, jj) +
                                    s3[i, k] * w[j, k]**2 * x[i, j]))

        d3N_dudx2 = np.zeros((n, m, H))
        for i in range(n):
            for j in range(m):
                for k in range(H):
                    d3N_dudx2[i, j, k] = v[k] * s3[i, k] * w[j, k]**2

        d3N_dvdx2 = np.zeros((n, m, H))
        for i in range(n):
            for j in range(m):
                for k in range(H):
                    d3N_dvdx2[i, j, k] = s2[i, k] * w[j, k]**2

        P = np.zeros(n)
        for i in range(n):
            P[i] = self.tf.P(x[i])

        delP = np.zeros((n, m))
        for i in range(n):
            delP[i] = self.tf.delP(x[i])

        del2P = np.zeros((n, m))
        for i in range(n):
            del2P[i] = self.tf.del2P(x[i])

        Yt = np.zeros(n)
        for i in range(n):
            Yt[i] = self.tf.Yt(x[i], N[i])

        delYt = np.zeros((n, m))
        for i in range(n):
            delYt[i] = self.tf.delYt(x[i], N[i], delN[i])

        del2Yt = np.zeros((n, m))
        for i in range(n):
            del2Yt[i] = self.tf.del2Yt(x[i], N[i], delN[i], del2N[i])

        dYt_dw = np.zeros((n, m, H))
        for i in range(n):
            for j in range(m):
                for k in range(H):
                    dYt_dw[i, j, k] = P[i] * dN_dw[i, j, k]

        dYt_du = np.zeros((n, H))
        for i in range(n):
            for k in range(H):
                dYt_du[i, k] = P[i] * dN_du[i, k]

        dYt_dv = np.zeros((n, H))
        for i in range(n):
            for k in range(H):
                dYt_dv[i, k] = P[i] * dN_dv[i, k]

        d2Yt_dwdx = np.zeros((n, m, m, H))
        for i in range(n):
            for j in range(m):
                for jj in range(m):
                    for k in range(H):
                        d2Yt_dwdx[i, j, jj,
                                  k] = (P[i] * d2N_dwdx[i, j, jj, k] +
                                        delP[i, jj] * dN_dw[i, j, k])

        d2Yt_dudx = np.zeros((n, m, H))
        for i in range(n):
            for j in range(m):
                for k in range(H):
                    d2Yt_dudx[i, j, k] = (P[i] * d2N_dudx[i, j, k] +
                                          delP[i, j] * dN_du[i, k])

        d2Yt_dvdx = np.zeros((n, m, H))
        for i in range(n):
            for j in range(m):
                for k in range(H):
                    d2Yt_dvdx[i, j, k] = (P[i] * d2N_dvdx[i, j, k] +
                                          delP[i, j] * dN_dv[i, k])

        d3Yt_dwdx2 = np.zeros((n, m, m, H))
        for i in range(n):
            for j in range(m):
                for jj in range(m):
                    for k in range(H):
                        d3Yt_dwdx2[i, j, jj, k] = (
                            P[i] * d3N_dwdx2[i, j, jj, k] +
                            2 * delP[i, jj] * d2N_dwdx[i, j, jj, k] +
                            del2P[i, jj] * dN_dw[i, j, k])

        d3Yt_dudx2 = np.zeros((n, m, H))
        for i in range(n):
            for j in range(m):
                for k in range(H):
                    d3Yt_dudx2[i, j, k] = (P[i] * d3N_dudx2[i, j, k] +
                                           2 * delP[i, j] * d2N_dudx[i, j, k] +
                                           del2P[i, j] * dN_du[i, k])

        d3Yt_dvdx2 = np.zeros((n, m, H))
        for i in range(n):
            for j in range(m):
                for k in range(H):
                    d3Yt_dvdx2[i, j, k] = (P[i] * d3N_dvdx2[i, j, k] +
                                           2 * delP[i, j] * d2N_dvdx[i, j, k] +
                                           del2P[i, j] * dN_dv[i, k])

        G = np.zeros(n)
        for i in range(n):
            G[i] = self.eq.G(x[i], Yt[i], delYt[i], del2Yt[i])

        dG_dYt = np.zeros(n)
        for i in range(n):
            dG_dYt[i] = self.eq.dG_dY(x[i], Yt[i], delYt[i], del2Yt[i])

        dG_ddelYt = np.zeros((n, m))
        for i in range(n):
            for j in range(m):
                dG_ddelYt[i, j] = (self.eq.dG_ddelY[j](x[i], Yt[i], delYt[i],
                                                       del2Yt[i]))

        dG_ddel2Yt = np.zeros((n, m))
        for i in range(n):
            for j in range(m):
                dG_ddel2Yt[i, j] = (self.eq.dG_ddel2Y[j](x[i], Yt[i], delYt[i],
                                                         del2Yt[i]))

        dG_dw = np.zeros((n, m, H))
        for i in range(n):
            for j in range(m):
                for k in range(H):
                    dG_dw[i, j, k] = dG_dYt[i] * dYt_dw[i, j, k]
                    for jj in range(m):
                        dG_dw[i, j, k] += (
                            dG_ddelYt[i, jj] * d2Yt_dwdx[i, j, jj, k] +
                            dG_ddel2Yt[i, jj] * d3Yt_dwdx2[i, j, jj, k])

        dG_du = np.zeros((n, H))
        for i in range(n):
            for k in range(H):
                dG_du[i, k] = dG_dYt[i] * dYt_du[i, k]
                for j in range(m):
                    dG_du[i, k] += (dG_ddelYt[i, j] * d2Yt_dudx[i, j, k] +
                                    dG_ddel2Yt[i, j] * d3Yt_dudx2[i, j, k])

        dG_dv = np.zeros((n, H))
        for i in range(n):
            for k in range(H):
                dG_dv[i, k] = dG_dYt[i] * dYt_dv[i, k]
                for j in range(m):
                    dG_dv[i, k] += (dG_ddelYt[i, j] * d2Yt_dvdx[i, j, k] +
                                    dG_ddel2Yt[i, j] * d3Yt_dvdx2[i, j, k])

        dE_dw = np.zeros((m, H))
        for j in range(m):
            for k in range(H):
                for i in range(n):
                    dE_dw[j, k] += 2 * G[i] * dG_dw[i, j, k]

        dE_du = np.zeros(H)
        for k in range(H):
            for i in range(n):
                dE_du[k] += 2 * G[i] * dG_du[i, k]

        dE_dv = np.zeros(H)
        for k in range(H):
            for i in range(n):
                dE_dv[k] += 2 * G[i] * dG_dv[i, k]

        jac = np.hstack((dE_dw.flatten(), dE_du, dE_dv))

        return jac