Algoritmo para crear un horario escolar

95

Me he estado preguntando si existen soluciones conocidas para el algoritmo de creación de un horario escolar. Básicamente, se trata de optimizar la "dispersión de horas" (tanto en el caso de los profesores como de las clases) para determinadas asociaciones de clase, asignatura y profesor. Podemos suponer que tenemos conjuntos de clases, asignaturas y profesores asociados entre sí en la entrada y que el horario debe ajustarse entre las 8 a. M. Y las 4 p. M.

Supongo que probablemente no exista un algoritmo preciso para eso, pero tal vez alguien conozca una buena aproximación o sugerencias para desarrollarla.

candó
fuente
2
Gracias por todas las respuestas. Parece que el algoritmo requiere más investigación. Lo consideraría como un buen tema para tesis de maestría o pequeña aplicación comercial. Si escribo uno, te lo haré saber aquí;)
cand
10
Como dijo Ian Ringrose de StackOverflow a otra pregunta, "todavía hay muchos PHD en software de programación".
Reed Debaets

Respuestas:

87

¡Este problema es NP-Complete !
En pocas palabras, es necesario explorar todas las combinaciones posibles para encontrar la lista de soluciones aceptables. Debido a las variaciones en las circunstancias en las que aparece el problema en las distintas escuelas (por ejemplo: ¿hay limitaciones en cuanto a las aulas ?, ¿algunas de las clases se dividen en subgrupos alguna vez ?, ¿es este un horario semanal? etc.) no existe una clase de problema bien conocida que corresponda a todos los problemas de programación. Quizás, el problema de la mochila tiene muchos elementos de similitud con estos problemas en general.

Una confirmación de que este es un problema difícil y para el que la gente busca constantemente una solución es consultar esta (larga) lista de herramientas de programación de software (en su mayoría comerciales)

Debido a la gran cantidad de variables involucradas, la mayor fuente de las cuales son, típicamente, los deseos del miembro de la facultad; -) ..., típicamente no es práctico considerar enumerar todas las combinaciones posibles . En su lugar, debemos elegir un enfoque que visite un subconjunto de los espacios de problema / solución.
- Los algoritmos genéticos , citados en otra respuesta, están (o, en mi humilde opinión, parecen ) bien equipados para realizar este tipo de búsqueda semi-guiada (el problema es encontrar una buena función de evaluación para que los candidatos se mantengan para la próxima generación)
- Gráfico Los enfoques de reescritura también son útiles con este tipo de problemas de optimización combinatoria.

