/// <summary>
        /// Computes the runtime of an allocation
        /// </summary>
        /// <returns>
        /// The runtime of an allocation
        /// </returns>
        /// <param name="configFileContent">Content of a configuration file</param>
        /// <param name="allocation">A single allocation of tasks on processors</param>
        public static float GetAllocationRuntime(string configFileContent, List <List <bool> > allocation)
        {
            List <float> processorFrequencies      = ConfigFileParser.GetProcessorFrequencies(configFileContent);
            List <float> taskRuntimes              = ConfigFileParser.GetTaskRuntimes(configFileContent);
            float        runtimeReferenceFrequency = ConfigFileParser.GetRuntimeReferenceFrequency(configFileContent);
            float        allocationRuntime         = 0;

            if (processorFrequencies.Count == 0 || taskRuntimes.Count == 0 || allocation.Count == 0 || runtimeReferenceFrequency == -1)
            {
                return(-1);
            }
            else
            {
                for (int processorId = 0; processorId < allocation.Count; processorId++)
                {
                    float processorRuntime = 0;

                    for (int taskId = 0; taskId < allocation[processorId].Count; taskId++)
                    {
                        if (allocation[processorId][taskId])
                        {
                            processorRuntime += GetTaskRuntime(runtimeReferenceFrequency, taskRuntimes[taskId], processorFrequencies[processorId]);
                        }
                    }

                    if (processorRuntime >= allocationRuntime)
                    {
                        allocationRuntime = processorRuntime;
                    }
                }

                return(allocationRuntime);
            }
        }
        /// <summary>
        /// Checks if a provided configuration file contains frequencies of processors
        /// </summary>
        /// <returns>
        /// An empty string if it is valid,
        /// an error message if invalid
        /// </returns>
        /// <param name="configFileContent">Content of a configuration file</param>
        public static string ContainsProcessorFrequencies(string configFileContent)
        {
            List <float>  processorFrequencies = ConfigFileParser.GetProcessorFrequencies(configFileContent);
            List <string> processorIds         = ConfigFileParser.GetProcessorIds(configFileContent);

            if (processorFrequencies.Count == 0 || processorIds.Count == 0 || processorFrequencies.Count != processorIds.Count)
            {
                return(ConfigErrors["ProcessorFrequencies"]);
            }
            else
            {
                // check if processor ids are unique
                if (processorIds.Distinct().Count() != processorIds.Count)
                {
                    return(ConfigErrors["ProcessorFrequenciesIds"]);
                }

                return("");
            }
        }
        /// <summary>
        /// Computes the energy consumed by an allocation
        /// </summary>
        /// <returns>
        /// The energy consumed by an allocation
        /// </returns>
        /// <param name="configFileContent">Content of a configuration file</param>
        /// <param name="allocation">Allocation of tasks on processors</param>
        public static float GetTotalEnergyConsumed(string configFileContent, List <List <bool> > allocation)
        {
            List <float> coefficients              = ConfigFileParser.GetCoefficients(configFileContent);
            List <float> processorFrequencies      = ConfigFileParser.GetProcessorFrequencies(configFileContent);
            List <float> taskRuntimes              = ConfigFileParser.GetTaskRuntimes(configFileContent);
            float        runtimeReferenceFrequency = ConfigFileParser.GetRuntimeReferenceFrequency(configFileContent);
            float        totalEnergyConsumed       = 0;

            if (coefficients.Count == 0 || processorFrequencies.Count == 0 || taskRuntimes.Count == 0 || allocation.Count == 0 || runtimeReferenceFrequency == -1)
            {
                return(-1);
            }
            else
            {
                // Calculate energy consumed by each task
                for (int taskId = 0; taskId < taskRuntimes.Count; taskId++)
                {
                    int processorId = 0;

                    // Find the processor that handles a given task
                    for (int allocationProcessorId = 0; allocationProcessorId < allocation.Count; allocationProcessorId++)
                    {
                        if (allocation[allocationProcessorId][taskId])
                        {
                            processorId = allocationProcessorId;
                            break;
                        }
                    }

                    float runtimeOnGivenProcessor = GetTaskRuntime(runtimeReferenceFrequency, taskRuntimes[taskId], processorFrequencies[processorId]);
                    float energyConsumedPerTask   = GetEnergyConsumedPerTask(coefficients, processorFrequencies[processorId], runtimeOnGivenProcessor);
                    totalEnergyConsumed += energyConsumedPerTask;
                }

                return(totalEnergyConsumed);
            }
        }