Added CS B.S. degree requirements rule.

Added CS B.S. degree requirements rule.

;; Define templates for model classes
(import com.joshktan.advisor.model.*)
(deftemplate Course
  (declare (from-class Course)))
(deftemplate Record
  (declare (from-class Record)))
(deftemplate Advice
  (declare (from-class Advice)))

;; GLOBAL VARIABLES
(defglobal ?*total-credit-req* = (get-member com.joshktan.advisor.req.TotalCreditsRequirement TOTAL_CREDITS_REQUIRED))
(defglobal ?*lab-seq-credits* = 8)

;; GEN ED REQUIREMENTS

;; First Year Experience (F) Requirements
(defrule gen-ed-f
  "Advise student if Gen Ed First Year Experience requirements not satisfied."
  (not (Course {courseId == "UNIV 189"}))
  =>
  (assert (gen-ed-ld-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed First Year Experience requirements not satisfied" "Skills for Academic Success (UNIV 189) is required, but is not listed among courses." "ISSUE")))

;; Communication (C) Requirements
(defrule gen-ed-c
  "Advise student if Gen Ed Communication requirements not satisfied."
  (not (exists (Course {courseId == "COMM 110"})))
  (not (exists (Course {courseId == "ENGL 110"})))
  (not (exists (Course {courseId == "ENGL 120"})))
  =>
  (assert (gen-ed-ld-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed Communication requirements not satisfied" "College Composition I (ENGL 110), College Composition II (ENGL 120), and Fundamentals of Public Speaking (COMM 110) are required." "ISSUE")))

;; Quantitative Reasoning (R) Requirements
(defrule gen-ed-r
  "Advise student if Gen Ed Quantitative Reasoning requirements not satisfied."
  (not (Course {courseId == "MATH 165"}))
  =>
  (assert (gen-ed-ld-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed Quantitative Reasoning requirements not satisfied" "Calculus I (MATH 165) is required, but is not listed among courses." "ISSUE")))

;; Science & Technology (S) Requirements
;; TODO - make sure all different
(defrule gen-ed-s
  "Advise student if Gen Ed Science & Technology requirements not satisfied."
  ?totalCredits <- (accumulate (bind ?count 0)                                                ;; initializer
			       (bind ?count (+ ?count ?credits))                              ;; action
			       ?count                                                         ;; result
			       (Course (credits ?credits) (courseId ?t&:(is-gen-ed ?t "S")))) ;; CE
  (test (< ?totalCredits 10))
  =>
;;  ((System.out) println (?totalCredits toString))
  (assert (gen-ed-ld-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed Science & Technology requirements not satisfied" "At least 10 credits in the General Education Science and Technology area are required." "ISSUE")))

;; Humanities & Fine Arts (A) Requirements
;; TODO - make sure all different
(defrule gen-ed-a
  "Advise student if Gen Ed Humanities & Fine Arts requirements not satisfied."
  ?totalCredits <- (accumulate (bind ?count 0)                                                ;; initializer
			       (bind ?count (+ ?count ?credits))                              ;; action
			       ?count                                                         ;; result
			       (Course (credits ?credits) (courseId ?t&:(is-gen-ed ?t "A")))) ;; CE
  (test (< ?totalCredits 6))
  =>
  (assert (gen-ed-ld-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed Humanities & Fine Arts requirements not satisfied" "At least 6 credits in the General Education Humanities & Fine Arts area are required." "ISSUE")))

;; Social & Behavioral Sciences (B) Requirements
;; TODO - make sure all different
(defrule gen-ed-b
  "Advise student if Gen Ed Social & Behavioral Sciences requirements not satisfied."
  ?totalCredits <- (accumulate (bind ?count 0)                                                ;; initializer
			       (bind ?count (+ ?count ?credits))                              ;; action
			       ?count                                                         ;; result
			       (Course (credits ?credits) (courseId ?t&:(is-gen-ed ?t "B")))) ;; CE
  (test (< ?totalCredits 6))
  =>
  (assert (gen-ed-ld-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed Social & Behavioral Sciences requirements not satisfied" "At least 6 credits in the General Education Social & Behavioral Sciences area are required." "ISSUE")))

;; Wellness (W) Requirements
;; TODO - make sure all different
(defrule gen-ed-w
  "Advise student if Gen Ed Wellness requirements not satisfied."
  ?totalCredits <- (accumulate (bind ?count 0)                                                ;; initializer
			       (bind ?count (+ ?count ?credits))                              ;; action
			       ?count                                                         ;; result
			       (Course (credits ?credits) (courseId ?t&:(is-gen-ed ?t "W")))) ;; CE
  (test (< ?totalCredits 2))
  =>
  (assert (gen-ed-ld-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed Wellness requirements not satisfied" "At least 6 credits in the General Education Wellness area are required." "ISSUE")))

;; Cultural Diversity (D) Requirements
(defrule gen-ed-d
  "Advise student if Gen Ed Cultural Diversity requirements not satisfied."
  (not (exists (Course (courseId ?t&:(is-gen-ed ?t "D")))))
  =>
  (assert (gen-ed-ld-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed Cultural Diversity requirements not satisfied" "At least 1 course in the General Education Cultural Diversity area is required." "ISSUE")))

;; Global Perspectives (G) Requirements
(defrule gen-ed-g
  "Advise student if Gen Ed Global Perspectives requirements not satisfied."
  (not (exists (Course (courseId ?t&:(is-gen-ed ?t "G")))))
  =>
  (assert (gen-ed-ld-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed Global Perspectives requirements not satisfied" "At least 1 course in the General Education Global Perspectives area is required." "ISSUE")))

;; Gen Ed Lower Division Requirements
(defrule gen-ed-ld
  "Adivce student if Gen Ed lower division requirements are not satisfied."
  (exists (gen-ed-ld-not-satisfied))
  =>
  (assert (gen-ed-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed lower division requirements not satisfied" "See curriculum guide for details." "ISSUE")))

;; Gen Ed Upper Division Requirements
(defrule gen-ed-ud
  "Advise student if Gen Ed upper division requirements not satisfied."
  (not (exists (Course {courseId == "ENGL 321" || courseId == "ENGL 324"})))
  =>
  (assert (gen-ed-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed upper division requirements not satisfied" "Either Writing in the Technical Professions (ENGL 321) or Writing in the Sciences (ENGL 324) is required, but neither is listed among courses." "ISSUE")))

;; Gen Ed Requirements
(defrule gen-ed
  "Advise student if Gen Ed requirements not satisfied."
  (or (exists (gen-ed-ld-not-satisfied)) (exists (gen-ed-ud-not-satisfied)))
  =>
  (assert (deg-req-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed requirements not satisfied" "See curriculm guide for details." "ISSUE")))

;; One Year Lab Science Sequence Requirement
(defrule lab-sci-biol-126
  (not (exists (Course {courseId == "BIOL 126"})))
  (not (exists (Course {courseId == "BIOL 126L"})))
  (not (exists (Course {courseId == "BIOL 220"})))
  (not (exists (Course {courseId == "BIOL 220L"})))
  =>
  (assert (no-biol-126-seq)))

(defrule lab-sci-chem-121
  (not (exists (Course {courseId == "CHEM 121"})))
  (not (exists (Course {courseId == "CHEM 121L"})))
  (not (exists (Course {courseId == "CHEM 122"})))
  (not (exists (Course {courseId == "CHEM 122L"})))
  =>
  (assert (no-chem-121-seq)))

(defrule lab-sci-chem-150
  (not (exists (Course {courseId == "CHEM 150"})))
  (not (exists (Course {courseId == "CHEM 160"})))
  (not (exists (Course {courseId == "CHEM 151"})))
  (not (exists (Course {courseId == "CHEM 161"})))
  =>
  (assert (no-chem-150-seq)))

(defrule lab-sci-geol-105
  (not (exists (Course {courseId == "GEOL 105"})))
  (not (exists (Course {courseId == "GEOL 105L"})))
  (not (exists (Course {courseId == "GEOL 106"})))
  (not (exists (Course {courseId == "GEOL 106L"})))
  =>
  (assert (no-geol-105-seq)))

(defrule lab-sci-phys-211
  (not (exists (Course {courseId == "PHYS 211"})))
  (not (exists (Course {courseId == "PHYS 211L"})))
  (not (exists (Course {courseId == "PHYS 212"})))
  (not (exists (Course {courseId == "PHYS 212L"})))
  =>
  (assert (no-phys-211-seq)))

(defrule lab-sci-phys-251
  (not (exists (Course {courseId == "PHYS 251"})))
  (not (exists (Course {courseId == "PHYS 251L"})))
  (not (exists (Course {courseId == "PHYS 252"})))
  (not (exists (Course {courseId == "PHYS 252L"})))
  =>
  (bind ?*lab-seq-credits* 10)
  (assert (no-phys-251-seq)))

(defrule lab-sci-seq-req
  (no-biol-126-seq)
  (no-chem-121-seq)
  (no-chem-150-seq)
  (no-geol-105-seq)
  (no-phys-211-seq)
  (no-phys-251-seq)
  =>
  (add (new Advice "LabScienceRequirement" "Lab Science Sequence requirements not satisfied" "A one year sequence of lab science courses (with corresponding labs) is required." "ISSUE")))

;; B.S. COMPUTER SCIENCE REQUIREMENTS

;; "C" or better required for all CSCI courses
(defrule c-in-cs-course
  "Advise that will have to retake a CS course if it's a degree requirement and a D or worse received."
  (exists (Course (courseId ?cId&:(is-core ?cId))
 		  (grade "D"|"F")))
  =>
  (assert (bs-cs-degree-req-not-met))
  (add (new Advice "MajorRequirement" "Computer Science Major requirements not satisfied" "A grade of 'C' or better is required for all CSCI courses." "ISSUE")))

;; all core CSCI courses taken
(defrule core-courses-taken
  "Advise student if all core CSCI courses have not been taken."
  (not (exists (Record (studentId ?s&:(core-courses-satisfied ?s)))))
  =>
  (assert (bs-cs-degree-req-not-met))
  (add (new Advice "MajorRequirement" "Major requirements not satisfied" "All core CSCI courses have not been taken." "ISSUE")))

;; Computer Science Electives
(defrule cs-elective-req
  "Computer Science Elective requirements"
  (exists (elective-req-not-met))
  =>
  (assert (bs-cs-degree-req-not-met))
  (add (new Advice "ElectiveRequirement" "Computer Science Elective requirements not satisfied" "3 CS electives are required from at least 2 categories." "ISSUE")))

(defrule cs-elective-req-credits
  "Credit subrequirement for Computer Science Elective requirements"
  ?totalCourses <- (accumulate (bind ?count 0)
			       (bind ?count (+ ?count 1))
			       ?count
			       (Course (courseId ?cId&:(is-elective ?cId))))
  (test (< ?totalCourses 3))
  =>
  (assert (elective-req-not-met)))

(defrule cs-elective-req-cat
  "Category subrequirement for Computer Science Elective requirements"
  (not (exists (Record (studentId ?sId&:(at-least-2-elect-cat ?sId)))))
  =>
  (assert (elective-req-not-met)))

(defrule bs-cs-degree-req
  "Requirements for a B.S. in CS"
  (exists (bs-cs-degree-req-not-met))
  =>
  (add (new Advice "MajorRequirement" "Computer Science B.S. degree requirements not satisfied" "Must take all required core courses and at least 3 computer science electives." "ISSUE")))

;; RELATED REQUIRED COURSES
(defrule related-course-req
  (exists (related-course-req-not-sat))
  =>
  (add (new Advice "RelatedRequirement" "Related course requirements not satisfied." "See curriculum guide for details." "ISSUE")))

;; Related required courses (MATH and STATS)
(defrule related-course-req-math-stats
  (not (exists (Course {courseId == "MATH 166"})))
  (not (exists (Course {courseId == "STAT 367"})))
  (not (exists (Course {courseId == "STAT 368"})))
  =>
  (assert (related-course-req-not-sat))
  (add (new Advice "RelatedRequirement" "Related course requirements for mathemtatics and statistics not satisfied." "Calculus II (MATH 166), Probability (STATS 367), and Statistics (STATS 368) are required." "ISSUE")))

;; Additional Science course
(defrule related-course-req-science
  "Advise student if additional science course requiremnet not fulfilled."
  ?totalCredits <- (accumulate (bind ?count 0)                                                ;; initializer
			       (bind ?count (+ ?count ?credits))                              ;; action
			       ?count                                                         ;; result
			       (Course (credits ?credits) (courseId ?t&:(is-gen-ed ?t "S")))) ;; CE
  (test (< (- ?totalCredits ?*lab-seq-credits*) 3))
  =>
;;  ((System.out) println (?totalCredits toString))
  (assert (related-course-req-not-sat))
  (add (new Advice "RelatedRequirement" "Related course requirements for additianl science course not satisfied." "One additional science course that satisifies general education is required." "ISSUE")))

;; UNIVERSITY GRADUATION REQUIREMENTS
;; Total Degree Credits Requirement
(defrule total-credits
    "Advise to take more credits if total credit amount is less than the required amount."
    ?r <- (Record)
    =>
    (if (< ?r.totalCredits ?*total-credit-req*) then
    (assert (not-enough-credits))
    else
    (assert (enough-credits))))

(defrule not-enough-credits
    "Advise to take more credits if total credit amount is less than the required amount."
    (not-enough-credits)
    ?r <- (Record)
    =>
    (add (new Advice "TotalCreditsRequirement" "Too little credits" (str-cat "Have " ?r.totalCredits " credits, but need " ?*total-credit-req* ".") "ISSUE")))

;; CRITERA FOR GRADUATING WITH HONOR
(defrule graduate-with-honors
  ?record <- (Record {gpa >= 3.5})
  (not (exists (Course {grade == "NA"})))
  ;; TODO add other requirements here
  =>
   (assert (honors))
    (if (>= ?record.gpa 3.90) then
      (add (new Congrats "You will graduate summa cum laude."))
     elif (>= ?record.gpa 3.70) then
      (add (new Congrats "You will graduate magna cum laude."))
     else
      (add (new Congrats "You will graduate cum laude."))))

;; ---------------------------------------------------------------------- ;;

;; Just so you know how to do it
;; (defrule enough-credits-and-honors
;;   "enough credits and honors also"
;;   (and (honors) (enough-credits))
;;   =>
;;   ((System.out) println "Both enough credits and also honorable!"))

;; (# semesters left * 20 ) < (needed - already have) => advise warning: fill out form thing for +20 credits / semester (or summer school or postpone grad)

;; Graduating Honors (figure out how to chain rules: (if all courses have grades) && (all requirements fulfilled) => (add congrats)

;; COULD BE USEFUL:
;; The not CE can be used in arbitrary combination with the and and or CEs. You can define complex logical structures this way. For example, suppose you want a rule to fire once if for every fact (a ?x), there is a fact (b ?x). You could express that as
;; Jess> (defrule forall-example
;;   (not (and (a ?x) (not (b ?x))))
;;   =>)
;; i.e., "It is not true that for some ?x, there is an (a ?x) and no (b ?x)". This is actually how the the forall CE is implemented.

;; note: (instanceof <external-address> <class-name>)

;; COULD ALSO BE USEFUL
;; The logical conditional element lets you specify logical dependencies among facts. All the facts asserted on the RHS of a rule become dependent on the matches to the logical patterns on that rule's LHS. If any of the matches later become invalid, the dependent facts are retracted automatically.
;; (defrule rule-1
;;   (logical (faucet-open))
;;   =>
;;   (assert (water-flowing)))
;;   =>
;;   (assert (all-cour)))

;; Graduation with honor eligibility is determined in two steps:
;; Step One: Earn a minimum NDSU (institutional) GPA of 3.50
;; NDSU GPA's below 3.50 are not considered (and step two is not necessary)
;; Step Two: Earn an overall (cumulative) GPA of 3.50 or greater, which includes:
;; all credits and grades earned at NDSU
;; the inclusion of all transfer work and all attempts of repeated coursework
;;
;; Candidates who achieve an overall GPA of 3.50 or higher according to the criteria listed above will graduate:
;; Cum Laude — greater than or equal to 3.50 and less than 3.70
;; Magna Cum Laude — greater than or equal to 3.70 and less than 3.90
;; Summa Cum Laude — greater than or equal to 3.90 and up to 4.00
;; The complete Graduation with Honor policy may be reviewed in the online Undergraduate Bulletin
;; PLEASE BE AWARE grade-point averages are NOT rounded (for example, a GPA of 3.497 is not rounded to 3.5)
;; PLEASE BE AWARE graduation with honor levels are subject to change once final grades are determined and posted to the official academic record

;; ;; matches any
;; (defrule any
;;   (Record (studentId ?sId))
;;   =>
;;   ((System.out) println "Testing 1,2,3" ))

;; Old rule - University Graduation Requirements
;; (defrule total-credit-req
;;     "Advise to take more credits if total credit amount is less than the required amount."
;;     ?r <- (Record {totalCredits < ?*total-credit-req*})
;;     =>
;;    (assert (enough-credits))
;;     (add (new Advice "TotalCreditsRequirement" "Too little credits" (str-cat "Have " ?r.totalCredits " credits, but need " ?*total-credit-req* ".") "ISSUE")))

;; Define templates for model classes
(import com.joshktan.advisor.model.*)
(deftemplate Course
  (declare (from-class Course)))
(deftemplate Record
  (declare (from-class Record)))
(deftemplate Advice
  (declare (from-class Advice)))

;; GLOBAL VARIABLES
(defglobal ?*total-credit-req* = (get-member com.joshktan.advisor.req.TotalCreditsRequirement TOTAL_CREDITS_REQUIRED))

;; GEN ED REQUIREMENTS

;; First Year Experience (F) Requirements
(defrule gen-ed-f
  "Advise student if Gen Ed First Year Experience requirements not satisfied."
  (not (Course {courseId == "UNIV 189"}))
  =>
  (assert (gen-ed-ld-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed First Year Experience requirements not satisfied" "Skills for Academic Success (UNIV 189) is required, but is not listed among courses." "ISSUE")))

;; Communication (C) Requirements
(defrule gen-ed-c
  "Advise student if Gen Ed Communication requirements not satisfied."
  (not (exists (Course {courseId == "COMM 110"})))
  (not (exists (Course {courseId == "ENGL 110"})))
  (not (exists (Course {courseId == "ENGL 120"})))
  =>
  (assert (gen-ed-ld-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed Communication requirements not satisfied" "College Composition I (ENGL 110), College Composition II (ENGL 120), and Fundamentals of Public Speaking (COMM 110) are required." "ISSUE")))

;; Quantitative Reasoning (R) Requirements
(defrule gen-ed-r
  "Advise student if Gen Ed Quantitative Reasoning requirements not satisfied."
  (not (Course {courseId == "MATH 165"}))
  =>
  (assert (gen-ed-ld-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed Quantitative Reasoning requirements not satisfied" "Calculus I (MATH 165) is required, but is not listed among courses." "ISSUE")))

;; Science & Technology (S) Requirements
;; TODO - make sure all different
(defrule gen-ed-s
  "Advise student if Gen Ed Science & Technology requirements not satisfied."
  ?totalCredits <- (accumulate (bind ?count 0)                                                ;; initializer
			       (bind ?count (+ ?count ?credits))                              ;; action
			       ?count                                                         ;; result
			       (Course (credits ?credits) (courseId ?t&:(is-gen-ed ?t "S")))) ;; CE
  (test (< ?totalCredits 10))
  =>
;;  ((System.out) println (?totalCredits toString))
  (assert (gen-ed-ld-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed Science & Technology requirements not satisfied" "At least 10 credits in the General Education Science and Technology area are required." "ISSUE")))

;; Humanities & Fine Arts (A) Requirements
;; TODO - make sure all different
(defrule gen-ed-a
  "Advise student if Gen Ed Humanities & Fine Arts requirements not satisfied."
  ?totalCredits <- (accumulate (bind ?count 0)                                                ;; initializer
			       (bind ?count (+ ?count ?credits))                              ;; action
			       ?count                                                         ;; result
			       (Course (credits ?credits) (courseId ?t&:(is-gen-ed ?t "A")))) ;; CE
  (test (< ?totalCredits 6))
  =>
  (assert (gen-ed-ld-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed Humanities & Fine Arts requirements not satisfied" "At least 6 credits in the General Education Humanities & Fine Arts area are required." "ISSUE")))

;; Social & Behavioral Sciences (B) Requirements
;; TODO - make sure all different
(defrule gen-ed-b
  "Advise student if Gen Ed Social & Behavioral Sciences requirements not satisfied."
  ?totalCredits <- (accumulate (bind ?count 0)                                                ;; initializer
			       (bind ?count (+ ?count ?credits))                              ;; action
			       ?count                                                         ;; result
			       (Course (credits ?credits) (courseId ?t&:(is-gen-ed ?t "B")))) ;; CE
  (test (< ?totalCredits 6))
  =>
  (assert (gen-ed-ld-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed Social & Behavioral Sciences requirements not satisfied" "At least 6 credits in the General Education Social & Behavioral Sciences area are required." "ISSUE")))

;; Wellness (W) Requirements
;; TODO - make sure all different
(defrule gen-ed-w
  "Advise student if Gen Ed Wellness requirements not satisfied."
  ?totalCredits <- (accumulate (bind ?count 0)                                                ;; initializer
			       (bind ?count (+ ?count ?credits))                              ;; action
			       ?count                                                         ;; result
			       (Course (credits ?credits) (courseId ?t&:(is-gen-ed ?t "W")))) ;; CE
  (test (< ?totalCredits 2))
  =>
  (assert (gen-ed-ld-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed Wellness requirements not satisfied" "At least 6 credits in the General Education Wellness area are required." "ISSUE")))

;; Cultural Diversity (D) Requirements
(defrule gen-ed-d
  "Advise student if Gen Ed Cultural Diversity requirements not satisfied."
  (not (exists (Course (courseId ?t&:(is-gen-ed ?t "D")))))
  =>
  (assert (gen-ed-ld-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed Cultural Diversity requirements not satisfied" "At least 1 course in the General Education Cultural Diversity area is required." "ISSUE")))

;; Global Perspectives (G) Requirements
(defrule gen-ed-g
  "Advise student if Gen Ed Global Perspectives requirements not satisfied."
  (not (exists (Course (courseId ?t&:(is-gen-ed ?t "G")))))
  =>
  (assert (gen-ed-ld-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed Global Perspectives requirements not satisfied" "At least 1 course in the General Education Global Perspectives area is required." "ISSUE")))

;; Gen Ed Lower Division Requirements
(defrule gen-ed-ld
  "Adivce student if Gen Ed lower division requirements are not satisfied."
  (exists (gen-ed-ld-not-satisfied))
  =>
  (assert (gen-ed-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed lower division requirements not satisfied" "See curriculum guide for details." "ISSUE")))

;; Gen Ed Upper Division Requirements
(defrule gen-ed-ud
  "Advise student if Gen Ed upper division requirements not satisfied."
  (not (exists (Course {courseId == "ENGL 321" || courseId == "ENGL 324"})))
  =>
  (assert (gen-ed-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed upper division requirements not satisfied" "Either Writing in the Technical Professions (ENGL 321) or Writing in the Sciences (ENGL 324) is required, but neither is listed among courses." "ISSUE")))

;; Gen Ed Requirements
(defrule gen-ed
  "Advise student if Gen Ed requirements not satisfied."
  (or (exists (gen-ed-ld-not-satisfied)) (exists (gen-ed-ud-not-satisfied)))
  =>
  (assert (deg-req-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed requirements not satisfied" "See curriculm guide for details." "ISSUE")))

;; One Year Lab Science Sequence Requirement
(defrule lab-sci-biol-126
  (not (exists (Course {courseId == "BIOL 126"})))
  (not (exists (Course {courseId == "BIOL 126L"})))
  (not (exists (Course {courseId == "BIOL 220"})))
  (not (exists (Course {courseId == "BIOL 220L"})))
  =>
  (assert (no-biol-126-seq)))

(defrule lab-sci-chem-121
  (not (exists (Course {courseId == "CHEM 121"})))
  (not (exists (Course {courseId == "CHEM 121L"})))
  (not (exists (Course {courseId == "CHEM 122"})))
  (not (exists (Course {courseId == "CHEM 122L"})))
  =>
  (assert (no-chem-121-seq)))

(defrule lab-sci-chem-150
  (not (exists (Course {courseId == "CHEM 150"})))
  (not (exists (Course {courseId == "CHEM 160"})))
  (not (exists (Course {courseId == "CHEM 151"})))
  (not (exists (Course {courseId == "CHEM 161"})))
  =>
  (assert (no-chem-150-seq)))

(defrule lab-sci-geol-105
  (not (exists (Course {courseId == "GEOL 105"})))
  (not (exists (Course {courseId == "GEOL 105L"})))
  (not (exists (Course {courseId == "GEOL 106"})))
  (not (exists (Course {courseId == "GEOL 106L"})))
  =>
  (assert (no-geol-105-seq)))

(defrule lab-sci-phys-211
  (not (exists (Course {courseId == "PHYS 211"})))
  (not (exists (Course {courseId == "PHYS 211L"})))
  (not (exists (Course {courseId == "PHYS 212"})))
  (not (exists (Course {courseId == "PHYS 212L"})))
  =>
  (assert (no-phys-211-seq)))

(defrule lab-sci-phys-251
  (not (exists (Course {courseId == "PHYS 251"})))
  (not (exists (Course {courseId == "PHYS 251L"})))
  (not (exists (Course {courseId == "PHYS 252"})))
  (not (exists (Course {courseId == "PHYS 252L"})))
  =>
  (assert (no-phys-251-seq)))

(defrule lab-sci-seq-req
  (no-biol-126-seq)
  (no-chem-121-seq)
  (no-chem-150-seq)
  (no-geol-105-seq)
  (no-phys-211-seq)
  (no-phys-251-seq)
  =>
  (add (new Advice "LabScienceRequirement" "Lab Science Sequence requirements not satisfied" "A one year sequence of lab science courses (with corresponding labs) is required." "ISSUE")))

;; B.S. COMPUTER SCIENCE REQUIREMENTS

;; "C" or better required for all CSCI courses
(defrule c-in-cs-course
  "Advise that will have to retake a CS course if it's a degree requirement and a D or worse received."
  (exists (Course (courseId ?cId&:(is-core ?cId))
 		  (grade "D"|"F")))
  =>
  (add (new Advice "MajorRequirement" "Computer Science Major requirements not satisfied" "A grade of 'C' or better is required for all CSCI courses." "ISSUE")))

;; all core CSCI courses taken
(defrule core-courses-taken
  "Advise student if all core CSCI courses have not been taken."
  (not (exists (Record (studentId ?s&:(core-courses-satisfied ?s)))))
  =>
  (add (new Advice "MajorRequirement" "Major requirements not satisfied" "All core CSCI courses have not been taken." "ISSUE")))

;; Computer Science Electives
(defrule cs-elective-req
  "Computer Science Elective requirements"
  (exists (elective-req-not-met))
  =>
  (add (new Advice "ElectiveRequirement" "Computer Science Elective requirements not satisfied" "3 CS electives are required from at least 2 categories." "ISSUE")))

(defrule cs-elective-req-credits
  "Credit subrequirement for Computer Science Elective requirements"
  ?totalCourses <- (accumulate (bind ?count 0)
			       (bind ?count (+ ?count 1))
			       ?count
			       (Course (courseId ?cId&:(is-elective ?cId))))
  (test (< ?totalCourses 3))
  =>
  (assert (elective-req-not-met)))

(defrule cs-elective-req-cat
  "Category subrequirement for Computer Science Elective requirements"
  (not (exists (Record (studentId ?sId&:(at-least-2-elect-cat ?sId)))))
  =>
  (assert (elective-req-not-met)))

;; Related required courses (MATH and STATS)
(defrule related-course-req
  (not (exists (Course {courseId == "MATH 166"})))
  (not (exists (Course {courseId == "STAT 367"})))
  (not (exists (Course {courseId == "STAT 368"})))
  =>
  (add (new Advice "RelatedRequirement" "Related course requirements for mathemtatics and statistics not satisfied." "Calculus II (MATH 166), Probability (STATS 367), and Statistics (STATS 368) are required." "ISSUE")))

;; UNIVERSITY GRADUATION REQUIREMENTS
;; Total Degree Credits Requirement
(defrule total-credits
    "Advise to take more credits if total credit amount is less than the required amount."
    ?r <- (Record)
    =>
    (if (< ?r.totalCredits ?*total-credit-req*) then
    (assert (not-enough-credits))
    else
    (assert (enough-credits))))

(defrule not-enough-credits
    "Advise to take more credits if total credit amount is less than the required amount."
    (not-enough-credits)
    ?r <- (Record)
    =>
    (add (new Advice "TotalCreditsRequirement" "Too little credits" (str-cat "Have " ?r.totalCredits " credits, but need " ?*total-credit-req* ".") "ISSUE")))

;; CRITERA FOR GRADUATING WITH HONOR
(defrule graduate-with-honors
  ?record <- (Record {gpa >= 3.5})
  (not (exists (Course {grade == "NA"})))
  ;; TODO add other requirements here
  =>
   (assert (honors))
    (if (>= ?record.gpa 3.90) then
      (add (new Congrats "You will graduate summa cum laude."))
     elif (>= ?record.gpa 3.70) then
      (add (new Congrats "You will graduate magna cum laude."))
     else
      (add (new Congrats "You will graduate cum laude."))))

;; ---------------------------------------------------------------------- ;;

;; Just so you know how to do it
;; (defrule enough-credits-and-honors
;;   "enough credits and honors also"
;;   (and (honors) (enough-credits))
;;   =>
;;   ((System.out) println "Both enough credits and also honorable!"))

;; (# semesters left * 20 ) < (needed - already have) => advise warning: fill out form thing for +20 credits / semester (or summer school or postpone grad)

;; Graduating Honors (figure out how to chain rules: (if all courses have grades) && (all requirements fulfilled) => (add congrats)

;; COULD BE USEFUL:
;; The not CE can be used in arbitrary combination with the and and or CEs. You can define complex logical structures this way. For example, suppose you want a rule to fire once if for every fact (a ?x), there is a fact (b ?x). You could express that as
;; Jess> (defrule forall-example
;;   (not (and (a ?x) (not (b ?x))))
;;   =>)
;; i.e., "It is not true that for some ?x, there is an (a ?x) and no (b ?x)". This is actually how the the forall CE is implemented.

;; note: (instanceof <external-address> <class-name>)

;; COULD ALSO BE USEFUL
;; The logical conditional element lets you specify logical dependencies among facts. All the facts asserted on the RHS of a rule become dependent on the matches to the logical patterns on that rule's LHS. If any of the matches later become invalid, the dependent facts are retracted automatically.
;; (defrule rule-1
;;   (logical (faucet-open))
;;   =>
;;   (assert (water-flowing)))
;;   =>
;;   (assert (all-cour)))

;; Graduation with honor eligibility is determined in two steps:
;; Step One: Earn a minimum NDSU (institutional) GPA of 3.50
;; NDSU GPA's below 3.50 are not considered (and step two is not necessary)
;; Step Two: Earn an overall (cumulative) GPA of 3.50 or greater, which includes:
;; all credits and grades earned at NDSU
;; the inclusion of all transfer work and all attempts of repeated coursework
;;
;; Candidates who achieve an overall GPA of 3.50 or higher according to the criteria listed above will graduate:
;; Cum Laude — greater than or equal to 3.50 and less than 3.70
;; Magna Cum Laude — greater than or equal to 3.70 and less than 3.90
;; Summa Cum Laude — greater than or equal to 3.90 and up to 4.00
;; The complete Graduation with Honor policy may be reviewed in the online Undergraduate Bulletin
;; PLEASE BE AWARE grade-point averages are NOT rounded (for example, a GPA of 3.497 is not rounded to 3.5)
;; PLEASE BE AWARE graduation with honor levels are subject to change once final grades are determined and posted to the official academic record

;; ;; matches any
;; (defrule any
;;   (Record (studentId ?sId))
;;   =>
;;   ((System.out) println "Testing 1,2,3" ))

;; Old rule - University Graduation Requirements
;; (defrule total-credit-req
;;     "Advise to take more credits if total credit amount is less than the required amount."
;;     ?r <- (Record {totalCredits < ?*total-credit-req*})
;;     =>
;;    (assert (enough-credits))
;;     (add (new Advice "TotalCreditsRequirement" "Too little credits" (str-cat "Have " ?r.totalCredits " credits, but need " ?*total-credit-req* ".") "ISSUE")))


GLAPIArgumentConversion.clp: Added message handlers for code generation

;------------------------------------------------------------------------------
;Copyright (c) 2013, Joshua Scoggins
;All rights reserved.
;
;Redistribution and use in source and binary forms, with or without
;modification, are permitted provided that the following conditions are met:
;    * Redistributions of source code must retain the above copyright
;      notice, this list of conditions and the following disclaimer.
;    * Redistributions in binary form must reproduce the above copyright
;      notice, this list of conditions and the following disclaimer in the
;      documentation and/or other materials provided with the distribution.
;    * Neither the name of Joshua Scoggins nor the
;      names of its contributors may be used to endorse or promote products
;      derived from this software without specific prior written permission.
;
;THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
;ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
;WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
;DISCLAIMED. IN NO EVENT SHALL Joshua Scoggins BE LIABLE FOR ANY
;DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
;(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
;LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
;ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
;(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
;SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
;------------------------------------------------------------------------------
; GLAPIArgumentConversion.clp
;
; Written by Joshua Scoggins
;------------------------------------------------------------------------------
(defclass types::CLIPSGLAPIArgumentBuilder
  (is-a Object)
  (slot clips-type (type SYMBOL))
  (slot gl-type (type SYMBOL))
  (slot clips-function-name (type SYMBOL))
  (slot index (type INTEGER) (range 1 ?VARIABLE))
  (slot argument-name-base (type SYMBOL STRING))
  (slot data-object-argument-name (type SYMBOL STRING))
  (slot variable-argument-name (type SYMBOL STRING))
  (slot variable-declaration (type STRING))
  (slot data-object-declaration (type STRING))
  (message-handler get-type-check-code)
  (message-handler get-conversion-code))
;------------------------------------------------------------------------------
(defmessage-handler types::CLIPSGLAPIArgumentBuilder get-type-check-code ()
						  (return (format nil
												"if(EnvArgTypeCheck(theEnv,%s,%d,%s,&%s) == -1) { return; }"
												?self:clips-function-name
												?self:index
												?self:clips-type
												?self:data-object-argument-name)))
;------------------------------------------------------------------------------
(deffunction get-conversion-function (?symbol)
				 (bind ?fn-float "DOToFloat")
				 (bind ?fn-double "DOToDouble")
				 (bind ?fn-int "DOToInteger")
				 (bind ?fn-long "DOToLong")
				 (bind ?fn-string "DOToString")
				 (switch ?symbol
							(case float then ?fn-float)
							(case FLOAT then ?fn-float)
							(case Float then ?fn-float)
							(case double then ?fn-double)
							(case DOUBLE then ?fn-double)
							(case Double then ?fn-double)
							(case integer then ?fn-int)
							(case INTEGER then ?fn-int)
							(case Integer then ?fn-int)
							(case long then ?fn-long)
							(case LONG then ?fn-long)
							(case Long then ?fn-long)
							(case symbol then ?fn-string)
							(case Symbol then ?fn-string)
							(case SYMBOL then ?fn-string)
							(case string then ?fn-string)
							(case String then ?fn-string)
							(case STRING then ?fn-string)
							(default "ERROR_NO_CONVERSION_FOUND")))
;------------------------------------------------------------------------------
(defmessage-handler types::CLIPSGLAPIArgumentBuilder get-conversion-code ()
                    (return (format nil "%s = %s(%s);"
									  ?self:variable-argument-name
									  (get-conversion-function ?self:clips-type)
									  ?self:data-object-argument-name)))
;------------------------------------------------------------------------------
(defclass types::CLIPSGLAPIMultifieldArgumentBuilder
  (is-a CLIPSGLAPIArgumentBuilder)
  (slot multifield-length-variable-declaration)
  (slot multifield-length-variable-name)
  (slot multifield-pointer-argument-name)
  (slot multifield-pointer-declaration)
  (message-handler get-type-check-code)
  (message-handler get-conversion-code))
;------------------------------------------------------------------------------
(defmessage-handler types::CLIPSGLAPIMultifieldArgumentBuilder
 get-type-check-code primary ()
						  (return (format nil
												"if(EnvArgTypeCheck(theEnv,%s,%d,MULTIFIELD,&%s) == -1) { return; }"
												?self:clips-function-name
												?self:index
												?self:data-object-argument-name)))
 (
;------------------------------------------------------------------------------
(defmessage-handler types::CLIPSGLAPIMultifieldArgumentBuilder
 get-conversion-code ()
 (return (format nil "%s%n%s%n%s%n%s%n"
			 ;GetLength
			 (format nil "%s = GetDOLength(%s);"
			  				?self:multifield-length-variable-name
							?self:data-object-argument-name)
			 ;GetValue
			 (format nil "%s = GetValue(%s);"
			  ?self:multifield-pointer-argument-name
			  ?self:data-object-argument-name)
			 ;Conversion
			 ;(format nil "%
			 ;get the multifield pointer out
			)))
;------------------------------------------------------------------------------
(defclass types::CLIPSGLAPIFixedSizeMultifieldArgumentBuilder
  (is-a CLIPSGLAPIMultifieldArgumentBuilder)
  (slot multifield-size))
;------------------------------------------------------------------------------
(defrule grouping-update::construct-function-argument-builder
			?f <- (message (to grouping-update)
								(action construct-entry)
								(arguments ?arg => ?name))
			(object (is-a GLAPIArgument)
					  (id ?arg)
					  (index ?index)
					  (is-pointer FALSE))
			=>
			(make-instance ?name of CLIPSGLAPIArgumentBuilder
								(index (+ 1 ?index))
								(parent ?arg)
								(argument-name-base (sym-cat (format nil "arg%d" ?index))))
			(modify ?f (action make-variable-declaration))
			(duplicate ?f (action make-type-check-code))
			(duplicate ?f (action make-data-object-declaration))
			(duplicate ?f (action make-conversion-code)))
;------------------------------------------------------------------------------
(defrule grouping-update::construct-function-argument-builder-multifield
			?f <- (message (to grouping-update)
								(action construct-entry)
								(arguments ?arg => ?name))
			(object (is-a GLAPIArgument)
					  (id ?arg)
					  (index ?index)
					  (is-pointer TRUE))
			=>
			(make-instance ?name of CLIPSGLAPIMultifieldArgumentBuilder
								(index (+ 1 ?index))
								(parent ?arg)
								(argument-name-base (sym-cat (format nil "arg%d" ?index))))
			(modify ?f (action make-variable-declaration))
			(duplicate ?f (action make-type-check-code))
			(duplicate ?f (action make-data-object-declaration))
			(duplicate ?f (action make-multifield-conversion-code))
			(duplicate ?f (action make-conversion-code)))
;------------------------------------------------------------------------------
(defrule grouping-update::construct-function-argument-builder-multifield-fixed
			(declare (salience 1))
			?f <- (message (to grouping-update)
								(action construct-entry)
								(arguments ?arg => ?name))
			(object (is-a GLAPIFixedArrayArgument)
					  (id ?arg)
					  (index ?index)
					  (size ?size))
			=>
			(make-instance ?name of CLIPSGLAPIFixedMultifieldArgumentBuilder
								(index (+ 1 ?index))
								(parent ?arg)
								(multifield-size ?size)
								(argument-name-base (sym-cat (format nil "arg%d" ?index))))
			(modify ?f (action make-variable-declaration))
			(duplicate ?f (action make-type-check-code))
			(duplicate ?f (action make-data-object-declaration))
			(duplicate ?f (action make-multifield-conversion-code))
			(duplicate ?f (action make-conversion-code)))
;------------------------------------------------------------------------------
(defrule grouping-update::construct-multifield-conversion-code
			?f <- (message (to grouping-update)
								(action make-multifield-conversion-code)
								(arguments ?arg => ?name))
			?o <- (object (is-a CLIPSGLAPIMultifieldArgumentBuilder)
							  (id ?name)
							  (argument-name-base ?anb))
			=>
			(modify ?f (action completed-make-multifield-conversion-code))
			(bind ?baseName (sym-cat (format nil "%s_MF" ?anb)))
			(modify-instance ?o
								  (multifield-pointer-argument-name ?baseName)
								  (multifield-pointer-declaration (format nil "void* %s;" ?baseName))))
;------------------------------------------------------------------------------
(defrule grouping-update::construct-data-object-declaration
			?f <- (message (to grouping-update)
								(action make-data-object-declaration)
								(arguments ?arg => ?name))
			?ab <- (object (is-a CLIPSGLAPIArgumentBuilder)
								(id ?name)
								(argument-name-base ?anb))
			=>
			(modify ?f (action completed-data-object-declaration))
			(bind ?doArg (sym-cat (format nil "%s_DO" ?anb)))
			(modify-instance ?ab
								  (data-object-argument-name ?doArg)
								  (data-object-declaration
									 (format nil "DATA_OBJECT %s;" ?doArg))))
;------------------------------------------------------------------------------
(defrule grouping-update::construct-type-check-contents
			?fct <- (message (to grouping-update)
								  (action make-type-check-code)
								  (arguments ?arg => ?name))
			(object (is-a GLAPIArgument)
					  (id ?arg)
					  (parent ?p)
					  (argument-type ?arg-type)
					  (is-pointer FALSE))
			(object (is-a GLAPIFunction)
					  (id ?p)
					  (function-name ?fname))
			?b <- (object (is-a CLIPSGLAPIArgumentBuilder)
							  (id ?name))
			=>
			)
;------------------------------------------------------------------------------

;------------------------------------------------------------------------------
;Copyright (c) 2013, Joshua Scoggins
;All rights reserved.
;
;Redistribution and use in source and binary forms, with or without
;modification, are permitted provided that the following conditions are met:
;    * Redistributions of source code must retain the above copyright
;      notice, this list of conditions and the following disclaimer.
;    * Redistributions in binary form must reproduce the above copyright
;      notice, this list of conditions and the following disclaimer in the
;      documentation and/or other materials provided with the distribution.
;    * Neither the name of Joshua Scoggins nor the
;      names of its contributors may be used to endorse or promote products
;      derived from this software without specific prior written permission.
;
;THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
;ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
;WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
;DISCLAIMED. IN NO EVENT SHALL Joshua Scoggins BE LIABLE FOR ANY
;DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
;(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
;LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
;ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
;(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
;SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
;------------------------------------------------------------------------------
; GLAPIArgumentConversion.clp
;
; Written by Joshua Scoggins
;------------------------------------------------------------------------------
(defclass types::CLIPSGLAPIArgumentBuilder
  (is-a Object)
  (slot index (type INTEGER) (range 1 ?VARIABLE))
  (slot argument-name-base (type SYMBOL STRING))
  (slot data-object-argument-name (type SYMBOL STRING))
  (slot variable-argument-name (type SYMBOL STRING))
  (slot variable-declaration (type STRING))
  (slot data-object-declaration (type STRING))
  (slot type-check-code (type STRING))
  (slot conversion-code (type STRING)))
;------------------------------------------------------------------------------
(defclass types::CLIPSGLAPIMultifieldArgumentBuilder
  (is-a CLIPSGLAPIArgumentBuilder)
  (slot multifield-pointer-argument-name)
  (slot multifield-pointer-declaration))
;------------------------------------------------------------------------------
(defclass types::CLIPSGLAPIFixedSizeMultifieldArgumentBuilder
  (is-a CLIPSGLAPIMultifieldArgumentBuilder)
  (slot multifield-size))
;------------------------------------------------------------------------------
(defrule grouping-update::construct-function-argument-builder
			?f <- (message (to grouping-update)
								(action construct-entry)
								(arguments ?arg => ?name))
			(object (is-a GLAPIArgument)
					  (id ?arg)
					  (index ?index)
					  (is-pointer FALSE))
			=>
			(make-instance ?name of CLIPSGLAPIArgumentBuilder
								(index (+ 1 ?index))
								(parent ?arg)
								(argument-name-base (sym-cat (format nil "arg%d" ?index))))
			(modify ?f (action make-variable-declaration))
			(duplicate ?f (action make-type-check-code))
			(duplicate ?f (action make-data-object-declaration))
			(duplicate ?f (action make-conversion-code)))
;------------------------------------------------------------------------------
(defrule grouping-update::construct-function-argument-builder-multifield
			?f <- (message (to grouping-update)
								(action construct-entry)
								(arguments ?arg => ?name))
			(object (is-a GLAPIArgument)
					  (id ?arg)
					  (index ?index)
					  (is-pointer TRUE))
			=>
			(make-instance ?name of CLIPSGLAPIMultifieldArgumentBuilder
								(index (+ 1 ?index))
								(parent ?arg)
								(argument-name-base (sym-cat (format nil "arg%d" ?index))))
			(modify ?f (action make-variable-declaration))
			(duplicate ?f (action make-type-check-code))
			(duplicate ?f (action make-data-object-declaration))
			(duplicate ?f (action make-multifield-conversion-code))
			(duplicate ?f (action make-conversion-code)))
;------------------------------------------------------------------------------
(defrule grouping-update::construct-function-argument-builder-multifield-fixed
			(declare (salience 1))
			?f <- (message (to grouping-update)
								(action construct-entry)
								(arguments ?arg => ?name))
			(object (is-a GLAPIFixedArrayArgument)
					  (id ?arg)
					  (index ?index)
					  (size ?size))
			=>
			(make-instance ?name of CLIPSGLAPIFixedMultifieldArgumentBuilder
								(index (+ 1 ?index))
								(parent ?arg)
								(multifield-size ?size)
								(argument-name-base (sym-cat (format nil "arg%d" ?index))))
			(modify ?f (action make-variable-declaration))
			(duplicate ?f (action make-type-check-code))
			(duplicate ?f (action make-data-object-declaration))
			(duplicate ?f (action make-multifield-conversion-code))
			(duplicate ?f (action make-conversion-code)))
;------------------------------------------------------------------------------
(defrule grouping-update::construct-multifield-conversion-code
			?f <- (message (to grouping-update)
								(action make-multifield-conversion-code)
								(arguments ?arg => ?name))
			?o <- (object (is-a CLIPSGLAPIMultifieldArgumentBuilder)
							  (id ?name)
							  (argument-name-base ?anb))
			=>
			(modify ?f (action completed-make-multifield-conversion-code))
			(bind ?baseName (sym-cat (format nil "%s_MF" ?anb)))
			(modify-instance ?o
								  (multifield-pointer-argument-name ?baseName)
								  (multifield-pointer-declaration (format nil "void* %s;" ?baseName))))
;------------------------------------------------------------------------------
(defrule grouping-update::construct-data-object-declaration
			?f <- (message (to grouping-update)
								(action make-data-object-declaration)
								(arguments ?arg => ?name))
			?ab <- (object (is-a CLIPSGLAPIArgumentBuilder)
								(id ?name)
								(argument-name-base ?anb))
			=>
			(modify ?f (action completed-data-object-declaration))
			(bind ?doArg (sym-cat (format nil "%s_DO" ?anb)))
			(modify-instance ?ab
								  (data-object-argument-name ?doArg)
								  (data-object-declaration
									 (format nil "DATA_OBJECT %s;" ?doArg))))
;------------------------------------------------------------------------------
(defrule grouping-update::construct-type-check-code
			?fct <- (message (to grouping-update)
								  (action make-type-check-code)
								  (arguments ?arg => ?name))
			(object (is-a GLAPIArgument)
					  (id ?arg)
					  (parent ?p)
					  (argument-type ?arg-type)
					  (is-pointer FALSE))
			(object (is-a GLAPIFunction)
					  (id ?p)
					  (function-name ?fname))
			?b <- (object (is-a CLIPSGLAPIArgumentBuilder)
							  (id ?name))
			=>
			)
;------------------------------------------------------------------------------


Added rules to look for GLAPI calls

Added rules to look for GLAPI calls

;------------------------------------------------------------------------------
;Copyright (c) 2013, Joshua Scoggins
;All rights reserved.
;
;Redistribution and use in source and binary forms, with or without
;modification, are permitted provided that the following conditions are met:
;    * Redistributions of source code must retain the above copyright
;      notice, this list of conditions and the following disclaimer.
;    * Redistributions in binary form must reproduce the above copyright
;      notice, this list of conditions and the following disclaimer in the
;      documentation and/or other materials provided with the distribution.
;    * Neither the name of Joshua Scoggins nor the
;      names of its contributors may be used to endorse or promote products
;      derived from this software without specific prior written permission.
;
;THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
;ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
;WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
;DISCLAIMED. IN NO EVENT SHALL Joshua Scoggins BE LIABLE FOR ANY
;DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
;(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
;LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
;ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
;(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
;SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
;------------------------------------------------------------------------------
; GLConstantConversion.clp - an expert system that reads a define and generates
; conversion code for it.
;------------------------------------------------------------------------------
(defclass opened-file
  (is-a USER)
  (slot id)
  (slot index (type INTEGER) (range 0 ?VARIABLE))
  (message-handler next-index)
  (message-handler read-line)
  (message-handler close-file))
;------------------------------------------------------------------------------
(defmessage-handler opened-file next-index ()
                    (bind ?old ?self:index)
                    (bind ?self:index (+ ?old 1))
                    (return ?old))
;------------------------------------------------------------------------------
(defmessage-handler opened-file read-line ()
                    (readline ?self:id))
;------------------------------------------------------------------------------
(defmessage-handler opened-file close-file ()
                    (close ?self:id))
;------------------------------------------------------------------------------
(deftemplate file-line
             (slot index)
             (slot parent)
             (slot type)
             (multifield contents))
;------------------------------------------------------------------------------
; INPUT FACT FORM: (parse constant file ?path)
;------------------------------------------------------------------------------
(deffunction get-input-form-factor ()
             (printout t "(parse constant file ?path)" crlf))
;------------------------------------------------------------------------------
(defrule open-target-file
         "This rule takes a fact of the above INPUT FORM and attempts to open the file"
         ?fct <- (parse constant file ?path)
         =>
         (bind ?name (gensym*))
         (retract ?fct)
         (if (open ?path ?name "r") then
           (make-instance of opened-file (id ?name) (index 0))
           (assert (read file ?name))
           else
           (printout t "ERROR: target file at " ?path " does not exist!" crlf
                     "Halting!" crlf)
           (halt)))
;------------------------------------------------------------------------------
(defrule build-file-line
         ?fct <- (read file ?fid)
         ?obj <- (object (is-a opened-file)
                         (id ?fid))
         =>
         (retract ?fct)
         (bind ?result (send ?obj read-line))
         (if (neq ?result EOF) then
           (assert (read file ?fid)
                   (file-line (index (send ?obj next-index))
                              (type UNKNOWN)
                              (parent ?fid)
                              (contents (explode$ ?result))))
           else
           (send ?obj close-file)
           (unmake-instance ?obj)))
;------------------------------------------------------------------------------
;(defrule retract-unknowns
; (declare (salience -10))
; ?f <- (file-line (type UNKNOWN))
; =>
; (retract ?f))
;------------------------------------------------------------------------------
(defrule mark-heading-groups
         "Tags lines that consist of /* $? */ as group headings"
         ?f <- (file-line (type UNKNOWN)
                          (contents /* $? */))
         =>
         (modify ?f (type heading)))
;------------------------------------------------------------------------------
(defrule mark-entry-line
         "Tags lines that are defines and modifies the associated contents"
         ?f <- (file-line (type UNKNOWN)
                          (contents #define ?name ?))
         =>
         (modify ?f (type #define) (contents ?name)))
;------------------------------------------------------------------------------
(defrule merge-three-line-headers
         "Merges simple three line headings into one rule"
         ?f0 <- (file-line (index ?i)
                           (type UNKNOWN)
                           (contents /*))
         ?f1 <- (file-line (index ?i2&:(= ?i2 (+ ?i 1)))
                           (type UNKNOWN)
                           (contents $?c))
         ?f2 <- (file-line (index ?i3&:(= ?i3 (+ ?i 2)))
                           (type UNKNOWN)
                           (contents */))
         =>
         (retract ?f1 ?f2)
         (modify ?f0 (contents /* $?c */)))
;------------------------------------------------------------------------------
(defrule mark-glapi-calls
         "marks glapi calls"
         ?f <- (file-line (type UNKNOWN)
                          (contents GLAPI $? "(" $? ")"))
         =>
         (modify ?f (type GLAPI-DEF)))
;------------------------------------------------------------------------------
(defrule merge-potential-glapi-calls
         "Merges the next line of a GLAPI call if the line doesn't end with )"
         (declare (salience -1))
         ?f <- (file-line (type UNKNOWN)
                          (contents GLAPI $?vals "(" $?c)
                          (index ?i))
         (test (not (member$ ")" $?c)))
         ?f0 <- (file-line (index ?i0&:(= ?i0 (+ ?i 1)))
                           (type UNKNOWN)
                           (contents $?contents))
         =>
         (retract ?f)
         (modify ?f0 (contents GLAPI $?vals "(" $?c $?contents)))
;------------------------------------------------------------------------------


Gen Ed lower division requirements rule implemented.

;; Define templates for model classes
(import com.joshktan.advisor.model.*)
(deftemplate Course
  (declare (from-class Course)))
(deftemplate Record
  (declare (from-class Record)))
(deftemplate Advice
  (declare (from-class Advice)))

;; GLOBAL VARIABLES
(defglobal ?*total-credit-req* = (get-member com.joshktan.advisor.req.TotalCreditsRequirement TOTAL_CREDITS_REQUIRED))

;; GEN ED REQUIREMENTS

;; First Year Experience (F) Requirements
(defrule gen-ed-f
  "Advise student if Gen Ed First Year Experience requirements not satisfied."
  (not (Course {title == "UNIV 189"}))
  =>
  (assert (gen-ed-f-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed First Year Experience requirements not satisfied" "Skills for Academic Success (UNIV 189) is required, but is not listed among courses." "ISSUE")))

;; Communication (C) Requirements
(defrule gen-ed-c
  "Advise student if Gen Ed Communication requirements not satisfied."
  (not (exists (Course {title == "COMM 110"})))
  (not (exists (Course {title == "ENGL 110"})))
  (not (exists (Course {title == "ENGL 120"})))
  =>
  (assert (gen-ed-c-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed Communication requirements not satisfied" "College Composition I (ENGL 110), College Composition II (ENGL 120), and Fundamentals of Public Speaking (COMM 110) are required." "ISSUE")))

;; Quantitative Reasoning (R) Requirements
(defrule gen-ed-r
  "Advise student if Gen Ed Quantitative Reasoning requirements not satisfied."
  (not (Course {title == "MATH 165"}))
  =>
  (assert (gen-ed-r-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed Quantitative Reasoning requirements not satisfied" "Calculus I (MATH 165) is required, but is not listed among courses." "ISSUE")))

;; Science & Technology (S) Requirements
;; TODO - make sure all different
(defrule gen-ed-s
  "Advise student if Gen Ed Science & Technology requirements not satisfied."
  ?totalCredits <- (accumulate (bind ?count 0)                                                ;; initializer
			       (bind ?count (+ ?count ?credits))                              ;; action
			       ?count                                                         ;; result
			       (Course (credits ?credits) (courseId ?t&:(is-gen-ed ?t "S")))) ;; CE
  (test (< ?totalCredits 10))
  =>
;;  ((System.out) println (?totalCredits toString))
  (assert (gen-ed-s-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed Science & Technology requirements not satisfied" "At least 10 credits in the General Education Science and Technology area are required." "ISSUE")))

;; Humanities & Fine Arts (A) Requirements
;; TODO - make sure all different
(defrule gen-ed-a
  "Advise student if Gen Ed Humanities & Fine Arts requirements not satisfied."
  ?totalCredits <- (accumulate (bind ?count 0)                                                ;; initializer
			       (bind ?count (+ ?count ?credits))                              ;; action
			       ?count                                                         ;; result
			       (Course (credits ?credits) (courseId ?t&:(is-gen-ed ?t "A")))) ;; CE
  (test (< ?totalCredits 6))
  =>
  (assert (gen-ed-a-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed Humanities & Fine Arts requirements not satisfied" "At least 6 credits in the General Education Humanities & Fine Arts area are required." "ISSUE")))

;; Social & Behavioral Sciences (B) Requirements
;; TODO - make sure all different
(defrule gen-ed-b
  "Advise student if Gen Ed Social & Behavioral Sciences requirements not satisfied."
  ?totalCredits <- (accumulate (bind ?count 0)                                                ;; initializer
			       (bind ?count (+ ?count ?credits))                              ;; action
			       ?count                                                         ;; result
			       (Course (credits ?credits) (courseId ?t&:(is-gen-ed ?t "B")))) ;; CE
  (test (< ?totalCredits 6))
  =>
  (assert (gen-ed-b-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed Social & Behavioral Sciences requirements not satisfied" "At least 6 credits in the General Education Social & Behavioral Sciences area are required." "ISSUE")))

;; Wellness (W) Requirements
;; TODO - make sure all different
(defrule gen-ed-w
  "Advise student if Gen Ed Wellness requirements not satisfied."
  ?totalCredits <- (accumulate (bind ?count 0)                                                ;; initializer
			       (bind ?count (+ ?count ?credits))                              ;; action
			       ?count                                                         ;; result
			       (Course (credits ?credits) (courseId ?t&:(is-gen-ed ?t "W")))) ;; CE
  (test (< ?totalCredits 2))
  =>
  (assert (gen-ed-w-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed Wellness requirements not satisfied" "At least 6 credits in the General Education Wellness area are required." "ISSUE")))

;; Cultural Diversity (D) Requirements
(defrule gen-ed-d
  "Advise student if Gen Ed Cultural Diversity requirements not satisfied."
  (not (exists (Course (courseId ?t&:(is-gen-ed ?t "D")))))
  =>
  (assert (gen-ed-w-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed Cultural Diversity requirements not satisfied" "At least 1 course in the General Education Cultural Diversity area is required." "ISSUE")))

;; Global Perspectives (G) Requirements
(defrule gen-ed-g
  "Advise student if Gen Ed Global Perspectives requirements not satisfied."
  (not (exists (Course (courseId ?t&:(is-gen-ed ?t "G")))))
  =>
  (assert (gen-ed-g-not-satisfied))
  (add (new Advice "GenEdRequirement" "Gen Ed Global Perspectives requirements not satisfied" "At least 1 course in the General Education Global Perspectives area is required." "ISSUE")))

;; Gen Ed Lower Division Requirements
(defrule gen-ed-ld
  "Adivce student if Gen Ed lower division requirements are not satisfied."
  (or (gen-ed-f-not-satisfied)
      (gen-ed-c-not-satisfied)
      (gen-ed-r-not-satisfied)
      (gen-ed-s-not-satisfied)
      (gen-ed-a-not-satisfied)
      (gen-ed-b-not-satisfied)
      (gen-ed-w-not-satisfied)
      (gen-ed-d-not-satisfied)
      (gen-ed-g-not-satisfied))
  =>
  (add (new Advice "GenEdRequirement" "Gen Ed lower division requirements not satisfied" "See curriculum guide for details." "ISSUE")))

;; UNIVERSITY GRADUATION REQUIREMENTS
;; Total Degree Credits Requirement
(defrule total-credits
    "Advise to take more credits if total credit amount is less than the required amount."
    ?r <- (Record)
    =>
    (if (< ?r.totalCredits ?*total-credit-req*) then
    (assert (not-enough-credits))
    else
    (assert (enough-credits))))
(defrule not-enough-credits
    "Advise to take more credits if total credit amount is less than the required amount."
    (not-enough-credits)
    ?r <- (Record)
    =>
    (add (new Advice "TotalCreditsRequirement" "Too little credits" (str-cat "Have " ?r.totalCredits " credits, but need " ?*total-credit-req* ".") "ISSUE")))

;; CRITERA FOR GRADUATING WITH HONOR
(defrule graduate-with-honors
  ?record <- (Record {gpa >= 3.5})
  (not (exists (Course {grade == "NA"})))
  ;; TODO add other requirements here
  =>
   (assert (honors))
    (if (>= ?record.gpa 3.90) then
      (add (new Congrats "You will graduate summa cum laude."))
     elif (>= ?record.gpa 3.70) then
      (add (new Congrats "You will graduate magna cum laude."))
     else
      (add (new Congrats "You will graduate cum laude."))))

;; ---------------------------------------------------------------------- ;;

;; Just so you know how to do it
;; (defrule enough-credits-and-honors
;;   "enough credits and honors also"
;;   (and (honors) (enough-credits))
;;   =>
;;   ((System.out) println "Both enough credits and also honorable!"))

;; (# semesters left * 20 ) < (needed - already have) => advise warning: fill out form thing for +20 credits / semester (or summer school or postpone grad)

;; Graduating Honors (figure out how to chain rules: (if all courses have grades) && (all requirements fulfilled) => (add congrats)

;; COULD BE USEFUL:
;; The not CE can be used in arbitrary combination with the and and or CEs. You can define complex logical structures this way. For example, suppose you want a rule to fire once if for every fact (a ?x), there is a fact (b ?x). You could express that as
;; Jess> (defrule forall-example
;;   (not (and (a ?x) (not (b ?x))))
;;   =>)
;; i.e., "It is not true that for some ?x, there is an (a ?x) and no (b ?x)". This is actually how the the forall CE is implemented.

;; note: (instanceof <external-address> <class-name>)

;; COULD ALSO BE USEFUL
;; The logical conditional element lets you specify logical dependencies among facts. All the facts asserted on the RHS of a rule become dependent on the matches to the logical patterns on that rule's LHS. If any of the matches later become invalid, the dependent facts are retracted automatically.
;; (defrule rule-1
;;   (logical (faucet-open))
;;   =>
;;   (assert (water-flowing)))
;;   =>
;;   (assert (all-cour)))

;; Graduation with honor eligibility is determined in two steps:
;; Step One: Earn a minimum NDSU (institutional) GPA of 3.50
;; NDSU GPA's below 3.50 are not considered (and step two is not necessary)
;; Step Two: Earn an overall (cumulative) GPA of 3.50 or greater, which includes:
;; all credits and grades earned at NDSU
;; the inclusion of all transfer work and all attempts of repeated coursework
;;
;; Candidates who achieve an overall GPA of 3.50 or higher according to the criteria listed above will graduate:
;; Cum Laude — greater than or equal to 3.50 and less than 3.70
;; Magna Cum Laude — greater than or equal to 3.70 and less than 3.90
;; Summa Cum Laude — greater than or equal to 3.90 and up to 4.00
;; The complete Graduation with Honor policy may be reviewed in the online Undergraduate Bulletin
;; PLEASE BE AWARE grade-point averages are NOT rounded (for example, a GPA of 3.497 is not rounded to 3.5)
;; PLEASE BE AWARE graduation with honor levels are subject to change once final grades are determined and posted to the official academic record

;; ;; matches any
;; (defrule any
;;   (Record (studentId ?sId))
;;   =>
;;   ((System.out) println "Testing 1,2,3" ))

;; Old rule - University Graduation Requirements
;; (defrule total-credit-req
;;     "Advise to take more credits if total credit amount is less than the required amount."
;;     ?r <- (Record {totalCredits < ?*total-credit-req*})
;;     =>
;;    (assert (enough-credits))
;;     (add (new Advice "TotalCreditsRequirement" "Too little credits" (str-cat "Have " ?r.totalCredits " credits, but need " ?*total-credit-req* ".") "ISSUE")))

;; Define templates for model classes
(import com.joshktan.advisor.model.*)
(deftemplate Course
  (declare (from-class Course)))
(deftemplate Record
  (declare (from-class Record)))
(deftemplate Advice
  (declare (from-class Advice)))

;; GLOBAL VARIABLES
(defglobal ?*total-credit-req* = (get-member com.joshktan.advisor.req.TotalCreditsRequirement TOTAL_CREDITS_REQUIRED))

;; GEN ED REQUIREMENTS
;; First Year Experience (F) Requirements
(defrule gen-ed-f
  "Advise student if Gen Ed First Year Experience requirements not satisfied."
  (not (Course {title == "UNIV 189"}))
  =>
  (add (new Advice "GenEdRequirement" "Gen Ed First Year Experience requirements not satisfied" "Skills for Academic Success (UNIV 189) is required, but is not listed among courses." "ISSUE")))
;; Communication (C) Requirements
(defrule gen-ed-c
  "Advise student if Gen Ed Communication requirements not satisfied."
  ;; (and (not (exists (Course {title == "COMM 110"}))) (not (exists (GradedCourse {title == "COMM 110"}))))
  ;; (and (not (exists (Course {title == "ENGL 110"}))) (not (exists (GradedCourse {title == "ENGL 110"}))))
  ;; (and (not (exists (Course {title == "ENGL 120"}))) (not (exists (GradedCourse {title == "ENGL 120"}))))
  (not (exists (Course {title == "COMM 110"})))
  (not (exists (Course {title == "ENGL 110"})))
  (not (exists (Course {title == "ENGL 120"})))
  =>
  (add (new Advice "GenEdRequirement" "Gen Ed Communication requirements not satisfied" "College Composition I (ENGL 110), College Composition II (ENGL 120), and Fundamentals of Public Speaking (COMM 110) are required." "ISSUE")))
;; Quantitative Reasoning (R) Requirements
(defrule gen-ed-r
  "Advise student if Gen Ed Quantitative Reasoning requirements not satisfied."
  (not (Course {title == "MATH 165"}))
  =>
  (add (new Advice "GenEdRequirement" "Gen Ed Quantitative Reasoning requirements not satisfied" "Calculus I (MATH 165) is required, but is not listed among courses." "ISSUE")))
;; Science & Technology (S) Requirements
;; TODO - make sure all different
(defrule gen-ed-s
  "Advise student if Gen Ed Science & Technology requirements not satisfied."
  ?totalCredits <- (accumulate (bind ?count 0)                                                ;; initializer
			       (bind ?count (+ ?count ?credits))                              ;; action
			       ?count                                                         ;; result
			       (Course (credits ?credits) (courseId ?t&:(is-gen-ed ?t "S")))) ;; CE
  (test (< ?totalCredits 10))
  =>
;;  ((System.out) println (?totalCredits toString))
  (add (new Advice "GenEdRequirement" "Gen Ed Science & Technology requirements not satisfied" "At least 10 credits in the General Education Science and Technology area are required." "ISSUE")))

;; UNIVERSITY GRADUATION REQUIREMENTS
;; Total Degree Credits Requirement
(defrule total-credits
    "Advise to take more credits if total credit amount is less than the required amount."
    ?r <- (Record)
    =>
    (if (< ?r.totalCredits ?*total-credit-req*) then
    (assert (not-enough-credits))
    else
    (assert (enough-credits))))
(defrule not-enough-credits
    "Advise to take more credits if total credit amount is less than the required amount."
    (not-enough-credits)
    ?r <- (Record)
    =>
    (add (new Advice "TotalCreditsRequirement" "Too little credits" (str-cat "Have " ?r.totalCredits " credits, but need " ?*total-credit-req* ".") "ISSUE")))

;; CRITERA FOR GRADUATING WITH HONOR
(defrule graduate-with-honors
  ?record <- (Record {gpa >= 3.5})
;;  (not (exists ((Course {grade != "NA"}))))
  (not (exists (Course {grade == "NA"})))
;;	  ( ?course "GradedCourse"))
  ;; TODO add other requirements here
  =>
   (assert (honors))
    (if (>= ?record.gpa 3.90) then
      (add (new Congrats "You will graduate summa cum laude."))
     elif (>= ?record.gpa 3.70) then
      (add (new Congrats "You will graduate magna cum laude."))
     else
      (add (new Congrats "You will graduate cum laude."))))

;; ---------------------------------------------------------------------- ;;

;; Just so you know how to do it
;; (defrule enough-credits-and-honors
;;   "enough credits and honors also"
;;   (and (honors) (enough-credits))
;;   =>
;;   ((System.out) println "Both enough credits and also honorable!"))

;; (# semesters left * 20 ) < (needed - already have) => advise warning: fill out form thing for +20 credits / semester (or summer school or postpone grad)

;; Graduating Honors (figure out how to chain rules: (if all courses have grades) && (all requirements fulfilled) => (add congrats)

;; COULD BE USEFUL:
;; The not CE can be used in arbitrary combination with the and and or CEs. You can define complex logical structures this way. For example, suppose you want a rule to fire once if for every fact (a ?x), there is a fact (b ?x). You could express that as
;; Jess> (defrule forall-example
;;   (not (and (a ?x) (not (b ?x))))
;;   =>)
;; i.e., "It is not true that for some ?x, there is an (a ?x) and no (b ?x)". This is actually how the the forall CE is implemented.

;; note: (instanceof <external-address> <class-name>)

;; COULD ALSO BE USEFUL
;; The logical conditional element lets you specify logical dependencies among facts. All the facts asserted on the RHS of a rule become dependent on the matches to the logical patterns on that rule's LHS. If any of the matches later become invalid, the dependent facts are retracted automatically.
;; (defrule rule-1
;;   (logical (faucet-open))
;;   =>
;;   (assert (water-flowing)))
;;   =>
;;   (assert (all-cour)))

;; Graduation with honor eligibility is determined in two steps:
;; Step One: Earn a minimum NDSU (institutional) GPA of 3.50
;; NDSU GPA's below 3.50 are not considered (and step two is not necessary)
;; Step Two: Earn an overall (cumulative) GPA of 3.50 or greater, which includes:
;; all credits and grades earned at NDSU
;; the inclusion of all transfer work and all attempts of repeated coursework
;;
;; Candidates who achieve an overall GPA of 3.50 or higher according to the criteria listed above will graduate:
;; Cum Laude — greater than or equal to 3.50 and less than 3.70
;; Magna Cum Laude — greater than or equal to 3.70 and less than 3.90
;; Summa Cum Laude — greater than or equal to 3.90 and up to 4.00
;; The complete Graduation with Honor policy may be reviewed in the online Undergraduate Bulletin
;; PLEASE BE AWARE grade-point averages are NOT rounded (for example, a GPA of 3.497 is not rounded to 3.5)
;; PLEASE BE AWARE graduation with honor levels are subject to change once final grades are determined and posted to the official academic record

;; ;; matches any
;; (defrule any
;;   (Record (studentId ?sId))
;;   =>
;;   ((System.out) println "Testing 1,2,3" ))

;; Old rule - University Graduation Requirements
;; (defrule total-credit-req
;;     "Advise to take more credits if total credit amount is less than the required amount."
;;     ?r <- (Record {totalCredits < ?*total-credit-req*})
;;     =>
;;    (assert (enough-credits))
;;     (add (new Advice "TotalCreditsRequirement" "Too little credits" (str-cat "Have " ?r.totalCredits " credits, but need " ?*total-credit-req* ".") "ISSUE")))