diff --git a/components/bpmn-q/.bpmnlintrc b/components/bpmn-q/.bpmnlintrc index e153bd98..449be45a 100644 --- a/components/bpmn-q/.bpmnlintrc +++ b/components/bpmn-q/.bpmnlintrc @@ -5,6 +5,7 @@ ], "rules": { "custom/quantme-tasks": "warn", + "custom/pre-deployed-pattern-on-demand-policy": "error", "custom/subprocess-connected-end-event": "warn", "custom/subprocess-required-start-event": "warn", "camunda/no-collapsed-sub-processes": "off" diff --git a/components/bpmn-q/bpmnlint-plugin-custom/index.js b/components/bpmn-q/bpmnlint-plugin-custom/index.js index f4c2403d..13b79771 100644 --- a/components/bpmn-q/bpmnlint-plugin-custom/index.js +++ b/components/bpmn-q/bpmnlint-plugin-custom/index.js @@ -6,6 +6,7 @@ module.exports = { all: { rules: { "quantme-tasks": "warn", + "pre-deployed-pattern-on-demand-policy": "error", "subprocess-required-start-event": "warn", "subprocess-connected-end-event": "warn", }, diff --git a/components/bpmn-q/bpmnlint-plugin-custom/rules/pre-deployed-pattern-on-demand-policy.js b/components/bpmn-q/bpmnlint-plugin-custom/rules/pre-deployed-pattern-on-demand-policy.js new file mode 100644 index 00000000..b8ff95ef --- /dev/null +++ b/components/bpmn-q/bpmnlint-plugin-custom/rules/pre-deployed-pattern-on-demand-policy.js @@ -0,0 +1,60 @@ +const { is } = require("bpmnlint-utils"); + +/** + * A rule that checks that no on-demand policy is inside the subprocess to which a pre-deployed pattern is attached. + */ +module.exports = function () { + function check(node, reporter) { + if (!is(node, "pattern:PredeployedExecution")) { + return; + } + + function checkForOnDemandPolicyInSubprocesses(subprocess) { + let containsOnDemandPolicy = false; + const flowElements = subprocess.flowElements || []; + flowElements.forEach(function (flowElement) { + if (is(flowElement, "opentosca:OnDemandPolicy")) { + policies.push(flowElement); + containsOnDemandPolicy = true; + } + if (is(flowElement, "bpmn:SubProcess")) { + containsOnDemandPolicy = + checkForOnDemandPolicyInSubprocesses(flowElement) || + containsOnDemandPolicy; + } + }); + return containsOnDemandPolicy; + } + + let attachedSubprocess = node.attachedToRef.id; + let parent; + let policies = []; + const flowElements = node.$parent.flowElements || []; + flowElements.forEach(function (flowElement) { + if (flowElement.id === attachedSubprocess) { + parent = flowElement; + } + }); + + let containsOnDemandPolicy = checkForOnDemandPolicyInSubprocesses(parent); + + if (containsOnDemandPolicy) { + reporter.report( + node.id, + "Pre-deployed Pattern and on-demand policy cannot be used together", + ["eventDefinitions"] + ); + for (let i = 0; i < policies.length; i++) { + reporter.report( + policies[i].id, + "Pre-deployed Pattern and on-demand policy cannot be used together", + ["eventDefinitions"] + ); + } + } + } + + return { + check, + }; +}; diff --git a/components/bpmn-q/bpmnlint-plugin-custom/rules/subprocess-connected-end-event.js b/components/bpmn-q/bpmnlint-plugin-custom/rules/subprocess-connected-end-event.js index 3e50dc44..269608cf 100644 --- a/components/bpmn-q/bpmnlint-plugin-custom/rules/subprocess-connected-end-event.js +++ b/components/bpmn-q/bpmnlint-plugin-custom/rules/subprocess-connected-end-event.js @@ -20,7 +20,6 @@ module.exports = function () { } function check(node, reporter) { - console.log(node); if (!isAny(node, ["bpmn:SubProcess"])) { return; } diff --git a/components/bpmn-q/karma.conf.js b/components/bpmn-q/karma.conf.js index 5d9eb494..81955a62 100644 --- a/components/bpmn-q/karma.conf.js +++ b/components/bpmn-q/karma.conf.js @@ -29,6 +29,8 @@ module.exports = function (config) { "test/tests/dataflow/data-flow-configurations-endpoint.spec.js", "test/tests/dataflow/data-flow-palette.spec.js", "test/tests/dataflow/data-flow-replace-menu.spec.js", + "test/tests/pattern/pattern-config.spec.js", + "test/tests/pattern/pattern-transformation.spec.js", ], // list of files / patterns to exclude diff --git a/components/bpmn-q/modeler-component/editor/EditorConstants.js b/components/bpmn-q/modeler-component/editor/EditorConstants.js index 187b0660..9aac6d42 100644 --- a/components/bpmn-q/modeler-component/editor/EditorConstants.js +++ b/components/bpmn-q/modeler-component/editor/EditorConstants.js @@ -43,3 +43,19 @@ export const saveFileFormats = { ZIP: ".zip", CSAR: ".csar", }; + +// workflow with a start event to use as template for new workflows +export const INITIAL_DIAGRAM_XML = + '\n' + + '\n' + + ' \n' + + ' \n' + + " \n" + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + " \n" + + " \n" + + " \n" + + ""; diff --git a/components/bpmn-q/modeler-component/editor/util/HttpUtilities.js b/components/bpmn-q/modeler-component/editor/util/HttpUtilities.js index f197db80..165e740e 100644 --- a/components/bpmn-q/modeler-component/editor/util/HttpUtilities.js +++ b/components/bpmn-q/modeler-component/editor/util/HttpUtilities.js @@ -13,11 +13,17 @@ * Retrieves the Json data from the given endpoint. * * @param endpoint the endpoint to retrieve the data form + * @param method * @returns */ -export async function fetchDataFromEndpoint(endpoint) { +export async function fetchDataFromEndpoint(endpoint, method = "GET") { try { - const response = await fetch(endpoint); + const response = await fetch(endpoint, { + method: method, + headers: { + Accept: ["application/json", "application/hal+json"], + }, + }); if (!response.ok) { throw new Error(`HTTP error! Status: ${response.status}`); } @@ -27,3 +33,17 @@ export async function fetchDataFromEndpoint(endpoint) { return {}; } } + +export async function fetchSolutionFromEndpoint(endpoint) { + try { + const response = await fetch(endpoint); + if (!response.ok) { + throw new Error(`HTTP error! Status: ${response.status}`); + } + const data = await response.text(); + return data; + } catch (error) { + console.error("Error fetching data:", error); + return {}; + } +} diff --git a/components/bpmn-q/modeler-component/editor/util/IoUtilities.js b/components/bpmn-q/modeler-component/editor/util/IoUtilities.js index a08b2a83..af76cb2f 100644 --- a/components/bpmn-q/modeler-component/editor/util/IoUtilities.js +++ b/components/bpmn-q/modeler-component/editor/util/IoUtilities.js @@ -4,6 +4,7 @@ import { saveFileFormats, transformedWorkflowHandlers, workflowEventTypes, + INITIAL_DIAGRAM_XML, } from "../EditorConstants"; import { getModeler } from "../ModelerHandler"; import { dispatchWorkflowEvent } from "../events/EditorEventHandler"; @@ -22,22 +23,6 @@ const quantmeConfig = require("../../extensions/quantme/framework-config/config- let FormData = require("form-data"); -// workflow with a start event to use as template for new workflows -const NEW_DIAGRAM_XML = - '\n' + - '\n' + - ' \n' + - ' \n' + - " \n" + - ' \n' + - ' \n' + - ' \n' + - ' \n' + - " \n" + - " \n" + - " \n" + - ""; - /** * Saves a given bpmn diagram as a bpmn file to the locale storage of the user. * @@ -241,7 +226,7 @@ export async function loadDiagram(xml, modeler, dispatchEvent = true) { * @param modeler the given modeler to open the new bpmn diagram in. */ export function createNewDiagram(modeler) { - loadDiagram(NEW_DIAGRAM_XML, modeler).then(); + loadDiagram(INITIAL_DIAGRAM_XML, modeler).then(); } /** diff --git a/components/bpmn-q/modeler-component/extensions/dataflow/modeling/DataFlowRulesProvider.js b/components/bpmn-q/modeler-component/extensions/dataflow/modeling/DataFlowRulesProvider.js index 979848bd..98a36c37 100644 --- a/components/bpmn-q/modeler-component/extensions/dataflow/modeling/DataFlowRulesProvider.js +++ b/components/bpmn-q/modeler-component/extensions/dataflow/modeling/DataFlowRulesProvider.js @@ -50,12 +50,7 @@ export default class CustomRulesProvider extends BpmnRules { * Fired when a new shape for an element is created */ this.addRule("shape.create", 200, function (context) { - return canCreate( - context.shape, - context.target, - context.source, - context.position - ); + return canCreate(context.shape, context.target); }); } @@ -213,7 +208,7 @@ export default class CustomRulesProvider extends BpmnRules { * @param position The position where the shape should be created * @returns {boolean|*|boolean} */ - canCreate(shape, target, source, position) { + canCreate(shape, target) { console.log("##### can create"); // do not allow insertion of DataMapObjects @@ -222,8 +217,6 @@ export default class CustomRulesProvider extends BpmnRules { return false; } } - - return super.canCreate(shape, target, source, position); } /** diff --git a/components/bpmn-q/modeler-component/extensions/opentosca/deployment/BindingUtils.js b/components/bpmn-q/modeler-component/extensions/opentosca/deployment/BindingUtils.js index 4b10e9af..5d78a498 100644 --- a/components/bpmn-q/modeler-component/extensions/opentosca/deployment/BindingUtils.js +++ b/components/bpmn-q/modeler-component/extensions/opentosca/deployment/BindingUtils.js @@ -10,6 +10,7 @@ */ import * as config from "../framework-config/config-manager"; import { fetchDataFromEndpoint } from "../../../editor/util/HttpUtilities"; +import { getRootProcess } from "../../../editor/util/ModellingUtilities"; const QUANTME_NAMESPACE_PULL_ENCODED = encodeURIComponent( encodeURIComponent("http://quantil.org/quantme/pull") @@ -110,11 +111,18 @@ export function bindUsingPull(csar, serviceTaskId, elementRegistry, modeling) { * @param elementRegistry the element registry of the modeler to find workflow elements * @return {{success: boolean}} true if binding is successful, false otherwise */ -export async function bindUsingPush(csar, serviceTaskId, elementRegistry) { +export async function bindUsingPush( + csar, + serviceTaskId, + elementRegistry, + modeler +) { console.log("binding using push"); console.log(csar); - let url = await extractSelfserviceApplicationUrl(csar.buildPlanUrl); - console.log(url); + let selfServiceApplicationUrl = await extractSelfserviceApplicationUrl( + csar.properties + ); + console.log(selfServiceApplicationUrl); let success = false; if ( @@ -162,37 +170,71 @@ export async function bindUsingPush(csar, serviceTaskId, elementRegistry) { connectorElement[0].inputOutput.inputParameters.filter( (x) => x.name === "url" )[0].value; - if (url.slice(-1) === "/") { - url = url.substring(url.length - 1); + if ( + selfServiceApplicationUrl.charAt( + selfServiceApplicationUrl.length - 1 + ) === "/" + ) { + selfServiceApplicationUrl = selfServiceApplicationUrl.substring( + selfServiceApplicationUrl.length - 1 + ); } - if (connectorUrl.slice(0) === "/") { + if (connectorUrl.charAt(0) === "/") { connectorUrl = connectorUrl.substring(1, connectorUrl.length); } - inputParameter.value = url + "/" + connectorUrl; + inputParameter.value = + selfServiceApplicationUrl + "/" + connectorUrl; success = true; } } } } } + + const qprovEndpoint = await extractQProvEndpoint(csar.properties); + let moddle = modeler.get("moddle"); + const rootElement = getRootProcess(modeler.getDefinitions()); + let rootStartEvent = rootElement.flowElements.filter( + (flowElement) => flowElement.$type === "bpmn:StartEvent" + ); + let formFields = rootStartEvent[0]?.extensionElements?.values.filter( + (x) => x.$type === "camunda:FormData" + )[0].fields; + const formFieldQProvEndpoint = moddle.create("camunda:FormField", { + defaultValue: qprovEndpoint, + id: serviceTaskId + "_qProvUrl", + label: "QProv Endpoint for corresponding Task ID", + type: "string", + }); + formFields.push(formFieldQProvEndpoint); + return { success: success }; } +async function extractQProvEndpoint(propertiesUrl) { + let propertiesResponse = await fetchDataFromEndpoint(propertiesUrl); + console.log(propertiesResponse); + const qprovEndpoint = propertiesResponse.qProvUrl; + if (qprovEndpoint === undefined) { + console.error("Unable to fetch qprov endpoint from: " + propertiesUrl); + return undefined; + } + console.log(qprovEndpoint); + return qprovEndpoint; +} + async function extractSelfserviceApplicationUrl(propertiesUrl) { - let buildPlanResponse = await fetchDataFromEndpoint(propertiesUrl); - console.log(buildPlanResponse); - const selfServiceApplicationUrl = buildPlanResponse.outputs.filter( - (x) => x.name.toLowerCase() === "selfserviceapplicationurl" - ); - if ( - selfServiceApplicationUrl === undefined || - selfServiceApplicationUrl.length < 1 - ) { + let propertiesResponse = await fetchDataFromEndpoint(propertiesUrl); + console.log(propertiesResponse); + const selfServiceApplicationUrl = + propertiesResponse.selfServiceApplicationUrl; + if (selfServiceApplicationUrl === undefined) { console.error( - "Unable to fetch selfServiceApplicationUrl from: " + propertiesUrl + "Unable to fetch selfServiceApplicationUrl endpoint from: " + + propertiesUrl ); return undefined; } console.log(selfServiceApplicationUrl); - return selfServiceApplicationUrl[0].value; + return selfServiceApplicationUrl; } diff --git a/components/bpmn-q/modeler-component/extensions/opentosca/deployment/DeploymentUtils.js b/components/bpmn-q/modeler-component/extensions/opentosca/deployment/DeploymentUtils.js index 7c8969cb..241254c2 100644 --- a/components/bpmn-q/modeler-component/extensions/opentosca/deployment/DeploymentUtils.js +++ b/components/bpmn-q/modeler-component/extensions/opentosca/deployment/DeploymentUtils.js @@ -104,7 +104,8 @@ export function isDeployableServiceTask(element) { element.$type && element.$type === "bpmn:ServiceTask" && element.deploymentModelUrl && - getBindingType(element) !== undefined + getBindingType(element) !== undefined && + !element.$attrs["opentosca:isDeployedAndBound"] ); } diff --git a/components/bpmn-q/modeler-component/extensions/opentosca/modeling/OpenTOSCARenderer.js b/components/bpmn-q/modeler-component/extensions/opentosca/modeling/OpenTOSCARenderer.js index 25162134..1efb0a71 100644 --- a/components/bpmn-q/modeler-component/extensions/opentosca/modeling/OpenTOSCARenderer.js +++ b/components/bpmn-q/modeler-component/extensions/opentosca/modeling/OpenTOSCARenderer.js @@ -200,7 +200,8 @@ export default class OpenTOSCARenderer extends BpmnRenderer { execute: ({ showDeploymentModel }) => { const elementsWithDeploymentModel = this.elementRegistry.filter( (element) => - element.businessObject.get("opentosca:deploymentModelUrl") + element.businessObject.get("opentosca:deploymentModelUrl") !== + undefined ); const changed = []; for (const element of elementsWithDeploymentModel) { @@ -274,7 +275,12 @@ export default class OpenTOSCARenderer extends BpmnRenderer { let deploymentModelUrl = element.businessObject.get( "opentosca:deploymentModelUrl" ); - if (!deploymentModelUrl) return; + console.log(deploymentModelUrl); + console.log(element); + console.log(deploymentModelUrl === undefined); + console.log(!deploymentModelUrl); + if (!deploymentModelUrl || deploymentModelUrl === undefined) return; + console.log("render button"); const button = drawTaskSVG( parentGfx, diff --git a/components/bpmn-q/modeler-component/extensions/opentosca/modeling/OpenTOSCAReplaceMenuProvider.js b/components/bpmn-q/modeler-component/extensions/opentosca/modeling/OpenTOSCAReplaceMenuProvider.js index b6a256b8..0c70f529 100644 --- a/components/bpmn-q/modeler-component/extensions/opentosca/modeling/OpenTOSCAReplaceMenuProvider.js +++ b/components/bpmn-q/modeler-component/extensions/opentosca/modeling/OpenTOSCAReplaceMenuProvider.js @@ -11,7 +11,10 @@ import * as opentoscaReplaceOptions from "./OpenTOSCAReplaceOptions"; import { is } from "bpmn-js/lib/util/ModelUtil"; -import { createMenuEntries } from "../../../editor/util/PopupMenuUtilities"; +import { + createMenuEntries, + createMoreOptionsEntryWithReturn, +} from "../../../editor/util/PopupMenuUtilities"; import { filter } from "min-dash"; import { isDifferentType } from "bpmn-js/lib/features/popup-menu/util/TypeUtil"; @@ -42,9 +45,10 @@ export default class OpenTOSCAReplaceMenuProvider { getPopupMenuEntries(element) { const self = this; + const popupMenu = this.popupMenu; return function (entries) { // add additional elements to replace policies - if (is(element, "bpmn:Event")) { + if (is(element, "bpmn:Event") && !element.type.startsWith("pattern")) { if (element.host !== undefined) { let attachers = element.host.attachers; let attacherTypes = []; @@ -77,7 +81,18 @@ export default class OpenTOSCAReplaceMenuProvider { self.translate, self.bpmnReplace.replaceElement ); - return Object.assign(policyEntries, entries); + console.log("policyEntr"); + + return { + ["replace-by-more-options"]: createMoreOptionsEntryWithReturn( + element, + "Policies", + "Policies", + popupMenu, + policyEntries, + "bpmn-icon-policy" + ), + }; } } diff --git a/components/bpmn-q/modeler-component/extensions/opentosca/modeling/OpenTOSCARules.js b/components/bpmn-q/modeler-component/extensions/opentosca/modeling/OpenTOSCARules.js index 9da72e5c..7c4b0376 100644 --- a/components/bpmn-q/modeler-component/extensions/opentosca/modeling/OpenTOSCARules.js +++ b/components/bpmn-q/modeler-component/extensions/opentosca/modeling/OpenTOSCARules.js @@ -19,16 +19,15 @@ export default class OpenTOSCARules extends RuleProvider { this.modeling = modeling; this.addRule("shape.create", 10000, function (context) { - var shape = context.shape, - target = context.target; + let shape = context.shape; - if (shape.type.includes("Policy") && target.type !== "bpmn:ServiceTask") { + if (shape.type.includes("Policy")) { return false; } }); function canMove(context) { - var target = context.target; + let target = context.target; if (target != undefined) { if (context.shapes[0].type.includes("Policy")) { diff --git a/components/bpmn-q/modeler-component/extensions/opentosca/resources/styling/opentosca.css b/components/bpmn-q/modeler-component/extensions/opentosca/resources/styling/opentosca.css index 0aa1228e..63198371 100644 --- a/components/bpmn-q/modeler-component/extensions/opentosca/resources/styling/opentosca.css +++ b/components/bpmn-q/modeler-component/extensions/opentosca/resources/styling/opentosca.css @@ -178,3 +178,14 @@ background-repeat: no-repeat; display: inline-block; } + +.qwm .bpmn-icon-policy:before { + content: ""; + margin-top: 1px; + width: 25px; + height: 15px; + background-size: contain; + background-image: url("../icons/Policy.svg"); + background-repeat: no-repeat; + display: inline-block; +} diff --git a/components/bpmn-q/modeler-component/extensions/opentosca/ui/deployment/services/DeploymentPlugin.js b/components/bpmn-q/modeler-component/extensions/opentosca/ui/deployment/services/DeploymentPlugin.js index 94245f28..48240ba9 100644 --- a/components/bpmn-q/modeler-component/extensions/opentosca/ui/deployment/services/DeploymentPlugin.js +++ b/components/bpmn-q/modeler-component/extensions/opentosca/ui/deployment/services/DeploymentPlugin.js @@ -33,12 +33,23 @@ import { getRootProcess } from "../../../../../editor/util/ModellingUtilities"; import ExtensibleButton from "../../../../../editor/ui/ExtensibleButton"; import { loadDiagram } from "../../../../../editor/util/IoUtilities"; import { startOnDemandReplacementProcess } from "../../../replacement/OnDemandTransformator"; -import { deletePolicies, getPolicies } from "../../../utilities/Utilities"; +import { + deletePolicies, + getPolicies, + injectWineryEndpoint, +} from "../../../utilities/Utilities"; import { CLOUD_DEPLOYMENT_MODEL_POLICY, DEDICATED_HOSTING_POLICY, LOCATION_POLICY, } from "../../../Constants"; +import { forEach } from "min-dash"; +import { + getOpenTOSCAEndpoint, + getWineryEndpoint, +} from "../../../framework-config/config-manager"; +import { fetchDataFromEndpoint } from "../../../../../editor/util/HttpUtilities"; +import * as config from "../../../framework-config/config-manager"; const defaultState = { windowOpenOnDemandDeploymentOverview: false, @@ -181,13 +192,153 @@ export default class DeploymentPlugin extends PureComponent { this.csarList = csarList; - this.setState({ - windowOpenDeploymentOverview: false, - windowOpenDeploymentInput: true, - windowOpenDeploymentBinding: false, - windowOpenOnDemandDeploymentOverview: false, - csarList: csarList, - }); + // if services shall be pre-deployed and no dedicated instance policy is attached, check if suitable services are already running + // if this is the case - bind them and remove them from the csarList + // TODO adjust behavior for multiple tasks with same CSAR that are not all deployed dedicated / non dedicated + let completeNotDedicatedCsars = csarList + .filter((csar) => !csar.incomplete) + .filter((csar) => { + let policyShapes = getPolicies(this.modeler, csar.serviceTaskIds[0]); + let foundDedicatedHosting = false; + policyShapes.forEach((policy) => { + console.log("Found policy: ", policy); + switch (policy.type) { + case DEDICATED_HOSTING_POLICY: + csar.dedicatedHosting = true; + foundDedicatedHosting = true; + break; + default: + break; + } + }); + return !foundDedicatedHosting; + }); + + console.log(completeNotDedicatedCsars); + for (let csar of completeNotDedicatedCsars) { + const csarWineryUrl = csar.url + .replace("{{ wineryEndpoint }}", getWineryEndpoint()) + .replace("/?csar", ""); + const equivalencyUrl = + csarWineryUrl + + "/topologytemplate/checkforequivalentcsars?includeSelf=true"; + let matchingCsarUrls = await fetch(equivalencyUrl, { + method: "POST", + headers: { + Accept: "application/json", + "Content-Type": "text/plain", + }, + }).then((x) => x.json()); + console.log( + "Found %i matching Csars for %s", + matchingCsarUrls.length, + csar.csarName + ); + const containerUrl = getOpenTOSCAEndpoint(); + for (let matchingCsarUrl of matchingCsarUrls) { + let urlParts = matchingCsarUrl.split("/"); + let csarName = urlParts[urlParts.length - 2]; + console.log( + "Checking availability for CSAR with name: %s and url %s", + csarName, + matchingCsarUrl + ); + const containerCsarUrl = containerUrl + "/" + csarName + ".csar"; + const containerReference = await fetchDataFromEndpoint( + containerCsarUrl + ); + console.log(result); + const serviceTemplateLink = + containerReference._links.servicetemplate.href + "/instances"; + console.log( + "Retrieved link to ServiceTemplate: %s", + serviceTemplateLink + ); + let instanceReferences = await fetchDataFromEndpoint( + serviceTemplateLink + ); + let serviceTemplateInstances = + instanceReferences?.service_template_instances + ? instanceReferences.service_template_instances + : []; + + for (let serviceTemplateInstance of serviceTemplateInstances) { + console.log( + "Check instance with Id %i", + serviceTemplateInstance.id + ); + if (serviceTemplateInstance.state != "CREATED") { + console.log( + "Instance has invalid state: %s", + serviceTemplateInstance.state + ); + continue; + } + + console.log( + "found instance with state CREATED. Extracting selfserviceUrl..." + ); + const instancePropertiesLink = + serviceTemplateInstance._links.self.href + "/properties"; + console.log( + "Retrieving instance properties from URL: %s", + instancePropertiesLink + ); + csar.properties = instancePropertiesLink; + for (let j = 0; j < csar.serviceTaskIds.length; j++) { + let elementRegistry = this.modeler.get("elementRegistry"); + let task = elementRegistry.get(csar.serviceTaskIds[j]); + let isDeployedAndBound = task.businessObject.get( + "opentosca:isDeployedAndBound" + ); + if (isDeployedAndBound) { + continue; + } + let bindingResponse = undefined; + if (csar.type === "pull") { + bindingResponse = await bindUsingPull( + csar, + csar.serviceTaskIds[j], + this.modeler.get("elementRegistry"), + this.modeler.get("modeling") + ); + } else if (csar.type === "push") { + bindingResponse = await bindUsingPush( + csar, + csar.serviceTaskIds[j], + this.modeler.get("elementRegistry"), + this.modeler + ); + } + if (bindingResponse !== undefined && bindingResponse.success) { + csarList = csarList.filter((x) => x.csarName !== csar.csarName); + deletePolicies(this.modeler, csar.serviceTaskIds[j]); + injectWineryEndpoint(this.modeler, csar.serviceTaskIds[j]); + } + } + break; + } + } + } + + this.csarList = csarList; + + if (csarList.length === 0) { + this.setState({ + windowOpenDeploymentOverview: false, + windowOpenDeploymentInput: false, + windowOpenDeploymentBinding: false, + windowOpenOnDemandDeploymentOverview: false, + }); + } else { + this.setState({ + windowOpenDeploymentOverview: false, + windowOpenDeploymentInput: true, + windowOpenDeploymentBinding: false, + windowOpenOnDemandDeploymentOverview: false, + csarList: csarList, + }); + } return; } @@ -563,7 +714,8 @@ export default class DeploymentPlugin extends PureComponent { bindingResponse = bindUsingPush( csar, serviceTaskIds[j], - this.modeler.get("elementRegistry") + this.modeler.get("elementRegistry"), + this.modeler ); } @@ -593,6 +745,9 @@ export default class DeploymentPlugin extends PureComponent { windowOpenOnDemandDeploymentOverview: false, }); return; + } // on successful binding replace wineryendpoint in deploymentmodelurl + else { + injectWineryEndpoint(this.modeler, serviceTaskIds[j]); } } } else { @@ -653,7 +808,8 @@ export default class DeploymentPlugin extends PureComponent { } else if (csarsToDeploy.length === 0) { NotificationHandler.getInstance().displayNotification({ type: "info", - title: "No service tasks with associated deployment models", + title: + "No service tasks with associated deployment models that are not deployed", content: "The workflow does not contain service tasks with associated deployment models. No service deployment required!", duration: 20000, diff --git a/components/bpmn-q/modeler-component/extensions/opentosca/utilities/Utilities.js b/components/bpmn-q/modeler-component/extensions/opentosca/utilities/Utilities.js index c53a7295..0b3be294 100644 --- a/components/bpmn-q/modeler-component/extensions/opentosca/utilities/Utilities.js +++ b/components/bpmn-q/modeler-component/extensions/opentosca/utilities/Utilities.js @@ -11,6 +11,7 @@ import $ from "jquery"; import { ON_DEMAND_POLICY, POLICIES } from "../Constants"; +import * as config from "../framework-config/config-manager"; export function performAjax(targetUrl, dataToSend) { return new Promise(function (resolve, reject) { @@ -147,3 +148,22 @@ export function movePolicies(modeler, newTargetId, policies) { } }); } + +export function injectWineryEndpoint(modeler, taskId) { + let elementRegistry = modeler.get("elementRegistry"); + let modeling = modeler.get("modeling"); + let task = elementRegistry.get(taskId); + let deploymentModelUrl = task.businessObject.get( + "opentosca:deploymentModelUrl" + ); + if (deploymentModelUrl.startsWith("{{ wineryEndpoint }}")) { + deploymentModelUrl = deploymentModelUrl.replace( + "{{ wineryEndpoint }}", + config.getWineryEndpoint() + ); + } + modeling.updateProperties(task, { + "opentosca:deploymentModelUrl": deploymentModelUrl, + "opentosca:isDeployedAndBound": true, + }); +} diff --git a/components/bpmn-q/modeler-component/extensions/pattern/Constants.js b/components/bpmn-q/modeler-component/extensions/pattern/Constants.js index 700c067c..d2986d5e 100644 --- a/components/bpmn-q/modeler-component/extensions/pattern/Constants.js +++ b/components/bpmn-q/modeler-component/extensions/pattern/Constants.js @@ -10,4 +10,71 @@ */ export const PATTERN_ALGORITHM = "algorithm"; export const PATTERN_BEHAVIORAL = "behavioral"; +export const PATTERN_BEHAVIORAL_EXCLUSIVE = "behavioralExclusive"; export const PATTERN_AUGMENTATION = "augmentation"; + +export const PATTERN = "pattern:Pattern"; + +export const QUANTUM_KERNEL_ESTIMATOR = "pattern:QuantumKernelEstimator"; +export const ALTERNATING_OPERATOR_ANSATZ = "pattern:AlternatingOperatorAnsatz"; +export const QUANTUM_APPROXIMATE_OPTIMIZATION_ALGORITHM = + "pattern:QuantumApproximateOptimizationAlgorithm"; +export const QUANTUM_PHASE_ESTIMATION = "pattern:QuantumPhaseEstimation"; +export const VARIATIONAL_QUANTUM_ALGORITHM = + "pattern:VariationalQuantumAlgorithm"; +export const VARIATIONAL_QUANTUM_EIGENSOLVER = + "pattern:VariationalQuantumEigensolver"; + +export const ORCHESTRATED_EXECUTION = "pattern:OrchestratedExecution"; +export const PRE_DEPLOYED_EXECUTION = "pattern:PredeployedExecution"; +export const PRIORITIZED_EXECUTION = "pattern:PrioritizedExecution"; + +export const ERROR_CORRECTION = "pattern:ErrorCorrection"; +export const GATE_ERROR_MITIGATION = "pattern:GateErrorMitigation"; +export const READOUT_ERROR_MITIGATION = "pattern:ReadoutErrorMitigation"; +export const CIRCUIT_CUTTING = "pattern:CircuitCutting"; + +export const BIASED_INITIAL_STATE = "pattern:BiasedInitialState"; +export const VARIATIONAL_PARAMETER_TRANSFER = + "pattern:VariationalParameterTransfer"; +export const CHAINED_OPTIMIZATION = "pattern:ChainedOptimization"; +export const PRE_TRAINED_FEATURE_EXTRACTOR = + "pattern:PreTrainedFeatureExtractor"; + +export const PATTERN_MITIGATION = "mitigation"; + +export const ALGORITHM_PATTERNS = [ + QUANTUM_KERNEL_ESTIMATOR, + ALTERNATING_OPERATOR_ANSATZ, + QUANTUM_APPROXIMATE_OPTIMIZATION_ALGORITHM, + QUANTUM_PHASE_ESTIMATION, + VARIATIONAL_QUANTUM_ALGORITHM, + VARIATIONAL_QUANTUM_EIGENSOLVER, +]; + +export const BEHAVIORAL_PATTERNS = [ + ORCHESTRATED_EXECUTION, + PRE_DEPLOYED_EXECUTION, + PRIORITIZED_EXECUTION, +]; + +export const WARM_STARTING_PATTERNS = [ + BIASED_INITIAL_STATE, + CHAINED_OPTIMIZATION, + PRE_TRAINED_FEATURE_EXTRACTOR, + VARIATIONAL_PARAMETER_TRANSFER, +]; + +export const AUGMENTATION_PATTERNS = [ + ERROR_CORRECTION, + GATE_ERROR_MITIGATION, + READOUT_ERROR_MITIGATION, + CIRCUIT_CUTTING, + ...WARM_STARTING_PATTERNS, +]; + +export const PATTERNS = [PATTERN].concat( + ...ALGORITHM_PATTERNS, + ...BEHAVIORAL_PATTERNS, + ...AUGMENTATION_PATTERNS +); diff --git a/components/bpmn-q/modeler-component/extensions/pattern/PatternPlugin.js b/components/bpmn-q/modeler-component/extensions/pattern/PatternPlugin.js index 5b84c288..6806659a 100644 --- a/components/bpmn-q/modeler-component/extensions/pattern/PatternPlugin.js +++ b/components/bpmn-q/modeler-component/extensions/pattern/PatternPlugin.js @@ -14,6 +14,13 @@ import React from "react"; import PatternConfigTab from "./configTabs/PatternConfigTab"; import patternStyles from "./resources/styling/pattern.css"; import PatternPluginButton from "./ui/PatternPluginButton"; +import PatternExtensionModule from "./modeling"; +import TransformationButton from "../../editor/ui/TransformationButton"; +import { startPatternReplacementProcess } from "./replacement/PatternTransformator"; +import * as camundaConfig from "../../editor/config/EditorConfigManager"; +import * as config from "../quantme/framework-config/config-manager"; +import { getModeler } from "../../editor/ModelerHandler"; +let patternModdleExtension = require("./resources/pattern4bpmn.json"); /** * Plugin Object of the QuantME extension. Used to register the plugin in the plugin handler of the modeler. @@ -28,6 +35,24 @@ export default { }, ], name: "pattern", - extensionModule: [], + extensionModule: [PatternExtensionModule], + moddleDescription: patternModdleExtension, styling: [patternStyles], + transformExtensionButton: ( + { + let modeler = getModeler(); + modeler.views = modeler.views || {}; + modeler.views["view-with-patterns"] = xml; + let currentQRMs = []; + return await startPatternReplacementProcess(xml, currentQRMs, { + nisqAnalyzerEndpoint: config.getNisqAnalyzerEndpoint(), + transformationFrameworkEndpoint: + config.getTransformationFrameworkEndpoint(), + camundaEndpoint: camundaConfig.getCamundaEndpoint(), + }); + }} + /> + ), }; diff --git a/components/bpmn-q/modeler-component/extensions/pattern/configTabs/PatternConfigTab.js b/components/bpmn-q/modeler-component/extensions/pattern/configTabs/PatternConfigTab.js index 83d0f34c..9338ca8f 100644 --- a/components/bpmn-q/modeler-component/extensions/pattern/configTabs/PatternConfigTab.js +++ b/components/bpmn-q/modeler-component/extensions/pattern/configTabs/PatternConfigTab.js @@ -27,6 +27,9 @@ export default function PatternConfigTab() { const [patternAtlasUIEndpoint, setPatternAtlasUIEndpoint] = useState( config.getPatternAtlasUIEndpoint() ); + const [qcAtlasEndpoint, setQcAtlasEndpoint] = useState( + config.getQcAtlasEndpoint() + ); const modeler = getModeler(); const editorActions = modeler.get("editorActions"); @@ -51,11 +54,21 @@ export default function PatternConfigTab() { }); } + if (!editorActions._actions.hasOwnProperty("qcAtlasEndpointChanged")) { + editorActions.register({ + qcAtlasEndpointChanged: function (qcAtlasEndpoint) { + self.modeler.config.qcAtlasEndpoint = qcAtlasEndpoint; + eventBus.fire("config.updated", self.modeler.config); + }, + }); + } // save changed config entries on close PatternConfigTab.prototype.onClose = () => { modeler.config.patternAtlasEndpoint = patternAtlasEndpoint; + modeler.config.qcAtlasEndpoint = qcAtlasEndpoint; modeler.config.patternAtlasUIEndpoint = patternAtlasUIEndpoint; config.setPatternAtlasEndpoint(patternAtlasEndpoint); + config.setQcAtlasEndpoint(qcAtlasEndpoint); config.setPatternAtlasUIEndpoint(patternAtlasUIEndpoint); }; @@ -92,6 +105,18 @@ export default function PatternConfigTab() { /> + + QC Atlas Endpoint + + setQcAtlasEndpoint(event.target.value)} + /> + + @@ -102,5 +127,6 @@ PatternConfigTab.prototype.config = () => { const modeler = getModeler(); modeler.config.patternAtlasEndpoint = config.getPatternAtlasEndpoint(); + modeler.config.qcAtlasEndpoint = config.getQcAtlasEndpoint(); modeler.config.patternAtlasUIEndpoint = config.getPatternAtlasUIEndpoint(); }; diff --git a/components/bpmn-q/modeler-component/extensions/pattern/framework-config/config-manager.js b/components/bpmn-q/modeler-component/extensions/pattern/framework-config/config-manager.js index e6719422..71592604 100644 --- a/components/bpmn-q/modeler-component/extensions/pattern/framework-config/config-manager.js +++ b/components/bpmn-q/modeler-component/extensions/pattern/framework-config/config-manager.js @@ -57,6 +57,29 @@ export function setPatternAtlasUIEndpoint(patternAtlasUIEndpoint) { config.patternAtlasUIEndpoint = patternAtlasUIEndpoint; } } + +/** + * Get the endpoint of the connected Qc Atlas + */ +export function getQcAtlasEndpoint() { + if (config.qcAtlasEndpoint === undefined) { + setQcAtlasEndpoint( + getPluginConfig("pattern").qcAtlasEndpoint || + defaultConfig.qcAtlasEndpoint + ); + } + return config.qcAtlasEndpoint; +} + +/** + * Set the endpoint of the connected Qc Atlas + */ +export function setQcAtlasEndpoint(qcAtlasEndpoint) { + if (qcAtlasEndpoint !== null && qcAtlasEndpoint !== undefined) { + config.qcAtlasEndpoint = qcAtlasEndpoint; + } +} + /** * Reset all saved endpoints and configuration values back to default or the value of the respective plugin config * by setting this.comfig to an empty js object. diff --git a/components/bpmn-q/modeler-component/extensions/pattern/framework-config/config.js b/components/bpmn-q/modeler-component/extensions/pattern/framework-config/config.js index 727487f0..0c503700 100644 --- a/components/bpmn-q/modeler-component/extensions/pattern/framework-config/config.js +++ b/components/bpmn-q/modeler-component/extensions/pattern/framework-config/config.js @@ -13,5 +13,6 @@ const defaultConfig = { patternAtlasEndpoint: process.env.PATTERN_ATLAS_ENDPOINT, patternAtlasUIEndpoint: process.env.PATTERN_ATLAS_UI_ENDPOINT, + qcAtlasEndpoint: process.env.QC_ATLAS_ENDPOINT, }; export default defaultConfig; diff --git a/components/bpmn-q/modeler-component/extensions/pattern/modeling/PatternContextPadProvider.js b/components/bpmn-q/modeler-component/extensions/pattern/modeling/PatternContextPadProvider.js new file mode 100644 index 00000000..b20dc76a --- /dev/null +++ b/components/bpmn-q/modeler-component/extensions/pattern/modeling/PatternContextPadProvider.js @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2023 Institute of Architecture of Application Systems - + * University of Stuttgart + * + * This program and the accompanying materials are made available under the + * terms the Apache Software License 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: Apache-2.0 + */ +import inherits from "inherits"; + +import ContextPadProvider from "bpmn-js/lib/features/context-pad/ContextPadProvider"; + +import { bind } from "min-dash"; + +import * as consts from "../Constants"; + +export default function PatternContextPadProvider(injector) { + injector.invoke(ContextPadProvider, this); + bind(this.getContextPadEntries, this); + + const _getContextPadEntries = + ContextPadProvider.prototype.getContextPadEntries; + ContextPadProvider.prototype.getContextPadEntries = function (element) { + const entries = _getContextPadEntries.apply(this, [element]); + if (consts.PATTERNS.includes(element.type)) { + delete entries["append.end-event"]; + delete entries["append.intermediate-event"]; + delete entries["append.gateway"]; + delete entries["append.append-task"]; + delete entries["append.text-annotation"]; + delete entries["connect"]; + } + return entries; + }; +} + +inherits(PatternContextPadProvider, ContextPadProvider); + +PatternContextPadProvider.$inject = ["injector", "connect", "translate"]; diff --git a/components/bpmn-q/modeler-component/extensions/pattern/modeling/PatternPaletteProvider.js b/components/bpmn-q/modeler-component/extensions/pattern/modeling/PatternPaletteProvider.js new file mode 100644 index 00000000..4d981b31 --- /dev/null +++ b/components/bpmn-q/modeler-component/extensions/pattern/modeling/PatternPaletteProvider.js @@ -0,0 +1,52 @@ +export default class PatternPaletteProvider { + constructor(bpmnFactory, create, elementFactory, palette, translate) { + this.bpmnFactory = bpmnFactory; + this.create = create; + this.elementFactory = elementFactory; + this.translate = translate; + + palette.registerProvider(this); + } + + getPaletteEntries() { + return this.createPatternEntry(); + } + + createPatternEntry() { + const { bpmnFactory, create, elementFactory, translate } = this; + + function createPattern(event) { + const businessObject = bpmnFactory.create("pattern:Pattern"); + let shape = elementFactory.createShape({ + type: "pattern:Pattern", + businessObject: businessObject, + }); + create.start(event, shape); + } + + return { + // add separator line to delimit the new group + "pattern-separator": { + group: "pattern", + separator: true, + }, + "create.pattern": { + group: "pattern", + className: "qwm-pattern-icon", + title: translate("Creates a pattern"), + action: { + click: createPattern, + dragstart: createPattern, + }, + }, + }; + } +} + +PatternPaletteProvider.$inject = [ + "bpmnFactory", + "create", + "elementFactory", + "palette", + "translate", +]; diff --git a/components/bpmn-q/modeler-component/extensions/pattern/modeling/PatternPathMap.js b/components/bpmn-q/modeler-component/extensions/pattern/modeling/PatternPathMap.js new file mode 100644 index 00000000..f151b738 --- /dev/null +++ b/components/bpmn-q/modeler-component/extensions/pattern/modeling/PatternPathMap.js @@ -0,0 +1,414 @@ +/** + * Copyright (c) 2023 Institute of Architecture of Application Systems - + * University of Stuttgart + * + * This program and the accompanying materials are made available under the + * terms the Apache Software License 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +export default function QuantMEPathMap() { + this.quantMEPathMap = { + TASK_TYPE_QUANTUM_COMPUTATION: { + d: + "M 41.60,42.32 " + + "C 41.60,39.45 43.93,37.12 46.80,37.12 " + + "49.67,37.12 52.00,39.45 52.00,42.32 " + + "52.00,45.19 49.67,47.52 46.80,47.52 " + + "43.93,47.52 41.60,45.19 41.60,42.32 " + + "41.60,42.32 41.60,42.32 41.60,42.32 Z " + + "M 20.88,26.36 " + + "C 17.85,31.40 27.00,42.47 41.31,51.07 " + + "55.62,59.67 69.69,62.55 72.72,57.50 " + + "75.75,52.46 66.60,41.40 52.29,32.79 " + + "37.97,24.19 23.91,21.31 20.88,26.36 " + + "20.88,26.36 20.88,26.36 20.88,26.36 Z " + + "M 46.00,11.68 " + + "C 40.12,11.68 35.36,25.22 35.36,41.92 " + + "35.36,58.62 40.12,72.16 46.00,72.16 " + + "51.88,72.16 56.64,58.62 56.64,41.92 " + + "56.64,25.22 51.88,11.68 46.00,11.68 Z " + + "M 72.72,27.90 " + + "C 69.69,22.85 55.62,25.73 41.31,34.33 " + + "27.00,42.93 17.85,54.00 20.88,59.04 " + + "23.91,64.09 37.97,61.21 52.29,52.60 " + + "66.60,44.00 75.75,32.94 72.72,27.90 Z", + }, + TASK_TYPE_CIRCUIT_LOADING: { + d: + "M 18.88,16.64 " + + "C 18.88,16.64 95.43,16.64 95.43,16.64M 18.88,39.52 " + + "C 18.88,39.52 95.43,39.52 95.43,39.52M 18.88,64.00 " + + "C 18.88,64.00 95.43,64.00 95.43,64.00M 42.72,16.64 " + + "C 42.72,16.64 42.72,73.37 42.72,73.37M 33.12,63.92 " + + "C 33.12,58.66 37.42,54.40 42.72,54.40 " + + "48.02,54.40 52.32,58.66 52.32,63.92 " + + "52.32,69.18 48.02,73.44 42.72,73.44 " + + "37.42,73.44 33.12,69.18 33.12,63.92 Z " + + "M 63.84,39.52 " + + "C 63.84,34.22 68.14,29.92 73.44,29.92 " + + "78.74,29.92 83.04,34.22 83.04,39.52 " + + "83.04,44.82 78.74,49.12 73.44,49.12 " + + "68.14,49.12 63.84,44.82 63.84,39.52 Z " + + "M 73.28,30.24 " + + "C 73.28,30.24 73.28,62.78 73.28,62.78", + }, + TASK_TYPE_CIRCUIT_LOADING_FILL: { + d: + "M 36.48,17.36 " + + "C 36.48,13.87 39.35,11.04 42.88,11.04 " + + "46.41,11.04 49.28,13.87 49.28,17.36 " + + "49.28,20.85 46.41,23.68 42.88,23.68 " + + "39.35,23.68 36.48,20.85 36.48,17.36 " + + "36.48,17.36 36.48,17.36 36.48,17.36 Z " + + "M 67.04,63.36 " + + "C 67.04,59.83 69.91,56.96 73.44,56.96 " + + "76.97,56.96 79.84,59.83 79.84,63.36 " + + "79.84,66.89 76.97,69.76 73.44,69.76 " + + "69.91,69.76 67.04,66.89 67.04,63.36 Z", + }, + TASK_TYPE_DATA_PREPARATION: { + d: + "M 76.50,21.50 " + + "C 76.50,21.50 143.25,21.50 143.25,21.50M 76.50,36.50 " + + "C 76.50,36.50 143.25,36.50 143.25,36.50M 76.50,53.50 " + + "C 76.50,53.50 143.25,53.50 143.25,53.50M 109.18,21.82 " + + "C 109.18,21.82 109.09,60.45 109.09,60.45M 102.50,54.00 " + + "C 102.50,50.41 105.41,47.50 109.00,47.50 " + + "112.59,47.50 115.50,50.41 115.50,54.00 " + + "115.50,57.59 112.59,60.50 109.00,60.50 " + + "105.41,60.50 102.50,57.59 102.50,54.00 Z " + + "M 123.50,37.00 " + + "C 123.50,33.41 126.41,30.50 130.00,30.50 " + + "133.59,30.50 136.50,33.41 136.50,37.00 " + + "136.50,40.59 133.59,43.50 130.00,43.50 " + + "126.41,43.50 123.50,40.59 123.50,37.00 Z " + + "M 130.00,31.00 " + + "C 130.00,31.00 129.91,53.00 129.91,53.00", + }, + TASK_TYPE_DATA_PREPARATION_BACKGROUND: { + d: + "M 52.50,23.83" + + "C 52.50,27.88 45.11,31.17 36.00,31.17 " + + "26.89,31.17 19.50,27.88 19.50,23.83", + }, + TASK_TYPE_DATA_PREPARATION_FILL_BLACK: { + d: + "M 19.50,23.83 " + + "C 19.50,19.78 26.89,16.50 36.00,16.50 " + + "45.11,16.50 52.50,19.78 52.50,23.83 " + + "52.50,23.83 52.50,53.17 52.50,53.17 " + + "52.50,57.22 45.11,60.50 36.00,60.50 " + + "26.89,60.50 19.50,57.22 19.50,53.17 " + + "19.50,53.17 19.50,23.83 19.50,23.83 Z " + + "M 66.73,37.73 " + + "C 66.73,37.73 58.45,37.64 58.45,37.64 " + + "58.45,37.64 58.55,35.18 58.55,35.18 " + + "58.55,35.18 66.82,35.18 66.82,35.18 " + + "66.82,35.18 66.73,37.73 66.73,37.73 Z " + + "M 66.60,32.00 " + + "C 66.60,32.00 72.60,36.50 72.60,36.50 " + + "72.60,36.50 66.60,41.01 66.60,41.01 " + + "66.60,41.01 66.60,32.00 66.60,32.00 Z " + + "M 95.50,16.50 " + + "C 95.50,16.50 95.50,26.50 95.50,26.50 " + + "95.50,26.50 84.50,26.50 84.50,26.50 " + + "84.50,26.50 84.50,16.50 84.50,16.50 " + + "84.50,16.50 95.50,16.50 95.50,16.50 Z " + + "M 94.50,48.50 " + + "C 94.50,48.50 94.50,58.50 94.50,58.50 " + + "94.50,58.50 84.50,58.50 84.50,58.50 " + + "84.50,58.50 84.50,48.50 84.50,48.50 " + + "84.50,48.50 94.50,48.50 94.50,48.50 Z", + }, + TASK_TYPE_DATA_PREPARATION_FILL_BACKGROUND: { + d: + "M 95.50,16.50 " + + "C 95.50,16.50 95.50,26.50 95.50,26.50 " + + "95.50,26.50 84.50,26.50 84.50,26.50 " + + "84.50,26.50 84.50,16.50 84.50,16.50 " + + "84.50,16.50 95.50,16.50 95.50,16.50 Z " + + "M 94.50,48.50 " + + "C 94.50,48.50 94.50,58.50 94.50,58.50 " + + "94.50,58.50 84.50,58.50 84.50,58.50 " + + "84.50,58.50 84.50,48.50 84.50,48.50 " + + "84.50,48.50 94.50,48.50 94.50,48.50 Z", + }, + TASK_TYPE_DATA_PREPARATION_DASHED: { + d: + "M 80.50,14.50 " + + "C 80.50,12.84 81.84,11.50 83.50,11.50 " + + "83.50,11.50 95.50,11.50 95.50,11.50 " + + "97.16,11.50 98.50,12.84 98.50,14.50 " + + "98.50,14.50 98.50,59.50 98.50,59.50 " + + "98.50,61.16 97.16,62.50 95.50,62.50 " + + "95.50,62.50 83.50,62.50 83.50,62.50 " + + "81.84,62.50 80.50,61.16 80.50,59.50 " + + "80.50,59.50 80.50,14.50 80.50,14.50 Z", + }, + TASK_TYPE_ORACLE_EXPANSION: { + d: + "M 86.24,15.04 " + + "C 86.24,15.04 149.20,15.04 149.20,15.04M 86.24,33.92 " + + "C 86.24,33.92 149.20,33.92 149.20,33.92M 86.24,54.08 " + + "C 86.24,54.08 149.20,54.08 149.20,54.08M 105.76,15.04 " + + "C 105.76,15.04 105.76,61.21 105.76,61.21M 97.92,53.92 " + + "C 97.92,49.59 101.43,46.08 105.76,46.08 " + + "110.09,46.08 113.60,49.59 113.60,53.92 " + + "113.60,58.25 110.09,61.76 105.76,61.76 " + + "101.43,61.76 97.92,58.25 97.92,53.92 Z " + + "M 123.20,33.92 " + + "C 123.20,29.59 126.71,26.08 131.04,26.08 " + + "135.37,26.08 138.88,29.59 138.88,33.92 " + + "138.88,38.25 135.37,41.76 131.04,41.76 " + + "126.71,41.76 123.20,38.25 123.20,33.92 Z " + + "M 130.88,26.40 " + + "C 130.88,26.40 130.88,53.16 130.88,53.16", + }, + TASK_TYPE_ORACLE_EXPANSION_FILL_BLACK: { + d: + "M 100.80,15.68 " + + "C 100.80,12.76 103.16,10.40 106.08,10.40 " + + "109.00,10.40 111.36,12.76 111.36,15.68 " + + "111.36,18.60 109.00,20.96 106.08,20.96 " + + "103.16,20.96 100.80,18.60 100.80,15.68 Z " + + "M 125.76,53.52 " + + "C 125.76,50.65 128.12,48.32 131.04,48.32 " + + "133.96,48.32 136.32,50.65 136.32,53.52 " + + "136.32,56.39 133.96,58.72 131.04,58.72 " + + "128.12,58.72 125.76,56.39 125.76,53.52 Z", + }, + TASK_TYPE_ORACLE_EXPANSION_BOX: { + d: + "M 16.80,60.96 " + + "C 16.80,60.96 54.40,60.96 54.40,60.96 " + + "54.40,60.96 54.40,25.44 54.40,25.44 " + + "54.40,25.44 16.80,25.44 16.80,25.44 " + + "16.80,25.44 16.80,60.96 16.80,60.96 Z " + + "M 54.40,25.44 " + + "C 54.40,25.44 66.24,13.60 66.24,13.60 " + + "66.24,13.60 66.24,49.12 66.24,49.12 " + + "66.24,49.12 54.40,60.96 54.40,60.96 " + + "54.40,60.96 54.40,25.44 54.40,25.44 Z " + + "M 16.80,25.44 " + + "C 16.80,25.44 28.64,13.60 28.64,13.60 " + + "28.64,13.60 66.24,13.60 66.24,13.60 " + + "66.24,13.60 54.40,25.44 54.40,25.44 " + + "54.40,25.44 16.80,25.44 16.80,25.44 Z", + }, + TASK_TYPE_ORACLE_EXPANSION_ARROW: { + d: + "M 70.80,33.28 " + + "C 70.80,33.28 78.59,33.28 78.59,33.28 " + + "78.59,33.28 78.59,36.00 78.59,36.00 " + + "78.59,36.00 70.80,36.00 70.80,36.00 " + + "70.80,36.00 70.80,33.28 70.80,33.28 Z " + + "M 77.09,29.45 " + + "C 77.09,29.45 81.82,34.36 81.82,34.36 " + + "81.82,34.36 77.09,38.91 77.09,38.91 " + + "77.09,38.91 77.09,29.45 77.09,29.45 Z", + }, + TASK_TYPE_CIRCUIT_EXECUTION: { + d: + "M 41.60,42.32 " + + "C 41.60,39.45 43.93,37.12 46.80,37.12 " + + "49.67,37.12 52.00,39.45 52.00,42.32 " + + "52.00,45.19 49.67,47.52 46.80,47.52 " + + "43.93,47.52 41.60,45.19 41.60,42.32 " + + "41.60,42.32 41.60,42.32 41.60,42.32 Z " + + "M 20.88,26.36 " + + "C 17.85,31.40 27.00,42.47 41.31,51.07 " + + "55.62,59.67 69.69,62.55 72.72,57.50 " + + "75.75,52.46 66.60,41.40 52.29,32.79 " + + "37.97,24.19 23.91,21.31 20.88,26.36 " + + "20.88,26.36 20.88,26.36 20.88,26.36 Z " + + "M 46.00,11.68 " + + "C 40.12,11.68 35.36,25.22 35.36,41.92 " + + "35.36,58.62 40.12,72.16 46.00,72.16 " + + "51.88,72.16 56.64,58.62 56.64,41.92 " + + "56.64,25.22 51.88,11.68 46.00,11.68 Z " + + "M 72.72,27.90 " + + "C 69.69,22.85 55.62,25.73 41.31,34.33 " + + "27.00,42.93 17.85,54.00 20.88,59.04 " + + "23.91,64.09 37.97,61.21 52.29,52.60 " + + "66.60,44.00 75.75,32.94 72.72,27.90 Z", + }, + TASK_TYPE_CIRCUIT_EXECUTION_FILL: { + d: + "M 124.15,33.80 " + + "C 121.33,34.98 119.35,37.74 119.35,40.96 " + + "119.35,45.25 122.87,48.73 127.21,48.73 " + + "131.56,48.73 135.08,45.25 135.08,40.96 " + + "135.08,36.67 131.56,33.19 127.21,33.19 " + + "126.13,33.19 125.09,33.40 124.15,33.80 Z " + + "M 122.72,18.88 " + + "C 122.72,18.88 131.71,18.88 131.71,18.88 " + + "131.71,18.88 131.71,26.31 131.71,26.31 " + + "131.71,26.31 134.64,27.49 134.64,27.49 " + + "134.64,27.49 140.00,22.19 140.00,22.19 " + + "140.00,22.19 146.35,28.47 146.35,28.47 " + + "146.35,28.47 141.00,33.75 141.00,33.75 " + + "141.52,34.53 141.88,35.39 142.16,36.28 " + + "142.16,36.28 149.44,36.28 149.44,36.28 " + + "149.44,36.28 149.44,45.17 149.44,45.17 " + + "149.44,45.17 142.24,45.17 142.24,45.17 " + + "141.89,46.49 141.36,47.73 140.67,48.87 " + + "140.67,48.87 145.80,53.94 145.80,53.94 " + + "145.80,53.94 139.44,60.22 139.44,60.22 " + + "139.44,60.22 133.88,54.72 133.88,54.72 " + + "133.22,55.15 132.48,55.41 131.71,55.61 " + + "131.71,55.61 131.71,63.04 131.71,63.04 " + + "131.71,63.04 122.72,63.04 122.72,63.04 " + + "122.72,63.04 122.72,55.61 122.72,55.61 " + + "122.72,55.61 120.07,54.53 120.07,54.53 " + + "120.07,54.53 114.73,59.82 114.73,59.82 " + + "114.73,59.82 108.37,53.53 108.37,53.53 " + + "108.37,53.53 113.54,48.43 113.54,48.43 " + + "112.94,47.42 112.50,46.32 112.19,45.17 " + + "112.19,45.17 105.12,45.17 105.12,45.17 " + + "105.12,45.17 105.12,36.28 105.12,36.28 " + + "105.12,36.28 112.27,36.28 112.27,36.28 " + + "112.27,36.28 113.55,33.49 113.55,33.49 " + + "113.55,33.49 108.37,28.38 108.37,28.38 " + + "108.37,28.38 114.73,22.09 114.73,22.09 " + + "114.73,22.09 120.07,27.38 120.07,27.38 " + + "120.88,26.89 121.78,26.55 122.72,26.31 " + + "122.72,26.31 122.72,18.88 122.72,18.88 Z " + + "M 77.04,39.20 " + + "C 77.04,39.20 86.45,39.20 86.45,39.20 " + + "86.45,39.20 86.45,41.92 86.45,41.92 " + + "86.45,41.92 77.04,41.92 77.04,41.92 " + + "77.04,41.92 77.04,39.20 77.04,39.20 Z " + + "M 85.18,33.64 " + + "C 85.18,33.64 98.00,40.36 98.00,40.36 " + + "98.00,40.36 85.27,47.36 85.27,47.36 " + + "85.27,47.36 85.18,33.64 85.18,33.64 Z", + }, + TASK_TYPE_ERROR_MITIGATION: { + d: + "M 20.09,71.91 " + + "C 20.09,71.91 20.25,12.50 20.25,12.50 " + + "20.25,12.50 24.88,12.38 24.88,12.38 " + + "24.88,12.38 24.75,67.00 24.75,67.00 " + + "24.75,67.00 79.62,67.25 79.62,67.25 " + + "79.62,67.25 79.70,72.04 79.70,72.04 " + + "79.70,72.04 20.04,71.87 20.04,71.87M 53.25,12.50 " + + "C 53.25,12.50 44.12,12.50 44.12,12.50 " + + "44.12,12.50 43.73,61.91 43.73,61.91 " + + "43.73,61.91 52.88,61.75 52.88,61.75 " + + "52.88,61.75 53.00,12.50 53.00,12.50M 30.38,61.50 " + + "C 30.38,61.50 30.50,31.38 30.50,31.38 " + + "30.50,31.38 40.00,31.38 40.00,31.38 " + + "40.00,31.38 39.73,61.45 39.73,61.45 " + + "39.73,61.45 30.45,61.55 30.45,61.55M 40.36,26.82M 57.12,61.78 " + + "C 57.12,61.78 57.12,30.88 57.12,30.88 " + + "57.12,30.88 66.75,30.88 66.75,30.88 " + + "66.75,30.88 66.75,61.75 66.75,61.75 " + + "66.75,61.75 57.12,61.81 57.12,61.81M 70.06,61.69 " + + "C 70.06,61.69 70.09,46.00 70.09,46.00 " + + "70.09,46.00 79.82,46.00 79.82,46.00 " + + "79.82,46.00 79.82,61.73 79.82,61.73 " + + "79.82,61.73 70.00,61.64 70.00,61.64", + }, + SUBPROCESS_QUANTUM_HARDWARE_SELECTION: { + d: + "M 75.94,17.84 " + + "C 75.94,16.56 76.93,15.52 78.17,15.52 " + + "79.40,15.52 80.40,16.56 80.40,17.84 " + + "80.40,19.12 79.40,20.16 78.17,20.16 " + + "76.93,20.16 75.94,19.12 75.94,17.84 Z " + + "M 66.89,10.91 " + + "C 65.58,13.11 69.55,17.93 75.77,21.68 " + + "81.99,25.43 88.10,26.69 89.42,24.49 " + + "90.74,22.29 86.76,17.47 80.54,13.72 " + + "74.32,9.97 68.21,8.71 66.89,10.91 " + + "66.89,10.91 66.89,10.91 66.89,10.91 Z " + + "M 77.85,4.48 " + + "C 75.29,4.48 73.22,10.39 73.22,17.68 " + + "73.22,24.97 75.29,30.88 77.85,30.88 " + + "80.40,30.88 82.48,24.97 82.48,17.68 " + + "82.48,10.39 80.40,4.48 77.85,4.48 Z " + + "M 89.42,11.58 " + + "C 88.10,9.38 81.99,10.64 75.77,14.39 " + + "69.55,18.14 65.58,22.96 66.89,25.16 " + + "68.21,27.36 74.32,26.10 80.54,22.35 " + + "86.76,18.60 90.74,13.78 89.42,11.58 " + + "89.42,11.58 89.42,11.58 89.42,11.58 Z " + + "M 75.94,49.12 " + + "C 75.94,47.88 76.93,46.88 78.17,46.88 " + + "79.40,46.88 80.40,47.88 80.40,49.12 " + + "80.40,50.36 79.40,51.36 78.17,51.36 " + + "76.93,51.36 75.94,50.36 75.94,49.12 Z " + + "M 66.86,42.16 " + + "C 65.54,44.36 69.52,49.18 75.74,52.93 " + + "81.96,56.68 88.07,57.94 89.39,55.74 " + + "90.71,53.54 86.73,48.72 80.51,44.97 " + + "74.29,41.22 68.18,39.96 66.86,42.16 Z " + + "M 77.77,35.84 " + + "C 75.17,35.84 73.06,41.71 73.06,48.96 " + + "73.06,56.21 75.17,62.08 77.77,62.08 " + + "80.37,62.08 82.48,56.21 82.48,48.96 " + + "82.48,41.71 80.37,35.84 77.77,35.84 Z " + + "M 89.39,42.83 " + + "C 88.07,40.63 81.96,41.89 75.74,45.64 " + + "69.52,49.39 65.54,54.21 66.86,56.41 " + + "68.18,58.61 74.29,57.35 80.51,53.60 " + + "86.73,49.85 90.71,45.03 89.39,42.83 Z " + + "M 4.15,23.20 " + + "C 4.15,23.20 36.33,23.20 36.33,23.20M 4.15,32.96 " + + "C 4.15,32.96 36.33,32.96 36.33,32.96M 4.15,43.20 " + + "C 4.15,43.20 36.33,43.20 36.33,43.20M 14.04,23.20 " + + "C 14.04,23.20 14.04,46.87 14.04,46.87M 10.05,43.20 " + + "C 10.05,40.99 11.87,39.20 14.12,39.20 " + + "16.36,39.20 18.19,40.99 18.19,43.20 " + + "18.19,45.41 16.36,47.20 14.12,47.20 " + + "11.87,47.20 10.05,45.41 10.05,43.20 " + + "10.05,43.20 10.05,43.20 10.05,43.20 Z " + + "M 22.97,32.88 " + + "C 22.97,30.63 24.76,28.80 26.96,28.80 " + + "29.16,28.80 30.95,30.63 30.95,32.88 " + + "30.95,35.13 29.16,36.96 26.96,36.96 " + + "24.76,36.96 22.97,35.13 22.97,32.88 Z " + + "M 26.96,28.96 " + + "C 26.96,28.96 26.96,42.68 26.96,42.68", + }, + SUBPROCESS_QUANTUM_HARDWARE_SELECTION_FILL: { + d: + "M 52.14,21.37 " + + "C 52.14,21.37 52.65,23.09 52.65,23.09 " + + "52.65,23.09 43.96,25.28 43.96,25.26 " + + "43.96,25.24 43.62,23.62 43.62,23.62 " + + "43.62,23.62 52.14,21.38 52.14,21.38 " + + "M 47.87,16.93 " + + "C 47.87,16.93 58.73,20.22 58.73,20.22 " + + "58.73,20.22 51.16,28.70 51.16,28.70 " + + "51.16,28.70 47.87,16.93 47.87,16.93 Z " + + "M 11.65,23.52 " + + "C 11.65,22.02 12.82,20.80 14.28,20.80 " + + "15.73,20.80 16.91,22.02 16.91,23.52 " + + "16.91,25.02 15.73,26.24 14.28,26.24 " + + "12.82,26.24 11.65,25.02 11.65,23.52 Z " + + "M 24.25,42.96 " + + "C 24.25,41.50 25.46,40.32 26.96,40.32 " + + "28.46,40.32 29.67,41.50 29.67,42.96 " + + "29.67,44.42 28.46,45.60 26.96,45.60 " + + "25.46,45.60 24.25,44.42 24.25,42.96 Z " + + "M 52.13,45.69 " + + "C 52.13,45.69 51.27,47.76 51.27,47.76 " + + "51.27,47.76 42.82,44.16 42.82,44.16 " + + "42.82,44.16 43.78,42.22 43.78,42.22 " + + "43.78,42.22 52.13,45.67 52.13,45.67 " + + "M 51.94,25.75 " + + "M 50.92,39.92 " + + "C 50.92,39.92 58.01,48.79 58.01,48.79 " + + "58.01,48.79 47.00,51.50 47.00,51.50 " + + "47.00,51.50 50.92,39.92 50.92,39.92 Z", + }, + }; + + this.getPath = function getPath(pathId) { + return this.quantMEPathMap[pathId].d; + }; +} diff --git a/components/bpmn-q/modeler-component/extensions/pattern/modeling/PatternRenderer.js b/components/bpmn-q/modeler-component/extensions/pattern/modeling/PatternRenderer.js new file mode 100644 index 00000000..3618e2af --- /dev/null +++ b/components/bpmn-q/modeler-component/extensions/pattern/modeling/PatternRenderer.js @@ -0,0 +1,374 @@ +/** + * Copyright (c) 2023 Institute of Architecture of Application Systems - + * University of Stuttgart + * + * This program and the accompanying materials are made available under the + * terms the Apache Software License 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +import BpmnRenderer from "bpmn-js/lib/draw/BpmnRenderer"; +import * as patternReplaceOptions from "./PatternReplaceOptions"; +import * as consts from "../Constants"; +import { + append as svgAppend, + attr as svgAttr, + create as svgCreate, + innerSVG, + select as svgSelect, +} from "tiny-svg"; +import { getPatternSVG } from "./PatternSVGMap"; +import { queryAll as domQueryAll } from "min-dom"; + +/** + * This class extends the default BPMNRenderer to render the newly introduced patterns + */ +export default class PatternRenderer extends BpmnRenderer { + constructor( + config, + eventBus, + styles, + pathMap, + patternPathMap, + canvas, + textRenderer + ) { + super(config, eventBus, styles, pathMap, canvas, textRenderer, 1001); + + function drawTaskSVG(parentGfx, iconID) { + var importsvg = getPatternSVG(iconID); + var innerSVGstring = importsvg.svg; + var transformDef = importsvg.transform; + + const groupDef = svgCreate("g"); + svgAttr(groupDef, { transform: transformDef }); + innerSVG(groupDef, innerSVGstring); + + // set task box opacity to 0 such that icon can be in the background + svgAttr(svgSelect(parentGfx, "rect"), { "fill-opacity": 0 }); + + // draw svg in the background + parentGfx.prepend(groupDef); + } + + this.patternHandlers = { + [consts.QUANTUM_KERNEL_ESTIMATOR]: function (self, parentGfx, element) { + let attrs = { + fill: "none", + stroke: "none", + }; + element.width = 43; + element.height = 43; + var task = self.renderer("bpmn:Activity")(parentGfx, element, attrs); + drawTaskSVG(parentGfx, "QUANTUM_KERNEL_ESTIMATOR"); + return task; + }, + [consts.ALTERNATING_OPERATOR_ANSATZ]: function ( + self, + parentGfx, + element + ) { + let attrs = { + fill: "none", + stroke: "none", + }; + element.width = 43; + element.height = 43; + var task = self.renderer("bpmn:Activity")(parentGfx, element, attrs); + drawTaskSVG(parentGfx, "ALTERNATING_OPERATOR_ANSATZ"); + return task; + }, + [consts.QUANTUM_APPROXIMATE_OPTIMIZATION_ALGORITHM]: function ( + self, + parentGfx, + element + ) { + let attrs = { + fill: "none", + stroke: "none", + }; + element.width = 43; + element.height = 43; + var task = self.renderer("bpmn:Activity")(parentGfx, element, attrs); + drawTaskSVG(parentGfx, "QUANTUM_APPROXIMATE_OPTIMIZATION_ALGORITHM"); + return task; + }, + [consts.QUANTUM_PHASE_ESTIMATION]: function (self, parentGfx, element) { + let attrs = { + fill: "none", + stroke: "none", + }; + element.width = 43; + element.height = 43; + var task = self.renderer("bpmn:Activity")(parentGfx, element, attrs); + drawTaskSVG(parentGfx, "QUANTUM_PHASE_ESTIMATION"); + return task; + }, + [consts.VARIATIONAL_QUANTUM_ALGORITHM]: function ( + self, + parentGfx, + element + ) { + let attrs = { + fill: "none", + stroke: "none", + }; + element.width = 43; + element.height = 43; + var task = self.renderer("bpmn:Activity")(parentGfx, element, attrs); + drawTaskSVG(parentGfx, "VARIATIONAL_QUANTUM_ALGORITHM"); + return task; + }, + [consts.VARIATIONAL_QUANTUM_EIGENSOLVER]: function ( + self, + parentGfx, + element + ) { + let attrs = { + fill: "none", + stroke: "none", + }; + element.width = 43; + element.height = 43; + var task = self.renderer("bpmn:Activity")(parentGfx, element, attrs); + drawTaskSVG(parentGfx, "VARIATIONAL_QUANTUM_EIGENSOLVER"); + return task; + }, + [consts.ORCHESTRATED_EXECUTION]: function (self, parentGfx, element) { + let attrs = { + fill: "none", + stroke: "none", + }; + element.width = 43; + element.height = 43; + var task = self.renderer("bpmn:Activity")(parentGfx, element, attrs); + drawTaskSVG(parentGfx, "ORCHESTRATED_EXECUTION"); + return task; + }, + [consts.PRE_DEPLOYED_EXECUTION]: function (self, parentGfx, element) { + let attrs = { + fill: "none", + stroke: "none", + }; + element.width = 43; + element.height = 43; + var task = self.renderer("bpmn:Activity")(parentGfx, element, attrs); + drawTaskSVG(parentGfx, "PRE_DEPLOYED_EXECUTION"); + return task; + }, + [consts.PRIORITIZED_EXECUTION]: function (self, parentGfx, element) { + let attrs = { + fill: "none", + stroke: "none", + }; + element.width = 43; + element.height = 43; + var task = self.renderer("bpmn:Activity")(parentGfx, element, attrs); + drawTaskSVG(parentGfx, "PRIORITIZED_EXECUTION"); + return task; + }, + [consts.ERROR_CORRECTION]: function (self, parentGfx, element) { + let attrs = { + fill: "none", + stroke: "none", + }; + element.width = 43; + element.height = 43; + var task = self.renderer("bpmn:Activity")(parentGfx, element, attrs); + drawTaskSVG(parentGfx, "ERROR_CORRECTION"); + return task; + }, + [consts.READOUT_ERROR_MITIGATION]: function (self, parentGfx, element) { + let attrs = { + fill: "none", + stroke: "none", + }; + element.width = 43; + element.height = 43; + var task = self.renderer("bpmn:Activity")(parentGfx, element, attrs); + drawTaskSVG(parentGfx, "READOUT_ERROR_MITIGATION"); + return task; + }, + [consts.GATE_ERROR_MITIGATION]: function (self, parentGfx, element) { + let attrs = { + fill: "none", + stroke: "none", + }; + console.log(parentGfx); + element.width = 43; + element.height = 43; + + var task = self.renderer("bpmn:Activity")(parentGfx, element, attrs); + drawTaskSVG(parentGfx, "GATE_ERROR_MITIGATION"); + return task; + }, + [consts.BIASED_INITIAL_STATE]: function (self, parentGfx, element) { + let attrs = { + fill: "none", + stroke: "none", + }; + element.width = 43; + element.height = 43; + var task = self.renderer("bpmn:Activity")(parentGfx, element, attrs); + drawTaskSVG(parentGfx, "BIASED_INITIAL_STATE"); + return task; + }, + [consts.PRE_TRAINED_FEATURE_EXTRACTOR]: function ( + self, + parentGfx, + element + ) { + let attrs = { + fill: "none", + stroke: "none", + }; + element.width = 43; + element.height = 43; + var task = self.renderer("bpmn:Activity")(parentGfx, element, attrs); + drawTaskSVG(parentGfx, "PRE_TRAINED_FEATURE_EXTRACTOR"); + return task; + }, + [consts.CHAINED_OPTIMIZATION]: function (self, parentGfx, element) { + let attrs = { + fill: "none", + stroke: "none", + }; + element.width = 43; + element.height = 43; + var task = self.renderer("bpmn:Activity")(parentGfx, element, attrs); + drawTaskSVG(parentGfx, "CHAINED_OPTIMIZATION"); + return task; + }, + [consts.VARIATIONAL_PARAMETER_TRANSFER]: function ( + self, + parentGfx, + element + ) { + let attrs = { + fill: "none", + stroke: "none", + }; + element.width = 43; + element.height = 43; + var task = self.renderer("bpmn:Activity")(parentGfx, element, attrs); + drawTaskSVG(parentGfx, "VARIATIONAL_PARAMETER_TRANSFER"); + return task; + }, + [consts.CIRCUIT_CUTTING]: function (self, parentGfx, element) { + let attrs = { + fill: "none", + stroke: "none", + }; + element.width = 44; + element.height = 44; + var task = self.renderer("bpmn:Activity")(parentGfx, element, attrs); + drawTaskSVG(parentGfx, "CIRCUIT_CUTTING"); + return task; + }, + [consts.PATTERN]: function (self, parentGfx, element) { + let attrs = { + fill: "none", + stroke: "none", + }; + element.width = 43; + element.height = 43; + var task = self.renderer("bpmn:Activity")(parentGfx, element, attrs); + drawTaskSVG(parentGfx, "PATTERN"); + return task; + }, + }; + + setTimeout(function () { + // TODO: pullrequest to change BpmnRenderer.js if issue persists in new Version + // extract markers out of task icon svgs when loading a saved diagram + // due to restrictions in BpmnRenderer.js that places them in first defs element in svg + + var existingDefs = domQueryAll("marker", canvas._svg); + if (existingDefs != null) { + var createdNewDefs = false; + for (let i = 0; i < existingDefs.length; i++) { + if (existingDefs[i].parentElement.parentElement.nodeName !== "svg") { + if (createdNewDefs === false) { + var newDefs = svgCreate("defs"); + svgAppend(canvas._svg, newDefs); + createdNewDefs = true; + } + svgAppend(newDefs, existingDefs[i]); + } + } + } + }, 1000); + } + + renderer(type) { + return this.handlers[type]; + } + + canRender(element) { + // default elements can be handled + if (super.canRender(element)) { + return true; + } + + // pattern elements can be handled + for (let i = 0; i < patternReplaceOptions.ALGORITHM_PATTERN.length; i++) { + if ( + element.type === patternReplaceOptions.ALGORITHM_PATTERN[i].target.type + ) { + return true; + } + } + + // pattern elements can be handled + for (let i = 0; i < patternReplaceOptions.BEHAVIORAL_PATTERN.length; i++) { + if ( + element.type === patternReplaceOptions.BEHAVIORAL_PATTERN[i].target.type + ) { + return true; + } + } + + // pattern elements can be handled + for ( + let i = 0; + i < patternReplaceOptions.AUGMENTATION_PATTERN.length; + i++ + ) { + if ( + element.type === + patternReplaceOptions.AUGMENTATION_PATTERN[i].target.type + ) { + return true; + } + } + + if (element.type === consts.PATTERN) { + return true; + } + + console.log("Unable to render element of type: " + element.type); + return false; + } + + drawShape(parentNode, element) { + // handle pattern elements + if (element.type in this.patternHandlers) { + var h = this.patternHandlers[element.type]; + + /* jshint -W040 */ + return h(this, parentNode, element); + } + } +} + +PatternRenderer.$inject = [ + "config", + "eventBus", + "styles", + "pathMap", + "patternPathMap", + "canvas", + "textRenderer", +]; diff --git a/components/bpmn-q/modeler-component/extensions/pattern/modeling/PatternReplaceMenuProvider.js b/components/bpmn-q/modeler-component/extensions/pattern/modeling/PatternReplaceMenuProvider.js new file mode 100644 index 00000000..fa0c58ad --- /dev/null +++ b/components/bpmn-q/modeler-component/extensions/pattern/modeling/PatternReplaceMenuProvider.js @@ -0,0 +1,270 @@ +/** + * Copyright (c) 2023 Institute of Architecture of Application Systems - + * University of Stuttgart + * + * This program and the accompanying materials are made available under the + * terms the Apache Software License 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +import * as quantmeReplaceOptions from "./PatternReplaceOptions"; +import { is } from "bpmn-js/lib/util/ModelUtil"; +import { + createMenuEntries, + createMoreOptionsEntryWithReturn, +} from "../../../editor/util/PopupMenuUtilities"; +import { filter } from "min-dash"; +import { isDifferentType } from "bpmn-js/lib/features/popup-menu/util/TypeUtil"; +import * as consts from "../Constants"; +import * as quantmeConsts from "../../quantme/Constants"; + +/** + * This class extends the default ReplaceMenuProvider with the newly introduced Pattern task types + */ +export default class PatternReplaceMenuProvider { + constructor( + bpmnFactory, + popupMenu, + modeling, + moddle, + bpmnReplace, + rules, + translate, + commandStack + ) { + this.popupMenu = popupMenu; + this.translate = translate; + this.bpmnReplace = bpmnReplace; + this.replaceElement = bpmnReplace.replaceElement; + this.bpmnFactory = bpmnFactory; + this.modeling = modeling; + this.commandStack = commandStack; + + popupMenu.registerProvider("bpmn-replace", this); + } + + getPopupMenuEntries(element) { + const self = this; + return function (entries) { + let attacherTypes = []; + + // remove elements from other plugins + if (is(element, "bpmn:Event") && !element.type.startsWith("opentosca")) { + if (element.host !== undefined) { + let attachers = element.host.attachers; + + for (let i = 0; i < attachers.length; i++) { + let attacher = attachers[i]; + let attacherType = attacher.type; + + // Add the attacher type to the array if it's not already there + if ( + !attacherTypes.includes(attacherType) && + attacherType !== element.type + ) { + attacherTypes.push(attacherType); + } + } + const patternReplaceOptions = self.createPatternReplacementOptions( + element, + attacherTypes + ); + return Object.assign(patternReplaceOptions, entries); + } + } + + return entries; + }; + } + + /** + * Create a MoreOptionsEntry which contains menu entries to replace the current element with all Pattern task types. + * + * @param element The given element + * @return {{'replace-by-more-options': {label: string, className: string, action: Function}}} + */ + createPatternReplacementOptions(element, attacherTypes) { + const popupMenu = this.popupMenu; + + let behavioralPatterns = {}; + + // behavior pattern require optimization candidates, therefore they need to be attached to subprocess + if (element.host.type === "bpmn:SubProcess") { + behavioralPatterns = this.createPatternTypeReplacementOptions( + element, + quantmeReplaceOptions.BEHAVIORAL_PATTERN, + consts.PATTERN_BEHAVIORAL, + attacherTypes + ); + } + let augmentationPatterns = this.createPatternTypeReplacementOptions( + element, + quantmeReplaceOptions.AUGMENTATION_PATTERN, + consts.PATTERN_AUGMENTATION, + attacherTypes + ); + + let patternEntries = {}; + const isEmptyObject = (obj) => { + return Object.entries(obj).length === 0; + }; + + if (!isEmptyObject(behavioralPatterns)) { + patternEntries = Object.assign(patternEntries, behavioralPatterns); + } + if (!isEmptyObject(augmentationPatterns)) { + patternEntries = Object.assign(patternEntries, augmentationPatterns); + } + + // Check if both behavioralPatterns and augmentationPatterns are empty + if ( + isEmptyObject(behavioralPatterns) && + isEmptyObject(augmentationPatterns) + ) { + return {}; + } + + //Object.assign( + // behavioralPatterns, + // augmentationPatterns + //); + + return { + ["replace-by-more-options"]: createMoreOptionsEntryWithReturn( + element, + "Patterns", + "Patterns", + popupMenu, + patternEntries, + "pattern-logo" + ), + }; + } + + createPatternTypeReplacementOptions( + element, + patternType, + specifier, + attacherTypes + ) { + const popupMenu = this.popupMenu; + const translate = this.translate; + const replaceElement = this.bpmnReplace.replaceElement; + let filteredOptions = filter(patternType, isDifferentType(element)); + + let filteredOptionsBasedOnAttachers = filteredOptions.filter((option) => { + return !attacherTypes.includes(option.target.type); + }); + + if (element.host.type === quantmeConsts.QUANTUM_CIRCUIT_LOADING_TASK) { + filteredOptionsBasedOnAttachers = + quantmeReplaceOptions.AUGMENTATION_PATTERN.filter((option) => { + return option.target.type === consts.BIASED_INITIAL_STATE; + }); + } + + if (element.host.type === quantmeConsts.QUANTUM_CIRCUIT_EXECUTION_TASK) { + filteredOptionsBasedOnAttachers = + quantmeReplaceOptions.AUGMENTATION_PATTERN.filter((option) => { + return option.target.type !== consts.BIASED_INITIAL_STATE; + }); + } + + // error correction is not allowed with error mitigation + if ( + element.type === consts.ERROR_CORRECTION || + attacherTypes.includes(consts.ERROR_CORRECTION) + ) { + filteredOptionsBasedOnAttachers = filteredOptionsBasedOnAttachers.filter( + (option) => { + return ( + option.target.type !== consts.READOUT_ERROR_MITIGATION && + option.target.type !== consts.GATE_ERROR_MITIGATION + ); + } + ); + } + + // error mitigation is not allowed with error correction + if ( + element.type === consts.READOUT_ERROR_MITIGATION || + element.type === consts.GATE_ERROR_MITIGATION || + attacherTypes.includes(consts.GATE_ERROR_MITIGATION) || + attacherTypes.includes(consts.READOUT_ERROR_MITIGATION) + ) { + filteredOptionsBasedOnAttachers = filteredOptionsBasedOnAttachers.filter( + (option) => { + return option.target.type !== consts.ERROR_CORRECTION; + } + ); + } + + // pre deployed execution is not allowd with orchestrated execution + if ( + element.type === consts.PRE_DEPLOYED_EXECUTION || + attacherTypes.includes(consts.PRE_DEPLOYED_EXECUTION) + ) { + filteredOptionsBasedOnAttachers = filteredOptionsBasedOnAttachers.filter( + (option) => { + return option.target.type !== consts.ORCHESTRATED_EXECUTION; + } + ); + } + + // pre deployed execution is not allowd with orchestrated execution + if ( + element.type === consts.ORCHESTRATED_EXECUTION || + attacherTypes.includes(consts.ORCHESTRATED_EXECUTION) + ) { + filteredOptionsBasedOnAttachers = filteredOptionsBasedOnAttachers.filter( + (option) => { + return option.target.type !== consts.PRE_DEPLOYED_EXECUTION; + } + ); + } + + // create menu entries for the Pattern task types + let options = createMenuEntries( + element, + filteredOptionsBasedOnAttachers, + translate, + replaceElement + ); + + const isEmptyObject = (obj) => { + return Object.entries(obj).length === 0; + }; + if (isEmptyObject(options)) { + return {}; + } + + return { + ["replace-by-" + specifier + "-pattern-options"]: + createMoreOptionsEntryWithReturn( + element, + capitalize(specifier) + " Patterns", + capitalize(specifier) + " Patterns", + popupMenu, + options, + "pattern-logo" + ), + }; + } +} + +function capitalize(s) { + return s && s[0].toUpperCase() + s.slice(1); +} + +PatternReplaceMenuProvider.$inject = [ + "bpmnFactory", + "popupMenu", + "modeling", + "moddle", + "bpmnReplace", + "rules", + "translate", + "commandStack", +]; diff --git a/components/bpmn-q/modeler-component/extensions/pattern/modeling/PatternReplaceOptions.js b/components/bpmn-q/modeler-component/extensions/pattern/modeling/PatternReplaceOptions.js new file mode 100644 index 00000000..5bb9e10a --- /dev/null +++ b/components/bpmn-q/modeler-component/extensions/pattern/modeling/PatternReplaceOptions.js @@ -0,0 +1,157 @@ +/** + * Copyright (c) 2023 Institute of Architecture of Application Systems - + * University of Stuttgart + * + * This program and the accompanying materials are made available under the + * terms the Apache Software License 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +import * as consts from "../Constants"; + +export var ALGORITHM_PATTERN = [ + { + label: "Quantum Kernel Estimator", + actionName: "replace-with-pattern-quantum-kernel-estimator", + className: "qwm bpmn-pattern-quantum-kernel-estimator-icon", + target: { + type: consts.QUANTUM_KERNEL_ESTIMATOR, + }, + }, + { + label: "Alternating Operator Ansatz", + actionName: "replace-with-pattern-alternating-operator-ansatz", + className: "qwm bpmn-pattern-alternating-opertaor-ansatz-icon", + target: { + type: consts.ALTERNATING_OPERATOR_ANSATZ, + }, + }, + { + label: "Quantum Approximate Optimization Algorithm", + actionName: + "replace-with-pattern-quantum-approximate-optimization-algorithm", + className: + "qwm bpmn-pattern-gate-equantum-approximate-optimization-algorithm-icon", + target: { + type: consts.QUANTUM_APPROXIMATE_OPTIMIZATION_ALGORITHM, + }, + }, + { + label: "Quantum Phase Estimation", + actionName: "replace-with-pattern-quantum-phase-estimation", + className: "qwm bpmn-pattern-quantum-phase-estimation-icon", + target: { + type: consts.QUANTUM_PHASE_ESTIMATION, + }, + }, + { + label: "Variational Quantum Algorithm", + actionName: "replace-with-pattern-variational-quantum-algorithm", + className: "qwm bpmn-pattern-variational-quantum-algorithm-icon", + target: { + type: consts.VARIATIONAL_QUANTUM_ALGORITHM, + }, + }, + { + label: "Variational Quantum Eigensolver", + actionName: "replace-with-pattern-variational-quantum-eigensolver", + className: "qwm bpmn-pattern-variational-quantum-eigensolver-icon", + target: { + type: consts.VARIATIONAL_QUANTUM_EIGENSOLVER, + }, + }, +]; +export var BEHAVIORAL_PATTERN = [ + { + label: "Orchestrated Execution", + actionName: "replace-with-pattern-orchestrated-execution", + className: "qwm bpmn-pattern-orchestrated-execution-icon", + target: { + type: consts.ORCHESTRATED_EXECUTION, + }, + }, + { + label: "Pre-deployed Execution", + actionName: "replace-with-pattern-pre-deployed-execution", + className: "qwm bpmn-pattern-pre-deployed-execution-icon", + target: { + type: consts.PRE_DEPLOYED_EXECUTION, + }, + }, + { + label: "Prioritized Execution", + actionName: "replace-with-pattern-prioritized-execution", + className: "qwm bpmn-pattern-prioritized-execution-icon", + target: { + type: consts.PRIORITIZED_EXECUTION, + }, + }, +]; +export var AUGMENTATION_PATTERN = [ + { + label: "Biased Initial State", + actionName: "replace-with-biased-initial-state", + className: "qwm bpmn-pattern-biased-initial-state-icon", + target: { + type: consts.BIASED_INITIAL_STATE, + }, + }, + { + label: "Chained Optimization", + actionName: "replace-with-chained-optimization", + className: "qwm bpmn-pattern-chained-optimization-icon", + target: { + type: consts.CHAINED_OPTIMIZATION, + }, + }, + { + label: "Circuit Cutting", + actionName: "replace-with-circuit-cutting-correction", + className: "qwm bpmn-pattern-circuit-cutting-icon", + target: { + type: consts.CIRCUIT_CUTTING, + }, + }, + { + label: "Error Correction", + actionName: "replace-with-pattern-error-correction", + className: "qwm bpmn-pattern-error-correction-icon", + target: { + type: consts.ERROR_CORRECTION, + }, + }, + { + label: "Gate Error Mitigation", + actionName: "replace-with-pattern-gate-error-mitigation", + className: "qwm bpmn-pattern-gate-error-mitigation-icon", + target: { + type: consts.GATE_ERROR_MITIGATION, + }, + }, + { + label: "Pre-Trained Feature Extractor", + actionName: "replace-with-pre-trained-feature-extractor", + className: "qwm bpmn-pattern-pre-trained-feature-extractor-icon", + target: { + type: consts.PRE_TRAINED_FEATURE_EXTRACTOR, + }, + }, + { + label: "Readout Error Mitigation", + actionName: "replace-with-pattern-readout-error-mitigation", + className: "qwm bpmn-pattern-gate-readout-error-mitigation-icon", + target: { + type: consts.READOUT_ERROR_MITIGATION, + }, + }, + { + label: "Variational Parameter Transfer", + actionName: "replace-with-variational-parameter-transfer", + className: "qwm bpmn-pattern-variational-parameter-transfer-icon", + target: { + type: consts.VARIATIONAL_PARAMETER_TRANSFER, + }, + }, +]; diff --git a/components/bpmn-q/modeler-component/extensions/pattern/modeling/PatternRules.js b/components/bpmn-q/modeler-component/extensions/pattern/modeling/PatternRules.js new file mode 100644 index 00000000..536567e5 --- /dev/null +++ b/components/bpmn-q/modeler-component/extensions/pattern/modeling/PatternRules.js @@ -0,0 +1,159 @@ +/** + * Copyright (c) 2023 Institute of Architecture of Application Systems - + * University of Stuttgart + * + * This program and the accompanying materials are made available under the + * terms the Apache Software License 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +import RuleProvider from "diagram-js/lib/features/rules/RuleProvider"; +import * as consts from "../Constants"; +import * as quantmeConsts from "../../quantme/Constants"; +import { getBoundaryAttachment as isBoundaryAttachment } from "bpmn-js/lib/features/snapping/BpmnSnappingUtil"; +export default class PatternRules extends RuleProvider { + constructor(eventBus, modeling) { + super(eventBus); + this.modeling = modeling; + + this.addRule("shape.create", 10000, function (context) { + let shape = context.shape; + if (shape.type.includes("pattern")) { + return false; + } + }); + + function canMove(context) { + let target = context.target; + + if (target != undefined) { + if (context.shapes[0].type.includes("pattern")) { + return false; + } + } + } + + this.addRule("elements.move", 4000, function (context) { + return canMove(context); + }); + + this.addRule("shape.replace", function (context) { + if (context.element.type.includes("pattern")) { + return false; + } + }); + + this.addRule("shape.append", 3000, function (context) { + if (consts.PATTERNS.includes(context.element.type)) { + return false; + } + }); + + this.addRule("connection.create", 3000, function (context) { + if (consts.PATTERNS.includes(context.target.type)) { + return false; + } + if (consts.PATTERNS.includes(context.source.type)) { + return false; + } + }); + + this.addRule("shape.attach", 4000, function (context) { + let shapeToAttach = context.shape; + let target = context.target; + console.log("attach pattern rule"); + + if (!isBoundaryAttachment(context.position, target)) { + return false; + } + if ( + consts.PATTERN.includes(shapeToAttach.type) && + target.type !== "bpmn:SubProcess" && + target.type !== quantmeConsts.QUANTUM_CIRCUIT_EXECUTION_TASK && + target.type !== quantmeConsts.QUANTUM_CIRCUIT_LOADING_TASK + ) { + return false; + } + + let attachedElementTypesWithPolicy = 0; + let specificPolicies = consts.PATTERNS; + specificPolicies = specificPolicies.filter( + (policy) => policy !== consts.PATTERN + ); + specificPolicies = specificPolicies.filter( + (policy) => !consts.ALGORITHM_PATTERNS.includes(policy) + ); + + for (let i = 0; i < target.attachers.length; i++) { + if (consts.PATTERNS.includes(target.attachers[i].type)) { + attachedElementTypesWithPolicy++; + } + } + + for (let i = 0; i < target.attachers.length; i++) { + if (specificPolicies.includes(target.attachers[i].type)) { + specificPolicies = specificPolicies.filter( + (policy) => policy !== target.attachers[i].type + ); + } + } + + // error correction is not allowed with mitigation + if (target.attachers.includes(consts.ERROR_CORRECTION)) { + attachedElementTypesWithPolicy++; + attachedElementTypesWithPolicy++; + } + + // mitigation is not allowed with error correction + if (target.attachers.includes(consts.READOUT_ERROR_MITIGATION)) { + attachedElementTypesWithPolicy++; + } + + if (target.attachers.includes(consts.GATE_ERROR_MITIGATION)) { + attachedElementTypesWithPolicy++; + } + + // orchestrated execution is not allowed with pre-deployed execution + if (target.attachers.includes(consts.ORCHESTRATED_EXECUTION)) { + attachedElementTypesWithPolicy++; + } + + // pre-deployed execution is not allowed with orchestrated execution + if (target.attachers.includes(consts.PRE_DEPLOYED_EXECUTION)) { + attachedElementTypesWithPolicy++; + } + + // reduce the number of possible patterns by the number of allowed patterns + if ( + attachedElementTypesWithPolicy === + consts.PATTERNS.length - consts.ALGORITHM_PATTERNS.length - 1 + ) { + return false; + } + + // If the specific policies are included, prevent attaching another policy + if (specificPolicies.length === 0) { + return false; + } + if ( + shapeToAttach.type.includes("pattern") && + (target.type === "bpmn:ServiceTask" || + target.type === "bpmn:SubProcess") + ) { + return true; + } + + if ( + shapeToAttach.type.includes("pattern:Pattern") && + (target.type === "quantme:QuantumCircuitExecutionTask" || + target.type === "quantme:QuantumCircuitLoadingTask") + ) { + return true; + } + }); + } +} + +PatternRules.$inject = ["eventBus"]; diff --git a/components/bpmn-q/modeler-component/extensions/pattern/modeling/PatternSVGMap.js b/components/bpmn-q/modeler-component/extensions/pattern/modeling/PatternSVGMap.js new file mode 100644 index 00000000..0750455d --- /dev/null +++ b/components/bpmn-q/modeler-component/extensions/pattern/modeling/PatternSVGMap.js @@ -0,0 +1,97 @@ +/** + * Copyright (c) 2023 Institute of Architecture of Application Systems - + * University of Stuttgart + * + * This program and the accompanying materials are made available under the + * terms the Apache Software License 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +export function getPatternSVG(svgId) { + // to insert svgs easily just open them in your browser, copy the outer html and insert it using ctrl + alt + shift + v in intellij to avoid formatting,escaping etc. + // matrix( Scalingfactor, 0, 0, Scalingfactor, shift X, shift y) + // IMPORTANT: ensure that definition Ids for new SVGs are UNIQUE + // viewbox is not required + const patternSVGMap = { + ORCHESTRATED_EXECUTION: { + transform: "matrix(0.22, 0, 0, 0.22, -3, -3)", + svg: '', + }, + PRE_DEPLOYED_EXECUTION: { + transform: "matrix(0.22, 0, 0, 0.22, -3, -3)", + svg: '', + }, + PRIORITIZED_EXECUTION: { + transform: "matrix(0.22, 0, 0, 0.22, -3, -3)", + svg: '', + }, + ERROR_CORRECTION: { + transform: "matrix(0.22, 0, 0, 0.22, -3, -3)", + svg: '', + }, + READOUT_ERROR_MITIGATION: { + transform: "matrix(0.22, 0, 0, 0.22, -3, -3)", + svg: '', + }, + GATE_ERROR_MITIGATION: { + transform: "matrix(0.22, 0, 0, 0.22, -3, -3)", + svg: '', + }, + WARM_START: { + transform: "matrix(0.22, 0, 0, 0.22, -3, -3)", + svg: '', + }, + VARIATIONAL_QUANTUM_EIGENSOLVER: { + transform: "matrix(0.22, 0, 0, 0.22, -3, -3)", + svg: ' 1 ⋯ 0 ⋮ ⋱ ⋮ 3 ⋯ 5 λ ', + }, + ALTERNATING_OPERATOR_ANSATZ: { + transform: "matrix(0.22, 0, 0, 0.22, -3, -3)", + svg: ' ( ) ( ) γ B C β ', + }, + VARIATIONAL_QUANTUM_ALGORITHM: { + transform: "matrix(0.22, 0, 0, 0.22, -3, -3)", + svg: ' CC ', + }, + QUANTUM_PHASE_ESTIMATION: { + transform: "matrix(0.22, 0, 0, 0.22, -3, -3)", + svg: ' ', + }, + QUANTUM_KERNEL_ESTIMATOR: { + transform: "matrix(0.22, 0, 0, 0.22, -3, -3)", + svg: ' (x x 1 , 2 ) κ ', + }, + QUANTUM_APPROXIMATE_OPTIMIZATION_ALGORITHM: { + transform: "matrix(0.22, 0, 0, 0.22, -3, -3)", + svg: ' $ ', + }, + CIRCUIT_CUTTING: { + transform: "matrix(0.22, 0, 0, 0.22, -2, -2)", + svg: ' ', + }, + PATTERN: { + transform: "matrix(0.22, 0, 0, 0.22, -3, -3)", + svg: ' ', + }, + BIASED_INITIAL_STATE: { + transform: "matrix(0.22, 0, 0, 0.22, -3, -3)", + svg: ' ', + }, + CHAINED_OPTIMIZATION: { + transform: "matrix(0.22, 0, 0, 0.22, -3, -3)", + svg: ' icon-chained-optimization Chained Optimization icon-chained-optimization ', + }, + VARIATIONAL_PARAMETER_TRANSFER: { + transform: "matrix(0.22, 0, 0, 0.22, -3, -3)", + svg: ' Parameter Transfer β γ ', + }, + PRE_TRAINED_FEATURE_EXTRACTOR: { + transform: "matrix(0.22, 0, 0, 0.22, -3, -3)", + svg: ' Pre - Trained Feature Extractor ', + }, + }; + + return patternSVGMap[svgId]; +} diff --git a/components/bpmn-q/modeler-component/extensions/pattern/modeling/index.js b/components/bpmn-q/modeler-component/extensions/pattern/modeling/index.js new file mode 100644 index 00000000..42a5863b --- /dev/null +++ b/components/bpmn-q/modeler-component/extensions/pattern/modeling/index.js @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2023 Institute of Architecture of Application Systems - + * University of Stuttgart + * + * This program and the accompanying materials are made available under the + * terms the Apache Software License 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: Apache-2.0 + */ +import PatternRenderer from "./PatternRenderer"; +import PatternReplaceMenuProvider from "./PatternReplaceMenuProvider"; +import PatternPathMap from "./PatternPathMap"; +import PatternPaletteProvider from "./PatternPaletteProvider"; +import PatternRules from "./PatternRules"; +import PatternContextPadProvider from "./PatternContextPadProvider"; + +export default { + __init__: [ + "patternRenderer", + "patternReplaceMenu", + "patternPathMap", + "patternPaletteProvider", + "patternRules", + "patternContextPadProvider", + ], + patternRenderer: ["type", PatternRenderer], + patternReplaceMenu: ["type", PatternReplaceMenuProvider], + patternPathMap: ["type", PatternPathMap], + patternPaletteProvider: ["type", PatternPaletteProvider], + patternRules: ["type", PatternRules], + patternContextPadProvider: ["type", PatternContextPadProvider], +}; diff --git a/components/bpmn-q/modeler-component/extensions/pattern/replacement/PatternTransformator.js b/components/bpmn-q/modeler-component/extensions/pattern/replacement/PatternTransformator.js new file mode 100644 index 00000000..7c59300b --- /dev/null +++ b/components/bpmn-q/modeler-component/extensions/pattern/replacement/PatternTransformator.js @@ -0,0 +1,518 @@ +/** + * Copyright (c) 2023 Institute of Architecture of Application Systems - + * University of Stuttgart + * + * This program and the accompanying materials are made available under the + * terms the Apache Software License 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: Apache-2.0 + */ +import { layout } from "../../quantme/replacement/layouter/Layouter"; +import * as constants from "../Constants"; +import { createTempModelerFromXml } from "../../../editor/ModelerHandler"; +import { getRootProcess } from "../../../editor/util/ModellingUtilities"; +import { getXml } from "../../../editor/util/IoUtilities"; +import { replaceWarmStart } from "./warm-start/WarmStartPatternHandler"; +import { replaceCuttingPattern } from "./cutting/CuttingPatternHandler"; +import { replaceErrorCorrectionPattern } from "./correction/ErrorCorrectionPatternHandler"; +import { replaceMitigationPattern } from "./mitigation/MitigationPatternHandler"; +import * as quantmeConsts from "../../quantme/Constants"; +import { attachPatternsToSuitableConstruct } from "../util/PatternUtil"; +import { findOptimizationCandidates } from "../../quantme/ui/adaptation/CandidateDetector"; +import { getQRMs } from "../../quantme/qrm-manager"; +import { rewriteWorkflow } from "../../quantme/ui/adaptation/WorkflowRewriter"; +import { getQiskitRuntimeProgramDeploymentModel } from "../../quantme/ui/adaptation/runtimes/QiskitRuntimeHandler"; +import { getHybridRuntimeProvenance } from "../../quantme/framework-config/config-manager"; + +/** + * Initiate the replacement process for the patterns that are contained in the current process model + * + * @param xml the BPMN diagram in XML format + */ +export async function startPatternReplacementProcess(xml) { + let modeler = await createTempModelerFromXml(xml); + let modeling = modeler.get("modeling"); + let elementRegistry = modeler.get("elementRegistry"); + let allFlow = []; + let patterns = []; + + // get root element of the current diagram + let definitions = modeler.getDefinitions(); + let rootElement = getRootProcess(definitions); + console.log(rootElement); + if (typeof rootElement === "undefined") { + console.log("Unable to retrieve root process element from definitions!"); + return { + status: "failed", + cause: "Unable to retrieve root process element from definitions!", + }; + } + + // get all patterns from the process + let replacementConstructs = getPatterns(rootElement, elementRegistry); + console.log( + "Process contains " + + replacementConstructs.length + + " patterns to replace..." + ); + if (!replacementConstructs || !replacementConstructs.length) { + return { status: "transformed", xml: xml }; + } + console.log(replacementConstructs); + + attachPatternsToSuitableTasks( + rootElement, + elementRegistry, + replacementConstructs, + modeling + ); + + replacementConstructs = getPatterns(rootElement, elementRegistry); + + // Mitigation have to be handled first since cutting inserts tasks after them + // if the general pattern is attached then we add it to the elements to delete + for (let replacementConstruct of replacementConstructs) { + if (replacementConstruct.task.$type === constants.PATTERN) { + const pattern = elementRegistry.get(replacementConstruct.task.id); + patterns.push(pattern); + } + if ( + replacementConstruct.task.$type === constants.READOUT_ERROR_MITIGATION || + replacementConstruct.task.$type === constants.GATE_ERROR_MITIGATION + ) { + let { replaced, flows, pattern } = await replaceMitigationPattern( + replacementConstruct.task, + replacementConstruct.parent, + modeler + ); + allFlow = allFlow.concat(flows); + patterns.push(pattern); + modeling.removeElements(flows); + if (!replaced) { + console.log( + "Replacement of Pattern with Id " + + replacementConstruct.task.id + + " failed. Aborting process!" + ); + return { + status: "failed", + cause: + "Replacement of Pattern with Id " + + replacementConstruct.task.id + + " failed. Aborting process!", + }; + } + } + if ( + constants.WARM_STARTING_PATTERNS.includes(replacementConstruct.task.$type) + ) { + let { replaced, flows, pattern } = await replaceWarmStart( + replacementConstruct.task, + replacementConstruct.parent, + modeler + ); + allFlow = allFlow.concat(flows); + patterns.push(pattern); + modeling.removeElements(flows); + if (!replaced) { + console.log( + "Replacement of Pattern with Id " + + replacementConstruct.task.id + + " failed. Aborting process!" + ); + return { + status: "failed", + cause: + "Replacement of Pattern with Id " + + replacementConstruct.task.id + + " failed. Aborting process!", + }; + } + } + } + + replacementConstructs = replacementConstructs.filter( + (construct) => + construct.task.$type !== constants.READOUT_ERROR_MITIGATION && + construct.task.$type !== constants.GATE_ERROR_MITIGATION && + construct.task.$type !== constants.PATTERN && + !constants.WARM_STARTING_PATTERNS.includes(construct.task.$type) + ); + + let augmentationReplacementConstructs = replacementConstructs.filter( + (construct) => + constants.AUGMENTATION_PATTERNS.includes(construct.task.$type) + ); + + let behaviorReplacementConstructs = replacementConstructs.filter( + (construct) => constants.BEHAVIORAL_PATTERNS.includes(construct.task.$type) + ); + + for (let replacementConstruct of augmentationReplacementConstructs) { + let replacementSuccess = false; + if (replacementConstruct.task.$type === constants.CIRCUIT_CUTTING) { + let { replaced, flows, pattern } = await replaceCuttingPattern( + replacementConstruct.task, + replacementConstruct.parent, + modeler + ); + allFlow = allFlow.concat(flows); + patterns.push(pattern); + modeling.removeElements(flows); + replacementSuccess = replaced; + } + + if (replacementConstruct.task.$type === constants.ERROR_CORRECTION) { + let { replaced, flows, pattern } = await replaceErrorCorrectionPattern( + replacementConstruct.task, + replacementConstruct.parent, + modeler + ); + allFlow = allFlow.concat(flows); + patterns.push(pattern); + replacementSuccess = replaced; + } + + if (!replacementSuccess) { + console.log( + "Replacement of Pattern with Id " + + replacementConstruct.task.id + + " failed. Aborting process!" + ); + return { + status: "failed", + cause: + "Replacement of Pattern with Id " + + replacementConstruct.task.id + + " failed. Aborting process!", + }; + } + } + + let elementsToDelete = patterns.concat(allFlow); + console.log("df"); + console.log(elementsToDelete); + modeling.removeElements(elementsToDelete); + const optimizationCandidates = await findOptimizationCandidates(modeler); + for (let replacementConstruct of behaviorReplacementConstructs) { + let replacementSuccess = false; + if (replacementConstruct.task.$type === constants.ORCHESTRATED_EXECUTION) { + let foundOptimizationCandidate = false; + for (let i = 0; i < optimizationCandidates.length; i++) { + console.log(optimizationCandidates[i].entryPoint); + let elementParent = elementRegistry.get( + optimizationCandidates[i].entryPoint.id + ); + if (elementParent !== undefined) { + let parent = elementParent.parent; + console.log(parent); + + if (parent.id === replacementConstruct.task.attachedToRef.id) { + foundOptimizationCandidate = true; + let attachedPatterns = parent.attachers; + console.log(attachedPatterns); + + // if another behavioral pattern is attached inside the subprocess, then the replacement strategy for this pattern is applied + const foundElement = attachedPatterns.find( + (attachedPattern) => + attachedPattern.type === constants.PRIORITIZED_EXECUTION + ); + if (!foundElement) { + const pattern = elementRegistry.get(replacementConstruct.task.id); + patterns.push(pattern); + console.log("replaced"); + replacementSuccess = true; + } + } + } + } + if (!foundOptimizationCandidate) { + const pattern = elementRegistry.get(replacementConstruct.task.id); + patterns.push(pattern); + replacementSuccess = true; + } + replacementSuccess = true; + } + if (replacementConstruct.task.$type === constants.PRE_DEPLOYED_EXECUTION) { + console.log("Replace pre-deployed execution"); + console.log(replacementConstruct); + let foundOptimizationCandidate = false; + for (let i = 0; i < optimizationCandidates.length; i++) { + console.log(optimizationCandidates[i].entryPoint); + let elementParent = elementRegistry.get( + optimizationCandidates[i].entryPoint.id + ); + if (elementParent !== undefined) { + let parent = elementParent.parent; + if (parent.id === replacementConstruct.task.attachedToRef.id) { + let attachedPatterns = parent.attachers; + console.log(attachedPatterns); + + // if another behavioral pattern is attached inside the subprocess, then the replacement strategy for this pattern is applied + const foundElement = attachedPatterns.find( + (attachedPattern) => + attachedPattern.type === constants.PRIORITIZED_EXECUTION + ); + console.log(foundElement); + if (foundElement) { + optimizationCandidates[i].modeler = modeler; + let programGenerationResult = + await getQiskitRuntimeProgramDeploymentModel( + optimizationCandidates[i], + modeler.config, + getQRMs() + ); + if (programGenerationResult.error !== undefined) { + return { + status: "failed", + cause: + "Replacement of Pattern with Id " + + replacementConstruct.task.id + + " failed. Aborting process!", + }; + } else { + console.log(programGenerationResult); + // only rewrite workflow if the hybrid program generation was successful + if (programGenerationResult.hybridProgramId !== undefined) { + await rewriteWorkflow( + modeler, + optimizationCandidates[i], + getHybridRuntimeProvenance(), + programGenerationResult.hybridProgramId + ); + const pattern = elementRegistry.get( + replacementConstruct.task.id + ); + patterns.push(pattern); + console.log("replaced"); + const prioPattern = elementRegistry.get(foundElement.id); + patterns.push(prioPattern); + replacementSuccess = true; + } + } + } + } + } + } + if (!foundOptimizationCandidate) { + const pattern = elementRegistry.get(replacementConstruct.task.id); + patterns.push(pattern); + replacementSuccess = true; + } + } + if (replacementConstruct.task.$type === constants.PRIORITIZED_EXECUTION) { + console.log("Replace prioritized execution"); + let foundOptimizationCandidate = false; + for (let i = 0; i < optimizationCandidates.length; i++) { + console.log(optimizationCandidates[i].entryPoint); + let elementParent = elementRegistry.get( + optimizationCandidates[i].entryPoint.id + ); + if (elementParent !== undefined) { + let parent = elementParent.parent; + if (parent.id === replacementConstruct.task.attachedToRef.id) { + let attachedPatterns = parent.attachers; + foundOptimizationCandidate = true; + + // if no other behavioral pattern is attached inside the subprocess, then the replacement strategy for this pattern is applied + const foundElement = attachedPatterns.find( + (attachedPattern) => + attachedPattern.type === constants.ORCHESTRATED_EXECUTION + ); + const foundPreElement = attachedPatterns.find( + (attachedPattern) => + attachedPattern.type === constants.PRE_DEPLOYED_EXECUTION + ); + console.log(foundElement); + if (!foundPreElement) { + optimizationCandidates[i].modeler = modeler; + await rewriteWorkflow( + modeler, + optimizationCandidates[i], + getHybridRuntimeProvenance(), + undefined + ); + const pattern = elementRegistry.get(replacementConstruct.task.id); + patterns.push(pattern); + console.log("replaced"); + console.log(pattern); + replacementSuccess = true; + if (foundElement) { + const orchestratedPattern = elementRegistry.get( + foundElement.id + ); + patterns.push(orchestratedPattern); + } + } else { + replacementSuccess = true; + } + } + } + } + if (!foundOptimizationCandidate) { + const pattern = elementRegistry.get(replacementConstruct.task.id); + patterns.push(pattern); + replacementSuccess = true; + } + } + + if (!replacementSuccess) { + console.log( + "Replacement of Pattern with Id " + + replacementConstruct.task.id + + " of type " + + replacementConstruct.task.$type + + " failed. Aborting process!" + ); + return { + status: "failed", + cause: + "Replacement of Pattern with Id " + + replacementConstruct.task.id + + " failed. Aborting process!", + }; + } + } + + elementsToDelete = patterns.concat(allFlow); + console.log(elementsToDelete); + modeling.removeElements(elementsToDelete); + + // layout diagram after successful transformation + layout(modeling, elementRegistry, rootElement); + let updated_xml = await getXml(modeler); + console.log(updated_xml); + return { status: "transformed", xml: updated_xml }; +} + +/** + * Get patterns from process + */ +export function getPatterns(process, elementRegistry) { + // retrieve parent object for later replacement + const processBo = elementRegistry.get(process.id); + const patterns = []; + const flowElements = process.flowElements; + for (let i = 0; i < flowElements.length; i++) { + let flowElement = flowElements[i]; + console.log(flowElement); + if (flowElement.$type && flowElement.$type.startsWith("pattern:")) { + patterns.push({ + task: flowElement, + parent: processBo, + attachedToRef: flowElement.attachedToRef, + }); + } + + // recursively retrieve patterns if subprocess is found + if ( + flowElement.$type && + (flowElement.$type === "bpmn:SubProcess" || + flowElement.$type === quantmeConsts.CIRCUIT_CUTTING_SUBPROCESS || + flowElement.$type === + quantmeConsts.QUANTUM_HARDWARE_SELECTION_SUBPROCESS) + ) { + Array.prototype.push.apply( + patterns, + getPatterns(flowElement, elementRegistry) + ); + } + } + return patterns; +} + +function retrieveFlowElements(flowElements, elementRegistry) { + const children = new Set(); + + flowElements.forEach((flowElement) => { + let element = elementRegistry.get(flowElement.id); + if ( + (element.$type && element.$type === "bpmn:SubProcess") || + (element.type && element.type === "bpmn:SubProcess") + ) { + console.log("searchFlow", element.id); + // Recursively search through subprocess's children or flowElements + let childrenOrFlowElements = element.children; + if (element.children === undefined) { + childrenOrFlowElements = element.flowElements; + } + console.log(childrenOrFlowElements); + if (childrenOrFlowElements) { + childrenOrFlowElements.forEach((child) => { + if (child.id !== undefined) { + children.add(child.id); + } + }); + children.add( + ...retrieveFlowElements(childrenOrFlowElements, elementRegistry) + ); + } + } + }); + flowElements.forEach((child) => { + if (child.id !== undefined) { + children.add(child.id); + } + }); + console.log(children); + return children; +} + +export function attachPatternsToSuitableTasks( + process, + elementRegistry, + patterns, + modeling +) { + let flowElements = process.flowElements; + if (!flowElements) { + flowElements = process.children; + } + + let pattern; + for (let j = 0; j < patterns.length; j++) { + pattern = elementRegistry.get(patterns[j].task.id); + + if (pattern !== undefined) { + console.log("Start with attachment of pattern ", pattern.id); + + // contains all flowElements of the parent and its children + let children = new Set(); + patterns[j].attachedToRef.flowElements.forEach((flowElement) => + children.add(flowElement.id) + ); + + patterns[j].attachedToRef.flowElements.forEach((child) => { + if ( + (child.$type && child.$type === "bpmn:SubProcess") || + (child.type && child.type === "bpmn:SubProcess") + ) { + // Recursively retrieve the subprocess's flowElements + let subProcessFlowElements = retrieveFlowElements( + child.flowElements, + elementRegistry + ); + subProcessFlowElements.forEach((flowElement) => + children.add(flowElement) + ); + } + }); + + children.values().forEach((id) => { + attachPatternsToSuitableConstruct( + elementRegistry.get(id), + pattern.type, + modeling + ); + }); + } + } + + for (let i = 0; i < patterns.length; i++) { + // behavioral patterns are deleted after acting on the optimization candidate + if (!constants.BEHAVIORAL_PATTERNS.includes(patterns[i].task.$type)) { + modeling.removeShape(elementRegistry.get(patterns[i].task.id)); + } + } +} diff --git a/components/bpmn-q/modeler-component/extensions/pattern/replacement/correction/ErrorCorrectionPatternHandler.js b/components/bpmn-q/modeler-component/extensions/pattern/replacement/correction/ErrorCorrectionPatternHandler.js new file mode 100644 index 00000000..e8db3822 --- /dev/null +++ b/components/bpmn-q/modeler-component/extensions/pattern/replacement/correction/ErrorCorrectionPatternHandler.js @@ -0,0 +1,72 @@ +/** + * Copyright (c) 2023 Institute of Architecture of Application Systems - + * University of Stuttgart + * + * This program and the accompanying materials are made available under the + * terms the Apache Software License 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: Apache-2.0 + */ +import * as quantmeConsts from "../../../quantme/Constants"; +/** + * Replace the given error correction pattern by a quantme error correction task + */ +export async function replaceErrorCorrectionPattern( + errorCorrectionPattern, + parent, + modeler +) { + console.log( + "Replace error correction pattern " + + errorCorrectionPattern.id + + "of parent " + + parent.id + ); + let modeling = modeler.get("modeling"); + let elementRegistry = modeler.get("elementRegistry"); + let internHost = elementRegistry.get(errorCorrectionPattern.id).host; + let errorCorrectionTask = modeling.createShape( + { type: quantmeConsts.ERROR_CORRECTION_TASK }, + { x: 50, y: 50 }, + parent, + {} + ); + let startEventBo = elementRegistry.get(errorCorrectionTask.id).businessObject; + startEventBo.name = "Correct Errors"; + let flows = []; + if (internHost.type === quantmeConsts.QUANTUM_CIRCUIT_EXECUTION_TASK) { + internHost.incoming.forEach((element) => { + flows.push(elementRegistry.get(element.id)); + modeling.connect( + elementRegistry.get(element.source.id), + errorCorrectionTask, + { type: "bpmn:SequenceFlow" } + ); + }); + modeling.connect(errorCorrectionTask, internHost, { + type: "bpmn:SequenceFlow", + }); + + console.log(flows); + } + if (internHost.type === quantmeConsts.QUANTUM_CIRCUIT_LOADING_TASK) { + internHost.outgoing.forEach((element) => { + flows.push(element); + modeling.connect( + errorCorrectionTask, + elementRegistry.get(element.target.id), + { type: "bpmn:SequenceFlow" } + ); + }); + for (let i = 0; i < flows.length; i++) { + let flow = elementRegistry.get(flows[i].id); + modeling.removeConnection(flow); + } + modeling.connect(internHost, errorCorrectionTask, { + type: "bpmn:SequenceFlow", + }); + } + const pattern = elementRegistry.get(errorCorrectionPattern.id); + return { replaced: true, flows: flows, pattern: pattern }; +} diff --git a/components/bpmn-q/modeler-component/extensions/pattern/replacement/cutting/CuttingPatternHandler.js b/components/bpmn-q/modeler-component/extensions/pattern/replacement/cutting/CuttingPatternHandler.js new file mode 100644 index 00000000..9989fe9b --- /dev/null +++ b/components/bpmn-q/modeler-component/extensions/pattern/replacement/cutting/CuttingPatternHandler.js @@ -0,0 +1,68 @@ +/** + * Copyright (c) 2023 Institute of Architecture of Application Systems - + * University of Stuttgart + * + * This program and the accompanying materials are made available under the + * terms the Apache Software License 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: Apache-2.0 + */ +import * as quantmeConsts from "../../../quantme/Constants"; +/** + * Replace the cutting pattern by quantme modeling constructs + */ +export async function replaceCuttingPattern(cuttingPattern, parent, modeler) { + console.log( + "Replace cutting pattern " + cuttingPattern.id + "of parent " + parent.id + ); + let modeling = modeler.get("modeling"); + let elementRegistry = modeler.get("elementRegistry"); + + let host = elementRegistry.get(cuttingPattern.id).host; + let elementToConnect = host; + let flows = []; + let cuttingTask = modeling.createShape( + { type: quantmeConsts.CIRCUIT_CUTTING_TASK }, + { x: 50, y: 50 }, + parent, + {} + ); + let startEventBo = elementRegistry.get(cuttingTask.id).businessObject; + startEventBo.name = "Cut Circuit"; + + let resultCombinationTaks = modeling.createShape( + { type: quantmeConsts.CUTTING_RESULT_COMBINATION_TASK }, + { x: 50, y: 50 }, + parent, + {} + ); + startEventBo = elementRegistry.get(resultCombinationTaks.id).businessObject; + startEventBo.name = "Combine Circuits"; + + host.incoming.forEach((element) => { + flows.push(elementRegistry.get(element.id)); + modeling.connect(elementRegistry.get(element.source.id), cuttingTask, { + type: "bpmn:SequenceFlow", + }); + }); + + modeling.connect(cuttingTask, host, { type: "bpmn:SequenceFlow" }); + + host.outgoing.forEach((element) => { + flows.push(elementRegistry.get(element.id)); + modeling.connect( + resultCombinationTaks, + elementRegistry.get(element.target.id), + { type: "bpmn:SequenceFlow" } + ); + }); + elementToConnect = resultCombinationTaks; + + modeling.connect(host, elementToConnect, { + type: "bpmn:SequenceFlow", + }); + + const pattern = elementRegistry.get(cuttingPattern.id); + return { replaced: true, flows: flows, pattern: pattern }; +} diff --git a/components/bpmn-q/modeler-component/extensions/pattern/replacement/mitigation/MitigationPatternHandler.js b/components/bpmn-q/modeler-component/extensions/pattern/replacement/mitigation/MitigationPatternHandler.js new file mode 100644 index 00000000..820da288 --- /dev/null +++ b/components/bpmn-q/modeler-component/extensions/pattern/replacement/mitigation/MitigationPatternHandler.js @@ -0,0 +1,58 @@ +/** + * Copyright (c) 2023 Institute of Architecture of Application Systems - + * University of Stuttgart + * + * This program and the accompanying materials are made available under the + * terms the Apache Software License 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: Apache-2.0 + */ +import * as quantmeConsts from "../../../quantme/Constants"; +import * as consts from "../../Constants"; +/** + * Replace the given mitigation by a quantme modeling construct + */ +export async function replaceMitigationPattern( + mitigationPattern, + parent, + modeler +) { + console.log( + "Replace mitigation pattern " + + mitigationPattern.id + + "of parent " + + parent.id + ); + let modeling = modeler.get("modeling"); + let elementRegistry = modeler.get("elementRegistry"); + let host = elementRegistry.get(mitigationPattern.id).host; + + // currently no replacement for gate error mitigation pattern + if (mitigationPattern.$type === consts.GATE_ERROR_MITIGATION) { + const pattern = elementRegistry.get(mitigationPattern.id); + return { replaced: true, flows: [], pattern: pattern }; + } else { + let internHost = elementRegistry.get(host.id); + let mitigationTask = modeling.createShape( + { type: quantmeConsts.READOUT_ERROR_MITIGATION_TASK }, + { x: 50, y: 50 }, + parent, + {} + ); + let readoutMitigationTaskBo = elementRegistry.get( + mitigationTask.id + ).businessObject; + readoutMitigationTaskBo.name = "Mitigate Errors"; + let outgoingFlows = []; + host.outgoing.forEach((element) => { + outgoingFlows.push(elementRegistry.get(element.id)); + modeling.connect(mitigationTask, elementRegistry.get(element.target.id), { + type: "bpmn:SequenceFlow", + }); + }); + modeling.connect(internHost, mitigationTask, { type: "bpmn:SequenceFlow" }); + const pattern = elementRegistry.get(mitigationPattern.id); + return { replaced: true, flows: outgoingFlows, pattern: pattern }; + } +} diff --git a/components/bpmn-q/modeler-component/extensions/pattern/replacement/warm-start/WarmStartPatternHandler.js b/components/bpmn-q/modeler-component/extensions/pattern/replacement/warm-start/WarmStartPatternHandler.js new file mode 100644 index 00000000..e6d8d34c --- /dev/null +++ b/components/bpmn-q/modeler-component/extensions/pattern/replacement/warm-start/WarmStartPatternHandler.js @@ -0,0 +1,57 @@ +/** + * Copyright (c) 2023 Institute of Architecture of Application Systems - + * University of Stuttgart + * + * This program and the accompanying materials are made available under the + * terms the Apache Software License 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: Apache-2.0 + */ +import * as quantmeConsts from "../../../quantme/Constants"; +/** + * Replace the given warm start pattern by a quantme warm starting task + */ +export async function replaceWarmStart(warmStartPattern, parent, modeler) { + console.log( + "Replace warm start pattern " + + warmStartPattern.id + + "of parent " + + parent.id + ); + let modeling = modeler.get("modeling"); + let elementRegistry = modeler.get("elementRegistry"); + let host = elementRegistry.get(warmStartPattern.id).host; + + let internHost = elementRegistry.get(host.id); + let warmStartTask = modeling.createShape( + { type: quantmeConsts.WARM_STARTING_TASK }, + { x: 50, y: 50 }, + parent, + {} + ); + let warmStartTaskBo = elementRegistry.get(warmStartTask.id).businessObject; + warmStartTaskBo.name = "Warm Start"; + + // remove the prefix + let warmStartPatternName = warmStartPattern.$type.replace("pattern:", ""); + + // first letter to lowerCase + warmStartPatternName = + warmStartPatternName.charAt(0).toLowerCase() + + warmStartPatternName.slice(1); + modeling.updateProperties(warmStartTask, { + warmStartingPattern: warmStartPatternName, + }); + let incomingFlows = []; + host.incoming.forEach((element) => { + incomingFlows.push(elementRegistry.get(element.id)); + modeling.connect(elementRegistry.get(element.source.id), warmStartTask, { + type: "bpmn:SequenceFlow", + }); + }); + modeling.connect(warmStartTask, internHost, { type: "bpmn:SequenceFlow" }); + + const pattern = elementRegistry.get(warmStartPattern.id); + return { replaced: true, flows: incomingFlows, pattern: pattern }; +} diff --git a/components/bpmn-q/modeler-component/extensions/pattern/resources/icons/aoa_icon.png b/components/bpmn-q/modeler-component/extensions/pattern/resources/icons/aoa_icon.png new file mode 100644 index 00000000..307b6b79 Binary files /dev/null and b/components/bpmn-q/modeler-component/extensions/pattern/resources/icons/aoa_icon.png differ diff --git a/components/bpmn-q/modeler-component/extensions/pattern/resources/icons/circuit-cutting-icon.svg b/components/bpmn-q/modeler-component/extensions/pattern/resources/icons/circuit-cutting-icon.svg new file mode 100644 index 00000000..e68666f6 --- /dev/null +++ b/components/bpmn-q/modeler-component/extensions/pattern/resources/icons/circuit-cutting-icon.svg @@ -0,0 +1,247 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/bpmn-q/modeler-component/extensions/pattern/resources/icons/error-correction-icon.png b/components/bpmn-q/modeler-component/extensions/pattern/resources/icons/error-correction-icon.png new file mode 100644 index 00000000..e3239b1e Binary files /dev/null and b/components/bpmn-q/modeler-component/extensions/pattern/resources/icons/error-correction-icon.png differ diff --git a/components/bpmn-q/modeler-component/extensions/pattern/resources/icons/gate_error_mitigation_icon.png b/components/bpmn-q/modeler-component/extensions/pattern/resources/icons/gate_error_mitigation_icon.png new file mode 100644 index 00000000..d260545f Binary files /dev/null and b/components/bpmn-q/modeler-component/extensions/pattern/resources/icons/gate_error_mitigation_icon.png differ diff --git a/components/bpmn-q/modeler-component/extensions/pattern/resources/icons/orchestrated-execution-thin.svg b/components/bpmn-q/modeler-component/extensions/pattern/resources/icons/orchestrated-execution-thin.svg new file mode 100644 index 00000000..eb01c719 --- /dev/null +++ b/components/bpmn-q/modeler-component/extensions/pattern/resources/icons/orchestrated-execution-thin.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/components/bpmn-q/modeler-component/extensions/pattern/resources/icons/pattern-palette.svg b/components/bpmn-q/modeler-component/extensions/pattern/resources/icons/pattern-palette.svg new file mode 100644 index 00000000..682f7281 --- /dev/null +++ b/components/bpmn-q/modeler-component/extensions/pattern/resources/icons/pattern-palette.svg @@ -0,0 +1,247 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/bpmn-q/modeler-component/extensions/pattern/resources/icons/pre-deployed-execution-thin.svg b/components/bpmn-q/modeler-component/extensions/pattern/resources/icons/pre-deployed-execution-thin.svg new file mode 100644 index 00000000..c2ad56c5 --- /dev/null +++ b/components/bpmn-q/modeler-component/extensions/pattern/resources/icons/pre-deployed-execution-thin.svg @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/bpmn-q/modeler-component/extensions/pattern/resources/icons/priortized-execution-thin.svg b/components/bpmn-q/modeler-component/extensions/pattern/resources/icons/priortized-execution-thin.svg new file mode 100644 index 00000000..28478a10 --- /dev/null +++ b/components/bpmn-q/modeler-component/extensions/pattern/resources/icons/priortized-execution-thin.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/components/bpmn-q/modeler-component/extensions/pattern/resources/icons/qaoa_icon.png b/components/bpmn-q/modeler-component/extensions/pattern/resources/icons/qaoa_icon.png new file mode 100644 index 00000000..4e7441aa Binary files /dev/null and b/components/bpmn-q/modeler-component/extensions/pattern/resources/icons/qaoa_icon.png differ diff --git a/components/bpmn-q/modeler-component/extensions/pattern/resources/icons/qke_icon.png b/components/bpmn-q/modeler-component/extensions/pattern/resources/icons/qke_icon.png new file mode 100644 index 00000000..82469919 Binary files /dev/null and b/components/bpmn-q/modeler-component/extensions/pattern/resources/icons/qke_icon.png differ diff --git a/components/bpmn-q/modeler-component/extensions/pattern/resources/icons/qpe_icon.png b/components/bpmn-q/modeler-component/extensions/pattern/resources/icons/qpe_icon.png new file mode 100644 index 00000000..719dc48a Binary files /dev/null and b/components/bpmn-q/modeler-component/extensions/pattern/resources/icons/qpe_icon.png differ diff --git a/components/bpmn-q/modeler-component/extensions/pattern/resources/icons/readout-error-mitigation-icon.png b/components/bpmn-q/modeler-component/extensions/pattern/resources/icons/readout-error-mitigation-icon.png new file mode 100644 index 00000000..752ffeac Binary files /dev/null and b/components/bpmn-q/modeler-component/extensions/pattern/resources/icons/readout-error-mitigation-icon.png differ diff --git a/components/bpmn-q/modeler-component/extensions/pattern/resources/icons/vqa_icon.png b/components/bpmn-q/modeler-component/extensions/pattern/resources/icons/vqa_icon.png new file mode 100644 index 00000000..d7c29835 Binary files /dev/null and b/components/bpmn-q/modeler-component/extensions/pattern/resources/icons/vqa_icon.png differ diff --git a/components/bpmn-q/modeler-component/extensions/pattern/resources/icons/vqe_icon.png b/components/bpmn-q/modeler-component/extensions/pattern/resources/icons/vqe_icon.png new file mode 100644 index 00000000..900bb368 Binary files /dev/null and b/components/bpmn-q/modeler-component/extensions/pattern/resources/icons/vqe_icon.png differ diff --git a/components/bpmn-q/modeler-component/extensions/pattern/resources/icons/warm-start-biased-initial-state-thin.svg b/components/bpmn-q/modeler-component/extensions/pattern/resources/icons/warm-start-biased-initial-state-thin.svg new file mode 100644 index 00000000..c12abcb9 --- /dev/null +++ b/components/bpmn-q/modeler-component/extensions/pattern/resources/icons/warm-start-biased-initial-state-thin.svg @@ -0,0 +1,1201 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/bpmn-q/modeler-component/extensions/pattern/resources/icons/warm-start-chained-optimization-thin.svg b/components/bpmn-q/modeler-component/extensions/pattern/resources/icons/warm-start-chained-optimization-thin.svg new file mode 100644 index 00000000..a3b38d62 --- /dev/null +++ b/components/bpmn-q/modeler-component/extensions/pattern/resources/icons/warm-start-chained-optimization-thin.svg @@ -0,0 +1,614 @@ + + + + + icon-chained-optimization + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Chained Optimization + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + icon-chained-optimization + + + + diff --git a/components/bpmn-q/modeler-component/extensions/pattern/resources/icons/warm-start-pre-trained-feature-extractor-thin.svg b/components/bpmn-q/modeler-component/extensions/pattern/resources/icons/warm-start-pre-trained-feature-extractor-thin.svg new file mode 100644 index 00000000..886d1516 --- /dev/null +++ b/components/bpmn-q/modeler-component/extensions/pattern/resources/icons/warm-start-pre-trained-feature-extractor-thin.svg @@ -0,0 +1,563 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Pre + + + + + - + + + + + Trained Feature Extractor + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/bpmn-q/modeler-component/extensions/pattern/resources/icons/warm-start-variational-parameter-transfer-thin.svg b/components/bpmn-q/modeler-component/extensions/pattern/resources/icons/warm-start-variational-parameter-transfer-thin.svg new file mode 100644 index 00000000..3024846b --- /dev/null +++ b/components/bpmn-q/modeler-component/extensions/pattern/resources/icons/warm-start-variational-parameter-transfer-thin.svg @@ -0,0 +1,568 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Parameter Transfer + + + + + + + + + + + + + + + + + β + + + + + γ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/bpmn-q/modeler-component/extensions/pattern/resources/pattern4bpmn.json b/components/bpmn-q/modeler-component/extensions/pattern/resources/pattern4bpmn.json new file mode 100644 index 00000000..5528735c --- /dev/null +++ b/components/bpmn-q/modeler-component/extensions/pattern/resources/pattern4bpmn.json @@ -0,0 +1,107 @@ +{ + "name": "Pattern", + "uri": "https://github.com/UST-QuAntiL/Pattern", + "prefix": "pattern", + "xml": { + "tagAlias": "lowerCase" + }, + "types": [ + { + "name": "QuantumKernelEstimator", + "superClass": ["bpmn:BoundaryEvent"], + "properties": [] + }, + { + "name": "AlternatingOperatorAnsatz", + "superClass": ["bpmn:BoundaryEvent"], + "properties": [] + }, + { + "name": "QuantumApproximateOptimizationAlgorithm", + "superClass": ["bpmn:BoundaryEvent"], + "properties": [] + }, + { + "name": "QuantumPhaseEstimation", + "superClass": ["bpmn:BoundaryEvent"], + "properties": [] + }, + { + "name": "VariationalQuantumAlgorithm", + "superClass": ["bpmn:BoundaryEvent"], + "properties": [] + }, + { + "name": "VariationalQuantumEigensolver", + "superClass": ["bpmn:BoundaryEvent"], + "properties": [] + }, + { + "name": "OrchestratedExecution", + "superClass": ["bpmn:BoundaryEvent"], + "properties": [] + }, + { + "name": "PredeployedExecution", + "superClass": ["bpmn:BoundaryEvent"], + "properties": [] + }, + { + "name": "PrioritizedExecution", + "superClass": ["bpmn:BoundaryEvent"], + "properties": [] + }, + { + "name": "ErrorCorrection", + "superClass": ["bpmn:BoundaryEvent"], + "properties": [] + }, + { + "name": "GateErrorMitigation", + "superClass": ["bpmn:BoundaryEvent"], + "properties": [] + }, + { + "name": "ReadoutErrorMitigation", + "superClass": ["bpmn:BoundaryEvent"], + "properties": [] + }, + { + "name": "WarmStart", + "superClass": ["bpmn:BoundaryEvent"], + "properties": [] + }, + { + "name": "BiasedInitialState", + "superClass": ["bpmn:BoundaryEvent"], + "properties": [] + }, + { + "name": "ChainedOptimization", + "superClass": ["bpmn:BoundaryEvent"], + "properties": [] + }, + { + "name": "VariationalParameterTransfer", + "superClass": ["bpmn:BoundaryEvent"], + "properties": [] + }, + { + "name": "PreTrainedFeatureExtractor", + "superClass": ["bpmn:BoundaryEvent"], + "properties": [] + }, + { + "name": "CircuitCutting", + "superClass": ["bpmn:BoundaryEvent"], + "properties": [] + }, + { + "name": "Pattern", + "superClass": ["bpmn:BoundaryEvent"], + "properties": [] + } + ], + "enumerations": [], + "associations": [] +} diff --git a/components/bpmn-q/modeler-component/extensions/pattern/resources/styling/pattern.css b/components/bpmn-q/modeler-component/extensions/pattern/resources/styling/pattern.css index 8bf5b3e7..39d43db5 100644 --- a/components/bpmn-q/modeler-component/extensions/pattern/resources/styling/pattern.css +++ b/components/bpmn-q/modeler-component/extensions/pattern/resources/styling/pattern.css @@ -9,6 +9,8 @@ background-repeat: no-repeat; display: inline-block; float: left; + padding: 4px 6px; + margin-top: -1px; } .actions-column { @@ -104,3 +106,167 @@ display: inline-block; float: left; } + +.qwm .bpmn-pattern-orchestrated-execution-icon:before { + content: ""; + height: 15px; + background-size: contain; + background-image: url("../icons/orchestrated-execution-thin.svg"); + background-repeat: no-repeat; + display: inline-block; +} + +.qwm .bpmn-pattern-pre-deployed-execution-icon:before { + content: ""; + height: 15px; + background-size: contain; + background-image: url("../icons/pre-deployed-execution-thin.svg"); + background-repeat: no-repeat; + display: inline-block; +} + +.qwm .bpmn-pattern-prioritized-execution-icon:before { + content: ""; + height: 15px; + background-size: contain; + background-image: url("../icons/priortized-execution-thin.svg"); + background-repeat: no-repeat; + display: inline-block; +} + +.qwm-popup-menu-more-options .pattern-logo .djs-popup-entry-name { + margin-top: 20px; /* Adjust the margin value as needed */ +} + +.djs-popup-results .djs-popup-group .entry[title="Patterns"] .djs-popup-label { + margin-top: 1px; /* Adjust the value as per your requirements */ +} + +.qwm-pattern-icon:before { + content: ""; + width: 10px; + height: 10px; + background-size: contain; + background-image: url("../icons/pattern-palette.svg"); + background-repeat: no-repeat; + display: inline-block; + margin-top: 10px; + padding: 11px 8px 11px 10px; + outline: none; +} + +.qwm-pattern-icon:hover { + filter: invert(0.5) sepia(1) hue-rotate(165deg) saturate(4) brightness(1); +} + +.qwm .bpmn-pattern-error-correction-icon:before { + content: ""; + height: 15px; + background-size: contain; + background-image: url("../icons/error-correction-icon.png"); + background-repeat: no-repeat; + display: inline-block; +} + +.qwm .bpmn-pattern-circuit-cutting-icon:before { + content: ""; + height: 15px; + background-size: contain; + background-image: url("../icons/circuit-cutting-icon.svg"); + background-repeat: no-repeat; + display: inline-block; +} + +.qwm .bpmn-pattern-circuit-cutting-icon:before { + content: ""; + height: 15px; + background-size: contain; + background-image: url("../icons/circuit-cutting-icon.svg"); + background-repeat: no-repeat; + display: inline-block; +} + +.qwm .bpmn-pattern-gate-error-mitigation-icon:before { + content: ""; + height: 15px; + background-size: contain; + background-image: url("../icons/gate_error_mitigation_icon.png"); + background-repeat: no-repeat; + display: inline-block; +} + +.qwm .bpmn-pattern-gate-readout-error-mitigation-icon:before { + content: ""; + height: 15px; + background-size: contain; + background-image: url("../icons/readout-error-mitigation-icon.png"); + background-repeat: no-repeat; + display: inline-block; +} + +.qwm .bpmn-pattern-biased-initial-state-icon:before { + content: ""; + height: 15px; + background-size: contain; + background-image: url("../icons/warm-start-biased-initial-state-thin.svg"); + background-repeat: no-repeat; + display: inline-block; +} + +.qwm .bpmn-pattern-variational-parameter-transfer-icon:before { + content: ""; + height: 15px; + background-size: contain; + background-image: url("../icons/warm-start-variational-parameter-transfer-thin.svg"); + background-repeat: no-repeat; + display: inline-block; +} + +.qwm .bpmn-pattern-pre-trained-feature-extractor-icon:before { + content: ""; + height: 15px; + background-size: contain; + background-image: url("../icons/warm-start-pre-trained-feature-extractor-thin.svg"); + background-repeat: no-repeat; + display: inline-block; +} + +.qwm .bpmn-pattern-chained-optimization-icon:before { + content: ""; + height: 15px; + background-size: contain; + background-image: url("../icons/warm-start-chained-optimization-thin.svg"); + background-repeat: no-repeat; + display: inline-block; +} + +.progress-bar-modal { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.5); + display: flex; + justify-content: center; + align-items: center; + z-index: 1000; +} + +.progress-bar-container { + width: 200px; + background: #fff; + padding: 10px; + border-radius: 5px; + box-shadow: 0 0 10px rgba(0, 0, 0, 0.2); +} + +.progress-bar { + height: 20px; + background-color: #3498db; + transition: width 0.5s ease-in-out; +} + +.stop-animation { + animation: none; +} diff --git a/components/bpmn-q/modeler-component/extensions/pattern/ui/pattern-selection/PatternModal.js b/components/bpmn-q/modeler-component/extensions/pattern/ui/pattern-selection/PatternModal.js index c506fd1e..a4c7485e 100644 --- a/components/bpmn-q/modeler-component/extensions/pattern/ui/pattern-selection/PatternModal.js +++ b/components/bpmn-q/modeler-component/extensions/pattern/ui/pattern-selection/PatternModal.js @@ -16,9 +16,9 @@ const Title = Modal.Title || (({ children }) =>

{children}

); const Body = Modal.Body || (({ children }) =>
{children}
); const Footer = Modal.Footer || (({ children }) =>
{children}
); -export default function PatternModal({ onClose }) { +export default function PatternModal({ onClose, onCancel }) { return ( - + Pattern Selection @@ -53,7 +53,7 @@ export default function PatternModal({ onClose }) { diff --git a/components/bpmn-q/modeler-component/extensions/pattern/ui/pattern-selection/PatternOverviewModal.js b/components/bpmn-q/modeler-component/extensions/pattern/ui/pattern-selection/PatternOverviewModal.js index 750c438a..c41fdce8 100644 --- a/components/bpmn-q/modeler-component/extensions/pattern/ui/pattern-selection/PatternOverviewModal.js +++ b/components/bpmn-q/modeler-component/extensions/pattern/ui/pattern-selection/PatternOverviewModal.js @@ -17,22 +17,27 @@ const Title = Modal.Title || (({ children }) =>

{children}

); const Body = Modal.Body || (({ children }) =>
{children}
); const Footer = Modal.Footer || (({ children }) =>
{children}
); -export default function PatternOverviewModal({ onClose, responseData }) { +export default function PatternOverviewModal({ + onClose, + element, + responseData, +}) { const [buttonSelectedPatterns, setButtonSelectedPatterns] = useState({}); - const [isAlgorithmicPatternModalOpen, setAlgorithmicPatternModalOpen] = + const [isAlgorithmPatternModalOpen, setAlgorithmPatternModalOpen] = useState(false); const [dynamicRows, setDynamicRows] = useState([]); const [editRow, setEditRow] = useState(null); // State to store the row being edited const [editRowData, setEditRowData] = useState(null); - const openAlgorithmicPatternModal = () => { - setAlgorithmicPatternModalOpen(true); + const openAlgorithmPatternModal = () => { + setAlgorithmPatternModalOpen(true); }; - const closeAlgorithmicPatternModal = () => { - setAlgorithmicPatternModalOpen(false); + const closeAlgorithmPatternModal = () => { + setAlgorithmPatternModalOpen(false); }; - const selectAlgorithmicPattern = useCallback( + + const selectAlgorithmPattern = useCallback( (selectedPattern) => { if (editRow !== null) { const updatedRows = [...dynamicRows]; @@ -59,7 +64,7 @@ export default function PatternOverviewModal({ onClose, responseData }) { [newButtonLabel]: [], }); } - closeAlgorithmicPatternModal(); + closeAlgorithmPatternModal(); }, [buttonSelectedPatterns, dynamicRows, editRow] ); @@ -87,6 +92,7 @@ export default function PatternOverviewModal({ onClose, responseData }) { const deleteRow = (index) => { const updatedRows = [...dynamicRows]; updatedRows.splice(index, 1); + resetData(); setDynamicRows(updatedRows); }; @@ -94,9 +100,30 @@ export default function PatternOverviewModal({ onClose, responseData }) { const rowToEdit = dynamicRows[index]; setEditRowData(rowToEdit); setEditRow(index); - openAlgorithmicPatternModal(); + openAlgorithmPatternModal(); }; + const disableButton = () => { + if (element !== undefined) { + console.log(element); + if (element.algorithmPattern !== undefined) { + return true; + } + return false; + } + if (responseData === null) { + return true; + } + return false; + }; + + const resetData = () => { + setButtonSelectedPatterns({}); + setAlgorithmPatternModalOpen(false); + setDynamicRows([]); + setEditRow(null); // State to store the row being edited + setEditRowData(null); + }; return ( Pattern Selection @@ -106,17 +133,17 @@ export default function PatternOverviewModal({ onClose, responseData }) { Selected Patterns{" "} - {isAlgorithmicPatternModalOpen && ( + {isAlgorithmPatternModalOpen && ( )} @@ -211,7 +238,9 @@ export default function PatternOverviewModal({ onClose, responseData }) { diff --git a/components/bpmn-q/modeler-component/extensions/pattern/ui/pattern-selection/PatternSelectionModal.js b/components/bpmn-q/modeler-component/extensions/pattern/ui/pattern-selection/PatternSelectionModal.js index 7b8aeb64..83a1d063 100644 --- a/components/bpmn-q/modeler-component/extensions/pattern/ui/pattern-selection/PatternSelectionModal.js +++ b/components/bpmn-q/modeler-component/extensions/pattern/ui/pattern-selection/PatternSelectionModal.js @@ -15,8 +15,10 @@ import { PATTERN_BEHAVIORAL, PATTERN_ALGORITHM, PATTERN_AUGMENTATION, + PATTERN_MITIGATION, + PATTERN_BEHAVIORAL_EXCLUSIVE, } from "../../Constants"; -import { getModeler } from "../../../../editor/ModelerHandler"; +import { getPatternAtlasUIEndpoint } from "../../framework-config/config-manager"; const Title = Modal.Title || (({ children }) =>

{children}

); const Body = Modal.Body || (({ children }) =>
{children}
); @@ -33,24 +35,115 @@ export default function PatternSelectionModal({ const [selectedBehavioralPatterns, setSelectedBehavioralPatterns] = useState( [] ); + const [ + selectedBehavioralExclusivePattern, + setSelectedBehavioralExclusivePattern, + ] = useState(null); + const [ + selectedBehavioralExclusivePatternRadioButton, + setSelectedBehavioralExclusivePatternRadioButton, + ] = useState(false); const [selectedAugmentationPatterns, setSelectedAugmentationPatterns] = useState([]); + const [selectedMitigatedPattern, setSelectedMitigitationPatterns] = + useState(null); + const [ + selectedMitigatedCombinedPattern, + setSelectedMitigitationCombinedPattern, + ] = useState([]); + const [ + selectedErrorMitigatedPatternRadioButton, + setSelectedErrorMitigatedPatternRadioButton, + ] = useState(false); const [errorMessage, setErrorMessage] = useState(""); useEffect(() => { if (initialSelectedPattern) { setSelectedAlgorithmPattern(initialSelectedPattern.algorithmPattern); - setSelectedBehavioralPatterns(initialSelectedPattern.behavioralPattern); + const behavioralPattern = initialSelectedPattern.behavioralPattern.find( + (element) => element.name !== "Prioritized Execution" + ); + + if (behavioralPattern) { + setSelectedBehavioralExclusivePattern(behavioralPattern); + setSelectedBehavioralExclusivePatternRadioButton(true); + } + const updatedBehavioralPatterns = + initialSelectedPattern.behavioralPattern.filter( + (element) => element.name === "Prioritized Execution" + ); + + setSelectedBehavioralPatterns(updatedBehavioralPatterns); + console.log(initialSelectedPattern.augmentationPattern); + const mitigationErrorPatterns = + initialSelectedPattern.augmentationPattern.filter( + (pattern) => + pattern.name === "Readout Error Mitigation" || + pattern.name === "Gate Error Mitigation" || + pattern.name === "Error Correction" + ); + if (mitigationErrorPatterns.length > 1) { + setSelectedMitigitationCombinedPattern(mitigationErrorPatterns); + setSelectedErrorMitigatedPatternRadioButton(true); + } else { + setSelectedMitigitationPatterns(mitigationErrorPatterns[0]); + setSelectedErrorMitigatedPatternRadioButton(true); + } setSelectedAugmentationPatterns( initialSelectedPattern.augmentationPattern ); + + const selectedMitigationIds = mitigationErrorPatterns.flatMap((pattern) => + pattern.id ? [pattern.id] : [] + ); + + const selectedCombinedMitigationIds = + selectedMitigatedCombinedPattern.flatMap((pattern) => + pattern.id ? [pattern.id] : [] + ); + + const updatedAugmentationPatterns = + initialSelectedPattern.augmentationPattern.filter( + (pattern) => + !selectedMitigationIds.includes(pattern.id) && + !selectedCombinedMitigationIds.includes(pattern.id) + ); + + setSelectedAugmentationPatterns(updatedAugmentationPatterns); } }, [initialSelectedPattern]); + const handleClick = (category) => { + if (category === PATTERN_BEHAVIORAL_EXCLUSIVE) { + if (selectedBehavioralExclusivePatternRadioButton) { + setSelectedBehavioralExclusivePattern(null); + } + setSelectedBehavioralExclusivePatternRadioButton( + !selectedBehavioralExclusivePatternRadioButton + ); + } else if (category === PATTERN_MITIGATION) { + if (selectedErrorMitigatedPatternRadioButton) { + setSelectedMitigitationPatterns(null); + } + setSelectedErrorMitigatedPatternRadioButton( + !selectedErrorMitigatedPatternRadioButton + ); + } else if (category === "combined") { + if (selectedErrorMitigatedPatternRadioButton) { + setSelectedMitigitationCombinedPattern([]); + } + setSelectedErrorMitigatedPatternRadioButton( + !selectedErrorMitigatedPatternRadioButton + ); + } + }; + const handlePatternSelection = (pattern, category) => { if (category === PATTERN_ALGORITHM) { setSelectedAlgorithmPattern(pattern); } else if (category === PATTERN_BEHAVIORAL) { + console.log(pattern); + console.log(selectedBehavioralPatterns); setSelectedBehavioralPatterns((prevSelected) => { if (prevSelected.includes(pattern)) { return prevSelected.filter((selected) => selected !== pattern); @@ -58,7 +151,12 @@ export default function PatternSelectionModal({ return [...prevSelected, pattern]; } }); + console.log(selectedBehavioralPatterns); + } else if (category === PATTERN_BEHAVIORAL_EXCLUSIVE) { + setSelectedBehavioralExclusivePattern(pattern); + setSelectedBehavioralExclusivePatternRadioButton(true); } else if (category === PATTERN_AUGMENTATION) { + console.log("add augmentation"); setSelectedAugmentationPatterns((prevSelected) => { if (prevSelected.includes(pattern)) { return prevSelected.filter((selected) => selected !== pattern); @@ -66,15 +164,64 @@ export default function PatternSelectionModal({ return [...prevSelected, pattern]; } }); + } else if (category === PATTERN_MITIGATION) { + setSelectedMitigitationPatterns(pattern); + handleMitigationCombinedSelection([]); + setSelectedErrorMitigatedPatternRadioButton(true); + } + }; + + const handleMitigationCombinedSelection = (patterns) => { + console.log("add combined"); + console.log(selectedMitigatedCombinedPattern); + console.log(patterns.length === 0); + if (selectedMitigatedCombinedPattern.length > 0) { + console.log("remove"); + setSelectedMitigitationCombinedPattern([]); + } else if (patterns.length === 0) { + console.log("empty"); + setSelectedMitigitationCombinedPattern([]); + } else { + console.log("add both"); + setSelectedMitigitationPatterns(null); + setSelectedMitigitationCombinedPattern(patterns); + setSelectedErrorMitigatedPatternRadioButton(true); } }; const handleConfirmSelection = () => { if (selectedAlgorithmPattern) { + let combinedAugmentationPatterns = selectedAugmentationPatterns; + if (selectedBehavioralExclusivePattern) { + selectedBehavioralPatterns.push(selectedBehavioralExclusivePattern); + } + console.log(selectedAugmentationPatterns); + if ( + selectedMitigatedPattern && + !selectedAugmentationPatterns.some( + (pattern) => pattern.id === selectedMitigatedPattern.id + ) + ) { + console.log("push"); + selectedAugmentationPatterns.push(selectedMitigatedPattern); + } + console.log(selectedMitigatedCombinedPattern); + if (selectedMitigatedCombinedPattern.length > 0) { + console.log("concat"); + combinedAugmentationPatterns = selectedAugmentationPatterns.concat( + selectedMitigatedCombinedPattern.filter( + (pattern) => + !selectedAugmentationPatterns.some( + (existingPattern) => existingPattern.id === pattern.id + ) + ) + ); + } + console.log(selectedAugmentationPatterns); const selectedPatterns = { algorithm: selectedAlgorithmPattern, behavioral: selectedBehavioralPatterns, - augmentation: selectedAugmentationPatterns, + augmentation: combinedAugmentationPatterns, }; onSelectPattern(selectedPatterns); onClose(); @@ -94,11 +241,28 @@ export default function PatternSelectionModal({ const behavioralPatterns = patterns.filter( (pattern) => pattern.tags && pattern.tags.includes(PATTERN_BEHAVIORAL) ); + const mitigationErrorPatterns = patterns.filter( + (pattern) => + pattern.name === "Readout Error Mitigation" || + pattern.name === "Gate Error Mitigation" || + pattern.name === "Error Correction" + ); + + const mitigationPatterns = patterns.filter( + (pattern) => + pattern.name === "Readout Error Mitigation" || + pattern.name === "Gate Error Mitigation" + ); const augmentationPatterns = patterns.filter( - (pattern) => pattern.tags && pattern.tags.includes(PATTERN_AUGMENTATION) + (pattern) => + pattern.tags && + pattern.tags.includes(PATTERN_AUGMENTATION) && + !mitigationErrorPatterns.some( + (mitigationPattern) => mitigationPattern.id === pattern.id + ) ); - const patternAtlasUIEndpoint = getModeler().config.patternAtlasUIEndpoint; + const patternAtlasUIEndpoint = getPatternAtlasUIEndpoint(); return ( Patterns @@ -203,13 +367,35 @@ export default function PatternSelectionModal({ /> - - handlePatternSelection(pattern, PATTERN_BEHAVIORAL) - } - /> + {pattern.name !== "Prioritized Execution" ? ( + + handlePatternSelection( + pattern, + PATTERN_BEHAVIORAL_EXCLUSIVE + ) + } + onClick={() => + handleClick(PATTERN_BEHAVIORAL_EXCLUSIVE) + } + /> + ) : ( + + handlePatternSelection(pattern, PATTERN_BEHAVIORAL) + } + /> + )} ))} @@ -270,6 +456,116 @@ export default function PatternSelectionModal({ ))} +

Mitigation & Error Correction Patterns

+ + + + + + + + + + + + + + + {mitigationErrorPatterns.map((pattern) => ( + + + + + + ))} + + + + + + +
NameIconSelect
+ + {pattern.name} + + + {pattern.name} + + + handlePatternSelection(pattern, PATTERN_MITIGATION) + } + onClick={() => handleClick(PATTERN_MITIGATION)} + /> +
+ + Gate & Readout Error Mitigation + + + {mitigationPatterns[0].name} + {mitigationPatterns[1].name} + + { + handleMitigationCombinedSelection([ + mitigationPatterns[0], + mitigationPatterns[1], + ]); + }} + onClick={() => handleClick("combined")} + /> +