APENDICE B BCÓDIGO FUENTE DEL PAQUETE COMPUTACIONAL 109 B. 1 Introducción Con el fin de dar solución al modelo propuesto se ha desarrollado un programa en Visual Basic .NET para resolver una gran variedad de problemas. A continuación se muestra el código fuente del paquete computacional B. 2 Información General SCUPA 1.0. Programa que resuelve un problema de localización de instalaciones considerando flujo de productos y el tiempo total del proceso. José Lorenzo Solar. Roberto Torres Maldonado. Cholula, Puebla. 10 de Noviembre del 2005. B. 3 Formulario Principal Public Class frmMain Inherits System.Windows.Forms.Form #Region " Windows Form Designer generated code " #End Region <STAThread()> _ Public Shared Sub Main() Application.Run(New frmMain) End Sub Private Sub MenuItem2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MenuItem2.Click Dim r = New Red End Sub Private Sub MenuItem5_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MenuItem5.Click Me.Close() 110 End Sub Private Sub frmMain_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Configuracion.CURMAIN = Me End Sub Private Sub MenuItem12_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) End Sub Private Sub MenuItem9_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) End Sub Private Sub MenuItem10_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MenuItem10.Click Dim f As New frmConfiguracion f.ShowDialog() Try f.Dispose() Catch ex As Exception End Try End Sub Private Sub MenuItem8_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MenuItem8.Click End Sub Private Sub MenuItem11_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MenuItem11.Click End Sub Private Sub MenuItem15_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MenuItem15.Click Me.LayoutMdi(MdiLayout.TileVertical) End Sub 111 Private Sub MenuItem16_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MenuItem16.Click Me.LayoutMdi(MdiLayout.TileHorizontal) End Sub Private Sub MenuItem3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MenuItem3.Click Red.FromFile() End Sub Private Sub MenuItem6_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MenuItem6.Click Dim f As Form f = Me.ActiveMdiChild() If TypeOf f Is frmRed Then Dim fred As frmRed = f fred.rd.Guardar() End If End Sub Private Sub tBar_ButtonClick(ByVal sender As System.Object, ByVal e As System.Windows.Forms.ToolBarButtonClickEventArgs) Handles tBar.ButtonClick If e.Button Is tbtnAbrir Then MenuItem3_Click(Nothing, Nothing) ElseIf e.Button Is tbtnGuardar Then MenuItem6_Click(Nothing, Nothing) ElseIf e.Button Is tbtnNuevo Then MenuItem2_Click(Nothing, Nothing) ElseIf e.Button Is tbtnOpciones Then MenuItem10_Click(Nothing, Nothing) End If End Sub Private Sub MenuItem14_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MenuItem14.Click 112 Dim f As New frmAbout f.ShowDialog() End Sub End Class B. 4 Clase que Genera Cada Una de las Matrices Public Class frmGenerarMatriz Inherits System.Windows.Forms.Form Public Sub LoadMatriz(ByVal m(,) As Decimal, Optional ByVal Nombre As String = "", Optional ByVal NombreCols As String = Nothing) Dim d As DataTable = Operaciones.MatrizToDataTable(m, "", NombreCols) Me.grid.DataSource = d t=d Me.lblTitle.Text = Nombre End Sub Public Sub LoadVector(ByVal m() As Decimal, Optional ByVal Nombre As String = "", Optional ByVal NombreCols As String = Nothing) Dim d As DataTable = Operaciones.VectorToDataTable(m, NombreCols) Me.grid.DataSource = d t=d Me.lblTitle.Text = Nombre End Sub Public Sub DefaultValues(ByVal val() As Decimal) Throw New Exception("No implementado") End Sub Private Sub GenerarMatriz(ByVal nombreCols As String, ByVal nombreRows As String, ByVal cols As Integer, ByVal rengs As Integer) t = New DataTable For i As Integer = 1 To cols t.Columns.Add(nombreCols & i) Next 113 For i As Integer = 1 To rengs Dim r As DataRow = t.NewRow() t.Rows.Add(r) Next t.DefaultView.AllowNew = False grid.DataSource = t 'Quitar capacidad de agregar elementos nuevos al datagrid 'Llenar de ceros For i As Integer = 0 To cols - 1 For j As Integer = 0 To rengs - 1 grid.Item(j, i) = "0" Next Next End Sub Private Sub btnGenerar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnGenerar.Click 'Llenar de randoms For i As Integer = 0 To t.Columns.Count - 1 For j As Integer = 0 To t.Rows.Count - 1 grid.Item(j, i) = Math.Round((Rnd() * (updMax.Value - updMin.Value)) + updMin.Value) Next Next End Sub Public Function GetMatriz() As Decimal(,) 'Creamos la matriz en la memoria Dim m(t.Rows.Count - 1, t.Columns.Count - 1) As Decimal 'Copiamos los valores del grid a la matriz For i As Integer = 0 To t.Rows.Count - 1 For j As Integer = 0 To t.Columns.Count - 1 m(i, j) = grid.Item(i, j) 114 Next Next 'Regresamos la matriz Return m End Function Public Function GetVector() As Decimal() 'Creamos la matriz en la memoria Dim m(t.Rows.Count - 1) As Decimal 'Copiamos los valores del grid a la matriz For i As Integer = 0 To t.Rows.Count - 1 m(i) = grid.Item(i, 0) Next 'Regresamos la matriz Return m End Function Private Sub btnCancelar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCancelar.Click Me.DialogResult = DialogResult.Cancel Me.Hide() End Sub Private Sub btnAceptar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAceptar.Click Me.DialogResult = DialogResult.OK Me.Hide() End Sub Private Sub frmGenerarMatriz_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load If Configuracion.GENERAR_AUTO Then Me.btnGenerar_Click(Nothing, Nothing) Me.btnAceptar_Click(Nothing, Nothing) End If 115 End Sub End Class B. 5 Clase que Especifica el Tamaño de la Nueva Red, Iteraciones y Tiempo Public Class frmNuevaRed Inherits System.Windows.Forms.Form Private Sub btnCancelar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCancelar.Click Me.DialogResult = DialogResult.Cancel Me.Hide() End Sub Private Sub btnAceptar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAceptar.Click Me.DialogResult = DialogResult.OK Me.Hide() End Sub Private Sub frmNuevaRed_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 'Me.updAlmacenes.Value = Rnd() * 10 'Me.updClientes.Value = Rnd() * 10 'Me.updIteracionesGRASP.Value = Rnd() * 10 'Me.updPlantas.Value = Rnd() * 10 'Me.updProveedores.Value = Rnd() * 10 'Me.updTiempoTotal.Value = Rnd() * 10 Me.updProveedores.Value = 10 Me.updPlantas.Value = 5 Me.updAlmacenes.Value = 3 Me.updClientes.Value = 2 Me.updIteracionesGRASP.Value = 1 Me.updTiempoTotal.Value = 1000 Me.updIteracionesGRASP.Maximum = 100000 116 End Sub End Class B. 6 Clase que Muestra a las Matrices de la Red, asi como la Mejor Solución Public Class frmRed Inherits System.Windows.Forms.Form Public rd As Red = Nothing Public Sub LoadRed(ByVal R As Red) Me.Text = R.NombreArchivo & " - Red" rd = R End Sub Private Sub btnAceptar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Me.Close() End Sub Private Sub frmRed_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load End Sub Private Sub Ver(ByRef mat(,) As Decimal, ByVal b As Button, ByVal cols As String) Configuracion.GENERAR_AUTO = False Dim d As New frmGenerarMatriz d.LoadMatriz(mat, b.Text, cols) d.ShowDialog() If d.DialogResult = DialogResult.OK Then mat = d.GetMatriz() End If End Sub Private Sub Ver(ByRef mat() As Decimal, ByVal b As Button, ByVal cols As String) Configuracion.GENERAR_AUTO = False Dim d As New frmGenerarMatriz 117 d.LoadVector(mat, b.Text, cols) d.ShowDialog() If d.DialogResult = DialogResult.OK Then mat = d.GetVector() End If End Sub Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Ver(rd.mCostProvPlant, sender, "Plantas") End Sub Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click Ver(rd.mTiemProvPlant, sender, "Plantas") End Sub Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click Ver(rd.mCostPlantAlmac, sender, "Almacenes") End Sub Private Sub Button4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button4.Click Ver(rd.mTiemPlantAlmac, sender, "Almacenes") End Sub Private Sub Button5_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button5.Click Ver(rd.mCostAlmacClient, sender, "Clientes") End Sub Private Sub Button6_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button6.Click Ver(rd.mTiemAlmacClient, sender, "Clientes") End Sub 118 Private Sub Button7_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button7.Click Ver(rd.vCostoProd, sender, "Plantas") End Sub Private Sub Button8_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button8.Click Ver(rd.vTiempoProd, sender, "Plantas") End Sub Private Sub Button9_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button9.Click Ver(rd.vOfertaProveedores, sender, "Proveedores") End Sub Private Sub Button10_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button10.Click Ver(rd.vDemandaClientes, sender, "Clientes") End Sub Private Sub Button11_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button11.Click Ver(rd.vCapacidadProd, sender, "Plantas") End Sub Private Sub Button12_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button12.Click Ver(rd.vCapacidadAlmacenaje, sender, "Almacenes") End Sub Private Sub Button13_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button13.Click Ver(rd.vCostoUbicacionPlantas, sender, "Plantas") End Sub Private Sub Button14_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button14.Click 119 Ver(rd.vCostoUbicacionAlmacenes, sender, "Almacenes") End Sub Private Sub btnVerMejorSol_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnVerMejorSol.Click rd.MejorSolucion.Mostrar() End Sub End Class B. 7 Clase que Define las Características de la Red Imports System.io Imports System.Runtime.Serialization Imports System.Runtime.Serialization.Formatters.Binary <Serializable()> _ Public Class Red #Region "Variables de entrada y Matrices" 'Variables de entrada Public Proveedores As Integer Public Plantas As Integer Public Almacenes As Integer Public Clientes As Integer Public TiempoDistribucion As Integer Public IteracionesGRASP As Integer 'Costo de proveedores a plantas Public mCostProvPlant(,) As Decimal 'Tiempo de proveedores a plantas Public mTiemProvPlant(,) As Decimal 'Costo de plantas a almacenes Public mCostPlantAlmac(,) As Decimal 'Tiempo de plantas a almacenes Public mTiemPlantAlmac(,) As Decimal 'Costo de almacenes a clientes 120 Public mCostAlmacClient(,) As Decimal 'Tiempo de almacenes a clientes Public mTiemAlmacClient(,) As Decimal 'Costo de producción de las plantas Public vCostoProd() As Decimal 'Tiempo de producción de las plantas Public vTiempoProd() As Decimal 'Oferta de productores Public vOfertaProveedores() As Decimal 'Demanda de clientes Public vDemandaClientes() As Decimal 'Capacidad de produccion Public vCapacidadProd() As Decimal 'Capacidad de almacenaje Public vCapacidadAlmacenaje() As Decimal 'Costos Ubicacion plantas y vectores Public vCostoUbicacionPlantas() As Decimal Public vCostoUbicacionAlmacenes() As Decimal 'Suma del vector de DemandaClientes Public DemandaTotal As Decimal 'Sumas de oferta total Public OfertaTotal As Decimal 'Suma de vCapacidadProd Public ProdTotal As Decimal 'Suma de vCapacidadAlmacenaje Public AlmacenajeTotal As Decimal 'Current Mejor Solución Public MejorSolucion As Solucion = Nothing 'Demanda a satisfacer Public DemandaSatisfacer As Decimal 'Peticion de cancelar 121 Public Cancelar As Boolean = False 'Nombre del archivo Public NombreArchivo As String = "Sin título" #End Region Public Sub New(Optional ByVal PedirDatos As Boolean = True) Randomize() If PedirDatos Then '1. Pedimos datos de entrada If Not PedirDatosEntrada() Then Return End If 'Calcular demanda a satisfacer EvaluarDemandaSatisfacer() Dim f As New Progreso f.pBar.Maximum = IteracionesGRASP f.Show() For i As Integer = 1 To IteracionesGRASP '2. Generar soluciones evaluadas y ordenadas de menor a mayor con respecto al costo total Dim sols() As Solucion = Me.GenenarSoluciones(Configuracion.NUMERO_DE_SOLUCIONES) '3. Seleccionar aleatoriamente una de las 3 más pequeñas Dim ganadora As Solucion = Me.SeleccionarSolucionRandom(sols, 0, Configuracion.K_MAS_PEQUEÑOS - 1) '4. Actualizar la mejor solución ActualizarMejorSolucion(ganadora) f.pBar.Value = i Application.DoEvents() Next Me.Mostrar() f.Close() 'Mostrar cual fue la mejor solucion 122 'MejorSolucion.Mostrar() End Sub Private Function PedirDatosEntrada() As Boolean PreguntaTodo: Cancelar = False 'Pedimos datos iniciales Dim f As New frmNuevaRed f.ShowDialog() 'Si dio clic en cancelar, se interrumpe If f.DialogResult = DialogResult.Cancel Then Return False Configuracion.GENERAR_AUTO = f.chkAll.Checked 'Pasar datos de entrada a memoria Proveedores = f.updProveedores.Value Plantas = f.updPlantas.Value Almacenes = f.updAlmacenes.Value Clientes = f.updClientes.Value TiempoDistribucion = f.updTiempoTotal.Value IteracionesGRASP = f.updIteracionesGRASP.Value 'Asignar matrices mCostProvPlant = PedirMatriz("Costos de proveedores a plantas", "Plantas", "Proveedores", f.updPlantas.Value, f.updProveedores.Value) If Cancelar Then Return False mTiemProvPlant = PedirMatriz("Tiempos de proveedores a plantas", "Plantas", "Proveedores", f.updPlantas.Value, f.updProveedores.Value) If Cancelar Then Return False mCostPlantAlmac = PedirMatriz("Costos de plantas a almacenes", "Almacenes", "Plantas", f.updAlmacenes.Value, f.updPlantas.Value) If Cancelar Then Return False mTiemPlantAlmac = PedirMatriz("Tiempos de plantas a almacenes", "Almacenes", "Plantas", f.updAlmacenes.Value, f.updPlantas.Value) If Cancelar Then Return False 123 mCostAlmacClient = PedirMatriz("Costos de almacenes a clientes", "Clientes", "Almacenes", f.updClientes.Value, f.updAlmacenes.Value) If Cancelar Then Return False mTiemAlmacClient = PedirMatriz("Tiempos de almacenes a clientes", "Clientes", "Almacenes", f.updClientes.Value, f.updAlmacenes.Value) If Cancelar Then Return False vCostoProd = PedirVector("Costo de producción", "Costos", "Plantas", 1, f.updPlantas.Value) If Cancelar Then Return False vTiempoProd = PedirVector("Tiempo de producción", "Tiempo", "Plantas", 1, f.updPlantas.Value) If Cancelar Then Return False vOfertaProveedores = PedirVector("Oferta de Proveedores", "Ofertas", "Proveedores", 1, f.updProveedores.Value) If Cancelar Then Return False vDemandaClientes = PedirVector("Demanda de clientes", "Demandas", "Cliente", 1, f.updClientes.Value) If Cancelar Then Return False 'Suma del vector de DemandaClientes DemandaTotal = Operaciones.SumaVector(vDemandaClientes) 'Sumas de oferta total OfertaTotal = Operaciones.SumaVector(vOfertaProveedores) vCapacidadProd = PedirVector("Capacidad de producción", "Capacidades", "", 1, f.updPlantas.Value) If Cancelar Then Return False vCapacidadAlmacenaje = PedirVector("Capacidad de almacenaje", "Capacidades", "", 1, f.updAlmacenes.Value) If Cancelar Then Return False 'Sumar vCapacidadProd ProdTotal = Operaciones.SumaVector(vCapacidadProd) 'Sumar vCapacidadAlmacenaje 124 AlmacenajeTotal = Operaciones.SumaVector(vCapacidadAlmacenaje) vCostoUbicacionPlantas = PedirVector("Costo de Ubicación de Plantas", "Costos", "", 1, f.updPlantas.Value) If Cancelar Then Return False vCostoUbicacionAlmacenes = PedirVector("Costo de Ubicación de Almacenes", "Costos", "", 1, f.updAlmacenes.Value) If Cancelar Then Return False 'Checar si la DemandaTotal >= Oferta total If (DemandaTotal > OfertaTotal) OrElse (DemandaTotal > ProdTotal) OrElse (DemandaTotal > AlmacenajeTotal) Then If (MsgBox("El problema no tiene solución. ¿Desea balancear los datos manualmente?", _ MsgBoxStyle.YesNo Or MsgBoxStyle.Question) = MsgBoxResult.Yes) Then 'Balancear proveedores GoTo PreguntaTodo Else MsgBox("La demanda a satisfacer será el mínimo entre: " & vbCrLf & _ "la oferta total, la demanda total," & vbCrLf & _ "la capacidad de producción total y" & vbCrLf & _ "la capacidad de almacenaje total") End If End If Return True End Function Private Sub EvaluarDemandaSatisfacer() 'si no esta balanceado el problema: If (DemandaTotal > OfertaTotal) OrElse (DemandaTotal > ProdTotal) OrElse (DemandaTotal > AlmacenajeTotal) Then 'DemandaSatisfacer es el mìnimo de Dim a() As Decimal = {ProdTotal, DemandaTotal, AlmacenajeTotal, OfertaTotal} Dim min As Decimal = Decimal.MaxValue 125 For i As Integer = 0 To a.Length - 1 If a(i) < min Then min = a(i) End If Next DemandaSatisfacer = min Else 'Si esta blanceado DemandaSatisfacer = Operaciones.SumaVector(vDemandaClientes) End If End Sub Private Function PedirMatriz(ByVal nombre As String, ByVal nombreCols As String, ByVal nombreRows As String, ByVal cols As Integer, ByVal rows As Integer) As Decimal(,) Dim f As New frmGenerarMatriz(nombre, nombreCols, nombreRows, cols, rows) f.ShowDialog() If f.DialogResult = DialogResult.Cancel Then Cancelar = True Return Nothing End If Return f.GetMatriz() End Function Private Function PedirVector(ByVal nombre As String, ByVal nombreCols As String, ByVal nombreRows As String, ByVal cols As Integer, ByVal rows As Integer, Optional ByVal defValues() As Decimal = Nothing) As Decimal() Dim f As New frmGenerarMatriz(nombre, nombreCols, nombreRows, cols, rows) f.ShowDialog() If f.DialogResult = DialogResult.Cancel Then Cancelar = True Return Nothing End If 126 Return f.GetVector() End Function 'Genera el número de soluciones que se pide, las evalúa y las ordena de menor a mayor con respecto al costo total Private Function GenenarSoluciones(ByVal n As Integer) As Solucion() Dim soluciones As New ArrayList For i As Integer = 1 To n Dim s As New Solucion(Me) 'Asignaciones Asignar(s) 'Evaluarla s.Evaluar() 'Agregar al resultado de la funcion soluciones.Add(s) Next Dim sols() As Solucion = soluciones.ToArray(GetType(Solucion)) 'Bubble sort para ordenar con respecto al costo total Dim tmp As Solucion For i As Integer = sols.Length - 1 To 0 Step -1 For j As Integer = 0 To i - 1 If (sols(j).CostoTotal > sols(j + 1).CostoTotal) Then tmp = sols(j) sols(j) = sols(j + 1) sols(j + 1) = tmp End If Next Next Return sols End Function Public Sub Asignar(ByVal s As Solucion) 127 '1. Asignación de Almacenes AsignacionAlmacenes(s) '2. Asignación de Plantas AsignacionPlantas(s) End Sub Public Sub AsignacionPlantas(ByVal s As Solucion) 'Vector de ubicaciones (check list) Dim UbicacionPlantas(Plantas - 1) As Decimal 'Llenar de ceros For i As Integer = 0 To UbicacionPlantas.Length - 1 UbicacionPlantas(i) = 1 Next 'Asignamos el checklist al array s.AsignacionPlantas = UbicacionPlantas End Sub Public Sub AsignacionAlmacenes(ByVal s As Solucion) 'Vector de ubicaciones (check list) Dim UbicacionAlmacenes(Almacenes - 1) As Decimal For i As Integer = 0 To UbicacionAlmacenes.Length - 1 UbicacionAlmacenes(i) = 1 Next 'Asignamos el checklist al array s.AsignacionAlmacenes = UbicacionAlmacenes End Sub 'Selecciona una solucion del arreglo, que esté entre el límite inf y el sup Private Function SeleccionarSolucionRandom(ByVal s() As Solucion, ByVal limInf As Integer, ByVal limSup As Integer) As Solucion Dim Margen As Integer = limSup - limInf Dim ticket As Integer = Rnd() * Margen ticket += limInf 128 Return s(ticket) End Function 'Actualiza la mejor solucion Private Sub ActualizarMejorSolucion(ByVal s As Solucion) 'Si no había mejor solución If MejorSolucion Is Nothing Then 'Se asigna la que se eligió MejorSolucion = s Else 'Si es mejor solución If s.CostoTotal < MejorSolucion.CostoTotal Then 'Asignarla como actual mejor solución MejorSolucion = s End If End If End Sub 'Crea una nueva red desde un archivo, el cual preguntará en un dialog Public Shared Sub FromFile() Dim d As New OpenFileDialog d.Filter = "SCUPA Files|*.scupa" If d.ShowDialog() = DialogResult.Cancel Then Return FromFile(New FileInfo(d.FileName)) End Sub 'Crea una nueva red desde un archivo Public Shared Sub FromFile(ByVal path As String) FromFile(New FileInfo(path)) End Sub 'Muestra la red en GUI Public Sub Mostrar() Dim f As New frmRed 129 f.LoadRed(Me) If Not Configuracion.CURMAIN Is Nothing Then f.MdiParent = Configuracion.CURMAIN End If f.Show() End Sub 'Guarda a disco la red Public Sub Guardar() Dim d As New SaveFileDialog d.Filter = "SCUPA Files|*.scupa" If d.ShowDialog() = DialogResult.Cancel Then Return Guardar(New FileInfo(d.FileName)) End Sub 'Guarda a disco la red Public Sub Guardar(ByVal f As FileInfo) Try Me.NombreArchivo = f.Name Dim bf As New BinaryFormatter bf.Serialize(f.OpenWrite(), Me) Catch ex As Exception MsgBox(ex.Message, MsgBoxStyle.Exclamation) Debug.Write(ex.ToString()) End Try End Sub 'Crea una nueva red desde un archivo Public Shared Sub FromFile(ByVal f As FileInfo) Try Dim bf As New BinaryFormatter Dim result As Red = bf.Deserialize(f.OpenRead()) result.Mostrar() Catch ex As Exception 130 MsgBox(ex.Message, MsgBoxStyle.Exclamation) Debug.Write(ex.ToString()) End Try End Sub End Class B. 8 Clase que Solciona el Problema de Localización <System.Serializable()> _ Public Class Solucion #Region "Attributos y matrices" 'Ubicaciones de plantas (vectores de boolean) Public AsignacionPlantas As Decimal() 'Ubicaciones de almacenes (vectores de boolean) Public AsignacionAlmacenes As Decimal() 'Unidades enviadas de proveedores a plantas Public mUEProveedoresPlantas(,) As Decimal 'Unidades enviadas de plantas a almacenes Public mUEPlantasAlmacenes(,) As Decimal 'Unidades enviadas de almacenes a clientes Public mUEAlmacenesClientes(,) As Decimal 'Unidades producidas en cada planta Public vUnidadesProducidas() As Decimal 'Costo total Public CostoTotal As Decimal 'Tiempo total Public TiempoTotal As Decimal 'Red a la que pertenezco Public MiRed As Red 'Mínimo entre demanda total y oferta total Private min As Decimal #End Region 131 Public Sub New(ByVal daddy As Red) 'Red a la que pertenezco Me.MiRed = daddy End Sub Public Sub Evaluar() 'Llenar mUEAlmacenesClientes Evaluar_mUEAlmacenesClientes() 'Llenar mUEPlantasAlmacenes Evaluar_mUEPlantasAlmacenes() 'Llenar mUEProveedoresPlantas Evaluar_mUEProveedoresPlantas() 'Llenar vUnidadesProducidas Evaluar_vUnidadesProducidas() 'Calcular Costo total EvaluarCostoTotal() 'Calcular Tiempo total EvaluarTiempoTotal() End Sub Public Sub Evaluar_mUEAlmacenesClientes() ReDim mUEAlmacenesClientes(MiRed.mCostAlmacClient.GetLength(0) - 1, MiRed.mCostAlmacClient.GetLength(1) - 1) Dim ListaAOrdenar As New ArrayList For i As Integer = 0 To AsignacionAlmacenes.Length - 1 If AsignacionAlmacenes(i) > 0 Then 'Meter todos los del renglon a la lista para ordenar For j As Integer = 0 To MiRed.mCostAlmacClient.GetLength(1) - 1 ListaAOrdenar.Add( _ New ValorMatriz(i, j, MiRed.mCostAlmacClient(i, j))) Next End If Next 132 'Ordenar de menor a mayor Operaciones.OrdenarValorMatriz(ListaAOrdenar) Dim ColaMinimos As New Queue(ListaAOrdenar) While (MiRed.DemandaSatisfacer > Operaciones.Sumar(mUEAlmacenesClientes)) 'Si ya no hay valores en la cola, abortar If ColaMinimos.Count = 0 Then Exit While '1. Seleccionar mínimo(x,y) (Dequeue de ColaMinimos) Dim v As ValorMatriz = ColaMinimos.Dequeue() Dim SumaAlmacenI As Decimal = Operaciones.SumarRenglon(mUEAlmacenesClientes, v.Row) Dim SumaClienteJ As Decimal = Operaciones.SumarColumna(mUEAlmacenesClientes, v.Column) Dim Minimo1 As Decimal = Math.Min((MiRed.DemandaSatisfacer SumaAlmacenI), (MiRed.vDemandaClientes(v.J) - SumaClienteJ)) Dim Minimo2 As Decimal = Math.Min((MiRed.DemandaSatisfacer SumaClienteJ), (MiRed.vCapacidadAlmacenaje(v.I) - SumaAlmacenI)) Dim Minimo3 As Decimal = Math.Min(Minimo1, Minimo2) mUEAlmacenesClientes(v.Row, v.Column) = Minimo3 End While For i As Integer = 0 To mUEAlmacenesClientes.GetLength(0) - 1 If Operaciones.SumarRenglon(mUEAlmacenesClientes, i) = 0 Then 'Le ponemos 0 en la asignacion AsignacionAlmacenes(i) = 0 End If Next End Sub Public Sub Evaluar_mUEPlantasAlmacenes() ReDim mUEPlantasAlmacenes(MiRed.mCostPlantAlmac.GetLength(0) - 1, MiRed.mCostPlantAlmac.GetLength(1) - 1) 133 ' Para la matriz mCostPlantAlmac hacemos una lista de menor a mayor (ColaMinimos) de los costos que nos interesen (Posiciones del vector de asignacion de almacenes y de plantas que sean diferentes de cero) Dim ListaAOrdenar As New ArrayList For j As Integer = 0 To AsignacionAlmacenes.Length - 1 For i As Integer = 0 To AsignacionPlantas.Length - 1 If AsignacionAlmacenes(j) > 0 AndAlso AsignacionPlantas(i) > 0 Then 'Meter ese elemento a la lista para ordenar ListaAOrdenar.Add(New ValorMatriz(i, j, MiRed.mCostPlantAlmac(i, j))) End If Next Next Operaciones.OrdenarValorMatriz(ListaAOrdenar) Dim ColaMinimos As New Queue(ListaAOrdenar) ' Mientras suma(mUEPlantasAlmacenes) < demandasatisfacer) While (MiRed.DemandaSatisfacer > Operaciones.Sumar(mUEPlantasAlmacenes)) 'Si ya no hay valores abortar If ColaMinimos.Count = 0 Then Exit While '1. Seleccionar mínimo(x,y) (Dequeue de ColaMinimos) Dim v As ValorMatriz = ColaMinimos.Dequeue() Dim SumaPlantaI As Decimal = Operaciones.SumarRenglon(mUEPlantasAlmacenes, v.Row) Dim SumaAlmacenJ As Decimal = Operaciones.SumarColumna(mUEPlantasAlmacenes, v.Column) Dim SumaAlmacenI As Decimal = Operaciones.SumarRenglon(mUEAlmacenesClientes, v.Column) Dim Minimo1 As Decimal = Math.Min((MiRed.DemandaSatisfacer SumaAlmacenJ), (MiRed.vCapacidadProd(v.I) - SumaPlantaI)) Dim Minimo2 As Decimal = Math.Min((MiRed.DemandaSatisfacer SumaPlantaI), (SumaAlmacenI - SumaAlmacenJ)) Dim Minimo3 As Decimal = Math.Min(Minimo1, Minimo2) 134 'MsgBox(Minimo3) mUEPlantasAlmacenes(v.Row, v.Column) = Minimo3 End While ' End para la matriz For i As Integer = 0 To mUEPlantasAlmacenes.GetLength(0) - 1 If Operaciones.SumarRenglon(mUEPlantasAlmacenes, i) = 0 Then 'Le ponemos 0 en la asignacion AsignacionPlantas(i) = 0 End If Next End Sub Public Sub Evaluar_mUEProveedoresPlantas() ReDim mUEProveedoresPlantas(MiRed.mCostProvPlant.GetLength(0) - 1, MiRed.mCostProvPlant.GetLength(1) - 1) ' Para la matriz mCostProvPlant hacemos una lista de menor a mayor (ColaMinimos) de los costos que nos interesen (Posiciones del vector de asignacion de plantas que sean diferentes de cero) Dim ListaAOrdenar As New ArrayList For j As Integer = 0 To AsignacionPlantas.Length - 1 If AsignacionPlantas(j) > 0 Then 'Meter todos los de la columna a la lista para ordenar For i As Integer = 0 To MiRed.mCostProvPlant.GetLength(0) - 1 ListaAOrdenar.Add(New ValorMatriz(i, j, MiRed.mCostProvPlant(i, j))) Next End If Next 'Ordenar de menor a mayor Operaciones.OrdenarValorMatriz(ListaAOrdenar) Dim ColaMinimos As New Queue(ListaAOrdenar) Dim Flujo As Decimal = 0 'Mientras suma(UEProveedoresPlantas) < DemandaSatisfacer 135 While (MiRed.DemandaSatisfacer > Operaciones.Sumar(Me.mUEProveedoresPlantas)) 'Si ya no hay valores en la cola, abortar If ColaMinimos.Count = 0 Then Exit While '1. Seleccionar mínimo(x,y) (Dequeue de ColaMinimos) Dim v As ValorMatriz = ColaMinimos.Dequeue() Dim SumaProveedorI As Decimal = Operaciones.SumarRenglon(mUEProveedoresPlantas, v.Row) Dim SumaPlantaJ As Decimal = Operaciones.SumarColumna(mUEProveedoresPlantas, v.Column) Dim SumaPlantaI As Decimal = Operaciones.SumarRenglon(mUEPlantasAlmacenes, v.Column) Dim Minimo1 As Decimal = Math.Min((MiRed.DemandaSatisfacer SumaPlantaJ), (MiRed.vOfertaProveedores(v.I) - SumaProveedorI)) Dim Minimo2 As Decimal = Math.Min((MiRed.DemandaSatisfacer SumaProveedorI), (SumaPlantaI - SumaPlantaJ)) Dim Minimo3 As Decimal = Math.Min(Minimo1, Minimo2) mUEProveedoresPlantas(v.Row, v.Column) = Minimo3 End While End Sub Public Sub Evaluar_vUnidadesProducidas() 'Sumar cada renglon de mUEPlantasAlmacenes y alojar el resultado en vUnidadesProducidas Dim units(Me.mUEPlantasAlmacenes.GetLength(0) - 1) As Decimal For i As Integer = 0 To units.Length - 1 units(i) = Operaciones.SumarRenglon(mUEPlantasAlmacenes, i) Next Me.vUnidadesProducidas = units End Sub Public Sub EvaluarCostoTotal() CostoTotal = 0 136 'Para cada matriz M en {mUE's} ' M1 = Multiplicar M x Su respectivo costo unitario(mCost's) ' CostoTotal += Suma de todos los elementos de M1 'End para cada matriz CostoTotal += Operaciones.Sumar(Operaciones.Multiplicarvector(AsignacionPlantas, MiRed.vCostoUbicacionPlantas)) CostoTotal += Operaciones.Sumar(Operaciones.Multiplicarvector(AsignacionAlmacenes, MiRed.vCostoUbicacionAlmacenes)) CostoTotal += Operaciones.Sumar(Operaciones.Multiplicarmatriz(MiRed.mCostProvPlant, Me.mUEProveedoresPlantas)) CostoTotal += Operaciones.Sumar(Operaciones.Multiplicarmatriz(MiRed.mCostPlantAlmac, Me.mUEPlantasAlmacenes)) CostoTotal += Operaciones.Sumar(Operaciones.Multiplicarmatriz(MiRed.mCostAlmacClient, Me.mUEAlmacenesClientes)) 'MM2 = Multiplicar vUnidadesProducidas x vCostoProd 'CostoTotal += suma de elementos en M2 CostoTotal += Operaciones.Sumar(Operaciones.Multiplicarvector(Me.vUnidadesProducidas, MiRed.vCostoProd)) End Sub Public Sub EvaluarTiempoTotal() TiempoTotal = 0 'Para cada matriz M en {mUE's} ' M1 = Multiplicar M x Su respectivo costo unitario(mTiem,'s) ' TiempoTotal += Suma de todos los elementos de M1 'End para cada matriz 137 TiempoTotal += Operaciones.Sumar(Operaciones.Multiplicarmatriz(MiRed.mTiemProvPlant, Me.mUEProveedoresPlantas)) TiempoTotal += Operaciones.Sumar(Operaciones.Multiplicarmatriz(MiRed.mTiemPlantAlmac, Me.mUEPlantasAlmacenes)) TiempoTotal += Operaciones.Sumar(Operaciones.Multiplicarmatriz(MiRed.mTiemAlmacClient, Me.mUEAlmacenesClientes)) 'M2 = Multiplicar vUnidadesProducidas x vTiempoProd 'TiempoTotal += suma de elementos en M2 TiempoTotal += Operaciones.Sumar(Operaciones.Multiplicarvector(Me.vUnidadesProducidas, MiRed.vTiempoProd)) End Sub Public Sub Mostrar() Dim f As New frmSolucion f.gridAsignacionAlmacenes.DataSource = Operaciones.VectorToDataTable(Me.AsignacionAlmacenes, "Almacenes") f.gridAsignacionPlantas.DataSource = Operaciones.VectorToDataTable(Me.AsignacionPlantas, "Plantas") f.gridUEAlmacenesClientes.DataSource = Operaciones.MatrizToDataTable(Me.mUEAlmacenesClientes, "Almacén", "Cliente") f.gridUEPlantasAlmacenes.DataSource = Operaciones.MatrizToDataTable(Me.mUEPlantasAlmacenes, "Planta", "Almacén") f.gridUEProveedoresPlantas.DataSource = Operaciones.MatrizToDataTable(Me.mUEProveedoresPlantas, "Proveedor", "Planta") f.gridUnidadesProducidas.DataSource = Operaciones.VectorToDataTable(Me.vUnidadesProducidas, "Unidades") f.LblDS.Text = Operaciones.SumaVector(MiRed.vDemandaClientes) f.lblCostoTotal.Text = Math.Round(Me.CostoTotal, 3) 138 f.lblTiempoTotal.Text = Math.Round(Me.TiempoTotal, 3) f.ShowDialog() End Sub End Class Public Structure ValorMatriz Public Column As Integer Public Row As Integer Public Value As Decimal Public Sub New(ByVal Row As Integer, ByVal Column As Integer, ByVal Value As Decimal) Me.Column = Column Me.Row = Row Me.Value = Value End Sub Public Property J() As Integer Get Return Column End Get Set(ByVal Value As Integer) Column = Value End Set End Property Public Property I() As Integer Get Return Row End Get Set(ByVal Value As Integer) Row = Value End Set End Property End Structure 139 B. 9 Clase de Configuración de los Parámetros de GRASP Public Class Configuracion 'Este es el k de cada iteración (los k más pequeños...) Public Shared K_MAS_PEQUEÑOS As Integer = 3 'Este es el número de soluciones que se generan en cada iteración de GRASP Public Shared NUMERO_DE_SOLUCIONES As Integer = 25 Public Shared GENERAR_AUTO As Boolean = False Public Shared CURMAIN As Form Public Shared ALFA As Double = 1 End Class 140