validation.py 12.1 KB
# -*- coding: utf-8 -*-

from django.db.models import Max

from dictionary.models import Lemma, reflex_phrase_types
from semantics.models import LexicalUnitExamples
from semantics.utils import get_structural_matching_frame

def validate_frames(lemma_id):
    lemma = Lemma.objects.get(id=lemma_id)
    visible_frames = lemma.entry_obj.visible_frames()
    error_msg = u''
    for frame in visible_frames.all():
        error_msg = frame_valid(lemma, frame, visible_frames)
        if error_msg:
            break
    return error_msg
        
def frame_valid(lemma, frame, frames):
    error_msg = ''
    complements = frame.complements.all()
    if not arguments_exists(complements):
        error_msg = u'Semantyka: Rama semantyczna %d jest pusta.' % frame.id
    elif not lexical_units_exists(frame):
        error_msg = u'Semantyka: Rama semantyczna %d nie ma dodanych znaczeń.' % frame.id
    elif not frame.opinion_selected():
        error_msg = u'Semantyka: Rama semantyczna %d nie ma wybranej opinii.' % frame.id
    elif not roles_unique(complements):
        error_msg = u'Semantyka: Rama semantyczna %d nie zawiera unikalnych ról.' % frame.id
    elif not arguments_pinned(complements):
        error_msg = u'Semantyka: Rama semantyczna %d zawiera argumenty, które nie są powiązane z żadnym schematem.' % frame.id
    elif not preferences_selected(complements):
        error_msg = u'Semantyka: Rama semantyczna %d zawiera argumenty bez zdefiniowanych preferencji selekcyjnych.' % frame.id
    elif not examples_added(lemma, frame):
        error_msg = u'Semantyka: Rama semantyczna %d nie ma dopiętych przykładów.' % frame.id
    elif duplicates_exists(frame, frames):
        error_msg = u'Semantyka: Rama semantyczna %d posiada duplikaty.' % frame.id
    elif not schemas_reflex_agreed(lemma, frame):
        error_msg = u'Semantyka: Rama semantyczna %d ma dopięte elementy o niezgodnej zwrotności.' % frame.id
    elif nonch_pinned(frame):
        error_msg = u'Semantyka: Rama semantyczna %d jest dopięta do typu frazy nonch.' % frame.id
    elif multiplied_same_arg_in_schema(frame):
        error_msg = u'Semantyka: Rama semantyczna %d posiada argument wielokrotnie powiązany z tym samym schematem.' % frame.id
    # phraseologic
    elif multiword_only_frame_connected_to_not_phr_schema(frame):
        error_msg = u'Semantyka: Rama semantyczna %d (o samych wielosłownych znaczeniach) może być podłączona jedynie do schematów frazeologicznych.' % frame.id
    elif not multiword_frame_connected_to_at_least_one_phr_schema(frame):
        error_msg = u'Semantyka: Rama semantyczna %d (posiadająca wielosłowne znaczenie) musi zostać podłączona do co najmniej jednego schematu frazeologicznego.' % frame.id
    elif not frame_is_using_phraseologic_phr_type(frame):
        error_msg = u'Semantyka: Rama semantyczna %d podłączona do schematu frazeologicznego musi wykorzystywać co najmniej jeden zleksykalizowany typ frazy.' % frame.id
    elif not multiword_frame_has_lemma(frame):
        error_msg = u'Semantyka: Rama semantyczna %d musi posiadać rolę Lemma.' % frame.id
    elif singleword_only_frame_has_lemma(frame):
        error_msg = u'Semantyka: Rama semantyczna %d nie powinna posiadać roli Lemma.' % frame.id
    elif not lemma_always_pinned(frame):
        error_msg = u'Semantyka (rama %d): Rola Lemma, dla ram o samych znaczeniach wielosłownych, musi być zawsze realizowana w podłączonych schematach.' % frame.id
        
    return error_msg

def arguments_exists(complements):
    return complements.exists()

def lexical_units_exists(frame):
    return frame.lexical_units.exists()

