Factorio-Paranoidal_mod/helmod/math/SolverMatrixAlgebra.lua

186 lines
7.5 KiB
Lua

-------------------------------------------------------------------------------
---Description of the module.
---@class SolverMatrixAlgebra : SolverMatrix
SolverMatrixAlgebra = newclass(SolverMatrix, function(base, object)
SolverMatrix.init(base, object)
end)
-------------------------------------------------------------------------------
---Retourne la colonne
---@param matrix Matrix
---@param xrow integer
---@param invert boolean
---@return integer
function SolverMatrixAlgebra:get_col(matrix, xrow, invert)
local row = matrix.rows[xrow]
local parameters = matrix.parameters[xrow]
local zrow = matrix.rows[#matrix.rows]
local xcol = 0
local max = 0
local col_master = -1
local col_exclude = -1
-- if row[self.col_Cn] > 0 then
-- col_master = row[self.col_Cn]
-- end
-- if row[self.col_Cn] < 0 then
-- col_exclude = -row[self.col_Cn]
-- end
---on cherche la plus grande demande
for icol, column in pairs(matrix.columns) do
local cell_value = row[icol] or 0
if ((invert ~= true and cell_value > 0) or (invert == true and cell_value < 0)) then
local objective = matrix.objective_values[icol] or 0
local zvalue = zrow[icol]
local Z = zvalue - objective ---valeur demandee (Z-input)
local C = -Z / cell_value
-- contraint
local has_contraint = parameters.contraint ~= nil
local is_master = parameters.contraint ~= nil and parameters.contraint.type == "master" and parameters.contraint.name == column.sysname
local is_exclude = parameters.contraint ~= nil and parameters.contraint.type == "exclude" and parameters.contraint.name ~= column.sysname
-- if zvalue = 0 the choose is already use
if (C > max and zvalue ~= 0 and has_contraint == false)
or (is_master)
or (C > max and is_exclude) then
max = C
xcol = icol
end
end
end
---cas des voider
if xcol == 0 then
for icol, column in pairs(matrix.columns) do
local cell_value = row[icol] or 0
if ((invert ~= true and cell_value > 0) or (invert == true and cell_value < 0)) then
local objective = matrix.objective_values[icol] or 0
local zvalue = zrow[icol]
local Z = zvalue - objective ---valeur demandee (Z-input)
local C = -Z / cell_value
if C > max then
max = C
xcol = icol
end
end
end
end
return xcol
end
-------------------------------------------------------------------------------
---Calcul de la ligne
---@param matrix Matrix
---@param xrow integer
---@param xcol integer
---@return Matrix
function SolverMatrixAlgebra:line_compute(matrix, xrow, xcol)
if matrix == nil or xrow == 0 or xcol == 0 then return matrix end
local row = matrix.rows[xrow]
local parameters = matrix.parameters[xrow]
local zrow = matrix.rows[#matrix.rows]
local P = parameters.recipe_production
local E = parameters.recipe_energy ---energy
local Z = zrow[xcol] ---valeur demandee Z
local V = row[xcol] ---valeur produite
local C = -Z / V ---coefficient
if Z < 0 then
parameters.coefficient = C
parameters.recipe_count = P * C
for icol, cell_value in pairs(row) do
local X = row[icol]
zrow[icol] = zrow[icol] + X * P * C
end
end
return matrix
end
-------------------------------------------------------------------------------
---Calcul de la ligne par factory
---@param matrix Matrix
---@param xrow integer
---@param time number
---@return Matrix
function SolverMatrixAlgebra:line_compute_by_factory(matrix, xrow, time)
if matrix == nil or xrow == 0 then return matrix end
local row = matrix.rows[xrow]
local parameters = matrix.parameters[xrow]
local zrow = matrix.rows[#matrix.rows]
local F = parameters.factory_count
local S = parameters.factory_speed
local P = parameters.recipe_production
local E = parameters.recipe_energy ---energy
local C = 1 ---coefficient
local R = time * F * S / E ---nombre de recette/seconde
parameters.coefficient = C
parameters.recipe_count = R
for icol, cell_value in pairs(row) do
local X = row[icol]
---calcul Z
zrow[icol] = zrow[icol] + X * R
end
return matrix
end
-------------------------------------------------------------------------------
---Resoud la matrice
---@param matrix_base Matrix
---@param debug boolean
---@param by_factory boolean
---@param time number
---@return Matrix, table
function SolverMatrixAlgebra:solve_matrix(matrix_base, debug, by_factory, time)
if matrix_base ~= nil then
local num_loop = 0
local icol = 0
local runtime = {}
self:add_runtime(debug, runtime, "Initial", matrix_base)
local Mstep = self:prepare(matrix_base)
self:add_runtime(debug, runtime, "Prepare", Mstep)
if by_factory == true then
-- start_row ligne de démarrage du calcul
local start_row = 0
for irow, row in pairs(Mstep.rows) do
if irow < #Mstep.rows then
local parameters = Mstep.parameters[irow]
local factory_count = parameters.factory_count
if factory_count > 0 then
if start_row == 0 then start_row = irow end
self:add_runtime(debug, runtime, "Step " .. num_loop, Mstep, { x = -1, y = irow })
Mstep = self:line_compute_by_factory(Mstep, irow, time)
num_loop = num_loop + 1
if start_row > 1 then
for xrow = start_row, 1, -1 do
local parameters = Mstep.parameters[xrow]
local factory_count = parameters.factory_count
if factory_count == 0 then
icol = self:get_col(Mstep, xrow, true)
self:add_runtime(debug, runtime, "Step " .. num_loop, Mstep, { x = icol, y = xrow })
Mstep = self:line_compute(Mstep, xrow, icol)
num_loop = num_loop + 1
end
end
end
elseif start_row ~= 0 then
icol = self:get_col(Mstep, irow, false)
self:add_runtime(debug, runtime, "Step " .. num_loop, Mstep, { x = icol, y = irow })
Mstep = self:line_compute(Mstep, irow, icol)
num_loop = num_loop + 1
end
end
end
else
for irow, _ in pairs(Mstep.rows) do
if irow < #Mstep.rows then
icol = self:get_col(Mstep, irow, false)
self:add_runtime(debug, runtime, "Step " .. num_loop, Mstep, { x = icol, y = irow })
Mstep = self:line_compute(Mstep, irow, icol)
num_loop = num_loop + 1
end
end
end
local matrix_result = self:finalize(Mstep)
matrix_result = self:apply_state(matrix_result)
self:add_runtime(debug, runtime, "final", matrix_result)
return matrix_result, runtime
end
end