En lugar de centrarme en implementaciones particulares de un programa generador automático de horarios, me gustaría sugerir algunas estrategias que se pueden aplicar, al nivel de la definición del problema .
El fundamento general es que en la mayoría de los problemas de programación del mundo real, se requerirán algunos compromisos, no todas las restricciones, expresas e implícitas: se cumplirán por completo. Por eso nos ayudamos a nosotros mismos:

  • Definir y clasificar todas las restricciones conocidas
  • Reducir el espacio del problema, de forma manual, proporcionando un conjunto de restricciones adicionales .
    Esto puede parecer contrario a la intuición, pero, por ejemplo, al proporcionar un horario inicial parcialmente llenado (digamos aproximadamente el 30% de los intervalos de tiempo), de una manera que satisfaga completamente todas las restricciones, y al considerar este horario parcial inmutable, reducimos significativamente el tiempo / espacio necesario para producir soluciones candidatas.
    Otra forma en que las restricciones adicionales ayudan es, por ejemplo, agregando "artificialmente" una restricción que impida enseñar algunas materias en algunos días de la semana (si se trata de un horario semanal ...); este tipo de restricciones da como resultado la reducción de los espacios de problema / solución, sin, por lo general, excluir a un número significativo de buenos candidatos.
  • Asegurarse de que algunas de las limitaciones del problema se puedan calcular rápidamente. Esto a menudo se asocia con la elección del modelo de datos utilizado para representar el problema; la idea es poder optar por (o eliminar) rápidamente algunas de las opciones.
  • Redefinir el problema y permitir que algunas de las restricciones se rompan, algunas veces (normalmente hacia los nodos finales del gráfico). La idea aquí es eliminar algunas de las restricciones para completar los últimos espacios en el horario, o hacer que el programa generador de horarios automático no complete el horario completo, en lugar de proporcionarnos una lista de una docena más o menos plausibles candidatos. A menudo, un humano está en una mejor posición para completar el rompecabezas, como se indica, posiblemente rompiendo algunas de las limitaciones, utilizando información que normalmente no se comparte con la lógica automatizada (por ejemplo, la regla "No hay matemáticas por la tarde" se puede romper en ocasiones para la clase de "matemáticas y física avanzadas"; o "Es mejor romper uno de los requisitos del Sr. Jones que uno de la Sra. Smith ... ;-))

Al revisar esta respuesta, me doy cuenta de que es bastante tímido para proporcionar una respuesta definitiva, pero no obstante, está llena de sugerencias prácticas. Espero que esto ayude con lo que, después de todo, es un "problema difícil".

mjv
fuente
1
Respuesta excelente, precisa y elaborada, gracias por las sugerencias y la mención sobre NP-Completeness (también fue mi suposición).
cand
3
¿Tiene alguna cita que explique la completitud NP de este problema?
Don
49

Es un desastre. un lío real. Para agregar a las respuestas, ya muy completas, quiero señalar mi experiencia familiar. Mi madre era maestra y solía participar en el proceso.

Resulta que tener una computadora para hacerlo no solo es difícil de codificar per-se, también es difícil porque hay condiciones que son difíciles de especificar para un programa de computadora prefabricado. Ejemplos:

  • un profesor enseña tanto en su escuela como en otro instituto. Claramente, si termina la lección allí a las 10.30, no puede comenzar en sus instalaciones a las 10.30, porque necesita algo de tiempo para desplazarse entre los institutos.
  • dos profesores están casados. En general, se considera una buena práctica no tener dos profesores casados ​​en la misma clase. Por tanto, estos dos profesores deben tener dos clases diferentes
  • dos maestros están casados ​​y su hijo asiste a la misma escuela. Nuevamente, debe evitar que los dos maestros enseñen en la clase específica donde está su hijo.
  • la escuela tiene instalaciones separadas, como un día la clase es en un instituto y otro día la clase es en otro.
  • la escuela tiene laboratorios compartidos, pero estos laboratorios están disponibles solo en ciertos días de la semana (por razones de seguridad, por ejemplo, cuando se requiere personal adicional).
  • algunos profesores tienen preferencias por el día libre: algunos prefieren el lunes, algunos el viernes, algunos el miércoles. Algunos prefieren llegar temprano por la mañana, otros prefieren llegar más tarde.
  • no debe haber situaciones en las que tenga una lección de historia, digamos, en la primera hora, luego tres horas de matemáticas, luego otra hora de historia. No tiene sentido para los alumnos, ni para el profesor.
  • debe distribuir los argumentos de manera uniforme. No tiene sentido tener los primeros días de la semana solo matemáticas y luego el resto de la semana solo literatura.
  • Debería dar a algunos profesores dos horas consecutivas para hacer pruebas de evaluación.

Como puede ver, el problema no es NP-completo, es NP-loco.

Entonces, lo que hacen es que tienen una mesa grande con pequeñas inserciones de plástico y mueven las inserciones hasta obtener un resultado satisfactorio. Nunca parten de cero: normalmente parten del horario del año anterior y hacen ajustes.

Stefano Borini
fuente
12
"NP-loco" - gran nombre;) Estoy de acuerdo en que es un problema realmente complejo, gracias por los comentarios sobre el tratamiento del "mundo real" de este problema. Mi padre y mi novia también son profesores y sé que la mayoría de las escuelas tienen mesas con inserciones de plástico, eso me llevó a pensar en un posible algoritmo para este problema, porque, si un hombre puede resolverlo, tal vez sea posible escribir como un algoritmo.
cand
10
lo que quiere escribir es un sistema experto: un sistema hecho de un montón de reglas heurísticas. Dejando a un lado los sistemas expertos, este es un campo donde los algoritmos genéticos se encuentran entre las mejores apuestas. La dificultad no radica en resolver el problema, no solo. La dificultad también radica en plantear el problema y sus limitaciones.
Stefano Borini
1
Tiene razón, el problema requiere proporcionar un conjunto complejo de condiciones y restricciones para cumplir, probablemente con una calificación de solución "aceptable". Estoy de acuerdo con los algoritmos genéticos, deberían encajar bien con este problema, también creo que será mejor comenzar a desarrollar con un conjunto simple de condiciones y mejorarlo a medida que se obtenga la respuesta correcta para ellos.
cand
1
También podría traducir de forma bastante directa estas limitaciones y objetivos en MAXSAT. Los algoritmos MAXSAT son generalmente más confiables que los algoritmos genéticos, pero es posible que tenga una explosión de cláusulas debido a objetivos como que las clases de matemáticas deberían distribuirse durante la semana.
Jules
26

