def two_exams_in_a_day_constraint(schedule, periods, exams):
    """Returns penalty

    In the case where there are three periods or more in a day, count the number of occurrences of students having 
    two exams in a day which are not directly adjacent, i.e. not back to back, and multiply this by the ' two in a 
    day' weighting provided within the 'Institutional Model Index'.
    """
    period_to_exam = get_period_to_exam_mapping(schedule, exams, periods)
    violations = 0
    for first_period in range(len(periods)):
        for second_period in range(first_period + 2, len(periods)):
            if periods[first_period].date == periods[second_period].date:
                intersect = student_intersection(period_to_exam[first_period], period_to_exam[second_period])
                violations += len(intersect)
    return violations
def two_exams_in_a_row_constraint(schedule, periods, exams):
    """Returns penalty

    Count the number of occurrences where two examinations are taken by students straight after one another i.e. back 
    to back. Once this has been established, the number of students involved in each occurance should be added and 
    multiplied by the number provided in the �two in a row' weighting within the �Institutional Model Index'.
    """
    period_to_exam = get_period_to_exam_mapping(schedule, exams, periods)
    periods_idx = range(len(periods))
    violations = 0
    for first_period, second_period in zip(periods_idx[:-1], periods_idx[1:]):
        if first_period in period_to_exam and second_period in period_to_exam and periods[first_period].date == periods[
            second_period].date:
            intersect = student_intersection(period_to_exam[first_period], period_to_exam[second_period])
            violations += len(intersect)
    return violations