source: trunk/src/json/isidorus-json/json_tmcl_validation.lisp

Last change on this file was 429, checked in by lgiessmann, 14 years ago

json: moved the json module to json/isidorus-json; added the module json/JTM; added all initila files needed by the JTM module

File size: 23.2 KB
Line 
1;;+-----------------------------------------------------------------------------
2;;+  Isidorus
3;;+  (c) 2008-2010 Marc Kuester, Christoph Ludwig, Lukas Georgieff
4;;+
5;;+  Isidorus is freely distributable under the LLGPL license.
6;;+  You can find a detailed description in trunk/docs/LLGPL-LICENSE.txt and
7;;+  trunk/docs/LGPL-LICENSE.txt.
8;;+-----------------------------------------------------------------------------
9
10(defpackage :json-tmcl
11  (:use :cl :datamodel :constants :json-tmcl-constants :json-importer :base-tools)
12  (:export :get-constraints-of-fragment
13           :topictype-p
14           :abstract-p
15           :valid-instance-p
16           :list-subtypes))
17
18
19(in-package :json-tmcl)
20
21
22(defun abstract-p (topic-instance &key (revision *TM-REVISION*))
23  "Returns t if this topic type is an abstract topic type."
24  (declare (type (or integer null) revision)
25           (TopicC topic-instance))
26  (let ((constraint-role (get-item-by-psi *constraint-role-psi* :revision revision))
27        (topictype-role (get-item-by-psi *topictype-role-psi* :revision revision))
28        (applies-to (get-item-by-psi *applies-to-psi* :revision revision))
29        (abstract-topictype-constraint
30         (get-item-by-psi *abstract-topictype-constraint-psi* :revision revision)))
31    (loop for role in (player-in-roles topic-instance :revision revision)
32       when (and (eq topictype-role (instance-of role :revision revision))
33                 (eq applies-to (instance-of (parent role :revision revision)
34                                             :revision revision)))
35       return (loop for other-role in (roles (parent role :revision revision)
36                                             :revision revision)
37                 when (and (eq constraint-role (instance-of other-role
38                                                            :revision revision))
39                           (topictype-of-p (player other-role :revision revision)
40                                           abstract-topictype-constraint nil nil
41                                           nil revision))
42                 return t))))
43
44
45(defun topictype-of-p (topic-instance type-instance &optional
46                       (topictype (get-item-by-psi *topictype-psi* :revision 0))
47                       (topictype-constraint (is-type-constrained :revision 0))
48                       checked-topics (revision *TM-REVISION*))
49  "Returns a list of all types and supertypes of this topic if this topic is a
50   valid instance-topic of the type-topic called type-instance. TMCL 4.4.2.
51   When the type-instance is set to nil there will be checked only if the
52   topic-instance is a valid instance."
53  (declare (type (or integer null) revision)
54           (TopicC topic-instance)
55           (type (or TopicC null) topictype-constraint)
56           (list checked-topics))
57  (let ((current-checked-topics (append checked-topics (list topic-instance)))
58        (isas-of-this (get-direct-types-of-topic topic-instance :revision revision))
59        (akos-of-this (get-direct-supertypes-of-topic topic-instance
60                                                      :revision revision)))
61    (when (eq topic-instance topictype)
62      t)
63    (when (and (not isas-of-this)
64               (not akos-of-this))
65      (return-from topictype-of-p nil))
66    (loop for isa-of-this in isas-of-this
67       do (let ((found-topics
68                 (topictype-p isa-of-this topictype topictype-constraint nil revision)))
69            (when (not found-topics)
70              (return-from topictype-of-p nil))
71            (dolist (item found-topics)
72              (pushnew item current-checked-topics))))
73    (loop for ako-of-this in akos-of-this
74       when (not (find ako-of-this current-checked-topics :test #'eq))
75       do (let ((found-topics
76                 (topictype-of-p ako-of-this type-instance topictype
77                                 topictype-constraint current-checked-topics
78                                 revision)))
79            (when (not found-topics)
80              (return-from topictype-of-p nil))
81            (dolist (item found-topics)
82              (pushnew item current-checked-topics))))
83    (if type-instance
84        (when (find type-instance current-checked-topics)
85          current-checked-topics)
86        current-checked-topics)))
87
88
89(defun topictype-p (topic-instance &optional
90                    (topictype (get-item-by-psi *topictype-psi* :revision 0))
91                    (topictype-constraint (is-type-constrained :revision 0))
92                    (checked-topics nil) (revision *TM-REVISION*))
93  "Returns a list of all instanceOf-topics and all Supertypes of this topic
94   if this topic is a valid topic (-type). I.e. the passed topic is the
95   topictype or it is an instanceOf of the topictype or it is a subtype of
96   the topictype. TMDM 7.2 + TMDM 7.3"
97  (declare (type (or integer null) revision)
98           (type (or TopicC null) topictype topic-instance)
99           (list checked-topics))
100  (let ((current-checked-topics (append checked-topics (list topic-instance)))
101        (akos-of-this (get-direct-supertypes-of-topic topic-instance
102                                                      :revision revision))
103        (isas-of-this (get-direct-types-of-topic topic-instance :revision revision)))
104    (when (eq topictype topic-instance)
105      (return-from topictype-p current-checked-topics))
106    (when (not (union akos-of-this isas-of-this :test #'eq))
107      (when topictype-constraint
108        (error "~a is not a valid type for ~a"
109               (uri (first (psis topic-instance :revision revision)))
110               (uri (first (psis topictype :revision revision)))))
111      (return-from topictype-p current-checked-topics))
112    (let ((akos-are-topictype nil))
113      (loop for ako-of-this in akos-of-this
114         when (not (find ako-of-this current-checked-topics))
115         do (let ((further-topics
116                   (topictype-p ako-of-this topictype topictype-constraint
117                                nil revision)))
118              (if further-topics
119                  (progn
120                    (dolist (item further-topics)
121                      (pushnew item current-checked-topics))
122                    (pushnew ako-of-this akos-are-topictype))
123                  (when topictype-constraint
124                    (error "~a is not a valid type for ~a"
125                           (uri (first (psis topic-instance :revision revision)))
126                           (uri (first (psis topictype :revision revision))))))))
127      (when isas-of-this
128        (let ((topictype-topics-of-isas nil))
129          (loop for isa-of-this in isas-of-this
130             do (let ((topic-akos (subtype-p isa-of-this topictype nil revision)))
131                  (when topic-akos
132                    (pushnew isa-of-this topictype-topics-of-isas)
133                    (pushnew isa-of-this current-checked-topics)
134                    (dolist (item topic-akos)
135                      (pushnew item current-checked-topics)))))
136          (when (and (not topictype-topics-of-isas)
137                     (not akos-are-topictype)
138                     topictype-constraint)
139            (error "~a is not a valid type for ~a"
140                   (uri (first (psis topic-instance :revision revision)))
141                   (uri (first (psis topictype :revision revision)))))
142          (loop for isa-of-this in isas-of-this
143             when (and (not (find isa-of-this current-checked-topics :test #'eq))
144                       (not (find isa-of-this topictype-topics-of-isas :test #'eq)))
145             do (let ((further-topic-types
146                       (topictype-p isa-of-this topictype topictype-constraint
147                                    current-checked-topics revision)))
148                  (if further-topic-types
149                      (dolist (item further-topic-types)
150                        (pushnew item current-checked-topics))
151                      (when topictype-constraint
152                        (error "~a is not a valid type for ~a"
153                               (uri (first (psis topic-instance :revision revision)))
154                               (uri (first (psis topictype :revision revision)))))))))))
155    current-checked-topics))
156
157
158(defun subtype-p (topic-instance &optional
159                  (topictype (get-item-by-psi *topictype-psi* :revision 0))
160                  (checked-topics nil) (revision *TM-REVISION*))
161  "Returns a list of all supertypes of the passed topic if the passed topic
162   is not an instanceOf any other topic but a subtype of some supertypes
163   of a topictype or it is the topictype-topic itself.
164   This function isn't useable as a standalone function - it's only necessary
165   for a special case in the function topictype-p."
166  (declare (type (or integer null) revision)
167           (TopicC topic-instance)
168           (type (or TopicC null) topictype)
169           (list checked-topics))
170  (let ((current-checked-topics
171         (remove-duplicates (append checked-topics (list topic-instance)))))
172    (when (eq topictype topic-instance)
173      (return-from subtype-p current-checked-topics))
174    (when (get-direct-types-of-topic topic-instance :revision revision)
175      (return-from subtype-p nil))
176    (let ((supertypes-of-this
177           (get-direct-supertypes-of-topic topic-instance :revision revision)))
178      (when (not supertypes-of-this)
179        (return-from subtype-p nil))
180      (when supertypes-of-this
181        (loop for supertype-of-this in supertypes-of-this
182           when (not (find supertype-of-this current-checked-topics :test #'eq))
183           do (let ((further-supertypes
184                     (subtype-p topictype supertype-of-this current-checked-topics
185                                revision)))
186                (when (not further-supertypes)
187                  (return-from subtype-p nil))
188                (dolist (item further-supertypes)
189                  (pushnew item current-checked-topics))))))
190    current-checked-topics))
191
192
193(defun get-direct-types-of-topic(topic-instance &key (revision *TM-REVISION*))
194  "Returns the direct types of the topic as a list passed to this function.
195   This function only returns the types of the type-instance-relationship -> TMDM 7.2
196   This function was defined for the use in topictype-p and not for a standalone
197   usage."
198  (declare (type (or integer null) revision)
199           (TopicC topic-instance))
200  (let ((type-instance (get-item-by-psi *type-instance-psi* :revision revision))
201        (instance (get-item-by-psi *instance-psi* :revision revision))
202        (type (get-item-by-psi *type-psi* :revision revision)))
203    (let ((topic-types
204           (loop for role in (player-in-roles topic-instance :revision revision)
205              when (and (eq instance (instance-of role :revision revision))
206                        (parent role :revision revision))
207              collect (loop for other-role in
208                           (roles (parent role :revision revision) :revision revision)
209                         when (and (not (eq role other-role))
210                                   (eq type-instance (instance-of
211                                                      (parent role :revision revision)
212                                                      :revision revision))
213                                   (eq type (instance-of other-role
214                                                         :revision revision)))
215                         return (player other-role :revision revision)))))
216      (when topic-types
217        (remove-if #'null topic-types)))))
218
219
220(defun get-direct-instances-of-topic(topic-instance &key (revision *TM-REVISION*))
221  "Returns the direct instances of the topic as a list.
222   This function only returns the types of the type-instance-relationship -> TMDM 7.2
223   This function was defined for the use in topictype-p and not for a standalone
224   usage."
225  (declare (type (or integer null) revision)
226           (TopicC topic-instance))
227  (let ((type-instance (get-item-by-psi *type-instance-psi* :revision revision))
228        (instance (get-item-by-psi *instance-psi* :revision revision))
229        (type (get-item-by-psi *type-psi* :revision revision)))
230    (let ((topic-instances
231           (loop for role in (player-in-roles topic-instance :revision revision)
232              when (and (eql type (instance-of role :revision revision))
233                        (parent role :revision revision))
234              collect (loop for other-role in (roles (parent role :revision revision)
235                                                     :revision revision)
236                         when (and (not (eq role other-role))
237                                   (eq type-instance
238                                       (instance-of (parent role :revision revision)
239                                                    :revision revision))
240                                   (eq instance (instance-of other-role
241                                                             :revision revision)))
242                         return (player other-role :revision revision)))))
243      (when topic-instances
244        (remove-if #'null topic-instances)))))
245
246
247(defun get-direct-supertypes-of-topic(topic-instance &key (revision *TM-REVISION*))
248  "Returns the direct supertypes of the topic as a list passed to this function.
249   This function only returns the types of the supertype-subtype-relationship -> TMDM 7.3.
250   This function was defined for the use in topictype-p and not for a standalone
251   usage."
252  (declare (type (or integer null) revision)
253           (TopicC topic-instance))
254  (let ((supertype-subtype (get-item-by-psi *supertype-subtype-psi* :revision revision))
255        (supertype (get-item-by-psi *supertype-psi* :revision revision))
256        (subtype (get-item-by-psi *subtype-psi* :revision revision)))
257    (let ((supertypes
258           (loop for role in (player-in-roles topic-instance :revision revision)
259              when (and (eq subtype (instance-of role :revision revision))
260                        (parent role :revision revision))
261              append (loop for other-role in (roles (parent role :revision revision)
262                                                    :revision revision)
263                         when (and (not (eq role other-role))
264                                   (eq supertype-subtype
265                                       (instance-of (parent role :revision revision)
266                                                    :revision revision))
267                                   (eq supertype
268                                       (instance-of other-role :revision revision)))
269                         collect (player other-role)))))
270      (when supertypes
271        (remove-if #'null supertypes)))))
272
273
274(defun get-direct-subtypes-of-topic(topic-instance &key (revision *TM-REVISION*))
275  "Returns the direct subtypes of the topic as a list.
276   This function only returns the types of the supertype-subtype-relationship
277   -> TMDM 7.3.
278   This function was defined for the use in topictype-p and not for a standalone
279   usage."
280  (declare (type (or integer null) revision)
281           (TopicC topic-instance))
282  (let ((supertype-subtype (get-item-by-psi *supertype-subtype-psi* :revision revision))
283        (supertype (get-item-by-psi *supertype-psi* :revision revision))
284        (subtype (get-item-by-psi *subtype-psi* :revision revision)))
285    (let ((subtypes
286           (loop for role in (player-in-roles topic-instance :revision revision)
287              when (and (eq supertype (instance-of role :revision revision))
288                        (parent role :revision revision))
289              append (loop for other-role in (roles (parent role :revision revision)
290                                                    :revision revision)
291                         when (and (not (eq role other-role))
292                                   (eq supertype-subtype
293                                       (instance-of (parent role :revision revision)
294                                                    :revision revision))
295                                   (eq subtype (instance-of other-role
296                                                            :revision revision)))
297                         collect (player other-role :revision revision)))))
298      (when subtypes
299        (remove-if #'null subtypes)))))
300
301
302(defun list-subtypes (topic-instance &optional
303                      (topictype (get-item-by-psi *topictype-psi* :revision 0))
304                      (topictype-constraint (is-type-constrained :revision 0))
305                      (checked-topics nil) (valid-subtypes nil)
306                      (revision *TM-REVISION*))
307  "Returns all valid subtypes of a topic, e.g.:
308   nametype-constraint ako constraint .
309   first-name isa nametype .
310   first-name-1 ako first-name .
311   // ...
312   The return value is a named list of the form (:subtypes (<topic> <...>)
313   :checked-topics (<topic> <...>)"
314  (let ((current-checked-topics (append checked-topics (list topic-instance))))
315    (handler-case (topictype-p topic-instance topictype topictype-constraint
316                               nil revision)
317      (condition () (return-from list-subtypes
318                      (list :subtypes nil :checked-topics current-checked-topics))))
319    (let ((subtype (get-item-by-psi *subtype-psi* :revision revision))
320          (supertype (get-item-by-psi *supertype-psi* :revision revision))
321          (supertype-subtype (get-item-by-psi *supertype-subtype-psi*
322                                              :revision revision))
323          (current-valid-subtypes (append valid-subtypes (list topic-instance))))
324      (loop for role in (player-in-roles topic-instance :revision revision)
325         when (and (parent role :revision revision)
326                   (eq supertype (instance-of role :revision revision))
327                   (eq supertype-subtype
328                       (instance-of (parent role :revision revision)
329                                    :revision revision)))
330         do (loop for other-role in (roles (parent role :revision revision)
331                                           :revision revision)
332               do (when (and (eq subtype (instance-of other-role :revision revision))
333                             (not (find (player other-role :revision revision)
334                                        current-checked-topics)))
335                    (let ((new-values
336                           (list-subtypes (player other-role :revision revision)
337                                          topictype topictype-constraint
338                                          current-checked-topics
339                                          current-valid-subtypes revision)))
340                      (dolist (item (getf new-values :subtypes))
341                        (pushnew item current-valid-subtypes))
342                      (dolist (item (getf new-values :checked-topics))
343                        (pushnew item current-checked-topics))))))
344      (list :subtypes current-valid-subtypes :checked-topics current-checked-topics))))
345
346
347(defun list-instances (topic-instance &optional
348                       (topictype (get-item-by-psi *topictype-psi* :revision 0))
349                       (topictype-constraint (is-type-constrained :revision 0))
350                       (revision *TM-REVISION*))
351  "Returns the topic-instance, all subtypes found by the function list-subtypes
352   and all direct instances for the found subtypes."
353  (let ((all-subtypes-of-this
354         (getf (list-subtypes topic-instance topictype topictype-constraint
355                              nil nil revision)
356               :subtypes))
357        (type (get-item-by-psi *type-psi* :revision revision))
358        (instance (get-item-by-psi *instance-psi* :revision revision))
359        (type-instance (get-item-by-psi *type-instance-psi* :revision revision)))
360    (let ((all-instances-of-this
361           (remove-duplicates
362            (loop for subtype-of-this in all-subtypes-of-this
363               append (loop for role in (player-in-roles subtype-of-this
364                                                         :revision revision)
365                         when (and (parent role :revision revision)
366                                   (eq type (instance-of role :revision revision))
367                                   (eq type-instance
368                                       (instance-of (parent role :revision revision)
369                                                    :revision revision)))
370                         append (loop for other-role in
371                                     (roles (parent role :revision revision)
372                                            :revision revision)
373                                   when (eq instance (instance-of other-role
374                                                                  :revision revision))
375                                   collect (player other-role :revision revision)))))))
376      (let ((all-subtypes-of-all-instances
377             (remove-if #'null
378                        (remove-duplicates
379                         (loop for subtype in all-instances-of-this
380                            append (getf
381                                    (list-subtypes subtype topictype
382                                                   nil nil nil revision)
383                                    :subtypes))))))
384        (union all-instances-of-this 
385               (remove-if #'null
386                          (map 'list #'(lambda(x)
387                                         (handler-case (progn
388                                                         (topictype-of-p x nil nil nil
389                                                                         nil revision)
390                                                         x)
391                                           (condition () nil)))
392                               all-subtypes-of-all-instances)))))))
393
394
395(defun valid-instance-p (topic-instance &optional
396                         (akos-checked nil) (all-checked-topics nil)
397                         (revision *TM-REVISION*))
398  "Returns a list of all checked topics or throws an exception if the given
399   topic is not a valid instance of any topictype in elephant."
400  (declare (type (or integer null) revision)
401           (TopicC topic-instance)
402           (list akos-checked all-checked-topics))
403  (let ((isas-of-this
404         (get-direct-types-of-topic topic-instance :revision revision))
405        (akos-of-this
406         (get-direct-supertypes-of-topic topic-instance :revision revision))
407        (psi-of-this (uri (first (psis topic-instance :revision revision))))
408        (topictype (get-item-by-psi *topictype-psi* :revision revision))
409        (topictype-constraint (is-type-constrained :revision revision))
410        (local-all-checked-topics all-checked-topics)
411        (local-akos-checked))
412    (when (not topictype-constraint)
413      (return-from valid-instance-p (list topic-instance)))
414    (when (and topictype-constraint
415               (not topictype))
416      (error "From valid-instance-p(): The topic \"~a\" does not exist - please create it or remove the topic \"~a\""
417             *topictype-psi*
418             (uri (first (psis topictype-constraint :revision revision)))))
419    (when (eql topic-instance topictype)
420      (return-from valid-instance-p
421        (remove-duplicates (append all-checked-topics (list topic-instance)))))
422    (unless (or isas-of-this akos-of-this)
423      (error "The topic \"~a\" is not a valid topic-instance for any topic-type"
424              psi-of-this))
425    (when (find topic-instance akos-checked)
426      (return-from valid-instance-p all-checked-topics))
427    (pushnew topic-instance local-all-checked-topics)
428    (pushnew topic-instance local-akos-checked)
429    (dolist (isa isas-of-this)
430      (handler-case (let ((topics
431                           (topictype-p isa topictype topictype-constraint
432                                        nil revision)))
433                      (dolist (top topics)
434                        (pushnew top local-all-checked-topics)))
435        (condition (err) (error "The topic \"~a\" is not a valid topic-instance for any topic-type~%~%~a"
436                                psi-of-this err))))
437
438    (dolist (ako akos-of-this)
439      (when (not (handler-case
440                     (let ((topics
441                            (topictype-p ako topictype topictype-constraint
442                                         all-checked-topics revision)))
443                                 (dolist (top topics)
444                                   (pushnew top local-all-checked-topics))
445                                 (pushnew ako local-akos-checked)
446                                 topics)
447                   (condition () nil)))
448        (handler-case 
449            (let ((topics
450                   (valid-instance-p ako akos-checked (append all-checked-topics
451                                                              (list ako)) revision)))
452                        (dolist (top topics)
453                          (pushnew top local-all-checked-topics)
454                          (pushnew top local-akos-checked))
455                        topics)
456          (condition (err) (error "The topic \"~a\" is not a valid topic-instance for any topic-type~%~%~a"
457                                  psi-of-this err)))))
458    local-all-checked-topics))
459
460
461(defun return-all-tmcl-types (&key (revision *TM-REVISION*))
462  "Returns all topics that are valid tmcl-types"
463  (declare (type (or integer null) revision))
464  (let ((all-topics (get-all-topics revision))
465        (topictype (get-item-by-psi json-tmcl-constants::*topictype-psi*
466                                    :revision revision))
467        (topictype-constraint (is-type-constrained :revision revision)))
468    (let ((all-types
469           (remove-if
470            #'null
471            (map 'list #'(lambda(x)
472                           (handler-case
473                               (progn
474                                 (topictype-p x topictype topictype-constraint
475                                              nil revision)
476                                 x)
477                             (condition () nil))) all-topics))))
478      (let ((not-abstract-types
479             (remove-if #'null
480                        (map 'list #'(lambda(x)
481                                       (unless (abstract-p x :revision revision)
482                                         x))
483                             all-types))))
484        not-abstract-types))))
485
486
487(defun return-all-tmcl-instances (&key (revision *TM-REVISION*))
488  "Returns all topics that are valid instances of any topic type.
489   The validity is only oriented on the typing of topics, e.g.
490   type-instance or supertype-subtype."
491  (declare (type (or integer null) revision))
492  (let ((all-topics (get-all-topics revision)))
493    (let ((valid-instances
494           (remove-if
495            #'null
496            (map 'list #'(lambda(x)
497                           (handler-case (progn
498                                           (valid-instance-p x nil nil revision)
499                                           x)
500                             (condition () nil))) all-topics))))
501      valid-instances)))
502
503
504(defun is-type-constrained (&key (what *topictype-constraint-psi*)
505                            (revision *TM-REVISION*))
506  "Returns nil if there is no type-constraint otherwise the instance of
507   the type-constraint."
508  (declare (string what)
509           (type (or integer null) revision))
510  (let ((topictype-constraint (get-item-by-psi what :revision revision)))
511    (when topictype-constraint
512      (let ((ttc
513             (remove-duplicates
514              (remove-if
515               #'null
516               (remove-if #'(lambda(x) (when (eql topictype-constraint x)
517                                         t))
518                          (get-direct-instances-of-topic topictype-constraint
519                                                         :revision revision))))))
520        ttc))))
521
522
523(defun list-all-supertypes (topic-instance &optional (checked-topics nil)
524                            (revision *TM-REVISION*))
525  "Returns all supertypes of the given topic recursively."
526  (declare (type (or integer null) revision)
527           (TopicC topic-instance)
528           (list checked-topics))
529  (let ((current-checked-topics (append checked-topics (list topic-instance)))
530        (akos-of-this (get-direct-supertypes-of-topic topic-instance
531                                                      :revision revision)))
532    (dolist (ako-of-this akos-of-this)
533      (when (not (find ako-of-this current-checked-topics))
534        (let ((new-checked-topics
535               (list-all-supertypes ako-of-this current-checked-topics revision)))
536          (dolist (new-topic new-checked-topics)
537            (pushnew new-topic current-checked-topics)))))
538    current-checked-topics))
539
540
541(defun get-all-upper-constrainted-topics (topic &key (revision *TM-REVISION*))
542  "Returns all topics that are supertypes or direct types
543   of the given topic-type. So all direct constraints of the found
544   topics are valid constraints for the given one."
545  (declare (TopicC topic)
546           (type (or integer null) revision))
547  ;; find all direct types
548  (let ((direct-isas-of-this
549         (get-direct-types-of-topic topic :revision revision)))
550  ;; find all supertypes (recursive -> transitive relationship
551    (let ((all-akos-of-this
552           (list-all-supertypes topic nil revision)))
553      (remove-duplicates (union direct-isas-of-this all-akos-of-this)))))
Note: See TracBrowser for help on using the repository browser.