El Concurso Internacional de Horarios 2007 tenía un itinerario de programación de lecciones y un itinerario de programación de exámenes. Muchos investigadores participaron en ese concurso. Se probaron muchas heurísticas y metaheurísticas, pero al final las metaheurísticas de búsqueda local (como Tabu Search y Simulated Annealing) superaron claramente a otros algoritmos (como los algoritmos genéticos).

Eche un vistazo a los 2 marcos de código abierto utilizados por algunos de los finalistas:

Geoffrey De Smet
fuente
17

Una de mis asignaciones de medio término fue una generación de tablas escolares con algoritmos genéticos.

Toda la mesa es un "organismo". Hubo algunos cambios y advertencias en el enfoque de los algoritmos genéticos genéricos:

  • Se establecieron reglas para las "mesas ilegales": dos clases en el mismo aula, un maestro enseñando a dos grupos al mismo tiempo, etc. Estas mutaciones se consideraron letales de inmediato y un nuevo "organismo" brotó en lugar del "fallecido" inmediatamente. El inicial fue generado por una serie de intentos aleatorios para obtener uno legal (aunque sin sentido). La mutación letal no se contabilizó para el recuento de mutaciones en iteración.

  • Las mutaciones de "intercambio" eran mucho más comunes que las mutaciones de "modificación". Los cambios se produjeron solo entre partes del gen que tenían sentido, sin sustituir a un maestro por un aula.

  • Se asignaron pequeñas bonificaciones por agrupar ciertas 2 horas juntas, por asignar la misma clase genérica en secuencia para el mismo grupo, por mantener continuas las horas de trabajo del maestro y la carga de la clase. Se asignaron bonificaciones moderadas por dar las aulas correctas para un tema determinado, mantener las horas de clase dentro de los límites (mañana o tarde), etc. Las grandes bonificaciones fueron por asignar el número correcto de asignaturas determinadas, carga de trabajo dada para un maestro, etc.

  • Los profesores pueden crear sus horarios de carga de trabajo de "quiere trabajar entonces", "está bien trabajar entonces", "no le gusta trabajar entonces", "no puedo trabajar entonces", con los pesos adecuados asignados. Las 24 horas completas eran horas de trabajo legales, excepto que la noche era muy indeseable.

  • La función de peso ... oh sí. La función de peso era un producto enorme y monstruoso (como en la multiplicación) de pesos asignados a características y propiedades seleccionadas. Era extremadamente empinado, una propiedad podía cambiarlo fácilmente en un orden de magnitud hacia arriba o hacia abajo, y había cientos o miles de propiedades en un organismo. Esto resultó en números absolutamente ENORMES como pesos y, como resultado directo, es necesario usar una biblioteca bignum (gmp) para realizar los cálculos. Para un caso de prueba pequeño de unos 10 grupos, 10 maestros y 10 aulas, el conjunto inicial comenzó con una nota de 10 ^ -200 algo y terminó con 10 ^ + 300 algo. Era totalmente ineficaz cuando era más plano. Además, los valores crecieron mucho más con las "escuelas" más grandes.

  • En cuanto al tiempo de cálculo, hubo poca diferencia entre una población pequeña (100) durante mucho tiempo y una población grande (10k +) durante menos generaciones. El cálculo durante el mismo tiempo produjo aproximadamente la misma calidad.

  • El cálculo (en una CPU de 1 GHz) tardaría alrededor de 1 hora en estabilizarse cerca de 10 ^ + 300, generando programas que se veían bastante bien, para dicho caso de prueba de 10x10x10.

  • El problema es fácilmente paralelizable al proporcionar una instalación de red que intercambiaría las mejores muestras entre computadoras que ejecutan el cálculo.

