Scheduling algorithm in Racket (ASL)

170 Views Asked by At

I need to blend aspects of an arbitrary arity tree with generative recursion and backtracking in order to come up with a simple valid schedule.

So far I have two structures, one that identifies the individual with her availability slots and maximum number of slots that she can work: (define-struct ta [name max avail]) and an assignment structure as an ordered pair: (define-struct assignment [ta slot]) where slot is simply a natural number. So for instance I have the following unit tests with the following dummies:

(define SOBA (make-ta "Soba" 2 (list 1 3)))
(define UDON (make-ta "Udon" 1 (list 3 4)))
(define RAMEN (make-ta "Ramen" 1 (list 2)))

(define NOODLE-TAs (list SOBA UDON RAMEN))
(check-expect (schedule-tas empty empty) empty)
(check-expect (schedule-tas empty (list 1 2)) false)
(check-expect (schedule-tas (list SOBA) empty) empty) 
(check-expect (schedule-tas NOODLE-TAs (list 1 2 3 4)) 
              (list
               (make-assignment UDON 4)
               (make-assignment SOBA 3)
               (make-assignment RAMEN 2)
               (make-assignment SOBA 1)))

So my main function right now looks like this:

;; (listof TA) (listof Slot) -> Schedule or false
;; produces valid schedule given TAs and Slots; false if impossible;
;; Schedule is (listof Assignment), Assigment is (make-assignment TA Slot)
(define (schedule-tas tas slots)
  (local [(define (fn-for-tas tas)
            (cond [(empty? slots) empty]
                  [(and (empty? tas)(cons? slots)) #f]                    ;From two 'One-Of' type analysis
                  [else
                   (if (all-assigned? (next-assignments tas slots) slots) ;Generative-recursion through 'next-assignments'   
                       (next-assignments tas slots)                       ;I know about the duplication of the computation here.
                       (fn-for-loa (next-assignments tas slots)))]))      ;just waiting to have a working version before I make it less readable

          (define (fn-for-loa loa)
            (cond [(empty? loa) #f]
                  [else
                   (local [(define try (fn-for-tas (first loa)))]
                     (if (not (false? try))
                         try
                         (fn-for-loa (rest loa))))]))]
    (fn-for-tas tas)))

So to produce the data through generative recursion I wished for (next-assignments tas slots) as a composition of what I need: make all assignments and filter by availabity and maximum number of workable slots:

;; (listof TA) (listof Slot) -> (listof Assignment)
;; creates next list of possible valid assignments
(define (next-assignments tas slots)
  (filter-by-max (filter-by-availability (all-assignments tas slots))))
(define (all-assignments tas slots)
  (local [(define (assign-ta ta)
            (map (λ (s) (make-assignment ta s)) slots))

          (define (all-assignments tas)
            (cond [(empty? tas) empty]
                  [else
                   (append (assign-ta (first tas))
                           (all-assignments (rest tas)))]))]
    (all-assignments tas)))

However I am not convinced that this is what I need since it rather creating the whole searchable space in one go instead of the branch-and-prune strategy that I need to implement. Anyways, the rest of the auxiliary functions are here, for completeness:

(define (filter-by-availability loa)
  (cond [(empty? loa) empty]
        [else
         (if (member? (assignment-slot (first loa))
                      (ta-avail (assignment-ta (first loa))))
             (cons (first loa) (filter-by-availability (rest loa)))    
             (filter-by-availability (rest loa)))]))

(define (filter-by-max loa)
  (cond [(empty? loa) empty]
        [else
         (if (> (length loa) (ta-max (assignment-ta (first loa))))
             (filter-by-max (rest loa))
             loa)]))

I am also not very happy with these filtering functions as they seem too 'dumb' somehow; they just drop whichever ta they happen to find in order to satisfy the conditions.

And finally, I have the base case of the generative recursion:

(define (all-assigned? loa slots)
  (= (length loa)
     (length slots)))

which is somehow the 'dumbest' one of all, I think. Anyways, as you can see I am not happy with my code. But the main problem that I see with it is, again, that I don't think I am generating a bone-fide tree. So if you could just let know how to do that I would be immensely grateful!

N.B. This is for a course I am taking but I think you can tell that I have really tried. Please help!

0

There are 0 best solutions below