public static void Analyze(double[,] matrix, bool[] rev, bool[] trans, LinkedList<FluxPattern> forbidden_combinations, double max_value, double tolerance, bool lp, bool fc, bool do_efca, bool keep_witnesses, bool only_internal, bool show_output, out FluxPattern max, out IIntCoupling coupling, out EFCACount efca, out int reactions_unblocked, out int reactions_frev, out int couples, out ICollection<FluxPattern> circuits, out DateTime time_start, out DateTime time_unblocked, out DateTime time_frev, out DateTime time_couples, out DateTime time_efca, out DateTime[] time_reaction, out int lps_unblocked, out int lps_frev, out int lps_couples, out int lps_efca, out int[] lps_reaction, out int wits_unblocked, out int wits_frev, out int wits_couples, out int wits_efca, out int[] wits_reaction, out int[] wits_distribution, out int[] wits_usable, String name = null)
        {
            //initialisation
            time_start = DateTime.Now;
            efca = null;
            wits_usable = null;
            int n = rev.Length;

            List<int> irr = new List<int>();
            for (int i = 0; i < n; ++i)
                if (!rev[i])
                    irr.Add(i);

            LinkedList<FluxPattern> witnesses = new LinkedList<FluxPattern>();
            LinkedList<FluxPattern> blocking_witnesses, frev_witnesses;
            IIntFCACalculator<FluxPattern> fcacalculator = !lp ? (IIntFCACalculator<FluxPattern>)new MILPIntFCACalculator(matrix, rev, max_value, tolerance) :
                !fc ? (IIntFCACalculator<FluxPattern>)new LPIntFCACalculator(matrix, rev, max_value, tolerance) :
                forbidden_combinations == null || forbidden_combinations.Count == 0 ? (IIntFCACalculator<FluxPattern>)new FCIntFCACalculator(matrix, rev, trans, max_value, tolerance) :
                (IIntFCACalculator<FluxPattern>)new FastFCIntFCACalculator(matrix, rev, forbidden_combinations, max_value, tolerance);

            circuits = (fc && forbidden_combinations == null) ? ((FCIntFCACalculator) fcacalculator).Circles : null;

            // calculate blocked reactions
            FluxPattern calcs;
            int wits_used;

            bool[] internal_reactions = new bool[n];
            for(int i = 0; i<n; ++i)
                internal_reactions[i] = !trans[i];
            FluxPattern pattern_internal = new FluxPattern(internal_reactions, false);
            max = fcacalculator.CalculateMax(new List<int>(), n, new LinkedList<FluxPattern>(), out blocking_witnesses, out calcs, only_internal ? pattern_internal : null, null);
            reactions_unblocked = max.Count;

            foreach (FluxPattern a in blocking_witnesses)
                if (a.Count > 0)
                    witnesses.AddLast(a);
            if (name != null)
                SaveStatistics(witnesses, n, name + "_max.stats");
            time_unblocked = DateTime.Now;
            lps_unblocked = fcacalculator.SolverCalls;
            wits_unblocked = witnesses.Count;
            if (show_output)
                Console.WriteLine("({0})\tBlocked reactions calculated: {1} of {2} blocked.\n", time_unblocked, n-reactions_unblocked, n);

            // calculate fully reversible reactions
            FluxPattern frev = fcacalculator.CalculateMax(irr, n, blocking_witnesses, out frev_witnesses, out calcs, max, null);
            reactions_frev = frev.Count;

            foreach (FluxPattern a in frev_witnesses)
                if (a.Count > 0)
                    witnesses.AddLast(a);
            if (name != null)
                SaveStatistics(witnesses, n, name + "_frev.stats");
            time_frev = DateTime.Now;
            lps_frev = fcacalculator.SolverCalls - lps_unblocked;
            wits_frev = witnesses.Count - wits_unblocked;
            if (show_output)
                Console.WriteLine("({0})\tFRev calculated.\n", time_frev);

            // FCA
            Console.WriteLine("Witnesses so far:");
            foreach (FluxPattern a in witnesses)
                Console.WriteLine("\t{0}", a);
            Console.WriteLine("\nStarting FCA.\n");

            coupling = new IntCoupling(fcacalculator, show_output, witnesses, out time_reaction, out lps_reaction, out wits_reaction, out wits_used, max, frev);

            if (name != null)
                SaveStatistics(coupling.Witnesses, n, name + "_fca.stats");

            time_couples = DateTime.Now;
            wits_couples = coupling.Witnesses.Count - wits_frev - wits_unblocked;
            lps_couples = 0; wits_couples = 0;
            for (int i = 0; i < n; ++i)
            {
                lps_couples += lps_reaction[i];
                wits_couples += wits_reaction[i];
            }
            if (show_output)
                Console.WriteLine("({0})\tCouples calculated.\n", time_couples);

            wits_distribution = new int[n + 1];
            foreach (FluxPattern a in coupling.Witnesses)
                wits_distribution[a.Count]++;

            // EFCA
            lps_efca = 0;
            wits_efca = 0;
            if (do_efca)
            {
                efca = new EFCACount(fcacalculator, keep_witnesses, coupling.Witnesses, max, frev, out time_reaction, out lps_reaction, out wits_reaction, out wits_usable, coupling, null, show_output);
                lps_efca = efca.LPCount;
                wits_efca = efca.WitnessCount;
            }
            time_efca = DateTime.Now;

            couples = coupling.ToCoupling().Count;
        }
        /// <summary>
        /// Simulates all $\choose n 2$ double reaction knock-outs and creates a new EFCACount object for the results.
        /// </summary>
        /// <param name="calculator">An object that calculates the maximal set of reactions in the metabolic network constrained by disabled reactions.</param>
        /// <param name="witnesses">A subset of the flux lattice L.</param>
        /// <param name="max">The maximum of L / the set of all unblocked reactions in the metabolic network.</param>
        /// <param name="frev">The set of all fully reversible reactions in the metabolic network.</param>
        /// <param name="coupling">A flux coupling for the network</param>
        public EFCACount(IIntFCACalculator<FluxPattern> calculator, bool keep_witnesses, ICollection<FluxPattern> witnesses, FluxPattern max, FluxPattern frev, out DateTime[] time_reaction, out int[] lps_reaction, out int[] wits_reaction, out int[] wits_usable, IIntCoupling coupling = null, ICollection<int> T = null, bool show_output = true)
        {
            this.max = max;
            this.n = max.Length;

            time_reaction = new DateTime[n];
            lps_reaction = new int[n];
            for (int i = 0; i < n; ++i)
                lps_reaction[i] = -1;
            wits_reaction = new int[n];
            wits_usable = new int[n];

            DateTime[] time;
            int[] lps, wits;
            int temp_counter = calculator.SolverCalls, temp_wits;
            if (coupling == null)
            {
                coupling = new IntCoupling(calculator, false, witnesses, out time, out lps, out wits, out temp_wits, max, frev);
                this.witness_counter = coupling.Witnesses.Count;
                this.lp_counter = calculator.SolverCalls - temp_counter;
                temp_counter = calculator.SolverCalls;
            }

            if (T == null)
            {
                this.T = new List<int>(n);
                for (int i = 0; i < n; ++i)
                    this.T.Add(i);
            }
            else
                this.T = new List<int>(T);

            LinkedList<FluxPattern> new_witnesses = new LinkedList<FluxPattern>();
            witnesses_kept = new LinkedList<FluxPattern>(witnesses);
            IIntCoupling row;

            max_size = new int[n, n];
            targeted_size = new int[n, n];
            for (int i = 0; i < n; ++i)
            {
                max_size[i, i] = -1;
                targeted_size[i, i] = -1;
            }

            List<int> R = new List<int>();
            ICollection<int> c;
            int wits_used;
            R.Add(-1);
            for (int i = 0; i < n; ++i)
                if (max[i] && max_size[i, i] < 0)
                {
                    R[0] = i;

                    if (keep_witnesses)
                    {
                        foreach (FluxPattern a in new_witnesses)
                            if (rand.NextDouble() < ((double)a.Count) / witnesses_kept.Count)
                                witnesses_kept.AddLast(a);
                    }

                    row = new IntCoupling(calculator, false, witnesses_kept, out time, out lps, out wits, out wits_used, max, frev, R, coupling, i);
                    wits_usable[i] = wits_used;
                    if (show_output)
                        Console.WriteLine("({0})\tRow {1} from {2} calculated of EFCA. ({3} LPs solved, {4} kept.)\n", System.DateTime.Now, i + 1, n, calculator.SolverCalls - temp_counter, witnesses_kept.Count);

                    this.lp_counter += calculator.SolverCalls - temp_counter;
                    temp_counter = calculator.SolverCalls;
                    new_witnesses = row.Witnesses;
                    this.witness_counter += row.Witnesses.Count;

                    c = coupling[i];
                    foreach (int r in c)
                        if (r >= i && !coupling.Max(r)[i])
                            for (int j = r; j < n; ++j)
                                if (max[j])
                                {
                                    max_size[r, j] = row.Max(j).Count;
                                    max_size[j, r] = max_size[r, j];

                                    targeted_size[r, j] = row.Max(j).Values.Intersect(this.T).Count();
                                    targeted_size[j, r] = targeted_size[r, j];
                                }

                    lps_reaction[i] = lp_counter;
                    wits_reaction[i] = witness_counter;
                    time_reaction[i] = DateTime.Now;
                }

            if (show_output)
                Console.WriteLine("({0})\tEFCA uncompressed.\n", System.DateTime.Now);
        }