El programa resultante nunca vio la luz del día afuera, lo que me dio una buena calificación para el semestre. Se mostró prometedor, pero nunca tuve la motivación suficiente para agregar una GUI y hacerla utilizable para el público en general.

SF.
fuente
5
Entonces, ¿abrirlo, publicitarlo e intentar que algunos académicos lo utilicen? ¿Reutilizarlo para otros proyectos? Técnicamente, un programa como ese solo para 300 empleados valdría dinero para que las escuelas produzcan horarios óptimos, y no les importa pasar unos días para calcular genéticamente los horarios óptimos. Piense en el procesamiento por lotes. Hola contratos de hardware y software;)
jcolebrand
1
¡Suena genial! Me pregunto si la función de peso podría realizarse con flotadores en el rango 0..1.
Craig McQueen
1
@Craig: Algo tan plano produciría una población que se estancó o incluso degeneró en calidad con el tiempo, ya que las mutaciones aleatorias contribuyeron con más cambios negativos de los que la reproducción / selección podría compensar. Solo la función de calidad extremadamente pronunciada daría un crecimiento constante. Seguro que la función podría normalizarse, pero aún así, un gen "notch mejor" tenía que tener una mayor probabilidad de sobrevivir.
SF.
9

Este problema es más difícil de lo que parece.

Como otros han aludido, este es un problema NP-completo, pero analicemos lo que eso significa.

Básicamente, significa que debes buscar todas las combinaciones posibles.

Pero "mirar" no te dice mucho de lo que necesitas hacer.

Generar todas las combinaciones posibles es fácil. Puede producir una gran cantidad de datos, pero no debería tener muchos problemas para comprender los conceptos de esta parte del problema.

El segundo problema es el de juzgar si una combinación posible dada es buena, mala o mejor que la solución "buena" anterior.

Para ello, necesita algo más que "¿es una posible solución"?

Por ejemplo, ¿el mismo profesor trabaja 5 días a la semana durante X semanas seguidas? Incluso si esa es una solución que funciona, puede que no sea mejor que alternar entre dos personas para que cada maestro haga una semana cada uno. Oh, ¿no pensaste en eso? Recuerde, estas son personas con las que está tratando, no solo un problema de asignación de recursos.

Incluso si un maestro pudiera trabajar a tiempo completo durante 16 semanas seguidas, esa podría ser una solución subóptima en comparación con una solución en la que intentas alternar entre maestros, y este tipo de equilibrio es muy difícil de integrar en el software.

En resumen, producir una buena solución a este problema valdrá mucho, para muchas personas. Por lo tanto, no es un problema fácil de analizar y resolver. Esté preparado para marcar algunos objetivos que no están al 100% y llamarlos "suficientemente buenos".

Lasse V. Karlsen
fuente
1
Bueno, yo diría que es bastante difícil conocer todas las limitaciones al principio, se necesita experiencia e investigación del asunto. Prefiero dividir el problema en dos partes separadas y desarrollarlas simultáneamente. Primero será la estructura general del algoritmo, diciendo cómo debería poblar la "próxima generación de horarios", más bien un borrador del mecanismo, sin demasiada "lógica de sujeto" detrás (probablemente algoritmo genético). El segundo será un proveedor de reglas con un conjunto de restricciones que verifiquen la "corrección" del calendario; puede ser simple al principio y mejorado más tarde.
cand
8

