Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

amr-errors in dev interface, more amr check criteria #4451

Merged
merged 2 commits into from
Aug 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions packages/client/hmi-client/src/model-representation/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,14 @@ export function checkPetrinetAMR(amr: Model) {
const numInitials = ode?.initials?.length || 0;
const numRates = ode?.rates?.length || 0;

if (numStates === 0) {
results.push({ type: 'warn', content: 'zero states' });
}

if (numTransitions === 0) {
results.push({ type: 'warn', content: 'zero transitions' });
}

if (numStates !== numInitials) {
results.push({ type: 'error', content: 'states need to match initials' });
}
Expand All @@ -292,6 +300,8 @@ export function checkPetrinetAMR(amr: Model) {
});

// Check state
const stateSet = new Set<string>();
const initialSet = new Set<string>();
model.states.forEach((state) => {
const initial = initialMap.get(state.id);
if (!initial) {
Expand All @@ -303,9 +313,19 @@ export function checkPetrinetAMR(amr: Model) {
if (!isASCII(initial?.expression as string)) {
results.push({ type: 'warn', content: `${state.id} has non-ascii expression` });
}
if (stateSet.has(state.id)) {
results.push({ type: 'error', content: `state (${state.id}) has duplicate` });
}
if (initialSet.has(initial?.target as string)) {
results.push({ type: 'error', content: `initial (${initial?.target}) has duplicate` });
}
stateSet.add(state.id);
initialSet.add(initial?.target as string);
});

// Check transitions
const transitionSet = new Set<string>();
const rateSet = new Set<string>();
model.transitions.forEach((transition) => {
const rate = rateMap.get(transition.id);
if (!rate) {
Expand All @@ -317,6 +337,14 @@ export function checkPetrinetAMR(amr: Model) {
if (!isASCII(rate?.expression as string)) {
results.push({ type: 'warn', content: `${transition.id} has non-ascii expression` });
}
if (transitionSet.has(transition.id)) {
results.push({ type: 'error', content: `transition (${transition.id}) has duplicate` });
}
if (rateSet.has(rate?.target as string)) {
results.push({ type: 'error', content: `rate (${rate?.target}) has duplicate` });
}
transitionSet.add(transition.id);
rateSet.add(rate?.target as string);
});

return results;
Expand Down
105 changes: 38 additions & 67 deletions packages/client/hmi-client/src/temp/AMRPetriTest.vue
Original file line number Diff line number Diff line change
@@ -1,34 +1,40 @@
<template>
<div style="display: flex; flex-direction: row; padding: 1rem">
<div style="display: flex; flex-direction: column">
<textarea style="width: 550px; height: 550px; margin: 0 10px" v-model="jsonStr"> </textarea>
<textarea style="width: 600px; height: 425px; margin: 0 10px" v-model="jsonStr"> </textarea>
<div style="height: 150px; max-height: 150px; overflow-y: scroll; border: 1px solid #bbb; margin: 0.5rem">
<table style="width: 100%">
<tr v-for="(log, idx) in errors" :key="idx" style="border: 1px solid #ddd">
<td :class="[log.type]" style="width: 6rem">{{ log.type }}</td>
<td>{{ log.content }}</td>
</tr>
</table>
<div v-if="errors.length === 0">No problems found</div>
</div>
<div>
<button style="width: 10rem; margin: 3px; font-size: 125%" @click="isCollapsed = true">Collapse</button>
<button style="width: 10rem; margin: 3px; font-size: 125%" @click="isCollapsed = false">Expand</button>
<button style="width: 10rem; margin: 3px; font-size: 100%" @click="isCollapsed = true">Collapse</button>
<button style="width: 10rem; margin: 3px; font-size: 100%" @click="isCollapsed = false">Expand</button>
</div>
</div>
<div>
<div style="position: fixed; padding: 2px">
{{ strataType === null ? 'No strata' : strataType }}
</div>
<div ref="graphElement" class="canvas" style="height: 600px; width: 900px"></div>
<div ref="graphElement" class="canvas" style="height: 600px; width: 750px"></div>
</div>
</div>
</template>

<script setup lang="ts">
import _ from 'lodash';
import { getModelRenderer } from '@/model-representation/service';
import { checkPetrinetAMR, getModelRenderer } from '@/model-representation/service';
import { getMMT } from '@/services/model';

import { onMounted, ref, watch } from 'vue';
import * as mmtExample from '@/examples/mira-petri.json';
import { convertToIGraph, collapseParameters, createParameterMatrix } from '@/model-representation/mira/mira';
import { convertToIGraph } from '@/model-representation/mira/mira';

const graphElement = ref<HTMLDivElement | null>(null);
const jsonStr = ref('');
const strataType = ref<string | null>(null);
const isCollapsed = ref(true);
const errors = ref<any[]>([]);

onMounted(async () => {
jsonStr.value = JSON.stringify(mmtExample, null, 2);
Expand All @@ -37,69 +43,15 @@ onMounted(async () => {
() => [jsonStr.value, isCollapsed.value],
async () => {
const jsonData = JSON.parse(jsonStr.value);
errors.value = checkPetrinetAMR(jsonData);

const mmtR = await getMMT(jsonData);
const mmt = mmtR.mmt;
const template_params = mmtR.template_params;
const observable_summary = mmtR.observable_summary;

const renderer = getModelRenderer(mmt, graphElement.value as HTMLDivElement, false);
const renderer = getModelRenderer(mmt, graphElement.value as HTMLDivElement, true);
const graphData = convertToIGraph(mmt, observable_summary, isCollapsed.value);

// Create all possible matrices
const rootParams = collapseParameters(mmt, template_params);
const rootParamKeys = [...rootParams.keys()];

const lines: any[] = [];
rootParamKeys.forEach((key) => {
const matrices = createParameterMatrix(mmt, template_params, key);
let header = '';

const subjectOutcome = matrices.subjectOutcome;
const subjectControllers = matrices.subjectControllers;
const outcomeControllers = matrices.outcomeControllers;

if (subjectOutcome.matrix.length > 0) {
lines.push(`subject-outcome of ${key}`);
header = ',' + subjectOutcome.rowNames.join(',');
lines.push('');
lines.push(header);
subjectOutcome.matrix.forEach((r, idx) => {
const rowStr = subjectOutcome.colNames[idx] + r.map((d) => d.content.id).join(',');
lines.push(rowStr);
});
lines.push('');
lines.push('');
}

if (subjectControllers.matrix.length > 0) {
lines.push(`subject-controllers of ${key}`);
header = ',' + subjectControllers.rowNames.join(',');
lines.push('');
lines.push(header);
subjectControllers.matrix.forEach((r, idx) => {
const rowStr = subjectControllers.colNames[idx] + ',' + r.map((d) => d.content.id).join(',');
lines.push(rowStr);
});
lines.push('');
lines.push('');
}

if (outcomeControllers.matrix.length > 0) {
lines.push(`outcome-controllers of ${key}`);
header = ',' + outcomeControllers.rowNames.join(',');
lines.push('');
lines.push(header);
outcomeControllers.matrix.forEach((r, idx) => {
const rowStr = outcomeControllers.colNames[idx] + ',' + r.map((d) => d.content.id).join(',');
lines.push(rowStr);
});
lines.push('');
lines.push('');
}
});

console.log(lines.join('\n'));

await renderer.setData(graphData);
renderer.isGraphDirty = true;
renderer.render();
Expand All @@ -108,3 +60,22 @@ onMounted(async () => {
);
});
</script>

<style scoped>
table {
border-collapse: collapse;
}

td {
padding: 2px;
}

td.error {
background: #f20;
text-align: center;
}
td.warn {
background: #f80;
text-align: center;
}
</style>
Loading