def roles_unique(complements):
    roles = set()
    for complement in complements:
        role_ids = [role.id for role in complement.roles.all()]
        role_ids.sort()
        role = tuple(role_ids)
        if role in roles:
            return False
        else:
            roles.add(role)
    return True

def arguments_pinned(complements):
    for compl in complements:
        if not compl.realizations.exists():
            return False
    return True

def preferences_selected(complements):
    for complement in complements:
        if complement.realizations.exists() and complement.has_only_phraseologic_realizations():
            pass
        elif not preference_valid(complement):
            return False
    return True
    
def preference_valid(complement):
    preference = complement.selective_preference
    if preference is None:
        return False
    generals = preference.generals
    synsets = preference.synsets
    relations = preference.relations
    synset_relations = preference.synset_relations
    if generals.count() + synsets.count() + relations.count() + synset_relations.count() > 0:
        return True
    return False
    
def examples_added(lemma, frame):
    local_examples = lemma.nkjp_examples.all()
    for lexical_unit in frame.lexical_units.all():
        if LexicalUnitExamples.objects.filter(lexical_unit=lexical_unit,
                                              example__in=local_examples).exists():
            return True
    return False

def duplicates_exists(frame, frames):
    # frazeologicznych ram nie sprawdzamy
    if frame.complements.filter(roles__role='Lemma').exists():
        return False

    frames_to_check = frames.exclude(id=frame.id)
    if get_structural_matching_frame(frames_to_check, frame):
        return True
    return False

def schemas_reflex_agreed(lemma, frame):
    agreed = True
    complements = frame.complements.all()
    lexical_units = frame.lexical_units.all()
    for schema in lemma.frames.all():
        schema_agreed = False
        for lex_unit in lexical_units:
            if schema_lex_unit_reflex_agree(lex_unit, schema, complements):
                schema_agreed = True
                break
        if not schema_agreed:
            agreed = False
            break
    return agreed

def schema_lex_unit_reflex_agree(lexical_unit, schema, complements):
    if complements.filter(realizations__frame=schema).exists():
        if (not reflex_with_self_mark_agreed(lexical_unit, schema) and 
            not (lexical_unit.is_reflexive() and not lexical_unit.is_new() and
             reflex_with_phrase_types_agreed(lexical_unit, schema, complements))):
            return False
    return True

def reflex_with_self_mark_agreed(lexical_unit, schema):
    schema_self_mark = schema.get_char_value('ZWROTNOŚĆ').value
    if not lexical_unit.is_reflexive() == bool(schema_self_mark):
        return False
    return True

def reflex_with_phrase_types_agreed(lexical_unit, schema, complements):
    max_alternations = complements.all().aggregate(Max('realizations__alternation'))['realizations__alternation__max']
    for alternation in range(1, max_alternations+1):
        if not reflex_with_alternation_phrase_types_agreed(complements, schema, alternation):
            return False
    return True

def reflex_with_alternation_phrase_types_agreed(complements, schema, alternation):
    for compl in complements:
        if compl.realizations.filter(argument__type__in=reflex_phrase_types(),
                                     alternation=alternation,
                                     frame=schema).exists():
            return True
    return False

def nonch_pinned(frame):
    if frame.complements.filter(realizations__argument__text_rep='nonch').exists():
        return True
    return False

def multiplied_same_arg_in_schema(frame):
    for compl in frame.complements.all():
        if compl.roles.filter(role='Lemma').exists():
            continue
        else:
            for real in compl.realizations.all():
                same_frame_realizations = compl.realizations.filter(frame=real.frame,
                                                                    alternation=real.alternation)
                if same_frame_realizations.exclude(position=real.position).exists():
                    return True
    return False

# phraseologic
def multiword_only_frame_connected_to_not_phr_schema(frame):
    if (frame.multiword_meanings_only() and 
        frame.complements.filter(realizations__frame__phraseologic=False).exists()):
        return True
    return False