Mi algoritmo de programación de horarios, implementado en FET (Free Timetabling Software, http://lalescu.ro/liviu/fet/ , una aplicación exitosa):

El algoritmo es heurístico. Lo llamé "intercambio recursivo".

Entrada: un conjunto de actividades A_1 ... A_n y las limitaciones.

Salida: un conjunto de tiempos TA_1 ... TA_n (el intervalo de tiempo de cada actividad. Las habitaciones están excluidas aquí, por simplicidad). El algoritmo debe colocar cada actividad en un intervalo de tiempo, respetando las limitaciones. Cada TA_i está entre 0 (T_1) y max_time_slots-1 (T_m).

Limitaciones:

C1) Básico: una lista de pares de actividades que no pueden ser simultáneas (por ejemplo, A_1 y A_2, porque tienen el mismo profesor o los mismos alumnos);

C2) Muchas otras restricciones (excluidas aquí, por simplicidad).

El algoritmo de programación de horarios (que llamé "intercambio recursivo"):

  1. Clasifique las actividades, las más difíciles primero. No es un paso crítico, pero acelera el algoritmo tal vez 10 veces o más.
  2. Intente colocar cada actividad (A_i) en un intervalo de tiempo permitido, siguiendo el orden anterior, una a la vez. Busque un espacio disponible (T_j) para A_i, en el que esta actividad se pueda colocar respetando las restricciones. Si hay más espacios disponibles, elija uno al azar. Si no hay ninguno disponible, realice un intercambio recursivo:

    a . Para cada intervalo de tiempo T_j, considere lo que sucede si coloca A_i en T_j. Habrá una lista de otras actividades que no están de acuerdo con este movimiento (por ejemplo, la actividad A_k está en el mismo espacio T_j y tiene el mismo maestro o los mismos estudiantes que A_i). Mantenga una lista de actividades en conflicto para cada intervalo de tiempo T_j.

    b . Elija un espacio (T_j) con el menor número de actividades en conflicto. Digamos que la lista de actividades en este espacio contiene 3 actividades: A_p, A_q, A_r.

    c . Coloque A_i en T_j y haga que A_p, A_q, A_r no estén asignados.

    d . Intente recursivamente colocar A_p, A_q, A_r (si el nivel de recursividad no es demasiado grande, digamos 14, y si el número total de llamadas recursivas contadas desde el paso 2) en A_i comenzó no es demasiado grande, digamos 2 * n), como en el paso 2).

    e . Si colocó con éxito A_p, A_q, A_r, regrese con éxito; de lo contrario, pruebe con otras franjas horarias (vaya al paso 2 b) y elija la siguiente mejor franja horaria).

    f . Si todos (o un número razonable de) intervalos de tiempo se probaron sin éxito, regrese sin éxito.

    g . Si estamos en el nivel 0, y no tuvimos éxito en colocar A_i, colóquelo como en los pasos 2 b) y 2 c), pero sin recursividad. Ahora tenemos 3 - 1 = 2 actividades más para colocar. Vaya al paso 2) (aquí se utilizan algunos métodos para evitar el ciclismo).

Liviu Lalescu
fuente
1
FET me ha sido muy útil. ¡Gracias @Liviu Lalescu!
Noel Llevares
6

ACTUALIZACIÓN: de los comentarios ... ¡también debería tener heurística!

Yo iría con Prolog ... luego usaría Ruby o Perl o algo para limpiar su solución en una forma más bonita.

teaches(Jill,math).
teaches(Joe,history).

involves(MA101,math).
involves(SS104,history).

myHeuristic(D,A,B) :- [test_case]->D='<';D='>'.
createSchedule :- findall(Class,involves(Class,Subject),Classes),
                  predsort(myHeuristic,Classes,ClassesNew),
                  createSchedule(ClassesNew,[]).
createSchedule(Classes,Scheduled) :- [the actual recursive algorithm].

Estoy (todavía) en el proceso de hacer algo similar a este problema pero usando la misma ruta que acabo de mencionar. Prolog (como lenguaje funcional) realmente facilita la resolución de problemas NP-Hard.

