From 1539c27199229c6d11a56732572bd5f105b2d455 Mon Sep 17 00:00:00 2001 From: Guylerme Date: Tue, 4 May 2021 15:32:45 -0300 Subject: [PATCH 1/5] Create teste --- src/libs/teste | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/libs/teste diff --git a/src/libs/teste b/src/libs/teste new file mode 100644 index 00000000..6f16acbb --- /dev/null +++ b/src/libs/teste @@ -0,0 +1 @@ +teste From 6c0b6b0d05f22d4bd0fdc4235fb5dbb5af9d800e Mon Sep 17 00:00:00 2001 From: Guylerme Date: Tue, 4 May 2021 15:34:53 -0300 Subject: [PATCH 2/5] Relator Abstraction done and tested --- .../libs/abstraction/abstractor.basic.test.ts | 110 +++++++++++++++++ src/libs/abstraction/abstraction.ts | 90 ++++++++++++++ src/libs/abstraction/abstractor.ts | 111 ++++++++++++++++++ src/libs/abstraction/index.ts | 2 + 4 files changed, 313 insertions(+) create mode 100644 __tests__/libs/abstraction/abstractor.basic.test.ts create mode 100644 src/libs/abstraction/abstraction.ts create mode 100644 src/libs/abstraction/abstractor.ts create mode 100644 src/libs/abstraction/index.ts diff --git a/__tests__/libs/abstraction/abstractor.basic.test.ts b/__tests__/libs/abstraction/abstractor.basic.test.ts new file mode 100644 index 00000000..1dd7cf01 --- /dev/null +++ b/__tests__/libs/abstraction/abstractor.basic.test.ts @@ -0,0 +1,110 @@ +import { Project, Diagram } from '@libs/ontouml'; +import { Abstractor } from '@libs/abstraction'; + +describe('Basic clusterization example', () => { + const project = new Project(); + const model = project.createModel(); + + const person = model.createKind('Person'); + const woman = model.createSubkind('Woman'); + const man = model.createSubkind('Man'); + const living = model.createPhase('Living'); + const deceased = model.createPhase('Deceased'); + const child = model.createPhase('Child'); + const teenager = model.createPhase('Teenager'); + const adult = model.createPhase('Adult'); + const husband = model.createRole('Husband'); + const wife = model.createRole('Wife'); + const marriage = model.createRelator('Marriage'); + const organization = model.createKind('Organization'); + const agency = model.createSubkind('Car Agency'); + const ownership = model.createRelator('Car Ownership'); + const car = model.createKind('Car'); + const available = model.createPhase('Available Car'); + const underMaintenance = model.createPhase('Under Maintenance Car'); + const rentalCar = model.createRole('Rental Car'); + const rental = model.createRelator('Car Rental'); + const customer = model.createRoleMixin('Customer'); + const corporateCustomer = model.createRole('Corporate Customer'); + const personalCustomer = model.createRole('Personal Customer'); + + const genWifeWoman = woman.addChild(wife); + const genHusbandMan = man.addChild(husband); + available.addChild(rentalCar); + adult.addChild(personalCustomer); + organization.addChild(corporateCustomer); + organization.addChild(agency); + + model.createPartitionFromClasses(person, [woman, man]); + model.createPartitionFromClasses(person, [living, deceased]); + model.createPartitionFromClasses(living, [child, teenager, adult]); + model.createPartitionFromClasses(car, [available, underMaintenance]); + model.createPartitionFromClasses(customer, [personalCustomer, corporateCustomer]); + + const medMarriageWife = model.createMediationRelation(marriage, wife); + const medMarriagHusband = model.createMediationRelation(marriage, husband); + const medRentalCustomer = model.createMediationRelation(rental, customer); + const medRentalRentalCar = model.createMediationRelation(rental, rentalCar); + const medOwnershipAgency = model.createMediationRelation(ownership, agency); + const medOwnershipCar = model.createMediationRelation(ownership, car); + + let diagrams: Diagram[] = new Abstractor(project).buildAll(); + + + describe('Relator Abstraction Test', () => { + let diagram: Diagram = diagrams.find(d => d.getName() === 'Relator Abstraction'); + + + + it('Should not contain the main relator: Marriage', () => { + expect(diagram.findView(marriage)).toBeFalsy(); + }); + it('Should not contain the main relator: Car Rental', () => { + expect(diagram.findView(rental)).toBeFalsy(); + }); + it('Should not contain the main relator: Ownership', () => { + expect(diagram.findView(ownership)).toBeFalsy(); + }); + + + + + + + it('Should contain the expected classes (19)', () => { + expect(diagram.findView(person)).toBeTruthy(); + expect(diagram.findView(woman)).toBeTruthy(); + expect(diagram.findView(man)).toBeTruthy(); + expect(diagram.findView(husband)).toBeTruthy(); + expect(diagram.findView(wife)).toBeTruthy(); + expect(diagram.findView(deceased)).toBeTruthy(); + expect(diagram.findView(living)).toBeTruthy(); + expect(diagram.findView(child)).toBeTruthy(); + expect(diagram.findView(adult)).toBeTruthy(); + expect(diagram.findView(teenager)).toBeTruthy(); + expect(diagram.findView(personalCustomer)).toBeTruthy(); + expect(diagram.findView(organization)).toBeTruthy(); + expect(diagram.findView(agency)).toBeTruthy(); + expect(diagram.findView(car)).toBeTruthy(); + expect(diagram.findView(customer)).toBeTruthy(); + expect(diagram.findView(underMaintenance)).toBeTruthy(); + expect(diagram.findView(available)).toBeTruthy(); + expect(diagram.findView(corporateCustomer)).toBeTruthy(); + expect(diagram.findView(rentalCar)).toBeTruthy(); + + expect(diagram.getClassViews()).toHaveLength(19); + }); + + it('Should not contain the expected relations (6)', () => { + expect(diagram.findView(medMarriageWife)).toBeFalsy(); + expect(diagram.findView(medMarriagHusband)).toBeFalsy(); + expect(diagram.findView(medRentalRentalCar)).toBeFalsy(); + expect(diagram.findView(medRentalCustomer)).toBeFalsy(); + expect(diagram.findView(medOwnershipAgency)).toBeFalsy(); + expect(diagram.findView(medOwnershipCar)).toBeFalsy(); + + }); + + + }); +}); diff --git a/src/libs/abstraction/abstraction.ts b/src/libs/abstraction/abstraction.ts new file mode 100644 index 00000000..1f8dec87 --- /dev/null +++ b/src/libs/abstraction/abstraction.ts @@ -0,0 +1,90 @@ +import { + Package, + Class, + GeneralizationSet, + Generalization, + Relation, + ModelElement, + Diagram + } from '@libs/ontouml'; + import { uniqBy } from 'lodash'; + + export class Abstraction { + name: string; + classes: Class[]; + relations: Relation[]; + generalizations: Generalization[]; + generalizationSets: GeneralizationSet[]; + + constructor(name: string) { + this.name = name; + this.classes = []; + this.relations = []; + this.generalizations = []; + this.generalizationSets = []; + } + + createDiagram(owner: Package): Diagram { + let diagram = new Diagram(); + diagram.setName(this.name); + diagram.owner = owner; + + let pos: number = 40; + this?.classes.forEach(_class => { + let view = diagram.addClass(_class); + view.setX(pos); + view.setY(40); + pos += 120; + }); + + diagram.addModelElements(this.relations); + diagram.addModelElements(this.generalizations); + diagram.addModelElements(this.generalizationSets); + + return diagram; + } + + addClasses(classes: Class[]) { + this.classes = this.classes.concat(classes); + } + + containsRelation(relation: Relation): boolean { + return this.relations.findIndex(r => r.id === relation.id) >= 0; + } + + addRelations(relations: Relation[]) { + this.relations = this.relations.concat(relations); + } + + addGeneralizations(generalizations: Generalization[]) { + this.generalizations = this.generalizations.concat(generalizations); + } + + addGeneralizationSets(generalizationSets: GeneralizationSet[]) { + this.generalizationSets = this.generalizationSets.concat(generalizationSets); + } + + removeDuplicates() { + this.classes = Abstraction.removeDuplicatesArray(this.classes); + this.relations = Abstraction.removeDuplicatesArray(this.relations); + this.generalizations = Abstraction.removeDuplicatesArray(this.generalizations); + this.generalizationSets = Abstraction.removeDuplicatesArray(this.generalizationSets); + } + + static removeDuplicatesArray(elements: T[]): T[] { + return uniqBy(elements, 'id'); + } + + addAll(cluster: Abstraction): boolean { + if (!cluster) return false; + + this.addClasses(cluster.classes); + this.addRelations(cluster.relations); + this.addGeneralizations(cluster.generalizations); + this.addGeneralizationSets(cluster.generalizationSets); + + this.removeDuplicates(); + return true; + } + } + \ No newline at end of file diff --git a/src/libs/abstraction/abstractor.ts b/src/libs/abstraction/abstractor.ts new file mode 100644 index 00000000..d8a90596 --- /dev/null +++ b/src/libs/abstraction/abstractor.ts @@ -0,0 +1,111 @@ +import { Class, GeneralizationSet, Generalization, Diagram, Project, ClassStereotype } from '@libs/ontouml'; +import { Service } from '@libs/service'; +import { ServiceIssue } from '@libs/service_issue'; +import { Abstraction } from '@libs/abstraction'; + +/** + * Class that implements the relation-based model clustering strategy proposed in: + * + * Guizzardi, G., Figueiredo, G., Hedblom, M.M. and Poels, G., 2019, May. Ontology-based model abstraction. + * In 2019 13th International Conference on Research Challenges in Information Science (RCIS) (pp. 1-13). IEEE. + * https://ieeexplore.ieee.org/iel7/8868010/8876946/08876971.pdf + * + * @author Guylerme Figueiredo + */ + + export class Abstractor implements Service { + project: Project; + + constructor(project: Project, _options?: any) { + this.project = project; + + if (_options) { + console.log('Options ignored: this service does not support options'); + } + } + + run(): { result: any; issues?: ServiceIssue[] } { + let generatedDiagrams = this.buildAll(); + this.project.addDiagrams(generatedDiagrams); + + return { + result: this.project, + issues: null + }; + } + + buildAll(): Diagram[] { + const allRules = ["RelatorAbstraction", "NonSortalAbstraction","SortalAbstraction", "SubkindAndPhasePartitionsAbstraction"] + return allRules.map((rule, index) => this.abstract(String(index), rule)).map((abstraction) => abstraction.createDiagram(this.project.model)); + } + + abstract(id:string, rule:string): Abstraction{ + let abstraction = new Abstraction('Model Abstraction of rule ' + rule); + + switch(rule){ + case "RelatorAbstraction": abstraction = this.relatorAbstraction(); + break; + case "NonSortalAbstraction": abstraction = this.nonSortalAbstraction(); + break; + case "SortalAbstraction": abstraction = this.sortalAbstraction(); + break; + case "SubkindAndPhasePartitionsAbstraction": abstraction = this.subkindAndPhasePartitionsAbstraction(); + break; + } + + return abstraction; + } + + relatorAbstraction():Abstraction{ + const abstraction = new Abstraction('Relator Abstraction'); + + const allClasses = this.project.getAllClasses(); + + const relators = this.project.getAllClassesByStereotype(ClassStereotype.RELATOR); + + const relations = this.project.getAllRelations(); + + for(let i=relators.length-1; i>=0; i--){ + + + for (let j=relations.length-1; j>=0; j--){ + if((relations[j].getSourceClass()==relators[i])|| (relations[j].getTargetClass()==relators[i])){ + relations.splice(j, 1); + } + } + + var index = allClasses.indexOf(relators[i]); + console.log("Remover " + relators[i].getName() + " no indice " + index); + allClasses.splice(index, 1); + + } + + + + abstraction.addClasses(allClasses); + abstraction.addRelations(relations); + abstraction.removeDuplicates(); + + + return abstraction; + } + + nonSortalAbstraction():Abstraction{ + const abstraction = new Abstraction('Non Sortal Abstraction'); + + return abstraction; + } + + sortalAbstraction():Abstraction{ + const abstraction = new Abstraction('Sortal Abstraction'); + + return abstraction; + } + + subkindAndPhasePartitionsAbstraction():Abstraction{ + const abstraction = new Abstraction('Subkind And Phase Partitions Abstraction'); + + return abstraction; + } +} + diff --git a/src/libs/abstraction/index.ts b/src/libs/abstraction/index.ts new file mode 100644 index 00000000..114c21ee --- /dev/null +++ b/src/libs/abstraction/index.ts @@ -0,0 +1,2 @@ +export * from './abstractor'; +export * from './abstraction'; \ No newline at end of file From d31cdd969e9fefb7e7fcbf49305bac56fb947473 Mon Sep 17 00:00:00 2001 From: Guylerme Date: Tue, 4 May 2021 15:36:44 -0300 Subject: [PATCH 3/5] Deleted test file --- src/libs/teste | 1 - 1 file changed, 1 deletion(-) delete mode 100644 src/libs/teste diff --git a/src/libs/teste b/src/libs/teste deleted file mode 100644 index 6f16acbb..00000000 --- a/src/libs/teste +++ /dev/null @@ -1 +0,0 @@ -teste From 93de83c59e1844d6a21b961baeae4995aa25c124 Mon Sep 17 00:00:00 2001 From: Guylerme Date: Sun, 16 May 2021 03:28:47 -0300 Subject: [PATCH 4/5] NonSortal abstraction implemented and tested --- .../libs/abstraction/abstractor.basic.test.ts | 15 +- src/libs/abstraction/abstractor.ts | 208 +++++++++++++++--- 2 files changed, 188 insertions(+), 35 deletions(-) diff --git a/__tests__/libs/abstraction/abstractor.basic.test.ts b/__tests__/libs/abstraction/abstractor.basic.test.ts index 1dd7cf01..8a0ddf0e 100644 --- a/__tests__/libs/abstraction/abstractor.basic.test.ts +++ b/__tests__/libs/abstraction/abstractor.basic.test.ts @@ -95,7 +95,7 @@ describe('Basic clusterization example', () => { expect(diagram.getClassViews()).toHaveLength(19); }); - it('Should not contain the expected relations (6)', () => { + it('Should not contain the expected relations (6)', () => { expect(diagram.findView(medMarriageWife)).toBeFalsy(); expect(diagram.findView(medMarriagHusband)).toBeFalsy(); expect(diagram.findView(medRentalRentalCar)).toBeFalsy(); @@ -107,4 +107,17 @@ describe('Basic clusterization example', () => { }); + + describe('Non Sortal Abstraction Test', () => { + let diagram: Diagram = diagrams.find(d => d.getName() === 'Non Sortal Abstraction'); + + it('Should not contain the main relator: Ownership', () => { + expect(diagram.findView(customer)).toBeFalsy(); + }); + + it('Should not contain the expected relations (1)', () => { + expect(diagram.findView(medRentalCustomer)).toBeFalsy(); + }); + + }); }); diff --git a/src/libs/abstraction/abstractor.ts b/src/libs/abstraction/abstractor.ts index d8a90596..f334b021 100644 --- a/src/libs/abstraction/abstractor.ts +++ b/src/libs/abstraction/abstractor.ts @@ -1,4 +1,4 @@ -import { Class, GeneralizationSet, Generalization, Diagram, Project, ClassStereotype } from '@libs/ontouml'; +import { Class, GeneralizationSet, Generalization, Diagram, Project, ClassStereotype, Relation, ModelElement, RelationStereotype } from '@libs/ontouml'; import { Service } from '@libs/service'; import { ServiceIssue } from '@libs/service_issue'; import { Abstraction } from '@libs/abstraction'; @@ -13,36 +13,36 @@ import { Abstraction } from '@libs/abstraction'; * @author Guylerme Figueiredo */ - export class Abstractor implements Service { +export class Abstractor implements Service { project: Project; - + constructor(project: Project, _options?: any) { - this.project = project; - - if (_options) { - console.log('Options ignored: this service does not support options'); - } + this.project = project; + + if (_options) { + console.log('Options ignored: this service does not support options'); + } } - + run(): { result: any; issues?: ServiceIssue[] } { - let generatedDiagrams = this.buildAll(); - this.project.addDiagrams(generatedDiagrams); - - return { - result: this.project, - issues: null - }; + let generatedDiagrams = this.buildAll(); + this.project.addDiagrams(generatedDiagrams); + + return { + result: this.project, + issues: null + }; } - + buildAll(): Diagram[] { - const allRules = ["RelatorAbstraction", "NonSortalAbstraction","SortalAbstraction", "SubkindAndPhasePartitionsAbstraction"] - return allRules.map((rule, index) => this.abstract(String(index), rule)).map((abstraction) => abstraction.createDiagram(this.project.model)); + const allRules = ["RelatorAbstraction", "NonSortalAbstraction", "SortalAbstraction", "SubkindAndPhasePartitionsAbstraction"] + return allRules.map((rule, index) => this.abstract(String(index), rule)).map((abstraction) => abstraction.createDiagram(this.project.model)); } - abstract(id:string, rule:string): Abstraction{ + abstract(id: string, rule: string): Abstraction { let abstraction = new Abstraction('Model Abstraction of rule ' + rule); - switch(rule){ + switch (rule) { case "RelatorAbstraction": abstraction = this.relatorAbstraction(); break; case "NonSortalAbstraction": abstraction = this.nonSortalAbstraction(); @@ -56,7 +56,7 @@ import { Abstraction } from '@libs/abstraction'; return abstraction; } - relatorAbstraction():Abstraction{ + relatorAbstraction(): Abstraction { const abstraction = new Abstraction('Relator Abstraction'); const allClasses = this.project.getAllClasses(); @@ -65,18 +65,18 @@ import { Abstraction } from '@libs/abstraction'; const relations = this.project.getAllRelations(); - for(let i=relators.length-1; i>=0; i--){ + for (let i = relators.length - 1; i >= 0; i--) { + - - for (let j=relations.length-1; j>=0; j--){ - if((relations[j].getSourceClass()==relators[i])|| (relations[j].getTargetClass()==relators[i])){ + for (let j = relations.length - 1; j >= 0; j--) { + if ((relations[j].getSourceClass() == relators[i]) || (relations[j].getTargetClass() == relators[i])) { relations.splice(j, 1); } } var index = allClasses.indexOf(relators[i]); console.log("Remover " + relators[i].getName() + " no indice " + index); - allClasses.splice(index, 1); + allClasses.splice(index, 1); } @@ -90,22 +90,162 @@ import { Abstraction } from '@libs/abstraction'; return abstraction; } - nonSortalAbstraction():Abstraction{ + copyRelationFromGeneralToSpecific(general: Class, specific: Class, relation: Relation, inSource: boolean) { + if (inSource) { + switch (relation.stereotype) { + case RelationStereotype.MATERIAL: this.project.model.createMaterialRelation(specific, relation.getTargetClass(), relation.getName() + 'as' + general.getName()); + break; + case RelationStereotype.COMPARATIVE: this.project.model.createComparativeRelation(specific, relation.getTargetClass(), relation.getName() + 'as' + general.getName()); + break; + case RelationStereotype.MEDIATION: this.project.model.createMediationRelation(specific, relation.getTargetClass(), relation.getName() + 'as' + general.getName()); + break; + case RelationStereotype.CHARACTERIZATION: this.project.model.createCharacterizationRelation(specific, relation.getTargetClass(), relation.getName() + 'as' + general.getName()); + break; + case RelationStereotype.COMPONENT_OF: this.project.model.createComponentOfRelation(specific, relation.getTargetClass(), relation.getName() + 'as' + general.getName()); + break; + case RelationStereotype.MEMBER_OF: this.project.model.createMemberOfRelation(specific, relation.getTargetClass(), relation.getName() + 'as' + general.getName()); + break; + case RelationStereotype.SUBCOLLECTION_OF: this.project.model.createSubCollectionOfRelation(specific, relation.getTargetClass(), relation.getName() + 'as' + general.getName()); + break; + case RelationStereotype.SUBQUANTITY_OF: this.project.model.createSubQuantityOfRelation(specific, relation.getTargetClass(), relation.getName() + 'as' + general.getName()); + break; + case RelationStereotype.INSTANTIATION: this.project.model.createInstantiationRelation(specific, relation.getTargetClass(), relation.getName() + 'as' + general.getName()); + break; + case RelationStereotype.TERMINATION: this.project.model.createTerminationRelation(specific, relation.getTargetClass(), relation.getName() + 'as' + general.getName()); + break; + case RelationStereotype.PARTICIPATIONAL: this.project.model.createParticipationalRelation(specific, relation.getTargetClass(), relation.getName() + 'as' + general.getName()); + break; + case RelationStereotype.PARTICIPATION: this.project.model.createParticipationRelation(specific, relation.getTargetClass(), relation.getName() + 'as' + general.getName()); + break; + case RelationStereotype.HISTORICAL_DEPENDENCE: this.project.model.createHistoricalDependenceRelation(specific, relation.getTargetClass(), relation.getName() + 'as' + general.getName()); + break; + case RelationStereotype.CREATION: this.project.model.createCreationRelation(specific, relation.getTargetClass(), relation.getName() + 'as' + general.getName()); + break; + case RelationStereotype.MANIFESTATION: this.project.model.createManifestationRelation(specific, relation.getTargetClass(), relation.getName() + 'as' + general.getName()); + break; + case RelationStereotype.BRINGS_ABOUT: this.project.model.createBringsAboutRelation(specific, relation.getTargetClass(), relation.getName() + 'as' + general.getName()); + break; + case RelationStereotype.TRIGGERS: this.project.model.createTriggersRelation(specific, relation.getTargetClass(), relation.getName() + 'as' + general.getName()); + break; + } + } + else { + switch (relation.stereotype) { + case RelationStereotype.MATERIAL: this.project.model.createMaterialRelation(relation.getSourceClass(), specific, relation.getName() + 'as' + general.getName()); + break; + case RelationStereotype.COMPARATIVE: this.project.model.createComparativeRelation(relation.getSourceClass(), specific, relation.getName() + 'as' + general.getName()); + break; + case RelationStereotype.MEDIATION: this.project.model.createMediationRelation(relation.getSourceClass(), specific, relation.getName() + 'as' + general.getName()); + break; + case RelationStereotype.CHARACTERIZATION: this.project.model.createCharacterizationRelation(relation.getSourceClass(), specific, relation.getName() + 'as' + general.getName()); + break; + case RelationStereotype.COMPONENT_OF: this.project.model.createComponentOfRelation(relation.getSourceClass(), specific, relation.getName() + 'as' + general.getName()); + break; + case RelationStereotype.MEMBER_OF: this.project.model.createMemberOfRelation(relation.getSourceClass(), specific, relation.getName() + 'as' + general.getName()); + break; + case RelationStereotype.SUBCOLLECTION_OF: this.project.model.createSubCollectionOfRelation(relation.getSourceClass(), specific, relation.getName() + 'as' + general.getName()); + break; + case RelationStereotype.SUBQUANTITY_OF: this.project.model.createSubQuantityOfRelation(relation.getSourceClass(), specific, relation.getName() + 'as' + general.getName()); + break; + case RelationStereotype.INSTANTIATION: this.project.model.createInstantiationRelation(relation.getSourceClass(), specific, relation.getName() + 'as' + general.getName()); + break; + case RelationStereotype.TERMINATION: this.project.model.createTerminationRelation(relation.getSourceClass(), specific, relation.getName() + 'as' + general.getName()); + break; + case RelationStereotype.PARTICIPATIONAL: this.project.model.createParticipationalRelation(relation.getSourceClass(), specific, relation.getName() + 'as' + general.getName()); + break; + case RelationStereotype.PARTICIPATION: this.project.model.createParticipationRelation(relation.getSourceClass(), specific, relation.getName() + 'as' + general.getName()); + break; + case RelationStereotype.HISTORICAL_DEPENDENCE: this.project.model.createHistoricalDependenceRelation(relation.getSourceClass(), specific, relation.getName() + 'as' + general.getName()); + break; + case RelationStereotype.CREATION: this.project.model.createCreationRelation(relation.getSourceClass(), specific, relation.getName() + 'as' + general.getName()); + break; + case RelationStereotype.MANIFESTATION: this.project.model.createManifestationRelation(relation.getSourceClass(), specific, relation.getName() + 'as' + general.getName()); + break; + case RelationStereotype.BRINGS_ABOUT: this.project.model.createBringsAboutRelation(relation.getSourceClass(), specific, relation.getName() + 'as' + general.getName()); + break; + case RelationStereotype.TRIGGERS: this.project.model.createTriggersRelation(relation.getSourceClass(), specific, relation.getName() + 'as' + general.getName()); + break; + } + } + } + + copyRelationsFromGeneralToSpecificList(general: Class, specific: Class) { + const relations = this.project.getAllRelations(); + + for (let i = 0; i < relations.length; i++) { + if (relations[i].getSourceClass() == general) { + this.copyRelationFromGeneralToSpecific(general, specific, relations[i], true); + } else { + if (relations[i].getTargetClass() == general) { + this.copyRelationFromGeneralToSpecific(general, specific, relations[i], true); + } + } + } + } + + nonSortalAbstraction(): Abstraction { const abstraction = new Abstraction('Non Sortal Abstraction'); - + + const nonSortals = this.project.getAllClassesByStereotype(ClassStereotype.ROLE_MIXIN).concat(this.project.getAllClassesByStereotype(ClassStereotype.MIXIN).concat(this.project.getAllClassesByStereotype(ClassStereotype.CATEGORY))); + + const relations = this.project.getAllRelations(); + + const generealizations = this.project.getAllGeneralizationSets(); + + for (let i = 0; i < generealizations.length; i++) { + for (let j = 0; j < nonSortals.length; j++) { + if (generealizations[i].getGeneral() == nonSortals[j]) { + for (let x = 0; x < generealizations[i].getSpecifics().length; x++) { + this.copyRelationsFromGeneralToSpecificList(generealizations[i].getGeneralClass(), generealizations[i].getSpecificClasses()[x]); + } + } + } + } + + /*TODO Eliminar o não sortal + */ + const allClasses = this.project.getAllClasses(); + + const relations_new = this.project.getAllRelations(); + + for (let i = nonSortals.length - 1; i >= 0; i--) { + + + for (let j = relations_new.length - 1; j >= 0; j--) { + if ((relations_new[j].getSourceClass() == nonSortals[i]) || (relations_new[j].getTargetClass() == nonSortals[i])) { + relations_new.splice(j, 1); + } + } + + var index = allClasses.indexOf(nonSortals[i]); + console.log("Remover " + nonSortals[i].getName() + " no indice " + index); + allClasses.splice(index, 1); + + } + + abstraction.addClasses(allClasses); + abstraction.addRelations(relations_new); + abstraction.removeDuplicates(); + + console.log("Non Sortal Classes: " + allClasses.length) + return abstraction; } - sortalAbstraction():Abstraction{ + sortalAbstraction(): Abstraction { const abstraction = new Abstraction('Sortal Abstraction'); - + return abstraction; } - subkindAndPhasePartitionsAbstraction():Abstraction{ + subkindAndPhasePartitionsAbstraction(): Abstraction { const abstraction = new Abstraction('Subkind And Phase Partitions Abstraction'); - + return abstraction; } -} + + + +} + From a141cf409c2f978897e33dd689292dc503e206a2 Mon Sep 17 00:00:00 2001 From: Guylerme Date: Sat, 22 May 2021 01:27:12 -0300 Subject: [PATCH 5/5] Implementation of Abstraction Rules. --- .../libs/abstraction/abstractor.basic.test.ts | 35 ++ src/libs/abstraction/abstractor.ts | 392 ++++++++++++++---- src/libs/ontouml/model/generalization_set.ts | 10 + 3 files changed, 357 insertions(+), 80 deletions(-) diff --git a/__tests__/libs/abstraction/abstractor.basic.test.ts b/__tests__/libs/abstraction/abstractor.basic.test.ts index 8a0ddf0e..1732dba7 100644 --- a/__tests__/libs/abstraction/abstractor.basic.test.ts +++ b/__tests__/libs/abstraction/abstractor.basic.test.ts @@ -119,5 +119,40 @@ describe('Basic clusterization example', () => { expect(diagram.findView(medRentalCustomer)).toBeFalsy(); }); + }); + + + describe('Sortal Abstraction Test', () => { + let diagram: Diagram = diagrams.find(d => d.getName() === 'Sortal Abstraction'); + + it('Should not contain classes', () => { + expect(diagram.findView(husband)).toBeFalsy(); + expect(diagram.findView(wife)).toBeFalsy(); + expect(diagram.findView(personalCustomer)).toBeFalsy(); + expect(diagram.findView(rentalCar)).toBeFalsy(); + expect(diagram.findView(corporateCustomer)).toBeFalsy(); + + + }); + + + + }); + + describe('Subkind And Phase Partitions Abstraction Test', () => { + let diagram: Diagram = diagrams.find(d => d.getName() === 'Subkind And Phase Partitions Abstraction'); + + it('Should not contain classes', () => { + expect(diagram.findView(child)).toBeFalsy(); + expect(diagram.findView(adult)).toBeFalsy(); + expect(diagram.findView(teenager)).toBeFalsy(); + expect(diagram.findView(available)).toBeFalsy(); + expect(diagram.findView(underMaintenance)).toBeFalsy(); + + + }); + + + }); }); diff --git a/src/libs/abstraction/abstractor.ts b/src/libs/abstraction/abstractor.ts index f334b021..8dd4325b 100644 --- a/src/libs/abstraction/abstractor.ts +++ b/src/libs/abstraction/abstractor.ts @@ -2,6 +2,9 @@ import { Class, GeneralizationSet, Generalization, Diagram, Project, ClassStereo import { Service } from '@libs/service'; import { ServiceIssue } from '@libs/service_issue'; import { Abstraction } from '@libs/abstraction'; +import { getUnpackedSettings } from 'http2'; +import { lte, partition } from 'lodash'; +import { ClassVerification } from '@libs/verification'; /** * Class that implements the relation-based model clustering strategy proposed in: @@ -56,6 +59,12 @@ export class Abstractor implements Service { return abstraction; } + /** + * This method will abstract a model removing the Relators. If a relator is a truth maker of a relation, + * it will be abstracted to a material relation between the elements + * + * @returns A model abstracted using the Relator Abstraction Rule + */ relatorAbstraction(): Abstraction { const abstraction = new Abstraction('Relator Abstraction'); @@ -65,15 +74,22 @@ export class Abstractor implements Service { const relations = this.project.getAllRelations(); + /**Step 1: Search for all relators in the model + * + * Step 2: Remove all relations where a Relator is participating + * + * Step 3: Remove the relator from model. + */ for (let i = relators.length - 1; i >= 0; i--) { - + /**2 */ for (let j = relations.length - 1; j >= 0; j--) { if ((relations[j].getSourceClass() == relators[i]) || (relations[j].getTargetClass() == relators[i])) { relations.splice(j, 1); } } + /**3 */ var index = allClasses.indexOf(relators[i]); console.log("Remover " + relators[i].getName() + " no indice " + index); allClasses.splice(index, 1); @@ -90,85 +106,95 @@ export class Abstractor implements Service { return abstraction; } + /** + * This method will "move" a relation from Source class to a Target class. + * In fact the relation will not be moved, but a new relation just like the original one will be created with target class. + * For example, a class X have a material relation (r1) with class y. If this method will "move" the material relation(r1) from x to class w, + * this method will create a new material relation(r2), just like r1, however between class w and class y. + * + * @param source Source class that relation will be "moved" from + * @param target Target class that relation will be "moved" to + * @param relation Relation to be "moved" + */ + copyRelationFromSourceToTarget(source: Class, target: Class, relation: Relation) { + switch (relation.stereotype) { + case RelationStereotype.MATERIAL: this.project.model.createMaterialRelation(source, target, relation.getName() + 'as' + source.getName()); + break; + case RelationStereotype.COMPARATIVE: this.project.model.createComparativeRelation(source, target, relation.getName() + 'as' + source.getName()); + break; + case RelationStereotype.MEDIATION: this.project.model.createMediationRelation(source, target, relation.getName() + 'as' + source.getName()); + break; + case RelationStereotype.CHARACTERIZATION: this.project.model.createCharacterizationRelation(source, target, relation.getName() + 'as' + source.getName()); + break; + case RelationStereotype.COMPONENT_OF: this.project.model.createComponentOfRelation(source, target, relation.getName() + 'as' + source.getName()); + break; + case RelationStereotype.MEMBER_OF: this.project.model.createMemberOfRelation(source, target, relation.getName() + 'as' + source.getName()); + break; + case RelationStereotype.SUBCOLLECTION_OF: this.project.model.createSubCollectionOfRelation(source, target, relation.getName() + 'as' + source.getName()); + break; + case RelationStereotype.SUBQUANTITY_OF: this.project.model.createSubQuantityOfRelation(source, target, relation.getName() + 'as' + source.getName()); + break; + case RelationStereotype.INSTANTIATION: this.project.model.createInstantiationRelation(source, target, relation.getName() + 'as' + source.getName()); + break; + case RelationStereotype.TERMINATION: this.project.model.createTerminationRelation(source, target, relation.getName() + 'as' + source.getName()); + break; + case RelationStereotype.PARTICIPATIONAL: this.project.model.createParticipationalRelation(source, target, relation.getName() + 'as' + source.getName()); + break; + case RelationStereotype.PARTICIPATION: this.project.model.createParticipationRelation(source, target, relation.getName() + 'as' + source.getName()); + break; + case RelationStereotype.HISTORICAL_DEPENDENCE: this.project.model.createHistoricalDependenceRelation(source, target, relation.getName() + 'as' + source.getName()); + break; + case RelationStereotype.CREATION: this.project.model.createCreationRelation(source, target, relation.getName() + 'as' + source.getName()); + break; + case RelationStereotype.MANIFESTATION: this.project.model.createManifestationRelation(source, target, relation.getName() + 'as' + source.getName()); + break; + case RelationStereotype.BRINGS_ABOUT: this.project.model.createBringsAboutRelation(source, target, relation.getName() + 'as' + source.getName()); + break; + case RelationStereotype.TRIGGERS: this.project.model.createTriggersRelation(source, target, relation.getName() + 'as' + source.getName()); + break; + } + } + + + /** + * This method will "move" relations from General to Specific class in a generalization + * + * @param general General class of generalization that is being analysing + * @param specific Specific class of generalization that is being analysing + * @param relation Specifica class's Relation of generalization that is being analysing + * @param inSource True if the Specific Class is in the Relation's source, false otherwise + */ copyRelationFromGeneralToSpecific(general: Class, specific: Class, relation: Relation, inSource: boolean) { if (inSource) { - switch (relation.stereotype) { - case RelationStereotype.MATERIAL: this.project.model.createMaterialRelation(specific, relation.getTargetClass(), relation.getName() + 'as' + general.getName()); - break; - case RelationStereotype.COMPARATIVE: this.project.model.createComparativeRelation(specific, relation.getTargetClass(), relation.getName() + 'as' + general.getName()); - break; - case RelationStereotype.MEDIATION: this.project.model.createMediationRelation(specific, relation.getTargetClass(), relation.getName() + 'as' + general.getName()); - break; - case RelationStereotype.CHARACTERIZATION: this.project.model.createCharacterizationRelation(specific, relation.getTargetClass(), relation.getName() + 'as' + general.getName()); - break; - case RelationStereotype.COMPONENT_OF: this.project.model.createComponentOfRelation(specific, relation.getTargetClass(), relation.getName() + 'as' + general.getName()); - break; - case RelationStereotype.MEMBER_OF: this.project.model.createMemberOfRelation(specific, relation.getTargetClass(), relation.getName() + 'as' + general.getName()); - break; - case RelationStereotype.SUBCOLLECTION_OF: this.project.model.createSubCollectionOfRelation(specific, relation.getTargetClass(), relation.getName() + 'as' + general.getName()); - break; - case RelationStereotype.SUBQUANTITY_OF: this.project.model.createSubQuantityOfRelation(specific, relation.getTargetClass(), relation.getName() + 'as' + general.getName()); - break; - case RelationStereotype.INSTANTIATION: this.project.model.createInstantiationRelation(specific, relation.getTargetClass(), relation.getName() + 'as' + general.getName()); - break; - case RelationStereotype.TERMINATION: this.project.model.createTerminationRelation(specific, relation.getTargetClass(), relation.getName() + 'as' + general.getName()); - break; - case RelationStereotype.PARTICIPATIONAL: this.project.model.createParticipationalRelation(specific, relation.getTargetClass(), relation.getName() + 'as' + general.getName()); - break; - case RelationStereotype.PARTICIPATION: this.project.model.createParticipationRelation(specific, relation.getTargetClass(), relation.getName() + 'as' + general.getName()); - break; - case RelationStereotype.HISTORICAL_DEPENDENCE: this.project.model.createHistoricalDependenceRelation(specific, relation.getTargetClass(), relation.getName() + 'as' + general.getName()); - break; - case RelationStereotype.CREATION: this.project.model.createCreationRelation(specific, relation.getTargetClass(), relation.getName() + 'as' + general.getName()); - break; - case RelationStereotype.MANIFESTATION: this.project.model.createManifestationRelation(specific, relation.getTargetClass(), relation.getName() + 'as' + general.getName()); - break; - case RelationStereotype.BRINGS_ABOUT: this.project.model.createBringsAboutRelation(specific, relation.getTargetClass(), relation.getName() + 'as' + general.getName()); - break; - case RelationStereotype.TRIGGERS: this.project.model.createTriggersRelation(specific, relation.getTargetClass(), relation.getName() + 'as' + general.getName()); - break; - } + this.copyRelationFromSourceToTarget(general, relation.getTargetClass(), relation); } else { - switch (relation.stereotype) { - case RelationStereotype.MATERIAL: this.project.model.createMaterialRelation(relation.getSourceClass(), specific, relation.getName() + 'as' + general.getName()); - break; - case RelationStereotype.COMPARATIVE: this.project.model.createComparativeRelation(relation.getSourceClass(), specific, relation.getName() + 'as' + general.getName()); - break; - case RelationStereotype.MEDIATION: this.project.model.createMediationRelation(relation.getSourceClass(), specific, relation.getName() + 'as' + general.getName()); - break; - case RelationStereotype.CHARACTERIZATION: this.project.model.createCharacterizationRelation(relation.getSourceClass(), specific, relation.getName() + 'as' + general.getName()); - break; - case RelationStereotype.COMPONENT_OF: this.project.model.createComponentOfRelation(relation.getSourceClass(), specific, relation.getName() + 'as' + general.getName()); - break; - case RelationStereotype.MEMBER_OF: this.project.model.createMemberOfRelation(relation.getSourceClass(), specific, relation.getName() + 'as' + general.getName()); - break; - case RelationStereotype.SUBCOLLECTION_OF: this.project.model.createSubCollectionOfRelation(relation.getSourceClass(), specific, relation.getName() + 'as' + general.getName()); - break; - case RelationStereotype.SUBQUANTITY_OF: this.project.model.createSubQuantityOfRelation(relation.getSourceClass(), specific, relation.getName() + 'as' + general.getName()); - break; - case RelationStereotype.INSTANTIATION: this.project.model.createInstantiationRelation(relation.getSourceClass(), specific, relation.getName() + 'as' + general.getName()); - break; - case RelationStereotype.TERMINATION: this.project.model.createTerminationRelation(relation.getSourceClass(), specific, relation.getName() + 'as' + general.getName()); - break; - case RelationStereotype.PARTICIPATIONAL: this.project.model.createParticipationalRelation(relation.getSourceClass(), specific, relation.getName() + 'as' + general.getName()); - break; - case RelationStereotype.PARTICIPATION: this.project.model.createParticipationRelation(relation.getSourceClass(), specific, relation.getName() + 'as' + general.getName()); - break; - case RelationStereotype.HISTORICAL_DEPENDENCE: this.project.model.createHistoricalDependenceRelation(relation.getSourceClass(), specific, relation.getName() + 'as' + general.getName()); - break; - case RelationStereotype.CREATION: this.project.model.createCreationRelation(relation.getSourceClass(), specific, relation.getName() + 'as' + general.getName()); - break; - case RelationStereotype.MANIFESTATION: this.project.model.createManifestationRelation(relation.getSourceClass(), specific, relation.getName() + 'as' + general.getName()); - break; - case RelationStereotype.BRINGS_ABOUT: this.project.model.createBringsAboutRelation(relation.getSourceClass(), specific, relation.getName() + 'as' + general.getName()); - break; - case RelationStereotype.TRIGGERS: this.project.model.createTriggersRelation(relation.getSourceClass(), specific, relation.getName() + 'as' + general.getName()); - break; - } + this.copyRelationFromSourceToTarget(relation.getSourceClass(), specific, relation); } } + /** + * This method will "move" relations from Specific to General class in a generalization + * + * @param specific Specific class of generalization that is being analysing + * @param general General class of generalization that is being analysing + * @param relation Specifica class's Relation of generalization that is being analysing + * @param inSource True if the Specific Class is in the Relation's source, false otherwise + */ + copyRelationFromSpecificToGeneral(specific: Class, general: Class, relation: Relation, inSource: boolean) { + if (inSource) { + this.copyRelationFromSourceToTarget(specific, relation.getTargetClass(), relation); + } + else { + this.copyRelationFromSourceToTarget(relation.getSourceClass(), general, relation); + } + } + + /** + * This method will "move"relations from a General to the list of Specific class in a GeneralizationSet + * @param general General class of generalization that is being analysing + * @param specific Specific class of generalization that is being analysingß + */ copyRelationsFromGeneralToSpecificList(general: Class, specific: Class) { const relations = this.project.getAllRelations(); @@ -183,6 +209,13 @@ export class Abstractor implements Service { } } + + /** + * This method will abstract all non-sortals specializations by "moving" the general relations to respective specifics. + * After that, the general is removed from model + * + * @returns A model abstracted using the Non-Sortal Abstraction Rule + */ nonSortalAbstraction(): Abstraction { const abstraction = new Abstraction('Non Sortal Abstraction'); @@ -190,33 +223,48 @@ export class Abstractor implements Service { const relations = this.project.getAllRelations(); - const generealizations = this.project.getAllGeneralizationSets(); + const genereralizations = this.project.getAllGeneralizationSets(); - for (let i = 0; i < generealizations.length; i++) { + /** + * Step 1: Search for all generalizations in model + * + * Step 2: If a Non-Sortal is the general in the generalization, it will be removed from model + * + * 2.1: For each specific of the non-sortal general, general relations will be "moved" to specifics + */ + for (let i = 0; i < genereralizations.length; i++) { for (let j = 0; j < nonSortals.length; j++) { - if (generealizations[i].getGeneral() == nonSortals[j]) { - for (let x = 0; x < generealizations[i].getSpecifics().length; x++) { - this.copyRelationsFromGeneralToSpecificList(generealizations[i].getGeneralClass(), generealizations[i].getSpecificClasses()[x]); + /**2 */ + if (genereralizations[i].getGeneral() == nonSortals[j]) { + /**2.1 */ + for (let x = 0; x < genereralizations[i].getSpecifics().length; x++) { + this.copyRelationsFromGeneralToSpecificList(genereralizations[i].getGeneralClass(), genereralizations[i].getSpecificClasses()[x]); } } } } - /*TODO Eliminar o não sortal - */ + const allClasses = this.project.getAllClasses(); const relations_new = this.project.getAllRelations(); + /**Step 3 Remove all relations with the non-sortals + * 3.1: For each non-sortal in model will search for relations that contains a non-sortal. + * + * 3.2: If the relation has the non-sortal as Source or Target, it will be removed. + */ for (let i = nonSortals.length - 1; i >= 0; i--) { for (let j = relations_new.length - 1; j >= 0; j--) { + /**3.2 */ if ((relations_new[j].getSourceClass() == nonSortals[i]) || (relations_new[j].getTargetClass() == nonSortals[i])) { relations_new.splice(j, 1); } } + /**Step 4 Remove the non-sortal from model */ var index = allClasses.indexOf(nonSortals[i]); console.log("Remover " + nonSortals[i].getName() + " no indice " + index); allClasses.splice(index, 1); @@ -231,16 +279,198 @@ export class Abstractor implements Service { return abstraction; } + /** + * This method verify if a Generalization is part of a GeneralizationSet + * + * @param generalization Generalization to be verified in GeneralizationSet + * @returns True if the generalization is part of a GeneralizationSet, false if not. + */ + isInGeneralizationSet(generalization: Generalization): boolean { + let genSets = this.project.model.getAllGeneralizationSets(); + + /** + * For all GeneralizationSets in model, verify is the generalization is part of it. + */ + for (let i = 0; i < genSets.length; i++) { + + if (genSets[i].generalizations.includes(generalization)) { + return true; + } + + } + return false; + } + + /** + * This method will abstract all sortals specializations by "moving" the specific relations to respective general. + * After that, the specific is removed from model + * + * @returns A model abstracted using the Sortal Abstraction Rule + */ sortalAbstraction(): Abstraction { const abstraction = new Abstraction('Sortal Abstraction'); + const allClasses = this.project.getAllClasses(); + + const sortals = this.project.getAllClassesByStereotype(ClassStereotype.KIND).concat(this.project.getAllClassesByStereotype(ClassStereotype.SUBKIND).concat(this.project.getAllClassesByStereotype(ClassStereotype.ROLE).concat(this.project.getAllClassesByStereotype(ClassStereotype.PHASE).concat(this.project.getAllClassesByStereotype(ClassStereotype.COLLECTIVE).concat(this.project.getAllClassesByStereotype(ClassStereotype.QUANTITY)))))); + + const relations = this.project.getAllRelations(); + + let generalizations = this.project.model.getAllGeneralizations(); + + /**Step 1: Consider only Generalizations that isn`'t participating in a GeneralizationSet + * This loop will remove from the generalizations list all that is participating in a GeneralizationSet + */ + + for (let i = generalizations.length - 1; i > -0; i--) { + if (this.isInGeneralizationSet(generalizations[i])) { + generalizations.splice(i, 1); + } + } + + /** Step 2: Search for all Sortals Specializations and copy the Specific relation to General + * 2.1: First loop will consider only generalizations that isn't participation ina a GeneralizationSet + * + * 2.2: Second loop will consider all sortals in model to copy relations + * 2.2.1: For each sortal in model, if it's in a generalization will copy specific relations to general + * 2.2.1.1: Navigate in all relations searching for relations that need to be copied and copy the relation + * + * 2.3: Collect all relation that will be removed from model + * + * 2.4: Remove the specific from model + */ + + let relationToRemove = []; + + /**2.1 */ + for (let i = 0; i < generalizations.length; i++) { + /**2.2 */ + for (let j = 0; j < sortals.length; j++) { + /**2.2.1 */ + if ((generalizations[i].getGeneralClass() == sortals[j]) && (generalizations[i] != null)) { + /**2.2.1.1 */ + for (let w = 0; w < relations.length; w++) { + if (relations[w].getSourceClass() == generalizations[i].getSpecificClass()) { + this.copyRelationFromSpecificToGeneral(generalizations[i].getSpecificClass(), generalizations[i].getGeneralClass(), relations[w], true); + } else { + if (relations[w].getTargetClass() == generalizations[i].getSpecificClass()) { + this.copyRelationFromSpecificToGeneral(generalizations[i].getSpecificClass(), generalizations[i].getGeneralClass(), relations[w], true); + } + } + } + + } + } + + /**2.3*/ + for (let z = 0; z < relations.length; z++) { + console.log('Classe origem ' + relations[z].getSourceClass()); + if ((relations[z].getSourceClass() == generalizations[i].getSpecificClass()) || (relations[z].getTargetClass() == generalizations[i].getSpecificClass())) { + relationToRemove.push(relations[z]); + } + } + + + /**2.4*/ + var index = allClasses.indexOf(generalizations[i].getSpecificClass()); + console.log("Remover " + generalizations[i].getSpecificClass().getName() + " no indice " + index); + allClasses.splice(index, 1); + } + + + /**Step 3: Remove all relations with removed specific classes */ + + const relations_new = this.project.model.getAllRelations(); + for (let i = relations_new.length; i >= 0; i--) { + for (let j = 0; j < relationToRemove.length; j++) { + var index = relations_new.indexOf(relationToRemove[j]); + relations_new.splice(index, 1); + } + } + + + + abstraction.addClasses(allClasses); + abstraction.addRelations(relations_new); + abstraction.removeDuplicates(); + + return abstraction; } subkindAndPhasePartitionsAbstraction(): Abstraction { const abstraction = new Abstraction('Subkind And Phase Partitions Abstraction'); + const allClasses = this.project.getAllClasses(); + + const generalizationSets = this.project.model.getAllGeneralizationSets(); + + const relations = this.project.model.getAllRelations(); + + /**Step 1 Verify if the GeneralizationSet is a Phase Partition or a Subkind Partition + * + * Step 2 Get all specifics names to transform then in item of a enumeration + * + * Step 3 Move the relation from specific to general + * + * Step 4 Remove the specific from model + * + * Step 5 Create an Enumeration and a relation between the relation and general class + */ + let relationToRemove = []; + for (let i = 0; i < generalizationSets.length; i++) { + if ((generalizationSets[i].isPhasePartition()) || (generalizationSets[i].isSubkindPartition())) { + let itens = []; + /**2 */ + for (let j = 0; j < generalizationSets[i].getSpecificClasses().length; j++) { + itens.push(generalizationSets[i].getSpecificClasses()[j].getName()); + + /**3 */ + for (let w = 0; w < relations.length; w++) { + if (relations[w].getSourceClass() == generalizationSets[i].getSpecificClasses()[j]) { + this.copyRelationFromSpecificToGeneral(generalizationSets[i].getSpecificClasses()[j], generalizationSets[i].getGeneralClass(), relations[w], true); + relationToRemove.push(relations[w]); + } else { + if (relations[w].getTargetClass() == generalizationSets[i].getSpecificClasses()[j]) { + this.copyRelationFromSpecificToGeneral(generalizationSets[i].getSpecificClasses()[j], generalizationSets[i].getGeneralClass(), relations[w], false); + relationToRemove.push(relations[w]); + } + } + + + } + + /**4 */ + var index = allClasses.indexOf(generalizationSets[i].getSpecificClasses()[j]); + console.log("Remover " + generalizationSets[i].getSpecificClasses()[j].getName() + " no indice " + index); + allClasses.splice(index, 1); + + } + + /**5 */ + this.project.model.createBinaryRelation(generalizationSets[i].getGeneralClass(), this.project.model.createEnumeration(generalizationSets[i].getName(), itens)); + + } + } + + /**Step 6 Remove all relations with removed specific classes */ + + const relations_new = this.project.model.getAllRelations(); + for (let i = relations_new.length; i >= 0; i--) { + for (let j = 0; j < relationToRemove.length; j++) { + var index = relations_new.indexOf(relationToRemove[j]); + relations_new.splice(index, 1); + } + } + + + + abstraction.addClasses(allClasses); + abstraction.addRelations(relations_new); + abstraction.removeDuplicates(); + + return abstraction; } @@ -249,3 +479,5 @@ export class Abstractor implements Service { } + + diff --git a/src/libs/ontouml/model/generalization_set.ts b/src/libs/ontouml/model/generalization_set.ts index 9e96161c..390d6807 100644 --- a/src/libs/ontouml/model/generalization_set.ts +++ b/src/libs/ontouml/model/generalization_set.ts @@ -38,6 +38,16 @@ export class GeneralizationSet extends ModelElement { ); } + isSubkindPartition(): boolean { + return ( + this.isPartition() && + this.involvesClasses() && + ((this.getSpecificClasses().every(specific => specific.hasSubkindStereotype()) && + this.getGeneralClass().hasSortalStereotype())) + // + ); + } + /** * @throws exception if different generals are present */