def multiword_frame_connected_to_at_least_one_phr_schema(frame):
    valid = False
    if not frame.has_multiword_meaning():
        valid = True
    elif (frame.has_multiword_meaning() and 
        frame.complements.filter(realizations__frame__phraseologic=True).exists()):
        valid = True
    return valid

def frame_is_using_phraseologic_phr_type(frame):
    phr_connected_schemata = frame.connected_schemata().filter(phraseologic=True)
    for schema in phr_connected_schemata:
        schema_ok = False
        for compl in frame.complements.all():
            for real in compl.realizations.filter(frame=schema):
                if real.argument.is_phraseologic():
                    schema_ok = True
                    break
            if schema_ok:
                break
        if not schema_ok:
            return False
    return True

def multiword_frame_has_lemma(frame):
    valid = False
    if not frame.has_multiword_meaning():
        valid = True
    elif (frame.has_multiword_meaning() and frame.role_exists('Lemma')):
        valid = True
    return valid

def singleword_only_frame_has_lemma(frame):
    if(not frame.has_multiword_meaning() and frame.role_exists('Lemma')):
        return True
    return False

def lemma_always_pinned(frame):
    if frame.role_exists('Lemma') and frame.multiword_meanings_only():
        lemma_arg = frame.complements.get(roles__role='Lemma')
        connected_schemata = frame.connected_schemata()
        for schema in connected_schemata:
            if not lemma_arg.realizations.filter(frame=schema).exists():
                return False
    return True
        

def validate_schemas(lemma_id):
    error_msg = ''
    lemma = Lemma.objects.get(id=lemma_id, old=False)
    if missing_schemata_opinions(lemma):
        error_msg = u'Nie wszystkie schematy mają wybrane oceny.'
    elif not all_schemas_used(lemma):
        error_msg = u'Semantyka nie wykorzystuje wszystkich poprawnych schematów walencyjnych.'
    return error_msg

def missing_schemata_opinions(lemma):
    schemata = lemma.frames
    for schema in schemata.all():
        schema_opinion = lemma.frame_opinions.filter(frame=schema)
        if not schema_opinion.exists():
            return True
    return False

def all_schemas_used(lemma):
    frames = lemma.entry_obj.visible_frames()
    schemas = lemma.frames
    for schema in schemas.all():
        if not schema_is_bad(lemma, schema) and not schema_used(schema, frames):
            return False
    return True

def schema_is_bad(lemma, schema):
    schema_opinion = lemma.frame_opinions.get(frame=schema)
    if schema_opinion.value.short == 'bad':
        return True
    return False
        
def schema_used(schema, frames):
    for frame in frames:
        if frame.complements.filter(realizations__frame=schema).exists():
            return True
    return False

def validate_lexical_units(lemma_id):
    error_msg = ''
    lemma = Lemma.objects.get(id=lemma_id, old=False)
    lexical_units = lemma.entry_obj.meanings
    for lex_unit in lexical_units.all():
        if not examples_reflex_agreed(lex_unit):
            error_msg = u'Semantyka: Znaczenie %s ma podpięte przykłady o niezgodnej zwrotności.' % unicode(lex_unit)
        elif hanging_meaning(lex_unit):
            error_msg = u'Semantyka: Znaczenie %s nie jest reprezentowane przez żadną ramę semantyczną.' % unicode(lex_unit)
        if error_msg:
            break
    return error_msg

def examples_reflex_agreed(lexical_unit):
    lex_examples = LexicalUnitExamples.objects.filter(lexical_unit=lexical_unit)
    for lex_example in lex_examples:
        schema_reflex = lex_example.example.frame.get_char_value('ZWROTNOŚĆ').value
        if (not (lexical_unit.is_reflexive() == bool(schema_reflex)) and 
            not (lexical_unit.is_reflexive() and not lexical_unit.is_new() and
                 lex_example.example.arguments.filter(arguments__type__in=reflex_phrase_types()).exists())):
            return False
    return True

def hanging_meaning(lexical_unit):
    if lexical_unit.luid < 0 and not lexical_unit.connected():
        return True
    return False