Reed Debaets
fuente
1
Prolog es ciertamente un gran lenguaje para expresar los problemas requeridos, sin embargo, como usted señala: el problema ES NP-completo, si no NP-Difícil. Esto significa que Prolog puede no ser lo suficientemente rápido para una implementación práctica.
Poindexter
3
si tiene algo que ver con NP y no estaremos satisfechos con la aproximación, cualquier algoritmo determinista
apestará
1
Entonces, el objetivo es implementar heurísticas efectivas ... por ejemplo, un algoritmo simple de programación de 9 tareas tarda 3.078 s en completarse, pero con una heurística más pequeña de WindowFirst implementada, el mismo problema solo toma: 0.123s
Reed Debaets
2
JAJA, el prólogo (solo) NUNCA NUNCA RESOLVERÁ ESTO. Perdón por las letras mayúsculas, pero tuve la misma idea hace 10 o 15 años y fallé por completo. No es que fuera lento, no. ¡Simplemente no podría resolver ningún caso del mundo real;)!
Karussell
3

Trabajo en un motor de programación ampliamente utilizado que hace exactamente esto. Sí, es NP-Complete; los mejores enfoques buscan aproximarse a una solución óptima. Y, por supuesto, hay muchas formas diferentes de decir cuál es la "mejor" solución: ¿es más importante que sus profesores estén contentos con sus horarios o que los estudiantes asistan a todas sus clases, por ejemplo?

La pregunta más importante que debe resolver desde el principio es ¿qué hace que una forma de programar este sistema sea mejor que otra ? Es decir, si tengo un horario con la Sra. Jones enseñando matemáticas a las 8 y el Sr. Smith enseñando matemáticas a las 9, ¿es mejor o peor que una con ambos enseñando matemáticas a las 10? ¿Es mejor o peor que uno con la Sra. Jones enseñando a los 8 años y el Sr. Jones enseñando a los 2? ¿Por qué?

El principal consejo que daría aquí es dividir el problema tanto como sea posible, tal vez curso por curso, tal vez maestro por maestro, tal vez sala por sala, y trabajar primero en resolver el subproblema. Allí debería terminar con múltiples soluciones para elegir, y debe elegir una como la más probable. Luego, trabaje en hacer que los subproblemas "anteriores" tengan en cuenta las necesidades de los subproblemas posteriores al calificar sus posibles soluciones. Entonces, tal vez trabaje en cómo salir de situaciones arrinconadas (asumiendo que no puede anticipar esas situaciones en subproblemas anteriores) cuando llegue a un estado de "no hay soluciones válidas".

Un pase de optimización de búsqueda local se usa a menudo para "pulir" la respuesta final para obtener mejores resultados.

Tenga en cuenta que, por lo general, estamos tratando con sistemas de programación escolar con grandes limitaciones de recursos. Las escuelas no pasan el año con muchas aulas vacías o profesores sentados en el salón el 75% del día. Los enfoques que funcionan mejor en entornos ricos en soluciones no son necesariamente aplicables en la programación escolar.

Tom Dibble
fuente
2

He diseñado algoritmos comerciales tanto para el horario de clases como para el horario de exámenes. Para el primero usé programación de enteros; para el segundo, una heurística basada en maximizar una función objetivo eligiendo intercambios de tragamonedas, muy similar al proceso manual original que se había desarrollado. Lo principal para lograr la aceptación de tales soluciones es la capacidad de representar todas las limitaciones del mundo real; y que los cronometradores humanos no puedan ver formas de mejorar la solución. Al final, la parte algorítmica fue bastante sencilla y fácil de implementar en comparación con la preparación de las bases de datos, la interfaz de usuario, la capacidad de informar estadísticas como la utilización de la sala, la educación del usuario, etc.

Permaquid
fuente
1

Generalmente, la programación de restricciones es un buen enfoque para este tipo de problema de programación. Una búsqueda sobre "programación de restricciones" y programación o "programación basada en restricciones" tanto dentro del desbordamiento de pila como en Google generará algunas buenas referencias. No es imposible, es un poco difícil pensar en ello cuando se utilizan métodos de optimización tradicionales como la optimización lineal o entera. Un resultado sería: ¿existe un programa que satisfaga todos los requisitos? Eso, en sí mismo, es obviamente útil.

Buena suerte !

