@Override
    public void computeNormalisingConstant() throws InternalErrorException {
        totalTimer.start();
        PopulationVector N = qnm.N.copy();
        int r = 0, Nr;
        int R = qnm.R, M = qnm.M;
        BigRational[] curG = new BigRational[matrixSize], G_1 = null;
        for (int i = 0; i < matrixSize; i++) {
            curG[i] = BigRational.ONE;
        }
        PopulationVector N0 = new PopulationVector(0, R);
        N0.set(0, 1);
        System.out.println("Initialising data structures of class " + (r + 1));
        generateABU(N0, 1);
        try {
            Solver s;
            if (nThreads == 1) {
                s = new SimpleSolver();
            } else {
                s = new ModularSolver(nThreads);
            }
            Integer maxA = getMaxAElement();
            Integer val = matrixSize;
            BigInteger maxB = qnm.getMaxG().multiply(new BigInteger(maxA.toString())).multiply(new BigInteger(val.toString()));
            s.initialise(A, UList, uncomputables, maxA, maxB, new BigRational(qnm.getMaxG()));
            N0.set(0, 0);
            int N0r = 1;
            int Ntot = 0;

            for (r = 1; r <= R; r++) {
                System.out.println("Processing class " + r);
                for (Nr = N0r; Nr <= N.get(r - 1) - 1; Nr++) {
                    mulTimer.start();
                    BigRational[] sysB = MiscFunctions.matrixVectorMultiply(B, curG);
                    mulTimer.pause();
                    s.goToULevel(Nr - 1);
                    curG = solve(s, sysB);
                    Ntot++;
                    System.out.println("Population " + Nr + " completed (total population " + Ntot + " jobs)");
                }
                G_1 = curG;
                mulTimer.start();
                BigRational[] sysB = MiscFunctions.matrixVectorMultiply(B, curG);
                mulTimer.pause();
                s.goToULevel(Nr - 1);
                curG = solve(s, sysB);
                Ntot++;
                System.out.println("Population " + Nr + " completed (total population " + Ntot + " jobs)");
                N0.set(r - 1, N.get(r - 1));
                System.out.println("Class " + r + " completed");
                if (r < R) {
                    N0.set(r, 1);
                    N0r = 1;
                    System.out.println("Initialising data structures of class " + (r + 1));
                    generateABU(N0, r + 1);
                    s.initialise(A, UList, uncomputables, maxA, maxB, new BigRational(qnm.getMaxG()));
                }
            }
            if (!curG[0].isUndefined()) {
                this.G = curG[0];
            } else {
                throw new InconsistentLinearSystemException("Singular system. Cannot proceed.");
            }
            totalTimer.pause();
            memUsage = MiscFunctions.memoryUsage();
            solverTimer = s.getTimer();
            s.shutdown();
        } catch (OperationNotSupportedException ex) {
            //ex.printStackTrace();
            throw new InternalErrorException("Error in linear system solver.");
        } catch (InconsistentLinearSystemException ex) {
            //ex.printStackTrace();
            throw new InternalErrorException(ex.getMessage());
        }
        qnm.setNormalisingConstant(G);
        this.lastG = curG;
        this.prevG = G_1;
    }