Grembo
fuente
1

Puedes abordarlo con algoritmos genéticos, sí. Pero no deberías :). Puede ser demasiado lento y el ajuste de parámetros puede llevar demasiado tiempo, etc.

Hay otros enfoques exitosos. Todo implementado en proyectos de código abierto:

  • Enfoque basado en restricciones
    • Implementado en UniTime (no realmente para escuelas)
    • También puede ir más allá y usar la programación Integer. Hecho con éxito en la Universidad de Udine y también en la Universidad de Bayreuth (estuve involucrado allí) utilizando el software comercial (ILOG CPLEX)
    • Enfoque basado en reglas con heuristisc: consulte el planificador Drools
  • Diferentes heurísticas: FET y la mía

Consulte aquí para obtener una lista de software de programación de horarios

Karussell
fuente
0

Creo que deberías usar un algoritmo genético porque:

También eche un vistazo a: una pregunta similar y otra

Betamoo
fuente
0

No sé que nadie estará de acuerdo con este código, pero desarrollé este código con la ayuda de mi propio algoritmo y funciona para mí en ruby.Espero que les ayude a quienes lo buscan en el siguiente código: periodflag, dayflag subjectflag y teacherflag son el hash con la identificación correspondiente y el valor de la bandera que es booleano. Cualquier problema contáctame ....... (-_-)

periodflag.each do | k2, v2 |

            if(TimetableDefinition.find(k2).period.to_i != 0)
                subjectflag.each do |k3,v3|
                    if (v3 == 0)
                        if(getflag_period(periodflag,k2))
                            @teachers=EmployeesSubject.where(subject_name: @subjects.find(k3).name, division_id: division.id).pluck(:employee_id)
                            @teacherlists=Employee.find(@teachers)
                            teacherflag=Hash[teacher_flag(@teacherlists,teacherflag,flag).to_a.shuffle] 
                            teacherflag.each do |k4,v4|
                                if(v4 == 0)
                                    if(getflag_subject(subjectflag,k3))
                                        subjectperiod=TimetableAssign.where("timetable_definition_id = ? AND subject_id = ?",k2,k3)
                                        if subjectperiod.blank?
                                            issubjectpresent=TimetableAssign.where("section_id = ? AND subject_id = ?",section.id,k3)
                                            if issubjectpresent.blank?
                                                isteacherpresent=TimetableAssign.where("section_id = ? AND employee_id = ?",section.id,k4)
                                                if isteacherpresent.blank?
                                                    @finaltt=TimetableAssign.new
                                                    @finaltt.timetable_struct_id=@timetable_struct.id
                                                    @finaltt.employee_id=k4
                                                    @finaltt.section_id=section.id
                                                    @finaltt.standard_id=standard.id
                                                    @finaltt.division_id=division.id
                                                    @finaltt.subject_id=k3
                                                    @finaltt.timetable_definition_id=k2
                                                    @finaltt.timetable_day_id=k1
                                                    set_school_id(@finaltt,current_user)
                                                    if(@finaltt.save)

                                                        setflag_sub(subjectflag,k3,1)
                                                        setflag_period(periodflag,k2,1)
                                                        setflag_teacher(teacherflag,k4,1)
                                                    end
                                                end
                                            else
                                                @subjectdetail=TimetableAssign.find_by_section_id_and_subject_id(@section.id,k3)
                                                @finaltt=TimetableAssign.new
                                                @[email protected]_struct_id
                                                @[email protected]_id
                                                @finaltt.section_id=section.id
                                                @finaltt.standard_id=standard.id
                                                @finaltt.division_id=division.id
                                                @[email protected]_id
                                                @finaltt.timetable_definition_id=k2
                                                @finaltt.timetable_day_id=k1
                                                set_school_id(@finaltt,current_user)
                                                if(@finaltt.save)

                                                    setflag_sub(subjectflag,k3,1)
                                                    setflag_period(periodflag,k2,1)
                                                    setflag_teacher(teacherflag,k4,1)
                                                end
                                            end
                                        end
                                    end
                                end
                            end
                        end
                    end
                end
            end
        end

fuente